<commit_before>//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    options.go
//: details: vFlow options :: configuration and command line
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: 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 (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"

	"gopkg.in/yaml.v2"
)

var (
	version    string
	maxWorkers = runtime.NumCPU() * 1e4
)

// Options represents options
type Options struct {
	// global options
	Verbose    bool   `yaml:"verbose"`
	LogFile    string `yaml:"log-file"`
	PIDFile    string `yaml:"pid-file"`
	DynWorkers bool   `yaml:"dynamic-workers"`
	Logger     *log.Logger
	version    bool

	// stats options
	StatsEnabled  bool   `yaml:"stats-enabled"`
	StatsHTTPAddr string `yaml:"stats-http-addr"`
	StatsHTTPPort string `yaml:"stats-http-port"`

	// sFlow options
	SFlowEnabled bool `yaml:"sflow-enabled"`
	SFlowPort    int  `yaml:"sflow-port"`
	SFlowUDPSize int  `yaml:"sflow-udp-size"`
	SFlowWorkers int  `yaml:"sflow-workers"`

	// IPFIX options
	IPFIXEnabled       bool   `yaml:"ipfix-enabled"`
	IPFIXRPCEnabled    bool   `yaml:"ipfix-rpc-enabled"`
	IPFIXPort          int    `yaml:"ipfix-port"`
	IPFIXUDPSize       int    `yaml:"ipfix-udp-size"`
	IPFIXWorkers       int    `yaml:"ipfix-workers"`
	IPFIXMirrorAddr    string `yaml:"ipfix-mirror-addr"`
	IPFIXMirrorPort    int    `yaml:"ipfix-mirror-port"`
	IPFIXMirrorWorkers int    `yaml:"ipfix-mirror-workers"`
	IPFIXTplCacheFile  string `yaml:"ipfix-tpl-cache-file"`

	// producer
	MQName       string `yaml:"mq-name"`
	MQConfigFile string `yaml:"mq-config-file"`
}

func init() {
	if version == "" {
		version = "unknown"
	}
}

// NewOptions constructs new options
func NewOptions() *Options {
	return &Options{
		Verbose:    false,
		version:    false,
		DynWorkers: true,
		PIDFile:    "/var/run/vflow.pid",
		Logger:     log.New(os.Stderr, "[vflow] ", log.Ldate|log.Ltime),

		StatsEnabled:  true,
		StatsHTTPPort: "8081",
		StatsHTTPAddr: "",

		SFlowEnabled: true,
		SFlowPort:    6343,
		SFlowUDPSize: 1500,
		SFlowWorkers: 200,

		IPFIXEnabled:       true,
		IPFIXRPCEnabled:    true,
		IPFIXPort:          4739,
		IPFIXUDPSize:       1500,
		IPFIXWorkers:       200,
		IPFIXMirrorAddr:    "",
		IPFIXMirrorPort:    4172,
		IPFIXMirrorWorkers: 5,
		IPFIXTplCacheFile:  "/tmp/vflow.templates",

		MQName:       "kafka",
		MQConfigFile: "/usr/local/vflow/etc/kafka.conf",
	}
}

// GetOptions gets options through cmd and file
func GetOptions() *Options {
	opts := NewOptions()

	opts.vFlowFlagSet()
	opts.vFlowVersion()

	if opts.LogFile != "" {
		f, err := os.OpenFile(opts.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			opts.Logger.Println(err)
		} else {
			opts.Logger.SetOutput(f)
		}
	}

	if ok := opts.vFlowIsRunning(); ok {
		opts.Logger.Fatal("the vFlow already is running!")
	}

	opts.vFlowPIDWrite()

	return opts
}

func (opts Options) vFlowPIDWrite() {
	f, err := os.OpenFile(opts.PIDFile, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		opts.Logger.Println(err)
		return
	}

	_, err = fmt.Fprintf(f, "%d", os.Getpid())
	if err != nil {
		opts.Logger.Println(err)
	}
}

func (opts Options) vFlowIsRunning() bool {
	b, err := ioutil.ReadFile(opts.PIDFile)
	if err != nil {
		return false
	}

	cmd := exec.Command("kill", "-0", string(b))
	_, err = cmd.Output()
	if err != nil {
		return false
	}

	return true
}

func (opts Options) vFlowVersion() {
	if opts.version {
		fmt.Printf("vFlow version: %s\n", version)
		os.Exit(0)
	}
}

func (opts *Options) vFlowFlagSet() {

	var config string

	flag.StringVar(&config, "config", "/usr/local/vflow/etc/vflow.conf", "path to config file")

	vFlowLoadCfg(config, opts)

	// global options
	flag.BoolVar(&opts.Verbose, "verbose", opts.Verbose, "enable/disable verbose logging")
	flag.BoolVar(&opts.DynWorkers, "dynamic-workers", opts.DynWorkers, "enable/disable dynamic workers")
	flag.BoolVar(&opts.version, "version", opts.version, "show version")
	flag.StringVar(&opts.LogFile, "log-file", opts.LogFile, "log file name")
	flag.StringVar(&opts.PIDFile, "pid-file", opts.PIDFile, "pid file name")

	// stats options
	flag.BoolVar(&opts.StatsEnabled, "stats-enabled", opts.StatsEnabled, "enable/disable stats listener")
	flag.StringVar(&opts.StatsHTTPPort, "stats-http-port", opts.StatsHTTPPort, "stats port listener")
	flag.StringVar(&opts.StatsHTTPAddr, "stats-http-addr", opts.StatsHTTPAddr, "stats bind address listener")

	// sflow options
	flag.BoolVar(&opts.SFlowEnabled, "sflow-enabled", opts.SFlowEnabled, "enable/disable sflow listener")
	flag.IntVar(&opts.SFlowPort, "sflow-port", opts.SFlowPort, "sflow port number")
	flag.IntVar(&opts.SFlowUDPSize, "sflow-max-udp-size", opts.SFlowUDPSize, "sflow maximum UDP size")
	flag.IntVar(&opts.SFlowWorkers, "sflow-workers", opts.SFlowWorkers, "sflow workers number")

	// ipfix options
	flag.BoolVar(&opts.IPFIXEnabled, "ipfix-enabled", opts.IPFIXEnabled, "enable/disable IPFIX listener")
	flag.BoolVar(&opts.IPFIXRPCEnabled, "ipfix-rpc-enabled", opts.IPFIXRPCEnabled, "enable/disable RPC IPFIX")
	flag.IntVar(&opts.IPFIXPort, "ipfix-port", opts.IPFIXPort, "IPFIX port number")
	flag.IntVar(&opts.IPFIXUDPSize, "ipfix-max-udp-size", opts.IPFIXUDPSize, "IPFIX maximum UDP size")
	flag.IntVar(&opts.IPFIXWorkers, "ipfix-workers", opts.IPFIXWorkers, "IPFIX workers number")
	flag.StringVar(&opts.IPFIXTplCacheFile, "ipfix-tpl-cache-file", opts.IPFIXTplCacheFile, "IPFIX template cache file")
	flag.StringVar(&opts.IPFIXMirrorAddr, "ipfix-mirror-addr", opts.IPFIXMirrorAddr, "IPFIX mirror destination address")
	flag.IntVar(&opts.IPFIXMirrorPort, "ipfix-mirror-port", opts.IPFIXMirrorPort, "IPFIX mirror destination port number")
	flag.IntVar(&opts.IPFIXMirrorWorkers, "ipfix-mirror-workers", opts.IPFIXMirrorWorkers, "IPFIX mirror workers number")

	// producer options
	flag.StringVar(&opts.MQName, "mqueue", opts.MQName, "producer message queue name")
	flag.StringVar(&opts.MQConfigFile, "mqueue-conf", opts.MQConfigFile, "producer message queue configuration file")

	flag.Usage = func() {
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, `
    Example:
	# set workers
	vflow -sflow-workers 15 -ipfix-workers 20

	# set 3rd party ipfix collector
	vflow -ipfix-mirror-addr 192.168.1.10 -ipfix-mirror-port 4319

	# enaable verbose logging
	vflow -verbose=true

	# for more information
	https://github.com/VerizonDigital/vflow/blob/master/docs/config.md

    `)

	}

	flag.Parse()
}

func vFlowLoadCfg(f string, opts *Options) {
	b, err := ioutil.ReadFile(f)
	if err != nil {
		opts.Logger.Println(err)
		return
	}
	err = yaml.Unmarshal(b, opts)
	if err != nil {
		opts.Logger.Println(err)
	}
}
<commit_msg>add few netflow options<commit_after>//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    options.go
//: details: vFlow options :: configuration and command line
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: 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 (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"

	"gopkg.in/yaml.v2"
)

var (
	version    string
	maxWorkers = runtime.NumCPU() * 1e4
)

// Options represents options
type Options struct {
	// global options
	Verbose    bool   `yaml:"verbose"`
	LogFile    string `yaml:"log-file"`
	PIDFile    string `yaml:"pid-file"`
	DynWorkers bool   `yaml:"dynamic-workers"`
	Logger     *log.Logger
	version    bool

	// stats options
	StatsEnabled  bool   `yaml:"stats-enabled"`
	StatsHTTPAddr string `yaml:"stats-http-addr"`
	StatsHTTPPort string `yaml:"stats-http-port"`

	// sFlow options
	SFlowEnabled bool `yaml:"sflow-enabled"`
	SFlowPort    int  `yaml:"sflow-port"`
	SFlowUDPSize int  `yaml:"sflow-udp-size"`
	SFlowWorkers int  `yaml:"sflow-workers"`

	// IPFIX options
	IPFIXEnabled       bool   `yaml:"ipfix-enabled"`
	IPFIXRPCEnabled    bool   `yaml:"ipfix-rpc-enabled"`
	IPFIXPort          int    `yaml:"ipfix-port"`
	IPFIXUDPSize       int    `yaml:"ipfix-udp-size"`
	IPFIXWorkers       int    `yaml:"ipfix-workers"`
	IPFIXMirrorAddr    string `yaml:"ipfix-mirror-addr"`
	IPFIXMirrorPort    int    `yaml:"ipfix-mirror-port"`
	IPFIXMirrorWorkers int    `yaml:"ipfix-mirror-workers"`
	IPFIXTplCacheFile  string `yaml:"ipfix-tpl-cache-file"`

	// Netflow
	NetflowEnabled bool `yaml:"netflow-enabled"`
	NetflowPort    int  `yaml:"netflow-port"`
	NetflowWorkers int  `yaml:"netflow-workers"`

	// producer
	MQName       string `yaml:"mq-name"`
	MQConfigFile string `yaml:"mq-config-file"`
}

func init() {
	if version == "" {
		version = "unknown"
	}
}

// NewOptions constructs new options
func NewOptions() *Options {
	return &Options{
		Verbose:    false,
		version:    false,
		DynWorkers: true,
		PIDFile:    "/var/run/vflow.pid",
		Logger:     log.New(os.Stderr, "[vflow] ", log.Ldate|log.Ltime),

		StatsEnabled:  true,
		StatsHTTPPort: "8081",
		StatsHTTPAddr: "",

		SFlowEnabled: true,
		SFlowPort:    6343,
		SFlowUDPSize: 1500,
		SFlowWorkers: 200,

		IPFIXEnabled:       true,
		IPFIXRPCEnabled:    true,
		IPFIXPort:          4739,
		IPFIXUDPSize:       1500,
		IPFIXWorkers:       200,
		IPFIXMirrorAddr:    "",
		IPFIXMirrorPort:    4172,
		IPFIXMirrorWorkers: 5,
		IPFIXTplCacheFile:  "/tmp/vflow.templates",

		NetflowEnabled: false,
		NetflowPort:    4729,
		NetflowWorkers: 50,

		MQName:       "kafka",
		MQConfigFile: "/usr/local/vflow/etc/kafka.conf",
	}
}

// GetOptions gets options through cmd and file
func GetOptions() *Options {
	opts := NewOptions()

	opts.vFlowFlagSet()
	opts.vFlowVersion()

	if opts.LogFile != "" {
		f, err := os.OpenFile(opts.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			opts.Logger.Println(err)
		} else {
			opts.Logger.SetOutput(f)
		}
	}

	if ok := opts.vFlowIsRunning(); ok {
		opts.Logger.Fatal("the vFlow already is running!")
	}

	opts.vFlowPIDWrite()

	return opts
}

func (opts Options) vFlowPIDWrite() {
	f, err := os.OpenFile(opts.PIDFile, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		opts.Logger.Println(err)
		return
	}

	_, err = fmt.Fprintf(f, "%d", os.Getpid())
	if err != nil {
		opts.Logger.Println(err)
	}
}

func (opts Options) vFlowIsRunning() bool {
	b, err := ioutil.ReadFile(opts.PIDFile)
	if err != nil {
		return false
	}

	cmd := exec.Command("kill", "-0", string(b))
	_, err = cmd.Output()
	if err != nil {
		return false
	}

	return true
}

func (opts Options) vFlowVersion() {
	if opts.version {
		fmt.Printf("vFlow version: %s\n", version)
		os.Exit(0)
	}
}

func (opts *Options) vFlowFlagSet() {

	var config string

	flag.StringVar(&config, "config", "/usr/local/vflow/etc/vflow.conf", "path to config file")

	vFlowLoadCfg(config, opts)

	// global options
	flag.BoolVar(&opts.Verbose, "verbose", opts.Verbose, "enable/disable verbose logging")
	flag.BoolVar(&opts.DynWorkers, "dynamic-workers", opts.DynWorkers, "enable/disable dynamic workers")
	flag.BoolVar(&opts.version, "version", opts.version, "show version")
	flag.StringVar(&opts.LogFile, "log-file", opts.LogFile, "log file name")
	flag.StringVar(&opts.PIDFile, "pid-file", opts.PIDFile, "pid file name")

	// stats options
	flag.BoolVar(&opts.StatsEnabled, "stats-enabled", opts.StatsEnabled, "enable/disable stats listener")
	flag.StringVar(&opts.StatsHTTPPort, "stats-http-port", opts.StatsHTTPPort, "stats port listener")
	flag.StringVar(&opts.StatsHTTPAddr, "stats-http-addr", opts.StatsHTTPAddr, "stats bind address listener")

	// sflow options
	flag.BoolVar(&opts.SFlowEnabled, "sflow-enabled", opts.SFlowEnabled, "enable/disable sflow listener")
	flag.IntVar(&opts.SFlowPort, "sflow-port", opts.SFlowPort, "sflow port number")
	flag.IntVar(&opts.SFlowUDPSize, "sflow-max-udp-size", opts.SFlowUDPSize, "sflow maximum UDP size")
	flag.IntVar(&opts.SFlowWorkers, "sflow-workers", opts.SFlowWorkers, "sflow workers number")

	// ipfix options
	flag.BoolVar(&opts.IPFIXEnabled, "ipfix-enabled", opts.IPFIXEnabled, "enable/disable IPFIX listener")
	flag.BoolVar(&opts.IPFIXRPCEnabled, "ipfix-rpc-enabled", opts.IPFIXRPCEnabled, "enable/disable RPC IPFIX")
	flag.IntVar(&opts.IPFIXPort, "ipfix-port", opts.IPFIXPort, "IPFIX port number")
	flag.IntVar(&opts.IPFIXUDPSize, "ipfix-max-udp-size", opts.IPFIXUDPSize, "IPFIX maximum UDP size")
	flag.IntVar(&opts.IPFIXWorkers, "ipfix-workers", opts.IPFIXWorkers, "IPFIX workers number")
	flag.StringVar(&opts.IPFIXTplCacheFile, "ipfix-tpl-cache-file", opts.IPFIXTplCacheFile, "IPFIX template cache file")
	flag.StringVar(&opts.IPFIXMirrorAddr, "ipfix-mirror-addr", opts.IPFIXMirrorAddr, "IPFIX mirror destination address")
	flag.IntVar(&opts.IPFIXMirrorPort, "ipfix-mirror-port", opts.IPFIXMirrorPort, "IPFIX mirror destination port number")
	flag.IntVar(&opts.IPFIXMirrorWorkers, "ipfix-mirror-workers", opts.IPFIXMirrorWorkers, "IPFIX mirror workers number")

	// producer options
	flag.StringVar(&opts.MQName, "mqueue", opts.MQName, "producer message queue name")
	flag.StringVar(&opts.MQConfigFile, "mqueue-conf", opts.MQConfigFile, "producer message queue configuration file")

	flag.Usage = func() {
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, `
    Example:
	# set workers
	vflow -sflow-workers 15 -ipfix-workers 20

	# set 3rd party ipfix collector
	vflow -ipfix-mirror-addr 192.168.1.10 -ipfix-mirror-port 4319

	# enaable verbose logging
	vflow -verbose=true

	# for more information
	https://github.com/VerizonDigital/vflow/blob/master/docs/config.md

    `)

	}

	flag.Parse()
}

func vFlowLoadCfg(f string, opts *Options) {
	b, err := ioutil.ReadFile(f)
	if err != nil {
		opts.Logger.Println(err)
		return
	}
	err = yaml.Unmarshal(b, opts)
	if err != nil {
		opts.Logger.Println(err)
	}
}
<|endoftext|>


<commit_before>/* gobtcaddr v1.0
 * vsergeev
 * https://github.com/vsergeev/gobtcaddr
 * MIT Licensed
 */

package btckey

import (
	"bytes"
	"code.google.com/p/go.crypto/ripemd160"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"math/big"
	"strings"
)

/******************************************************************************/
/* Bitcoin Keypair Generation */
/******************************************************************************/

// PublicKey represents a Bitcoin public key.
type PublicKey struct {
	X, Y *big.Int
}

// PrivateKey represents a Bitcoin private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

// derive derives a Bitcoin public key from a Bitcoin private key.
func (priv *PrivateKey) derive() (pub *PublicKey, err error) {
	/* See SEC2 pg.9 http://www.secg.org/collateral/sec2_final.pdf */

	/* secp256k1 elliptic curve parameters */
	var curve = &EllipticCurve{}
	curve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
	curve.A, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000000", 16)
	curve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
	curve.G.X, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
	curve.G.Y, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
	curve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
	curve.H, _ = new(big.Int).SetString("01", 16)

	/* Derive public key from Q = d*G */
	Q := curve.PointScalarMultiply(priv.D, curve.G)

	/* Check that Q is on the curve */
	if !curve.IsOnCurve(Q) {
		return nil, fmt.Errorf("Catastrophic math logic failure.")
	}

	priv.X = Q.X
	priv.Y = Q.Y

	return &priv.PublicKey, nil
}

// GenerateKey generates a public and private key pair.
func GenerateKey() (priv PrivateKey, err error) {
	/* See SEC2 pg.9 http://www.secg.org/collateral/sec2_final.pdf */

	/* secp256k1 elliptic curve parameters */
	var curve = &EllipticCurve{}
	curve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
	curve.A, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000000", 16)
	curve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
	curve.G.X, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
	curve.G.Y, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
	curve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
	curve.H, _ = new(big.Int).SetString("01", 16)

	/* See SEC1 pg.23 http://www.secg.org/collateral/sec1_final.pdf */

	/* Select private key d randomly from [1, n) */

	/* Random integer uniformly selected from [0, n-1) range */
	d, err := rand.Int(rand.Reader, new(big.Int).Sub(curve.N, big.NewInt(1)))
	if err != nil {
		return priv, fmt.Errorf("Generating random private key.")
	}
	/* Add one to shift d to [1, n) range */
	d.Add(d, big.NewInt(1))

	priv.D = d

	/* Derive public key from private key */
	_, err = priv.derive()
	if err != nil {
		return priv, err
	}

	return priv, nil
}

/******************************************************************************/
/* Bitcoin Public and Private Key Export Mechanics */
/******************************************************************************/

// b58encode encodes a bytes slice b into a base-58 encoded string.
func b58encode(b []byte) (s string) {
	/* See https://en.bitcoin.it/wiki/Base58Check_encoding */

	const BITCOIN_BASE58_TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

	/* Convert big endian bytes to big int */
	x := new(big.Int).SetBytes(b)

	/* Initialize */
	r := new(big.Int)
	m := big.NewInt(58)
	zero := big.NewInt(0)
	s = ""

	/* Convert big int to string */
	for x.Cmp(zero) > 0 {
		/* x, r = (x / 58, x % 58) */
		x.QuoRem(x, m, r)
		/* Prepend ASCII character */
		s = string(BITCOIN_BASE58_TABLE[r.Int64()]) + s
	}

	return s
}

// b58decode decodes a base-58 encoded string into a bytes slice b.
func b58decode(s string) (b []byte, err error) {
	/* See https://en.bitcoin.it/wiki/Base58Check_encoding */

	const BITCOIN_BASE58_TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

	/* Initialize */
	x := big.NewInt(0)
	m := big.NewInt(58)

	/* Convert string to big int */
	for i := 0; i < len(s); i++ {
		b58index := strings.IndexByte(BITCOIN_BASE58_TABLE, s[i])
		if b58index == -1 {
			return nil, fmt.Errorf("Invalid base-58 character encountered: '%c', index %d.", s[i], i)
		}
		b58value := big.NewInt(int64(b58index))
		x.Mul(x, m)
		x.Add(x, b58value)
	}

	/* Convert big int to big endian bytes */
	b = x.Bytes()

	return b, nil
}

// b58checkencode encodes version ver and bytes slice b into a base-58 check encoded string.
func b58checkencode(ver uint8, b []byte) (s string) {
	/* Prepend version */
	bcpy := append([]byte{ver}, b...)

	/* Create a new SHA256 context */
	sha256_h := sha256.New()

	/* SHA256 Hash #1 */
	sha256_h.Reset()
	sha256_h.Write(bcpy)
	hash1 := sha256_h.Sum(nil)

	/* SHA256 Hash #2 */
	sha256_h.Reset()
	sha256_h.Write(hash1)
	hash2 := sha256_h.Sum(nil)

	/* Append first four bytes of hash */
	bcpy = append(bcpy, hash2[0:4]...)

	/* Encode base58 string */
	s = b58encode(bcpy)

	/* For number of leading 0's in bytes, prepend 1 */
	for _, v := range bcpy {
		if v != 0 {
			break
		}
		s = "1" + s
	}

	return s
}

// b58checkdecode decodes base-58 check encoded string s into a version ver and bytes slice b.
func b58checkdecode(s string) (ver uint8, b []byte, err error) {
	/* Decode base58 string */
	b, err = b58decode(s)
	if err != nil {
		return 0, nil, err
	}

	/* Add leading zero bytes */
	for i := 0; i < len(s); i++ {
		if s[i] != '1' {
			break
		}
		b = append([]byte{0x00}, b...)
	}

	/* Verify checksum */
	if len(b) < 5 {
		return 0, nil, fmt.Errorf("Invalid base-58 check string: missing checksum.")
	}

	/* Create a new SHA256 context */
	sha256_h := sha256.New()

	/* SHA256 Hash #1 */
	sha256_h.Reset()
	sha256_h.Write(b[:len(b)-4])
	hash1 := sha256_h.Sum(nil)

	/* SHA256 Hash #2 */
	sha256_h.Reset()
	sha256_h.Write(hash1)
	hash2 := sha256_h.Sum(nil)

	/* Compare checksum */
	if bytes.Compare(hash2[0:4], b[len(b)-4:]) != 0 {
		return 0, nil, fmt.Errorf("Invalid base-58 check string: invalid checksum.")
	}

	/* Strip checksum bytes */
	b = b[:len(b)-4]

	/* Extract and strip version */
	ver = b[0]
	b = b[1:]

	return ver, b, nil
}

// CheckWIF checks that string wif is a valid Wallet Import File string.
func CheckWIF(wif string) (valid bool, err error) {
	/* Base58 Check Decode the WIF string */
	ver, priv_bytes, err := b58checkdecode(wif)
	if err != nil {
		return false, err
	}

	/* Check that the version byte is 0x80 */
	if ver != 0x80 {
		return false, fmt.Errorf("Invalid version 0x%02x for WIF, expected 0x80.", ver)
	}

	/* Check that private key byte length is 32 */
	if len(priv_bytes) != 32 {
		return false, fmt.Errorf("Invalid private key bytes length %d, expected 32.", len(priv_bytes))
	}

	return true, nil
}

// ToBytes converts a Bitcoin private key to a bytes slice.
func (priv *PrivateKey) ToBytes() (b []byte) {
	return priv.D.Bytes()
}

// FromBytes converts a byte slice to a Bitcoin private key.
func (priv *PrivateKey) FromBytes(b []byte) (err error) {
	if len(b) != 32 {
		return fmt.Errorf("Invalid private key bytes length %d, expected 32.", len(b))
	}

	priv.D = new(big.Int).SetBytes(b)

	return nil
}

// ToWIF converts a Bitcoin private key to a Wallet Import Format string.
func (priv *PrivateKey) ToWIF() (wif string) {
	/* See https://en.bitcoin.it/wiki/Wallet_import_format */

	/* Convert the private key to big endian bytes */
	priv_bytes := priv.D.Bytes()

	/* Convert bytes to base-58 check encoded string with version 0x80 */
	wif = b58checkencode(0x80, priv_bytes)

	return wif
}

// ToBytes converts a Bitcoin public key to a bytes slice.
func (pub *PublicKey) ToBytes() (b []byte) {
	return append(pub.X.Bytes(), pub.Y.Bytes()...)
}

// FromBytes converts a byte slice to a Bitcoin public key.
func (pub *PublicKey) FromBytes(b []byte) (err error) {
	if len(b) != 64 {
		return fmt.Errorf("Invalid public key bytes length %d, expected 64.", len(b))
	}

	pub.X = new(big.Int).SetBytes(b[0:32])
	pub.Y = new(big.Int).SetBytes(b[32:64])

	return nil
}

// ToAddress converts a Bitcoin public key to a Bitcoin address string.
func (pub *PublicKey) ToAddress(version uint8) (address string) {
	/* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */

	/* Create a new SHA256 context */
	sha256_h := sha256.New()
	/* Create a new RIPEMD160 Context */
	ripemd160_h := ripemd160.New()

	/* Convert the public key to a byte sequence */
	pub_bytes := append(pub.X.Bytes(), pub.Y.Bytes()...)

	/* Prepend 0x04 */
	pub_bytes = append([]byte{0x04}, pub_bytes...)

	/* SHA256 Hash */
	sha256_h.Reset()
	sha256_h.Write(pub_bytes)
	pub_hash_1 := sha256_h.Sum(nil)

	/* RIPEMD-160 Hash */
	ripemd160_h.Reset()
	ripemd160_h.Write(pub_hash_1)
	pub_hash_2 := ripemd160_h.Sum(nil)

	/* Convert hash bytes to base58 check encoded sequence */
	address = b58checkencode(version, pub_hash_2)

	return address
}
<commit_msg>add static init of secp256k1 curve in btckey package<commit_after>/* gobtcaddr v1.0
 * vsergeev
 * https://github.com/vsergeev/gobtcaddr
 * MIT Licensed
 */

package btckey

import (
	"bytes"
	"code.google.com/p/go.crypto/ripemd160"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"math/big"
	"strings"
)

/******************************************************************************/
/* Bitcoin Keypair Generation */
/******************************************************************************/

var secp256k1 EllipticCurve

func init() {
	/* See SEC2 pg.9 http://www.secg.org/collateral/sec2_final.pdf */
	/* secp256k1 elliptic curve parameters */
	secp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
	secp256k1.A, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000000", 16)
	secp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
	secp256k1.G.X, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
	secp256k1.G.Y, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
	secp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
	secp256k1.H, _ = new(big.Int).SetString("01", 16)
}

// PublicKey represents a Bitcoin public key.
type PublicKey struct {
	X, Y *big.Int
}

// PrivateKey represents a Bitcoin private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

// derive derives a Bitcoin public key from a Bitcoin private key.
func (priv *PrivateKey) derive() (pub *PublicKey, err error) {
	/* See SEC2 pg.9 http://www.secg.org/collateral/sec2_final.pdf */

	/* Derive public key from Q = d*G */
	Q := secp256k1.PointScalarMultiply(priv.D, secp256k1.G)

	/* Check that Q is on the curve */
	if !secp256k1.IsOnCurve(Q) {
		return nil, fmt.Errorf("Catastrophic math logic failure.")
	}

	priv.X = Q.X
	priv.Y = Q.Y

	return &priv.PublicKey, nil
}

// GenerateKey generates a public and private key pair.
func GenerateKey() (priv PrivateKey, err error) {
	/* See SEC1 pg.23 http://www.secg.org/collateral/sec1_final.pdf */

	/* Select private key d randomly from [1, n) */

	/* Random integer uniformly selected from [0, n-1) range */
	d, err := rand.Int(rand.Reader, new(big.Int).Sub(secp256k1.N, big.NewInt(1)))
	if err != nil {
		return priv, fmt.Errorf("Generating random private key.")
	}
	/* Add one to shift d to [1, n) range */
	d.Add(d, big.NewInt(1))

	priv.D = d

	/* Derive public key from private key */
	_, err = priv.derive()
	if err != nil {
		return priv, err
	}

	return priv, nil
}

/******************************************************************************/
/* Bitcoin Public and Private Key Export Mechanics */
/******************************************************************************/

// b58encode encodes a bytes slice b into a base-58 encoded string.
func b58encode(b []byte) (s string) {
	/* See https://en.bitcoin.it/wiki/Base58Check_encoding */

	const BITCOIN_BASE58_TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

	/* Convert big endian bytes to big int */
	x := new(big.Int).SetBytes(b)

	/* Initialize */
	r := new(big.Int)
	m := big.NewInt(58)
	zero := big.NewInt(0)
	s = ""

	/* Convert big int to string */
	for x.Cmp(zero) > 0 {
		/* x, r = (x / 58, x % 58) */
		x.QuoRem(x, m, r)
		/* Prepend ASCII character */
		s = string(BITCOIN_BASE58_TABLE[r.Int64()]) + s
	}

	return s
}

// b58decode decodes a base-58 encoded string into a bytes slice b.
func b58decode(s string) (b []byte, err error) {
	/* See https://en.bitcoin.it/wiki/Base58Check_encoding */

	const BITCOIN_BASE58_TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

	/* Initialize */
	x := big.NewInt(0)
	m := big.NewInt(58)

	/* Convert string to big int */
	for i := 0; i < len(s); i++ {
		b58index := strings.IndexByte(BITCOIN_BASE58_TABLE, s[i])
		if b58index == -1 {
			return nil, fmt.Errorf("Invalid base-58 character encountered: '%c', index %d.", s[i], i)
		}
		b58value := big.NewInt(int64(b58index))
		x.Mul(x, m)
		x.Add(x, b58value)
	}

	/* Convert big int to big endian bytes */
	b = x.Bytes()

	return b, nil
}

// b58checkencode encodes version ver and bytes slice b into a base-58 check encoded string.
func b58checkencode(ver uint8, b []byte) (s string) {
	/* Prepend version */
	bcpy := append([]byte{ver}, b...)

	/* Create a new SHA256 context */
	sha256_h := sha256.New()

	/* SHA256 Hash #1 */
	sha256_h.Reset()
	sha256_h.Write(bcpy)
	hash1 := sha256_h.Sum(nil)

	/* SHA256 Hash #2 */
	sha256_h.Reset()
	sha256_h.Write(hash1)
	hash2 := sha256_h.Sum(nil)

	/* Append first four bytes of hash */
	bcpy = append(bcpy, hash2[0:4]...)

	/* Encode base58 string */
	s = b58encode(bcpy)

	/* For number of leading 0's in bytes, prepend 1 */
	for _, v := range bcpy {
		if v != 0 {
			break
		}
		s = "1" + s
	}

	return s
}

// b58checkdecode decodes base-58 check encoded string s into a version ver and bytes slice b.
func b58checkdecode(s string) (ver uint8, b []byte, err error) {
	/* Decode base58 string */
	b, err = b58decode(s)
	if err != nil {
		return 0, nil, err
	}

	/* Add leading zero bytes */
	for i := 0; i < len(s); i++ {
		if s[i] != '1' {
			break
		}
		b = append([]byte{0x00}, b...)
	}

	/* Verify checksum */
	if len(b) < 5 {
		return 0, nil, fmt.Errorf("Invalid base-58 check string: missing checksum.")
	}

	/* Create a new SHA256 context */
	sha256_h := sha256.New()

	/* SHA256 Hash #1 */
	sha256_h.Reset()
	sha256_h.Write(b[:len(b)-4])
	hash1 := sha256_h.Sum(nil)

	/* SHA256 Hash #2 */
	sha256_h.Reset()
	sha256_h.Write(hash1)
	hash2 := sha256_h.Sum(nil)

	/* Compare checksum */
	if bytes.Compare(hash2[0:4], b[len(b)-4:]) != 0 {
		return 0, nil, fmt.Errorf("Invalid base-58 check string: invalid checksum.")
	}

	/* Strip checksum bytes */
	b = b[:len(b)-4]

	/* Extract and strip version */
	ver = b[0]
	b = b[1:]

	return ver, b, nil
}

// CheckWIF checks that string wif is a valid Wallet Import File string.
func CheckWIF(wif string) (valid bool, err error) {
	/* Base58 Check Decode the WIF string */
	ver, priv_bytes, err := b58checkdecode(wif)
	if err != nil {
		return false, err
	}

	/* Check that the version byte is 0x80 */
	if ver != 0x80 {
		return false, fmt.Errorf("Invalid version 0x%02x for WIF, expected 0x80.", ver)
	}

	/* Check that private key byte length is 32 */
	if len(priv_bytes) != 32 {
		return false, fmt.Errorf("Invalid private key bytes length %d, expected 32.", len(priv_bytes))
	}

	return true, nil
}

// ToBytes converts a Bitcoin private key to a bytes slice.
func (priv *PrivateKey) ToBytes() (b []byte) {
	return priv.D.Bytes()
}

// FromBytes converts a byte slice to a Bitcoin private key.
func (priv *PrivateKey) FromBytes(b []byte) (err error) {
	if len(b) != 32 {
		return fmt.Errorf("Invalid private key bytes length %d, expected 32.", len(b))
	}

	priv.D = new(big.Int).SetBytes(b)

	return nil
}

// ToWIF converts a Bitcoin private key to a Wallet Import Format string.
func (priv *PrivateKey) ToWIF() (wif string) {
	/* See https://en.bitcoin.it/wiki/Wallet_import_format */

	/* Convert the private key to big endian bytes */
	priv_bytes := priv.D.Bytes()

	/* Convert bytes to base-58 check encoded string with version 0x80 */
	wif = b58checkencode(0x80, priv_bytes)

	return wif
}

// ToBytes converts a Bitcoin public key to a bytes slice.
func (pub *PublicKey) ToBytes() (b []byte) {
	return append(pub.X.Bytes(), pub.Y.Bytes()...)
}

// FromBytes converts a byte slice to a Bitcoin public key.
func (pub *PublicKey) FromBytes(b []byte) (err error) {
	if len(b) != 64 {
		return fmt.Errorf("Invalid public key bytes length %d, expected 64.", len(b))
	}

	pub.X = new(big.Int).SetBytes(b[0:32])
	pub.Y = new(big.Int).SetBytes(b[32:64])

	return nil
}

// ToAddress converts a Bitcoin public key to a Bitcoin address string.
func (pub *PublicKey) ToAddress(version uint8) (address string) {
	/* See https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses */

	/* Create a new SHA256 context */
	sha256_h := sha256.New()
	/* Create a new RIPEMD160 Context */
	ripemd160_h := ripemd160.New()

	/* Convert the public key to a byte sequence */
	pub_bytes := append(pub.X.Bytes(), pub.Y.Bytes()...)

	/* Prepend 0x04 */
	pub_bytes = append([]byte{0x04}, pub_bytes...)

	/* SHA256 Hash */
	sha256_h.Reset()
	sha256_h.Write(pub_bytes)
	pub_hash_1 := sha256_h.Sum(nil)

	/* RIPEMD-160 Hash */
	ripemd160_h.Reset()
	ripemd160_h.Write(pub_hash_1)
	pub_hash_2 := ripemd160_h.Sum(nil)

	/* Convert hash bytes to base58 check encoded sequence */
	address = b58checkencode(version, pub_hash_2)

	return address
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd Authors
//
// 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 clientv3 implements the official Go etcd client for v3.
//
// Create client using `clientv3.New`:
//
//	cli, err := clientv3.New(clientv3.Config{
//		Endpoints:   []string{"localhost:2379", "localhost:22379", "localhost:32379"},
//		DialTimeout: 5 * time.Second,
//	})
//	if err != nil {
//		// handle error!
//	}
//	defer cli.Close()
//
// Make sure to close the client after using it. If the client is not closed, the
// connection will have leaky goroutines.
//
// To specify a client request timeout, wrap the context with context.WithTimeout:
//
//	ctx, cancel := context.WithTimeout(context.Background(), timeout)
//	resp, err := kvc.Put(ctx, "sample_key", "sample_value")
//	cancel()
//	if err != nil {
//	    // handle error!
//	}
//	// use the response
//
// The Client has internal state (watchers and leases), so Clients should be reused instead of created as needed.
// Clients are safe for concurrent use by multiple goroutines.
//
// etcd client returns 2 types of errors:
//
//	1. context error: canceled or deadline exceeded.
//	2. gRPC error: see https://github.com/coreos/etcd/blob/master/etcdserver/api/v3rpc/rpctypes/error.go
//
// Here is the example code to handle client errors:
//
//	resp, err := kvc.Put(ctx, "", "")
//	if err != nil {
//		if err == context.Canceled {
//			// ctx is canceled by another routine
//		} else if err == context.DeadlineExceeded {
//			// ctx is attached with a deadline and it exceeded
//		} else if verr, ok := err.(*v3rpc.ErrEmptyKey); ok {
//			// process (verr.Errors)
//		} else {
//			// bad cluster endpoints, which are not etcd servers
//		}
//	}
//
package clientv3
<commit_msg>clientv3: document context timeout error with server-side clock skew<commit_after>// Copyright 2016 The etcd Authors
//
// 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 clientv3 implements the official Go etcd client for v3.
//
// Create client using `clientv3.New`:
//
//	cli, err := clientv3.New(clientv3.Config{
//		Endpoints:   []string{"localhost:2379", "localhost:22379", "localhost:32379"},
//		DialTimeout: 5 * time.Second,
//	})
//	if err != nil {
//		// handle error!
//	}
//	defer cli.Close()
//
// Make sure to close the client after using it. If the client is not closed, the
// connection will have leaky goroutines.
//
// To specify a client request timeout, wrap the context with context.WithTimeout:
//
//	ctx, cancel := context.WithTimeout(context.Background(), timeout)
//	resp, err := kvc.Put(ctx, "sample_key", "sample_value")
//	cancel()
//	if err != nil {
//	    // handle error!
//	}
//	// use the response
//
// The Client has internal state (watchers and leases), so Clients should be reused instead of created as needed.
// Clients are safe for concurrent use by multiple goroutines.
//
// etcd client returns 2 types of errors:
//
//	1. context error: canceled or deadline exceeded.
//	2. gRPC error: see https://github.com/coreos/etcd/blob/master/etcdserver/api/v3rpc/rpctypes/error.go
//
// Here is the example code to handle client errors:
//
//	resp, err := kvc.Put(ctx, "", "")
//	if err != nil {
//		if err == context.Canceled {
//			// ctx is canceled by another routine
//		} else if err == context.DeadlineExceeded {
//			// ctx is attached with a deadline and it exceeded
//		} else if ev, ok := status.FromError(err); ok {
//			code := ev.Code()
//			if code == codes.DeadlineExceeded {
//				// server-side context might have timed-out first (due to clock skew)
//				// while original client-side context is not timed-out yet
//			}
//		} else if verr, ok := err.(*v3rpc.ErrEmptyKey); ok {
//			// process (verr.Errors)
//		} else {
//			// bad cluster endpoints, which are not etcd servers
//		}
//	}
//
package clientv3
<|endoftext|>


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

//go:build unix

package net

import (
	"errors"
	"io/fs"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"
)

var dnsReadConfigTests = []struct {
	name string
	want *dnsConfig
}{
	{
		name: "testdata/resolv.conf",
		want: &dnsConfig{
			servers:    []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"},
			search:     []string{"localdomain."},
			ndots:      5,
			timeout:    10 * time.Second,
			attempts:   3,
			rotate:     true,
			unknownOpt: true, // the "options attempts 3" line
		},
	},
	{
		name: "testdata/domain-resolv.conf",
		want: &dnsConfig{
			servers:  []string{"8.8.8.8:53"},
			search:   []string{"localdomain."},
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
		},
	},
	{
		name: "testdata/search-resolv.conf",
		want: &dnsConfig{
			servers:  []string{"8.8.8.8:53"},
			search:   []string{"test.", "invalid."},
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
		},
	},
	{
		name: "testdata/search-single-dot-resolv.conf",
		want: &dnsConfig{
			servers:  []string{"8.8.8.8:53"},
			search:   []string{},
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
		},
	},
	{
		name: "testdata/empty-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/invalid-ndots-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    0,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/large-ndots-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    15,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/negative-ndots-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    0,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/openbsd-resolv.conf",
		want: &dnsConfig{
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
			lookup:   []string{"file", "bind"},
			servers:  []string{"169.254.169.254:53", "10.240.0.1:53"},
			search:   []string{"c.symbolic-datum-552.internal."},
		},
	},
	{
		name: "testdata/single-request-resolv.conf",
		want: &dnsConfig{
			servers:       defaultNS,
			ndots:         1,
			singleRequest: true,
			timeout:       5 * time.Second,
			attempts:      2,
			search:        []string{"domain.local."},
		},
	},
	{
		name: "testdata/single-request-reopen-resolv.conf",
		want: &dnsConfig{
			servers:       defaultNS,
			ndots:         1,
			singleRequest: true,
			timeout:       5 * time.Second,
			attempts:      2,
			search:        []string{"domain.local."},
		},
	},
	{
		name: "testdata/linux-use-vc-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			useTCP:   true,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/freebsd-usevc-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			useTCP:   true,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/openbsd-tcp-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			useTCP:   true,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
}

func TestDNSReadConfig(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()
	getHostname = func() (string, error) { return "host.domain.local", nil }

	for _, tt := range dnsReadConfigTests {
		if len(tt.want.search) == 0 {
			tt.want.search = append(tt.want.search, dnsDefaultSearch()...)
		}
		conf := dnsReadConfig(tt.name)
		if conf.err != nil {
			t.Fatal(conf.err)
		}
		conf.mtime = time.Time{}
		if !reflect.DeepEqual(conf, tt.want) {
			t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
		}
	}
}

func TestDNSReadMissingFile(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()
	getHostname = func() (string, error) { return "host.domain.local", nil }

	conf := dnsReadConfig("a-nonexistent-file")
	if !os.IsNotExist(conf.err) {
		t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, fs.ErrNotExist)
	}
	conf.err = nil
	want := &dnsConfig{
		servers:  defaultNS,
		ndots:    1,
		timeout:  5 * time.Second,
		attempts: 2,
		search:   []string{"domain.local."},
	}
	if !reflect.DeepEqual(conf, want) {
		t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
	}
}

var dnsDefaultSearchTests = []struct {
	name string
	err  error
	want []string
}{
	{
		name: "host.long.domain.local",
		want: []string{"long.domain.local."},
	},
	{
		name: "host.local",
		want: []string{"local."},
	},
	{
		name: "host",
		want: nil,
	},
	{
		name: "host.domain.local",
		err:  errors.New("errored"),
		want: nil,
	},
	{
		// ensures we don't return []string{""}
		// which causes duplicate lookups
		name: "foo.",
		want: nil,
	},
}

func TestDNSDefaultSearch(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()

	for _, tt := range dnsDefaultSearchTests {
		getHostname = func() (string, error) { return tt.name, tt.err }
		got := dnsDefaultSearch()
		if !reflect.DeepEqual(got, tt.want) {
			t.Errorf("dnsDefaultSearch with hostname %q and error %+v = %q, wanted %q", tt.name, tt.err, got, tt.want)
		}
	}
}

func TestDNSNameLength(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()
	getHostname = func() (string, error) { return "host.domain.local", nil }

	var char63 = ""
	for i := 0; i < 63; i++ {
		char63 += "a"
	}
	longDomain := strings.Repeat(char63+".", 5) + "example"

	for _, tt := range dnsReadConfigTests {
		conf := dnsReadConfig(tt.name)
		if conf.err != nil {
			t.Fatal(conf.err)
		}

		var shortestSuffix int
		for _, suffix := range tt.want.search {
			if shortestSuffix == 0 || len(suffix) < shortestSuffix {
				shortestSuffix = len(suffix)
			}
		}

		// Test a name that will be maximally long when prefixing the shortest
		// suffix (accounting for the intervening dot).
		longName := longDomain[len(longDomain)-254+1+shortestSuffix:]
		if longName[0] == '.' || longName[1] == '.' {
			longName = "aa." + longName[3:]
		}
		for _, fqdn := range conf.nameList(longName) {
			if len(fqdn) > 254 {
				t.Errorf("got %d; want less than or equal to 254", len(fqdn))
			}
		}

		// Now test a name that's too long for suffixing.
		unsuffixable := "a." + longName[1:]
		unsuffixableResults := conf.nameList(unsuffixable)
		if len(unsuffixableResults) != 1 {
			t.Errorf("suffixed names %v; want []", unsuffixableResults[1:])
		}

		// Now test a name that's too long for DNS.
		tooLong := "a." + longDomain
		tooLongResults := conf.nameList(tooLong)
		if tooLongResults != nil {
			t.Errorf("suffixed names %v; want nil", tooLongResults)
		}
	}
}
<commit_msg>net: do not modify shared test variable in TestDNSReadConfig<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build unix

package net

import (
	"errors"
	"io/fs"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"
)

var dnsReadConfigTests = []struct {
	name string
	want *dnsConfig
}{
	{
		name: "testdata/resolv.conf",
		want: &dnsConfig{
			servers:    []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"},
			search:     []string{"localdomain."},
			ndots:      5,
			timeout:    10 * time.Second,
			attempts:   3,
			rotate:     true,
			unknownOpt: true, // the "options attempts 3" line
		},
	},
	{
		name: "testdata/domain-resolv.conf",
		want: &dnsConfig{
			servers:  []string{"8.8.8.8:53"},
			search:   []string{"localdomain."},
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
		},
	},
	{
		name: "testdata/search-resolv.conf",
		want: &dnsConfig{
			servers:  []string{"8.8.8.8:53"},
			search:   []string{"test.", "invalid."},
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
		},
	},
	{
		name: "testdata/search-single-dot-resolv.conf",
		want: &dnsConfig{
			servers:  []string{"8.8.8.8:53"},
			search:   []string{},
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
		},
	},
	{
		name: "testdata/empty-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/invalid-ndots-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    0,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/large-ndots-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    15,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/negative-ndots-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    0,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/openbsd-resolv.conf",
		want: &dnsConfig{
			ndots:    1,
			timeout:  5 * time.Second,
			attempts: 2,
			lookup:   []string{"file", "bind"},
			servers:  []string{"169.254.169.254:53", "10.240.0.1:53"},
			search:   []string{"c.symbolic-datum-552.internal."},
		},
	},
	{
		name: "testdata/single-request-resolv.conf",
		want: &dnsConfig{
			servers:       defaultNS,
			ndots:         1,
			singleRequest: true,
			timeout:       5 * time.Second,
			attempts:      2,
			search:        []string{"domain.local."},
		},
	},
	{
		name: "testdata/single-request-reopen-resolv.conf",
		want: &dnsConfig{
			servers:       defaultNS,
			ndots:         1,
			singleRequest: true,
			timeout:       5 * time.Second,
			attempts:      2,
			search:        []string{"domain.local."},
		},
	},
	{
		name: "testdata/linux-use-vc-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			useTCP:   true,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/freebsd-usevc-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			useTCP:   true,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
	{
		name: "testdata/openbsd-tcp-resolv.conf",
		want: &dnsConfig{
			servers:  defaultNS,
			ndots:    1,
			useTCP:   true,
			timeout:  5 * time.Second,
			attempts: 2,
			search:   []string{"domain.local."},
		},
	},
}

func TestDNSReadConfig(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()
	getHostname = func() (string, error) { return "host.domain.local", nil }

	for _, tt := range dnsReadConfigTests {
		want := *tt.want
		if len(want.search) == 0 {
			want.search = dnsDefaultSearch()
		}
		conf := dnsReadConfig(tt.name)
		if conf.err != nil {
			t.Fatal(conf.err)
		}
		conf.mtime = time.Time{}
		if !reflect.DeepEqual(conf, &want) {
			t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, want)
		}
	}
}

func TestDNSReadMissingFile(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()
	getHostname = func() (string, error) { return "host.domain.local", nil }

	conf := dnsReadConfig("a-nonexistent-file")
	if !os.IsNotExist(conf.err) {
		t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, fs.ErrNotExist)
	}
	conf.err = nil
	want := &dnsConfig{
		servers:  defaultNS,
		ndots:    1,
		timeout:  5 * time.Second,
		attempts: 2,
		search:   []string{"domain.local."},
	}
	if !reflect.DeepEqual(conf, want) {
		t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
	}
}

var dnsDefaultSearchTests = []struct {
	name string
	err  error
	want []string
}{
	{
		name: "host.long.domain.local",
		want: []string{"long.domain.local."},
	},
	{
		name: "host.local",
		want: []string{"local."},
	},
	{
		name: "host",
		want: nil,
	},
	{
		name: "host.domain.local",
		err:  errors.New("errored"),
		want: nil,
	},
	{
		// ensures we don't return []string{""}
		// which causes duplicate lookups
		name: "foo.",
		want: nil,
	},
}

func TestDNSDefaultSearch(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()

	for _, tt := range dnsDefaultSearchTests {
		getHostname = func() (string, error) { return tt.name, tt.err }
		got := dnsDefaultSearch()
		if !reflect.DeepEqual(got, tt.want) {
			t.Errorf("dnsDefaultSearch with hostname %q and error %+v = %q, wanted %q", tt.name, tt.err, got, tt.want)
		}
	}
}

func TestDNSNameLength(t *testing.T) {
	origGetHostname := getHostname
	defer func() { getHostname = origGetHostname }()
	getHostname = func() (string, error) { return "host.domain.local", nil }

	var char63 = ""
	for i := 0; i < 63; i++ {
		char63 += "a"
	}
	longDomain := strings.Repeat(char63+".", 5) + "example"

	for _, tt := range dnsReadConfigTests {
		conf := dnsReadConfig(tt.name)
		if conf.err != nil {
			t.Fatal(conf.err)
		}

		suffixList := tt.want.search
		if len(suffixList) == 0 {
			suffixList = dnsDefaultSearch()
		}

		var shortestSuffix int
		for _, suffix := range suffixList {
			if shortestSuffix == 0 || len(suffix) < shortestSuffix {
				shortestSuffix = len(suffix)
			}
		}

		// Test a name that will be maximally long when prefixing the shortest
		// suffix (accounting for the intervening dot).
		longName := longDomain[len(longDomain)-254+1+shortestSuffix:]
		if longName[0] == '.' || longName[1] == '.' {
			longName = "aa." + longName[3:]
		}
		for _, fqdn := range conf.nameList(longName) {
			if len(fqdn) > 254 {
				t.Errorf("got %d; want less than or equal to 254", len(fqdn))
			}
		}

		// Now test a name that's too long for suffixing.
		unsuffixable := "a." + longName[1:]
		unsuffixableResults := conf.nameList(unsuffixable)
		if len(unsuffixableResults) != 1 {
			t.Errorf("suffixed names %v; want []", unsuffixableResults[1:])
		}

		// Now test a name that's too long for DNS.
		tooLong := "a." + longDomain
		tooLongResults := conf.nameList(tooLong)
		if tooLongResults != nil {
			t.Errorf("suffixed names %v; want nil", tooLongResults)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2013, Cong Ding. 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.
//
// author: Cong Ding <dinggnu@gmail.com>
//
package logging

import (
	"bytes"
	"fmt"
	"time"
)

// watcher watches the logger.queue channel, and writes the logs to output
func (logger *Logger) watcher() {
	var buf bytes.Buffer
	for {
		timeout := time.After(time.Second / 10)

		for i := 0; i < bufSize; i++ {
			select {
			case msg := <-logger.queue:
				fmt.Fprintln(&buf, msg)
			case <-timeout:
				break
			case <-logger.flush:
				break
			case <-logger.quit:
				// If quit signal received, cleans the channel
				// and writes all of them to io.Writer.
				for {
					select {
					case msg := <-logger.queue:
						fmt.Fprintln(&buf, msg)
					case <-logger.flush:
						// do nothing
					default:
						logger.flushBuf(&buf)
						logger.quit <- true
						return
					}
				}
			}

		}
		logger.flushBuf(&buf)
	}
}

// FlushBuf flushes the content of buffer to out and reset the buffer
func (logger *Logger) flushBuf(b *bytes.Buffer) {
	if len(b.Bytes()) > 0 {
		logger.out.Write(b.Bytes())
		b.Reset()
	}
}

// printLog is to print log to file, stdout, or others.
func (logger *Logger) printLog(message string) {
	logger.lock.Lock()
	defer logger.lock.Unlock()
	fmt.Fprintln(logger.out, message)
}

// log records log v... with level `level'.
func (logger *Logger) log(level Level, v ...interface{}) {
	if int(level) >= int(logger.level) {
		message := fmt.Sprint(v...)
		message = logger.genLog(level, message)
		if logger.sync {
			logger.printLog(message)
		} else {
			logger.queue <- message
		}
	}
}

// logf records log v... with level `level'.
func (logger *Logger) logf(level Level, format string, v ...interface{}) {
	if int(level) >= int(logger.level) {
		message := fmt.Sprintf(format, v...)
		message = logger.genLog(level, message)
		if logger.sync {
			logger.printLog(message)
		} else {
			logger.queue <- message
		}
	}
}

// Logln receives log request from the client. The request includes a set of
// variables.
func (logger *Logger) Log(level Level, v ...interface{}) {
	// Don't delete this calling. The calling is used to keep the same
	// calldepth for all the logging functions. The calldepth is used to
	// get runtime information such as line number, function name, etc.
	logger.log(level, v...)
}

// Logf receives log request from the client. The request has a string
// parameter to describe the format of output.
func (logger *Logger) Logf(level Level, format string, v ...interface{}) {
	logger.logf(level, format, v...)
}

// Other quick commands for different level

func (logger *Logger) Critical(v ...interface{}) {
	logger.log(CRITICAL, v...)
}

func (logger *Logger) Fatal(v ...interface{}) {
	logger.log(CRITICAL, v...)
}

func (logger *Logger) Error(v ...interface{}) {
	logger.log(ERROR, v...)
}

func (logger *Logger) Warn(v ...interface{}) {
	logger.log(WARNING, v...)
}

func (logger *Logger) Warning(v ...interface{}) {
	logger.log(WARNING, v...)
}

func (logger *Logger) Info(v ...interface{}) {
	logger.log(INFO, v...)
}

func (logger *Logger) Debug(v ...interface{}) {
	logger.log(DEBUG, v...)
}

func (logger *Logger) Notset(v ...interface{}) {
	logger.log(NOTSET, v...)
}

func (logger *Logger) Criticalf(format string, v ...interface{}) {
	logger.logf(CRITICAL, format, v...)
}

func (logger *Logger) Fatalf(format string, v ...interface{}) {
	logger.logf(CRITICAL, format, v...)
}

func (logger *Logger) Errorf(format string, v ...interface{}) {
	logger.logf(ERROR, format, v...)
}

func (logger *Logger) Warnf(format string, v ...interface{}) {
	logger.logf(WARNING, format, v...)
}

func (logger *Logger) Warningf(format string, v ...interface{}) {
	logger.logf(WARNING, format, v...)
}

func (logger *Logger) Infof(format string, v ...interface{}) {
	logger.logf(INFO, format, v...)
}

func (logger *Logger) Debugf(format string, v ...interface{}) {
	logger.logf(DEBUG, format, v...)
}

func (logger *Logger) Notsetf(format string, v ...interface{}) {
	logger.logf(NOTSET, format, v...)
}
<commit_msg>clean code<commit_after>// Copyright 2013, Cong Ding. 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.
//
// author: Cong Ding <dinggnu@gmail.com>
//
package logging

import (
	"bytes"
	"fmt"
	"time"
)

// watcher watches the logger.queue channel, and writes the logs to output
func (logger *Logger) watcher() {
	var buf bytes.Buffer
	for {
		timeout := time.After(time.Second / 10)

		for i := 0; i < bufSize; i++ {
			select {
			case msg := <-logger.queue:
				fmt.Fprintln(&buf, msg)
			case <-timeout:
				break
			case <-logger.flush:
				break
			case <-logger.quit:
				// If quit signal received, cleans the channel
				// and writes all of them to io.Writer.
				for {
					select {
					case msg := <-logger.queue:
						fmt.Fprintln(&buf, msg)
					case <-logger.flush:
						// do nothing
					default:
						logger.flushBuf(&buf)
						logger.quit <- true
						return
					}
				}
			}

		}
		logger.flushBuf(&buf)
	}
}

// FlushBuf flushes the content of buffer to out and reset the buffer
func (logger *Logger) flushBuf(b *bytes.Buffer) {
	if len(b.Bytes()) > 0 {
		logger.out.Write(b.Bytes())
		b.Reset()
	}
}

// printLog is to print log to file, stdout, or others.
func (logger *Logger) printLog(message string) {
	if logger.sync {
		logger.lock.Lock()
		defer logger.lock.Unlock()
		fmt.Fprintln(logger.out, message)
	} else {
		logger.queue <- message
	}
}

// log records log v... with level `level'.
func (logger *Logger) log(level Level, v ...interface{}) {
	if int(level) >= int(logger.level) {
		message := fmt.Sprint(v...)
		message = logger.genLog(level, message)
		logger.printLog(message)
	}
}

// logf records log v... with level `level'.
func (logger *Logger) logf(level Level, format string, v ...interface{}) {
	if int(level) >= int(logger.level) {
		message := fmt.Sprintf(format, v...)
		message = logger.genLog(level, message)
		logger.printLog(message)
	}
}

// Logln receives log request from the client. The request includes a set of
// variables.
func (logger *Logger) Log(level Level, v ...interface{}) {
	// Don't delete this calling. The calling is used to keep the same
	// calldepth for all the logging functions. The calldepth is used to
	// get runtime information such as line number, function name, etc.
	logger.log(level, v...)
}

// Logf receives log request from the client. The request has a string
// parameter to describe the format of output.
func (logger *Logger) Logf(level Level, format string, v ...interface{}) {
	logger.logf(level, format, v...)
}

// Other quick commands for different level

func (logger *Logger) Critical(v ...interface{}) {
	logger.log(CRITICAL, v...)
}

func (logger *Logger) Fatal(v ...interface{}) {
	logger.log(CRITICAL, v...)
}

func (logger *Logger) Error(v ...interface{}) {
	logger.log(ERROR, v...)
}

func (logger *Logger) Warn(v ...interface{}) {
	logger.log(WARNING, v...)
}

func (logger *Logger) Warning(v ...interface{}) {
	logger.log(WARNING, v...)
}

func (logger *Logger) Info(v ...interface{}) {
	logger.log(INFO, v...)
}

func (logger *Logger) Debug(v ...interface{}) {
	logger.log(DEBUG, v...)
}

func (logger *Logger) Notset(v ...interface{}) {
	logger.log(NOTSET, v...)
}

func (logger *Logger) Criticalf(format string, v ...interface{}) {
	logger.logf(CRITICAL, format, v...)
}

func (logger *Logger) Fatalf(format string, v ...interface{}) {
	logger.logf(CRITICAL, format, v...)
}

func (logger *Logger) Errorf(format string, v ...interface{}) {
	logger.logf(ERROR, format, v...)
}

func (logger *Logger) Warnf(format string, v ...interface{}) {
	logger.logf(WARNING, format, v...)
}

func (logger *Logger) Warningf(format string, v ...interface{}) {
	logger.logf(WARNING, format, v...)
}

func (logger *Logger) Infof(format string, v ...interface{}) {
	logger.logf(INFO, format, v...)
}

func (logger *Logger) Debugf(format string, v ...interface{}) {
	logger.logf(DEBUG, format, v...)
}

func (logger *Logger) Notsetf(format string, v ...interface{}) {
	logger.logf(NOTSET, format, v...)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package buffer provides a thin wrapper around a byte slice. Unlike the
// standard library's bytes.Buffer, it supports a portion of the strconv
// package's zero-allocation formatters.
package buffer

import "strconv"

const _size = 1024 // by default, create 1 KiB buffers

// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so
// the only way to construct one is via a Pool.
type Buffer struct {
	bs   []byte
	pool Pool
}

// AppendByte writes a single byte to the Buffer.
func (b *Buffer) AppendByte(v byte) {
	b.bs = append(b.bs, v)
}

// AppendString writes a string to the Buffer.
func (b *Buffer) AppendString(s string) {
	b.bs = append(b.bs, s...)
}

// AppendInt appends an integer to the underlying buffer (assuming base 10).
func (b *Buffer) AppendInt(i int64) {
	b.bs = strconv.AppendInt(b.bs, i, 10)
}

// AppendUint appends an unsigned integer to the underlying buffer (assuming
// base 10).
func (b *Buffer) AppendUint(i uint64) {
	b.bs = strconv.AppendUint(b.bs, i, 10)
}

// AppendBool appends a bool to the underlying buffer.
func (b *Buffer) AppendBool(v bool) {
	b.bs = strconv.AppendBool(b.bs, v)
}

// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
// or +/- Inf.
func (b *Buffer) AppendFloat(f float64, bitSize int) {
	b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
}

// Len returns the length of the underlying byte slice.
func (b *Buffer) Len() int {
	return len(b.bs)
}

// Cap returns the capacity of the underlying byte slice.
func (b *Buffer) Cap() int {
	return cap(b.bs)
}

// Bytes returns a mutable reference to the underlying byte slice.
func (b *Buffer) Bytes() []byte {
	return b.bs
}

// String returns a string copy of the underlying byte slice.
func (b *Buffer) String() string {
	return string(b.bs)
}

// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
// backing array.
func (b *Buffer) Reset() {
	b.bs = b.bs[:0]
}

// Write implements io.Writer.
func (b *Buffer) Write(bs []byte) (int, error) {
	b.bs = append(b.bs, bs...)
	return len(bs), nil
}

// Free returns the Buffer to its Pool.
//
// Callers must not retain references to the Buffer after calling Free.
func (b *Buffer) Free() {
	b.pool.put(b)
}
<commit_msg>Add missing import comment (#574)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package buffer provides a thin wrapper around a byte slice. Unlike the
// standard library's bytes.Buffer, it supports a portion of the strconv
// package's zero-allocation formatters.
package buffer // import "go.uber.org/zap/buffer"

import "strconv"

const _size = 1024 // by default, create 1 KiB buffers

// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so
// the only way to construct one is via a Pool.
type Buffer struct {
	bs   []byte
	pool Pool
}

// AppendByte writes a single byte to the Buffer.
func (b *Buffer) AppendByte(v byte) {
	b.bs = append(b.bs, v)
}

// AppendString writes a string to the Buffer.
func (b *Buffer) AppendString(s string) {
	b.bs = append(b.bs, s...)
}

// AppendInt appends an integer to the underlying buffer (assuming base 10).
func (b *Buffer) AppendInt(i int64) {
	b.bs = strconv.AppendInt(b.bs, i, 10)
}

// AppendUint appends an unsigned integer to the underlying buffer (assuming
// base 10).
func (b *Buffer) AppendUint(i uint64) {
	b.bs = strconv.AppendUint(b.bs, i, 10)
}

// AppendBool appends a bool to the underlying buffer.
func (b *Buffer) AppendBool(v bool) {
	b.bs = strconv.AppendBool(b.bs, v)
}

// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
// or +/- Inf.
func (b *Buffer) AppendFloat(f float64, bitSize int) {
	b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
}

// Len returns the length of the underlying byte slice.
func (b *Buffer) Len() int {
	return len(b.bs)
}

// Cap returns the capacity of the underlying byte slice.
func (b *Buffer) Cap() int {
	return cap(b.bs)
}

// Bytes returns a mutable reference to the underlying byte slice.
func (b *Buffer) Bytes() []byte {
	return b.bs
}

// String returns a string copy of the underlying byte slice.
func (b *Buffer) String() string {
	return string(b.bs)
}

// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
// backing array.
func (b *Buffer) Reset() {
	b.bs = b.bs[:0]
}

// Write implements io.Writer.
func (b *Buffer) Write(bs []byte) (int, error) {
	b.bs = append(b.bs, bs...)
	return len(bs), nil
}

// Free returns the Buffer to its Pool.
//
// Callers must not retain references to the Buffer after calling Free.
func (b *Buffer) Free() {
	b.pool.put(b)
}
<|endoftext|>


<commit_before>package completion

import (
	"context"
	"errors"
	"fmt"
	"os"
	"strings"
	"time"
	"unicode"

	"github.com/zetamatta/go-box/v2"

	"github.com/zetamatta/nyagos/readline"
	"github.com/zetamatta/nyagos/texts"
)

type Element interface {
	String() string
	Display() string
}

type Element2 [2]string

func (s Element2) String() string  { return s[0] }
func (s Element2) Display() string { return s[1] }

type Element1 string

func (s Element1) String() string  { return string(s) }
func (s Element1) Display() string { return string(s) }

type List struct {
	AllLine string
	List    []Element
	RawWord string // have quotation
	Word    string
	Pos     int
	Field   []string
	Left    string
}

var UseSlash = false

func isTop(s string, indexes [][]int) bool {
	if len(indexes) < 1 {
		return true
	}
	if len(indexes) == 1 {
		return indexes[0][1] == len(s)
	}
	prev := s[indexes[len(indexes)-2][0]:indexes[len(indexes)-2][1]]
	return prev == ";" || prev == "|" || prev == "&"
}

type CustomCompleter interface {
	Complete(context.Context, UncAccess, []string) ([]Element, error)
	String() string
}

type customComplete struct {
	Func func(context.Context, UncAccess, []string) ([]Element, error)
	Name string
}

func (f customComplete) Complete(ctx context.Context, ua UncAccess, args []string) ([]Element, error) {
	return f.Func(ctx, ua, args)
}

func (f customComplete) String() string {
	return f.Name
}

var CustomCompletion = map[string]CustomCompleter{
	"set":      &customComplete{Func: completionSet, Name: "Built-in `set` completer"},
	"cd":       &customComplete{Func: completionCd, Name: "Built-in `cd` completer"},
	"env":      &customComplete{Func: completionEnv, Name: "built-in `env` completer"},
	"which":    &customComplete{Func: completionWhich, Name: "built-in `which` completer"},
	"pushd":    &customComplete{Func: completionCd, Name: "Built-in `pushd` completer"},
	"rmdir":    &customComplete{Func: completionCd, Name: "Built-in `rmdir` completer"},
	"rd":       &customComplete{Func: completionCd, Name: "Built-in `rmdir` completer"},
	"killall":  &customComplete{Func: completionProcessName, Name: "Built-in `kill` completer"},
	"taskkill": &customComplete{Func: completionTaskKill, Name: "Built-in `taskkill` completer"},
}

func listUpComplete(ctx context.Context, this *readline.Buffer) (*List, rune, func(), error) {
	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()

	cmdline_recover := func() {}

	var err error
	rv := &List{
		AllLine: this.String(),
		Left:    this.SubString(0, this.Cursor),
	}

	// environment completion.

	indexes := texts.SplitLikeShell(rv.Left)
	for _, p := range indexes {
		rv.Field = append(rv.Field, rv.Left[p[0]:p[1]])
	}
	rv.List, rv.Pos, err = listUpEnv(rv.AllLine)
	default_delimiter := rune(readline.Delimiters[0])
	if len(rv.List) > 0 && rv.Pos >= 0 && err == nil {
		rv.RawWord = rv.AllLine[rv.Pos:]
		rv.Word = rv.RawWord
		return rv, default_delimiter, cmdline_recover, nil
	}

	// filename or commandname completion
	rv.RawWord, rv.Pos = this.CurrentWord()
	found_delimter := false
	rv.Word = strings.Map(func(c rune) rune {
		if strings.ContainsRune(readline.Delimiters, c) {
			if !found_delimter {
				default_delimiter = c
			}
			found_delimter = true
			return -1
		} else {
			return c
		}
	}, rv.RawWord)

	start := strings.LastIndexAny(rv.Word, ";=") + 1

	replace := false
	if isTop(rv.Left, indexes) {
		rv.List, err = listUpCommands(ctx, rv.Word[start:])
	} else {
		args := make([]string, 0, len(rv.Field))
		for i, w := range rv.Field {
			if indexes[i][0] > this.Cursor {
				break
			}
			args = append(args, strings.Replace(w, `"`, ``, -1))
		}
		if len(indexes) <= 0 || indexes[len(indexes)-1][1] < this.Cursor {
			args = append(args, "")
		}

		ua := UNC_PROMPT
		for {
			if f, ok := CustomCompletion[strings.ToLower(args[0])]; ok {
				rv.List, err = f.Complete(ctx, ua, args)
				if rv.List != nil && err == nil {
					replace = true
				} else {
					rv.List, err = listUpFiles(ctx, ua, rv.Word[start:])
				}
			} else {
				rv.List, err = listUpFiles(ctx, ua, rv.Word[start:])
			}
			if err != ErrAskRetry {
				break
			}
			fmt.Fprintf(this.Out, "\n%s [y/n] ", err.Error())
			this.Out.Flush()
			cmdline_recover = func() {
				fmt.Fprintln(this.Out)
				this.RepaintAll()
				this.Out.Flush()
			}
			key, err1 := this.GetKey()
			if err1 == nil {
				fmt.Fprint(this.Out, key)
				this.Out.Flush()
			}
			if err1 != nil || !strings.EqualFold(key, "y") {
				return rv, default_delimiter, cmdline_recover, errors.New("Canceled.")
			}
			ua = UNC_FORCE
		}
	}
	if err != nil {
		return rv, default_delimiter, cmdline_recover, err
	}
	if !replace {
		for i := 0; i < len(rv.List); i++ {
			rv.List[i] = Element2{
				rv.Word[:start] + rv.List[i].String(),
				rv.List[i].Display(),
			}
		}
	}
	for _, f := range HookToList {
		rv, err = f(ctx, this, rv)
		if err != nil {
			break
		}
	}
	return rv, default_delimiter, cmdline_recover, err
}

func toComplete(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.String()
	}
	return result
}

func toDisplay(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.Display()
	}
	return result
}

func CommonPrefix(list []string) string {
	if len(list) < 1 {
		return ""
	}
	common := list[0]
	var cr, fr *strings.Reader
	for _, f := range list[1:] {
		if cr != nil {
			cr.Reset(common)
		} else {
			cr = strings.NewReader(common)
		}
		if fr != nil {
			fr.Reset(f)
		} else {
			fr = strings.NewReader(f)
		}
		i := 0
		var buffer strings.Builder
		for {
			ch, _, err := cr.ReadRune()
			if err != nil {
				break
			}
			fh, _, err := fr.ReadRune()
			if err != nil || unicode.ToUpper(ch) != unicode.ToUpper(fh) {
				break
			}
			buffer.WriteRune(ch)
			i++
		}
		common = buffer.String()
	}
	return common
}

func endWithRoot(path string) bool {
	return len(path) >= 1 && os.IsPathSeparator(path[len(path)-1])
}

func showCompList(ctx context.Context, this *readline.Buffer, comp *List) {
	if len(comp.List) > 100 {
		fmt.Fprintf(this.Out, "Display all %d possibilities ? [y/n] ", len(comp.List))
		this.Out.Flush()
		key, err := this.GetKey()
		if err == nil {
			fmt.Fprintln(this.Out, key)
			this.Out.Flush()
		}
		if err != nil || !strings.EqualFold(key, "y") {
			this.RepaintAll()
			return
		}
	}
	box.Print(ctx, toDisplay(comp.List), this.Out)
	this.RepaintAll()
}

func KeyFuncCompletion(ctx context.Context, this *readline.Buffer) readline.Result {
	comp, default_delimiter, cmdline_recover, err := listUpComplete(ctx, this)
	if err != nil {
		fmt.Fprintf(this.Out, "\n%s\n", err)
		this.RepaintAll()
		return readline.CONTINUE
	}
	if comp.List == nil || len(comp.List) <= 0 {
		cmdline_recover()
		return readline.CONTINUE
	}

	complete_list := toComplete(comp.List)
	commonStr := CommonPrefix(complete_list)
	quotechar := byte(0)
	if i := strings.IndexAny(comp.Word, readline.Delimiters); i >= 0 {
		quotechar = comp.Word[i]
	} else {
		for _, node := range complete_list {
			if strings.ContainsAny(node, " &!") {
				quotechar = byte(default_delimiter)
				break
			}
		}
	}
	if quotechar != 0 {
		var buffer strings.Builder
		buffer.Grow(len(commonStr) + 3)
		if len(commonStr) >= 2 && commonStr[0] == '~' && (os.IsPathSeparator(commonStr[1]) || unicode.IsLetter(rune(commonStr[1]))) {
			buffer.WriteString(commonStr[:1])
			buffer.WriteByte(quotechar)
			buffer.WriteString(commonStr[1:])
		} else {
			buffer.WriteByte(quotechar)
			buffer.WriteString(commonStr)
		}
		if len(comp.List) == 1 && !endWithRoot(comp.List[0].String()) {
			buffer.WriteByte(quotechar)
		}
		commonStr = buffer.String()
	}
	if len(comp.List) == 1 && !endWithRoot(commonStr) && !strings.HasSuffix(commonStr, `%`) {
		commonStr += " "
	}
	if comp.RawWord == commonStr {
		this.Out.WriteByte('\n')
		if err != nil {
			fmt.Fprintf(this.Out, "(warning) %s\n", err.Error())
		}
		showCompList(nil, this, comp)
		return readline.CONTINUE
	} else {
		cmdline_recover()
	}
	this.ReplaceAndRepaint(comp.Pos, commonStr)
	return readline.CONTINUE
}
<commit_msg>Sub command completion: ignore command name's suffix<commit_after>package completion

import (
	"context"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"
	"unicode"

	"github.com/zetamatta/go-box/v2"

	"github.com/zetamatta/nyagos/readline"
	"github.com/zetamatta/nyagos/texts"
)

type Element interface {
	String() string
	Display() string
}

type Element2 [2]string

func (s Element2) String() string  { return s[0] }
func (s Element2) Display() string { return s[1] }

type Element1 string

func (s Element1) String() string  { return string(s) }
func (s Element1) Display() string { return string(s) }

type List struct {
	AllLine string
	List    []Element
	RawWord string // have quotation
	Word    string
	Pos     int
	Field   []string
	Left    string
}

var UseSlash = false

func isTop(s string, indexes [][]int) bool {
	if len(indexes) < 1 {
		return true
	}
	if len(indexes) == 1 {
		return indexes[0][1] == len(s)
	}
	prev := s[indexes[len(indexes)-2][0]:indexes[len(indexes)-2][1]]
	return prev == ";" || prev == "|" || prev == "&"
}

type CustomCompleter interface {
	Complete(context.Context, UncAccess, []string) ([]Element, error)
	String() string
}

type customComplete struct {
	Func func(context.Context, UncAccess, []string) ([]Element, error)
	Name string
}

func (f customComplete) Complete(ctx context.Context, ua UncAccess, args []string) ([]Element, error) {
	return f.Func(ctx, ua, args)
}

func (f customComplete) String() string {
	return f.Name
}

var CustomCompletion = map[string]CustomCompleter{
	"set":      &customComplete{Func: completionSet, Name: "Built-in `set` completer"},
	"cd":       &customComplete{Func: completionCd, Name: "Built-in `cd` completer"},
	"env":      &customComplete{Func: completionEnv, Name: "built-in `env` completer"},
	"which":    &customComplete{Func: completionWhich, Name: "built-in `which` completer"},
	"pushd":    &customComplete{Func: completionCd, Name: "Built-in `pushd` completer"},
	"rmdir":    &customComplete{Func: completionCd, Name: "Built-in `rmdir` completer"},
	"rd":       &customComplete{Func: completionCd, Name: "Built-in `rmdir` completer"},
	"killall":  &customComplete{Func: completionProcessName, Name: "Built-in `kill` completer"},
	"taskkill": &customComplete{Func: completionTaskKill, Name: "Built-in `taskkill` completer"},
}

func lookupCustomCompletion(s string) (CustomCompleter, bool) {
	s = strings.ToLower(s)
	s = s[:len(s)-len(filepath.Ext(s))]
	f, ok := CustomCompletion[s]
	return f, ok
}

func listUpComplete(ctx context.Context, this *readline.Buffer) (*List, rune, func(), error) {
	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()

	cmdline_recover := func() {}

	var err error
	rv := &List{
		AllLine: this.String(),
		Left:    this.SubString(0, this.Cursor),
	}

	// environment completion.

	indexes := texts.SplitLikeShell(rv.Left)
	for _, p := range indexes {
		rv.Field = append(rv.Field, rv.Left[p[0]:p[1]])
	}
	rv.List, rv.Pos, err = listUpEnv(rv.AllLine)
	default_delimiter := rune(readline.Delimiters[0])
	if len(rv.List) > 0 && rv.Pos >= 0 && err == nil {
		rv.RawWord = rv.AllLine[rv.Pos:]
		rv.Word = rv.RawWord
		return rv, default_delimiter, cmdline_recover, nil
	}

	// filename or commandname completion
	rv.RawWord, rv.Pos = this.CurrentWord()
	found_delimter := false
	rv.Word = strings.Map(func(c rune) rune {
		if strings.ContainsRune(readline.Delimiters, c) {
			if !found_delimter {
				default_delimiter = c
			}
			found_delimter = true
			return -1
		} else {
			return c
		}
	}, rv.RawWord)

	start := strings.LastIndexAny(rv.Word, ";=") + 1

	replace := false
	if isTop(rv.Left, indexes) {
		rv.List, err = listUpCommands(ctx, rv.Word[start:])
	} else {
		args := make([]string, 0, len(rv.Field))
		for i, w := range rv.Field {
			if indexes[i][0] > this.Cursor {
				break
			}
			args = append(args, strings.Replace(w, `"`, ``, -1))
		}
		if len(indexes) <= 0 || indexes[len(indexes)-1][1] < this.Cursor {
			args = append(args, "")
		}

		ua := UNC_PROMPT
		for {
			if f, ok := lookupCustomCompletion(args[0]); ok {
				rv.List, err = f.Complete(ctx, ua, args)
				if rv.List != nil && err == nil {
					replace = true
				} else {
					rv.List, err = listUpFiles(ctx, ua, rv.Word[start:])
				}
			} else {
				rv.List, err = listUpFiles(ctx, ua, rv.Word[start:])
			}
			if err != ErrAskRetry {
				break
			}
			fmt.Fprintf(this.Out, "\n%s [y/n] ", err.Error())
			this.Out.Flush()
			cmdline_recover = func() {
				fmt.Fprintln(this.Out)
				this.RepaintAll()
				this.Out.Flush()
			}
			key, err1 := this.GetKey()
			if err1 == nil {
				fmt.Fprint(this.Out, key)
				this.Out.Flush()
			}
			if err1 != nil || !strings.EqualFold(key, "y") {
				return rv, default_delimiter, cmdline_recover, errors.New("Canceled.")
			}
			ua = UNC_FORCE
		}
	}
	if err != nil {
		return rv, default_delimiter, cmdline_recover, err
	}
	if !replace {
		for i := 0; i < len(rv.List); i++ {
			rv.List[i] = Element2{
				rv.Word[:start] + rv.List[i].String(),
				rv.List[i].Display(),
			}
		}
	}
	for _, f := range HookToList {
		rv, err = f(ctx, this, rv)
		if err != nil {
			break
		}
	}
	return rv, default_delimiter, cmdline_recover, err
}

func toComplete(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.String()
	}
	return result
}

func toDisplay(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.Display()
	}
	return result
}

func CommonPrefix(list []string) string {
	if len(list) < 1 {
		return ""
	}
	common := list[0]
	var cr, fr *strings.Reader
	for _, f := range list[1:] {
		if cr != nil {
			cr.Reset(common)
		} else {
			cr = strings.NewReader(common)
		}
		if fr != nil {
			fr.Reset(f)
		} else {
			fr = strings.NewReader(f)
		}
		i := 0
		var buffer strings.Builder
		for {
			ch, _, err := cr.ReadRune()
			if err != nil {
				break
			}
			fh, _, err := fr.ReadRune()
			if err != nil || unicode.ToUpper(ch) != unicode.ToUpper(fh) {
				break
			}
			buffer.WriteRune(ch)
			i++
		}
		common = buffer.String()
	}
	return common
}

func endWithRoot(path string) bool {
	return len(path) >= 1 && os.IsPathSeparator(path[len(path)-1])
}

func showCompList(ctx context.Context, this *readline.Buffer, comp *List) {
	if len(comp.List) > 100 {
		fmt.Fprintf(this.Out, "Display all %d possibilities ? [y/n] ", len(comp.List))
		this.Out.Flush()
		key, err := this.GetKey()
		if err == nil {
			fmt.Fprintln(this.Out, key)
			this.Out.Flush()
		}
		if err != nil || !strings.EqualFold(key, "y") {
			this.RepaintAll()
			return
		}
	}
	box.Print(ctx, toDisplay(comp.List), this.Out)
	this.RepaintAll()
}

func KeyFuncCompletion(ctx context.Context, this *readline.Buffer) readline.Result {
	comp, default_delimiter, cmdline_recover, err := listUpComplete(ctx, this)
	if err != nil {
		fmt.Fprintf(this.Out, "\n%s\n", err)
		this.RepaintAll()
		return readline.CONTINUE
	}
	if comp.List == nil || len(comp.List) <= 0 {
		cmdline_recover()
		return readline.CONTINUE
	}

	complete_list := toComplete(comp.List)
	commonStr := CommonPrefix(complete_list)
	quotechar := byte(0)
	if i := strings.IndexAny(comp.Word, readline.Delimiters); i >= 0 {
		quotechar = comp.Word[i]
	} else {
		for _, node := range complete_list {
			if strings.ContainsAny(node, " &!") {
				quotechar = byte(default_delimiter)
				break
			}
		}
	}
	if quotechar != 0 {
		var buffer strings.Builder
		buffer.Grow(len(commonStr) + 3)
		if len(commonStr) >= 2 && commonStr[0] == '~' && (os.IsPathSeparator(commonStr[1]) || unicode.IsLetter(rune(commonStr[1]))) {
			buffer.WriteString(commonStr[:1])
			buffer.WriteByte(quotechar)
			buffer.WriteString(commonStr[1:])
		} else {
			buffer.WriteByte(quotechar)
			buffer.WriteString(commonStr)
		}
		if len(comp.List) == 1 && !endWithRoot(comp.List[0].String()) {
			buffer.WriteByte(quotechar)
		}
		commonStr = buffer.String()
	}
	if len(comp.List) == 1 && !endWithRoot(commonStr) && !strings.HasSuffix(commonStr, `%`) {
		commonStr += " "
	}
	if comp.RawWord == commonStr {
		this.Out.WriteByte('\n')
		if err != nil {
			fmt.Fprintf(this.Out, "(warning) %s\n", err.Error())
		}
		showCompList(nil, this, comp)
		return readline.CONTINUE
	} else {
		cmdline_recover()
	}
	this.ReplaceAndRepaint(comp.Pos, commonStr)
	return readline.CONTINUE
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/realglobe-Inc/edo/util"
	"time"
)

type token struct {
	// アクセストークン。
	Id string `json:"id"`
	// 発行したアカウント。
	AccId string `json:"account_id"`
	// 発行先 TA。
	TaId string `json:"ta_id"`
	// 有効期限。
	ExpiDate time.Time `json:"expires"`

	// リフレッシュトークン。
	RefTok string `json:"refresh_token,omitempty"`
	// scope
	Scops *util.StringSet `json:"scope,omitempty"`
}

func newToken(tokId, accId, taId string, expiDate time.Time, scops map[string]bool) *token {
	return &token{
		Id:       tokId,
		AccId:    accId,
		TaId:     taId,
		ExpiDate: expiDate,

		Scops: util.NewStringSet(scops),
	}
}

func (this *token) id() string {
	return this.Id
}

func (this *token) accountId() string {
	return this.AccId
}

func (this *token) taId() string {
	return this.TaId
}

func (this *token) expirationDate() time.Time {
	return this.ExpiDate
}

func (this *token) refreshToken() string {
	return this.RefTok
}

func (this *token) scopes() *util.StringSet {
	return this.Scops
}
<commit_msg>アクセストークン型に許可されたクレームを保持する領域を追加<commit_after>package main

import (
	"github.com/realglobe-Inc/edo/util"
	"time"
)

type token struct {
	// アクセストークン。
	Id string `json:"id"`
	// 発行したアカウント。
	AccId string `json:"account_id"`
	// 発行先 TA。
	TaId string `json:"ta_id"`
	// 有効期限。
	ExpiDate time.Time `json:"expires"`

	// リフレッシュトークン。
	RefTok string `json:"refresh_token,omitempty"`
	// scope
	Scops *util.StringSet `json:"scope,omitempty"`
	// 許可されたクレーム。
	Clms *util.StringSet `json:"claims,omitempty"`
}

func newToken(tokId, accId, taId string, expiDate time.Time, scops map[string]bool) *token {
	return &token{
		Id:       tokId,
		AccId:    accId,
		TaId:     taId,
		ExpiDate: expiDate,

		Scops: util.NewStringSet(scops),
	}
}

func (this *token) id() string {
	return this.Id
}

func (this *token) accountId() string {
	return this.AccId
}

func (this *token) taId() string {
	return this.TaId
}

func (this *token) expirationDate() time.Time {
	return this.ExpiDate
}

func (this *token) refreshToken() string {
	return this.RefTok
}

func (this *token) scopes() *util.StringSet {
	return this.Scops
}

func (this *token) claims() *util.StringSet {
	return this.Clms
}
<|endoftext|>


<commit_before>package vnet

import (
	"fmt"
	"net"
)

type udpConnMap struct {
	portMap map[int][]*UDPConn
}

func newUDPConnMap() *udpConnMap {
	return &udpConnMap{
		portMap: map[int][]*UDPConn{},
	}
}

func (m *udpConnMap) insert(conn *UDPConn) error {
	udpAddr := conn.LocalAddr().(*net.UDPAddr)

	// check if the port has a listener
	conns, ok := m.portMap[udpAddr.Port]
	if ok {
		if udpAddr.IP.IsUnspecified() {
			return fmt.Errorf("address already in use")
		}

		for _, conn := range conns {
			laddr := conn.LocalAddr().(*net.UDPAddr)
			if laddr.IP.IsUnspecified() {
				return fmt.Errorf("address already in use")
			}
			if laddr.IP.Equal(udpAddr.IP) {
				return fmt.Errorf("address already in use")
			}
		}

		conns = append(conns, conn)
	} else {
		conns = []*UDPConn{conn}
	}

	m.portMap[udpAddr.Port] = conns
	return nil
}

func (m *udpConnMap) find(addr net.Addr) (*UDPConn, bool) {
	udpAddr := addr.(*net.UDPAddr)

	if conns, ok := m.portMap[udpAddr.Port]; ok {
		if udpAddr.IP.IsUnspecified() {
			// pick the first one appears in the iteration
			if len(conns) == 0 {
				// This can't happen!
				delete(m.portMap, udpAddr.Port)
				return nil, false
			}
			return conns[0], true
		}

		for _, conn := range conns {
			laddr := conn.LocalAddr().(*net.UDPAddr)
			if laddr.IP.IsUnspecified() {
				return conn, ok
			}

			if laddr.IP.Equal(udpAddr.IP) {
				return conn, true
			}
		}
	}

	return nil, false
}

func (m *udpConnMap) delete(addr net.Addr) error {
	udpAddr := addr.(*net.UDPAddr)

	conns, ok := m.portMap[udpAddr.Port]
	if !ok {
		return fmt.Errorf("no such UDPConn")
	}

	if udpAddr.IP.IsUnspecified() {
		// remove all from this port
		delete(m.portMap, udpAddr.Port)
		return nil
	}

	newConns := []*UDPConn{}

	for _, conn := range conns {
		laddr := conn.LocalAddr().(*net.UDPAddr)
		if laddr.IP.IsUnspecified() {
			// This can't happen!
			return fmt.Errorf("cannot remove an unspecified IP by the specified IP")
		}

		if laddr.IP.Equal(udpAddr.IP) {
			continue
		}

		newConns = append(newConns, conn)
	}

	if len(newConns) == 0 {
		delete(m.portMap, udpAddr.Port)
	} else {
		m.portMap[udpAddr.Port] = newConns
	}

	return nil
}

// size returns the number of UDPConns (UDP listeners)
func (m *udpConnMap) size() int {
	n := 0
	for _, conns := range m.portMap {
		n += len(conns)
	}

	return n
}

// patterns
// * insert 0.0.0.0:1234
// * find 0.0.0.0:1234
// * find 192.168.0.1:1234
//   - find 192.168.0.1:1234
//   - find 0.0.0.0
// * delete 0.0.0.0:1234
// * delete 192.168.0.1:1234
// question
// * insert 192.168.0.1:1234 when 0.0.0.0 already exists => error
// * insert 0.0.0.0 when 192.168.0.1 already exists => error
<commit_msg>Combine if statements per code review feedback<commit_after>package vnet

import (
	"fmt"
	"net"
)

type udpConnMap struct {
	portMap map[int][]*UDPConn
}

func newUDPConnMap() *udpConnMap {
	return &udpConnMap{
		portMap: map[int][]*UDPConn{},
	}
}

func (m *udpConnMap) insert(conn *UDPConn) error {
	udpAddr := conn.LocalAddr().(*net.UDPAddr)

	// check if the port has a listener
	conns, ok := m.portMap[udpAddr.Port]
	if ok {
		if udpAddr.IP.IsUnspecified() {
			return fmt.Errorf("address already in use")
		}

		for _, conn := range conns {
			laddr := conn.LocalAddr().(*net.UDPAddr)
			if laddr.IP.IsUnspecified() || laddr.IP.Equal(udpAddr.IP) {
				return fmt.Errorf("address already in use")
			}
		}

		conns = append(conns, conn)
	} else {
		conns = []*UDPConn{conn}
	}

	m.portMap[udpAddr.Port] = conns
	return nil
}

func (m *udpConnMap) find(addr net.Addr) (*UDPConn, bool) {
	udpAddr := addr.(*net.UDPAddr)

	if conns, ok := m.portMap[udpAddr.Port]; ok {
		if udpAddr.IP.IsUnspecified() {
			// pick the first one appears in the iteration
			if len(conns) == 0 {
				// This can't happen!
				delete(m.portMap, udpAddr.Port)
				return nil, false
			}
			return conns[0], true
		}

		for _, conn := range conns {
			laddr := conn.LocalAddr().(*net.UDPAddr)
			if laddr.IP.IsUnspecified() || laddr.IP.Equal(udpAddr.IP) {
				return conn, ok
			}
		}
	}

	return nil, false
}

func (m *udpConnMap) delete(addr net.Addr) error {
	udpAddr := addr.(*net.UDPAddr)

	conns, ok := m.portMap[udpAddr.Port]
	if !ok {
		return fmt.Errorf("no such UDPConn")
	}

	if udpAddr.IP.IsUnspecified() {
		// remove all from this port
		delete(m.portMap, udpAddr.Port)
		return nil
	}

	newConns := []*UDPConn{}

	for _, conn := range conns {
		laddr := conn.LocalAddr().(*net.UDPAddr)
		if laddr.IP.IsUnspecified() {
			// This can't happen!
			return fmt.Errorf("cannot remove an unspecified IP by the specified IP")
		}

		if laddr.IP.Equal(udpAddr.IP) {
			continue
		}

		newConns = append(newConns, conn)
	}

	if len(newConns) == 0 {
		delete(m.portMap, udpAddr.Port)
	} else {
		m.portMap[udpAddr.Port] = newConns
	}

	return nil
}

// size returns the number of UDPConns (UDP listeners)
func (m *udpConnMap) size() int {
	n := 0
	for _, conns := range m.portMap {
		n += len(conns)
	}

	return n
}

// patterns
// * insert 0.0.0.0:1234
// * find 0.0.0.0:1234
// * find 192.168.0.1:1234
//   - find 192.168.0.1:1234
//   - find 0.0.0.0
// * delete 0.0.0.0:1234
// * delete 192.168.0.1:1234
// question
// * insert 192.168.0.1:1234 when 0.0.0.0 already exists => error
// * insert 0.0.0.0 when 192.168.0.1 already exists => error
<|endoftext|>