<commit_before>package cs

import (
	"fmt"
	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/ecs"
	"net/http"
	"time"
)

type SpotPrice struct {
	InstanceType string `json:"instance_type"`
	PriceLimit   string `json:"price_limit"`
}

type NodePoolInfo struct {
	NodePoolId      string        `json:"nodepool_id"`
	RegionId        common.Region `json:"region_id"`
	Name            string        `json:"name"`
	Created         time.Time     `json:"created"`
	Updated         time.Time     `json:"updated"`
	IsDefault       bool          `json:"is_default"`
	NodePoolType    string        `json:"type"`
	ResourceGroupId string        `json:"resource_group_id"`
}

type ScalingGroup struct {
	VpcId                      string             `json:"vpc_id"`
	VswitchIds                 []string           `json:"vswitch_ids"`
	InstanceTypes              []string           `json:"instance_types"`
	LoginPassword              string             `json:"login_password"`
	KeyPair                    string             `json:"key_pair"`
	SecurityGroupId            string             `json:"security_group_id"`
	SystemDiskCategory         ecs.DiskCategory   `json:"system_disk_category"`
	SystemDiskSize             int64              `json:"system_disk_size"`
	SystemDiskPerformanceLevel string             `json:"system_disk_performance_level"`
	DataDisks                  []NodePoolDataDisk `json:"data_disks"` //支持多个数据盘
	Tags                       []Tag              `json:"tags"`
	ImageId                    string             `json:"image_id"`
	Platform                   string             `json:"platform"`
	// 支持包年包月
	InstanceChargeType string `json:"instance_charge_type"`
	Period             int    `json:"period"`
	PeriodUnit         string `json:"period_unit"`
	AutoRenew          bool   `json:"auto_renew"`
	AutoRenewPeriod    int    `json:"auto_renew_period"`
	// spot实例
	SpotStrategy   string      `json:"spot_strategy"`
	SpotPriceLimit []SpotPrice `json:"spot_price_limit"`

	RdsInstances   []string `json:"rds_instances"`
	ScalingPolicy  string   `json:"scaling_policy"`
	ScalingGroupId string   `json:"scaling_group_id"`
}

type AutoScaling struct {
	Enable       bool   `json:"enable"`
	MaxInstances int64  `json:"max_instances"`
	MinInstances int64  `json:"min_instances"`
	Type         string `json:"type"`
	// eip
	IsBindEip *bool `json:"is_bond_eip"`
	// value: PayByBandwidth / PayByTraffic
	EipInternetChargeType string `json:"eip_internet_charge_type"`
	// default 5
	EipBandWidth int64 `json:"eip_bandwidth"`
}

type KubernetesConfig struct {
	NodeNameMode string  `json:"node_name_mode"`
	Taints       []Taint `json:"taints"`
	Labels       []Label `json:"labels"`
	CpuPolicy    string  `json:"cpu_policy"`
	UserData     string  `json:"user_data"`

	Runtime           string `json:"runtime,omitempty"`
	RuntimeVersion    string `json:"runtime_version"`
	CmsEnabled        bool   `json:"cms_enabled"`
	OverwriteHostname bool   `json:"overwrite_hostname"`
}

// 加密计算节点池
type TEEConfig struct {
	TEEType   string `json:"tee_type"`
	TEEEnable bool   `json:"tee_enable"`
}

// 托管节点池配置
type Management struct {
	Enable      bool        `json:"enable"`
	AutoRepair  bool        `json:"auto_repair"`
	UpgradeConf UpgradeConf `json:"upgrade_config"`
}

type UpgradeConf struct {
	AutoUpgrade       bool  `json:"auto_upgrade"`
	Surge             int64 `json:"surge"`
	SurgePercentage   int64 `json:"surge_percentage,omitempty"`
	MaxUnavailable    int64 `json:"max_unavailable"`
	KeepSurgeOnFailed bool  `json:"keep_surge_on_failed"`
}

type CreateNodePoolRequest struct {
	RegionId         common.Region `json:"region_id"`
	Count            int64         `json:"count"`
	NodePoolInfo     `json:"nodepool_info"`
	ScalingGroup     `json:"scaling_group"`
	KubernetesConfig `json:"kubernetes_config"`
	AutoScaling      `json:"auto_scaling"`
	TEEConfig        `json:"tee_config"`
	Management       `json:"management"`
}

type BasicNodePool struct {
	NodePoolInfo   `json:"nodepool_info"`
	NodePoolStatus `json:"status"`
}

type NodePoolStatus struct {
	TotalNodes   int `json:"total_nodes"`
	OfflineNodes int `json:"offline_nodes"`
	ServingNodes int `json:"serving_nodes"`
	//DesiredNodes int  `json:"desired_nodes"`
	RemovingNodes int    `json:"removing_nodes"`
	FailedNodes   int    `json:"failed_nodes"`
	InitialNodes  int    `json:"initial_nodes"`
	HealthyNodes  int    `json:"healthy_nodes"`
	State         string `json:"state"`
}

type NodePoolDetail struct {
	BasicNodePool
	KubernetesConfig `json:"kubernetes_config"`
	ScalingGroup     `json:"scaling_group"`
	AutoScaling      `json:"auto_scaling"`
	TEEConfig        `json:"tee_config"`
	Management       `json:"management"`
}

type CreateNodePoolResponse struct {
	Response
	NodePoolID string `json:"nodepool_id"`
	Message    string `json:"Message"`
}

type UpdateNodePoolRequest struct {
	RegionId         common.Region `json:"region_id"`
	Count            int64         `json:"count"`
	NodePoolInfo     `json:"nodepool_info"`
	ScalingGroup     `json:"scaling_group"`
	KubernetesConfig `json:"kubernetes_config"`
	AutoScaling      `json:"auto_scaling"`
	Management       `json:"management"`
}

type NodePoolsDetail struct {
	Response
	NodePools []NodePoolDetail `json:"nodepools"`
}

func (client *Client) CreateNodePool(request *CreateNodePoolRequest, clusterId string) (*CreateNodePoolResponse, error) {
	response := &CreateNodePoolResponse{}
	err := client.Invoke(request.RegionId, http.MethodPost, fmt.Sprintf("/clusters/%s/nodepools", clusterId), nil, request, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}

func (client *Client) DescribeNodePoolDetail(clusterId, nodePoolId string) (*NodePoolDetail, error) {
	nodePool := &NodePoolDetail{}
	err := client.Invoke("", http.MethodGet, fmt.Sprintf("/clusters/%s/nodepools/%s", clusterId, nodePoolId), nil, nil, nodePool)
	if err != nil {
		return nil, err
	}
	return nodePool, nil
}

func (client *Client) DescribeClusterNodePools(clusterId string) (*[]NodePoolDetail, error) {
	nodePools := &NodePoolsDetail{}
	err := client.Invoke("", http.MethodGet, fmt.Sprintf("/clusters/%s/nodepools", clusterId), nil, nil, nodePools)
	if err != nil {
		return nil, err
	}
	return &nodePools.NodePools, nil
}

func (client *Client) UpdateNodePool(clusterId string, nodePoolId string, request *UpdateNodePoolRequest) (*Response, error) {
	response := &Response{}
	err := client.Invoke(request.RegionId, http.MethodPut, fmt.Sprintf("/clusters/%s/nodepools/%s", clusterId, nodePoolId), nil, request, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}

func (client *Client) DeleteNodePool(clusterId, nodePoolId string) error {
	return client.Invoke("", http.MethodDelete, fmt.Sprintf("/clusters/%s/nodepools/%s", clusterId, nodePoolId), nil, nil, nil)
}
<commit_msg>create nodepool return taskID<commit_after>package cs

import (
	"fmt"
	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/ecs"
	"net/http"
	"time"
)

type SpotPrice struct {
	InstanceType string `json:"instance_type"`
	PriceLimit   string `json:"price_limit"`
}

type NodePoolInfo struct {
	NodePoolId      string        `json:"nodepool_id"`
	RegionId        common.Region `json:"region_id"`
	Name            string        `json:"name"`
	Created         time.Time     `json:"created"`
	Updated         time.Time     `json:"updated"`
	IsDefault       bool          `json:"is_default"`
	NodePoolType    string        `json:"type"`
	ResourceGroupId string        `json:"resource_group_id"`
}

type ScalingGroup struct {
	VpcId                      string             `json:"vpc_id"`
	VswitchIds                 []string           `json:"vswitch_ids"`
	InstanceTypes              []string           `json:"instance_types"`
	LoginPassword              string             `json:"login_password"`
	KeyPair                    string             `json:"key_pair"`
	SecurityGroupId            string             `json:"security_group_id"`
	SystemDiskCategory         ecs.DiskCategory   `json:"system_disk_category"`
	SystemDiskSize             int64              `json:"system_disk_size"`
	SystemDiskPerformanceLevel string             `json:"system_disk_performance_level"`
	DataDisks                  []NodePoolDataDisk `json:"data_disks"` //支持多个数据盘
	Tags                       []Tag              `json:"tags"`
	ImageId                    string             `json:"image_id"`
	Platform                   string             `json:"platform"`
	// 支持包年包月
	InstanceChargeType string `json:"instance_charge_type"`
	Period             int    `json:"period"`
	PeriodUnit         string `json:"period_unit"`
	AutoRenew          bool   `json:"auto_renew"`
	AutoRenewPeriod    int    `json:"auto_renew_period"`
	// spot实例
	SpotStrategy   string      `json:"spot_strategy"`
	SpotPriceLimit []SpotPrice `json:"spot_price_limit"`

	RdsInstances   []string `json:"rds_instances"`
	ScalingPolicy  string   `json:"scaling_policy"`
	ScalingGroupId string   `json:"scaling_group_id"`

	WorkerSnapshotPolicyId string `json:"worker_system_disk_snapshot_policy_id"`
	// 公网ip
	InternetChargeType      string `json:"internet_charge_type"`
	InternetMaxBandwidthOut int    `json:"internet_max_bandwidth_out"`
}

type AutoScaling struct {
	Enable       bool   `json:"enable"`
	MaxInstances int64  `json:"max_instances"`
	MinInstances int64  `json:"min_instances"`
	Type         string `json:"type"`
	// eip
	IsBindEip *bool `json:"is_bond_eip"`
	// value: PayByBandwidth / PayByTraffic
	EipInternetChargeType string `json:"eip_internet_charge_type"`
	// default 5
	EipBandWidth int64 `json:"eip_bandwidth"`
}

type KubernetesConfig struct {
	NodeNameMode string  `json:"node_name_mode"`
	Taints       []Taint `json:"taints"`
	Labels       []Label `json:"labels"`
	CpuPolicy    string  `json:"cpu_policy"`
	UserData     string  `json:"user_data"`

	Runtime           string `json:"runtime,omitempty"`
	RuntimeVersion    string `json:"runtime_version"`
	CmsEnabled        bool   `json:"cms_enabled"`
	OverwriteHostname bool   `json:"overwrite_hostname"`
	Unschedulable     bool   `json:"unschedulable"`
}

// 加密计算节点池
type TEEConfig struct {
	TEEType   string `json:"tee_type"`
	TEEEnable bool   `json:"tee_enable"`
}

// 托管节点池配置
type Management struct {
	Enable      bool        `json:"enable"`
	AutoRepair  bool        `json:"auto_repair"`
	UpgradeConf UpgradeConf `json:"upgrade_config"`
}

type UpgradeConf struct {
	AutoUpgrade       bool  `json:"auto_upgrade"`
	Surge             int64 `json:"surge"`
	SurgePercentage   int64 `json:"surge_percentage,omitempty"`
	MaxUnavailable    int64 `json:"max_unavailable"`
	KeepSurgeOnFailed bool  `json:"keep_surge_on_failed"`
}

type CreateNodePoolRequest struct {
	RegionId         common.Region `json:"region_id"`
	Count            int64         `json:"count"`
	NodePoolInfo     `json:"nodepool_info"`
	ScalingGroup     `json:"scaling_group"`
	KubernetesConfig `json:"kubernetes_config"`
	AutoScaling      `json:"auto_scaling"`
	TEEConfig        `json:"tee_config"`
	Management       `json:"management"`
}

type BasicNodePool struct {
	NodePoolInfo   `json:"nodepool_info"`
	NodePoolStatus `json:"status"`
}

type NodePoolStatus struct {
	TotalNodes   int `json:"total_nodes"`
	OfflineNodes int `json:"offline_nodes"`
	ServingNodes int `json:"serving_nodes"`
	//DesiredNodes int  `json:"desired_nodes"`
	RemovingNodes int    `json:"removing_nodes"`
	FailedNodes   int    `json:"failed_nodes"`
	InitialNodes  int    `json:"initial_nodes"`
	HealthyNodes  int    `json:"healthy_nodes"`
	State         string `json:"state"`
}

type NodePoolDetail struct {
	BasicNodePool
	KubernetesConfig `json:"kubernetes_config"`
	ScalingGroup     `json:"scaling_group"`
	AutoScaling      `json:"auto_scaling"`
	TEEConfig        `json:"tee_config"`
	Management       `json:"management"`
}

type CreateNodePoolResponse struct {
	Response
	NodePoolID string `json:"nodepool_id"`
	Message    string `json:"Message"`
	TaskID     string `json:"task_id"`
}

type UpdateNodePoolRequest struct {
	RegionId         common.Region `json:"region_id"`
	Count            int64         `json:"count"`
	NodePoolInfo     `json:"nodepool_info"`
	ScalingGroup     `json:"scaling_group"`
	KubernetesConfig `json:"kubernetes_config"`
	AutoScaling      `json:"auto_scaling"`
	Management       `json:"management"`
}

type NodePoolsDetail struct {
	Response
	NodePools []NodePoolDetail `json:"nodepools"`
}

func (client *Client) CreateNodePool(request *CreateNodePoolRequest, clusterId string) (*CreateNodePoolResponse, error) {
	response := &CreateNodePoolResponse{}
	err := client.Invoke(request.RegionId, http.MethodPost, fmt.Sprintf("/clusters/%s/nodepools", clusterId), nil, request, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}

func (client *Client) DescribeNodePoolDetail(clusterId, nodePoolId string) (*NodePoolDetail, error) {
	nodePool := &NodePoolDetail{}
	err := client.Invoke("", http.MethodGet, fmt.Sprintf("/clusters/%s/nodepools/%s", clusterId, nodePoolId), nil, nil, nodePool)
	if err != nil {
		return nil, err
	}
	return nodePool, nil
}

func (client *Client) DescribeClusterNodePools(clusterId string) (*[]NodePoolDetail, error) {
	nodePools := &NodePoolsDetail{}
	err := client.Invoke("", http.MethodGet, fmt.Sprintf("/clusters/%s/nodepools", clusterId), nil, nil, nodePools)
	if err != nil {
		return nil, err
	}
	return &nodePools.NodePools, nil
}

func (client *Client) UpdateNodePool(clusterId string, nodePoolId string, request *UpdateNodePoolRequest) (*Response, error) {
	response := &Response{}
	err := client.Invoke(request.RegionId, http.MethodPut, fmt.Sprintf("/clusters/%s/nodepools/%s", clusterId, nodePoolId), nil, request, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}

func (client *Client) DeleteNodePool(clusterId, nodePoolId string) error {
	return client.Invoke("", http.MethodDelete, fmt.Sprintf("/clusters/%s/nodepools/%s", clusterId, nodePoolId), nil, nil, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"math/big"
	"strings"
)

var errUnableToParseSize = errors.New("unable to parse size")

// parseSize converts strings of form 10GB to a size in bytes. Fractional sizes
// are truncated at the byte size. If parsing fails an error is returned.
func parseSize(strSize string) (string, error) {
	units := []struct {
		suffix     string
		multiplier int64
	}{
		{"kb", 1000},
		{"mb", 1000000},
		{"gb", 1000000000},
		{"tb", 1000000000000},
		{"kib", 1024},
		{"mib", 1048576},
		{"gib", 1073741824},
		{"tib", 1099511627776},
		{"b", 1}, // must be after others else it'll match on them all
		{"", 1},  // no suffix is still a valid suffix
	}

	strSize = strings.ToLower(strSize)
	for _, unit := range units {
		if strings.HasSuffix(strSize, unit.suffix) {
			r, ok := new(big.Rat).SetString(strings.TrimSuffix(strSize, unit.suffix))
			if !ok {
				return "", errUnableToParseSize
			}
			r.Mul(r, new(big.Rat).SetInt(big.NewInt(unit.multiplier)))
			if !r.IsInt() {
				f, _ := r.Float64()
				return fmt.Sprintf("%d", int64(f)), nil
			}
			return r.RatString(), nil
		}
	}

	return "", errUnableToParseSize
}

// coinUnits converts a siacoin amount to base units.
func coinUnits(amount string) (string, error) {
	units := []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"}
	for i, unit := range units {
		if strings.HasSuffix(amount, unit) {
			// scan into big.Rat
			r, ok := new(big.Rat).SetString(strings.TrimSuffix(amount, unit))
			if !ok {
				return "", errors.New("malformed amount")
			}
			// convert units
			exp := 24 + 3*(int64(i)-4)
			mag := new(big.Int).Exp(big.NewInt(10), big.NewInt(exp), nil)
			r.Mul(r, new(big.Rat).SetInt(mag))
			// r must be an integer at this point
			if !r.IsInt() {
				return "", errors.New("non-integer number of hastings")
			}
			return r.RatString(), nil
		}
	}
	// check for hastings separately
	if strings.HasSuffix(amount, "H") {
		return strings.TrimSuffix(amount, "H"), nil
	}

	return "", errors.New("amount is missing units; run 'wallet --help' for a list of units")
}
<commit_msg>Easier to read constants<commit_after>package main

import (
	"errors"
	"fmt"
	"math/big"
	"strings"
)

var errUnableToParseSize = errors.New("unable to parse size")

// parseSize converts strings of form 10GB to a size in bytes. Fractional sizes
// are truncated at the byte size. If parsing fails an error is returned.
func parseSize(strSize string) (string, error) {
	units := []struct {
		suffix     string
		multiplier int64
	}{
		{"kb", 1e3},
		{"mb", 1e6},
		{"gb", 1e9},
		{"tb", 1e12},
		{"kib", 1 << 10},
		{"mib", 1 << 20},
		{"gib", 1 << 30},
		{"tib", 1 << 40},
		{"b", 1}, // must be after others else it'll match on them all
		{"", 1},  // no suffix is still a valid suffix
	}

	strSize = strings.ToLower(strSize)
	for _, unit := range units {
		if strings.HasSuffix(strSize, unit.suffix) {
			r, ok := new(big.Rat).SetString(strings.TrimSuffix(strSize, unit.suffix))
			if !ok {
				return "", errUnableToParseSize
			}
			r.Mul(r, new(big.Rat).SetInt(big.NewInt(unit.multiplier)))
			if !r.IsInt() {
				f, _ := r.Float64()
				return fmt.Sprintf("%d", int64(f)), nil
			}
			return r.RatString(), nil
		}
	}

	return "", errUnableToParseSize
}

// coinUnits converts a siacoin amount to base units.
func coinUnits(amount string) (string, error) {
	units := []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"}
	for i, unit := range units {
		if strings.HasSuffix(amount, unit) {
			// scan into big.Rat
			r, ok := new(big.Rat).SetString(strings.TrimSuffix(amount, unit))
			if !ok {
				return "", errors.New("malformed amount")
			}
			// convert units
			exp := 24 + 3*(int64(i)-4)
			mag := new(big.Int).Exp(big.NewInt(10), big.NewInt(exp), nil)
			r.Mul(r, new(big.Rat).SetInt(mag))
			// r must be an integer at this point
			if !r.IsInt() {
				return "", errors.New("non-integer number of hastings")
			}
			return r.RatString(), nil
		}
	}
	// check for hastings separately
	if strings.HasSuffix(amount, "H") {
		return strings.TrimSuffix(amount, "H"), nil
	}

	return "", errors.New("amount is missing units; run 'wallet --help' for a list of units")
}
<|endoftext|>


<commit_before>package sim

import (
	"github.com/quells/LennardJones/space"
	"github.com/quells/LennardJones/vector"
	"math"
)

// PairwiseLennardJonesPotential calculates the Lennard Jones potential between two positions.
func PairwiseLennardJonesPotential(Ri, Rj [3]float64, L float64) float64 {
	r := space.Distance(Ri, Rj, L)
	return 4 * (math.Pow(r, -12) - math.Pow(r, -6))
}

// KineticEnergy calculates the kinetic energy of a particle.
func KineticEnergy(v [3]float64, m float64) float64 {
	s := vector.Length(v)
	return 0.5 * m * s * s
}

// TotalKineticEnergy calculates the kinetic energy of all particles in the system.
func TotalKineticEnergy(V [][3]float64, m float64) (sum float64) {
	for _, v := range V {
		sum += KineticEnergy(v, m)
	}
	return
}

// Temperature calculates the temperature of the system from the average kinetic energy of the particles.
func Temperature(V [][3]float64, m float64, N int) float64 {
	return TotalKineticEnergy(V, m) * 2 / 3 / float64(N)
}

// TotalPotentialEnergy calculates the potential energy of the system due to pairwise particle interactions.
func TotalPotentialEnergy(Rs [][3]float64, L float64) (sum float64) {
	for i := 0; i < len(Rs)-1; i++ {
		for j := i + 1; j < len(Rs); j++ {
			sum += PairwiseLennardJonesPotential(Rs[i], Rs[j], L)
		}
	}
	return
}

// TotalEnergy calculates the total energy of the system.
func TotalEnergy(Rs, Vs [][3]float64, L, M float64) (sum float64) {
	sum += TotalKineticEnergy(Vs, M)
	sum += TotalPotentialEnergy(Rs, L)
	return
}
<commit_msg>Update energy.go<commit_after>package sim

import (
	"github.com/quells/LennardJonesGo/space"
	"github.com/quells/LennardJonesGo/vector"
	"math"
)

// PairwiseLennardJonesPotential calculates the Lennard Jones potential between two positions.
func PairwiseLennardJonesPotential(Ri, Rj [3]float64, L float64) float64 {
	r := space.Distance(Ri, Rj, L)
	return 4 * (math.Pow(r, -12) - math.Pow(r, -6))
}

// KineticEnergy calculates the kinetic energy of a particle.
func KineticEnergy(v [3]float64, m float64) float64 {
	s := vector.Length(v)
	return 0.5 * m * s * s
}

// TotalKineticEnergy calculates the kinetic energy of all particles in the system.
func TotalKineticEnergy(V [][3]float64, m float64) (sum float64) {
	for _, v := range V {
		sum += KineticEnergy(v, m)
	}
	return
}

// Temperature calculates the temperature of the system from the average kinetic energy of the particles.
func Temperature(V [][3]float64, m float64, N int) float64 {
	return TotalKineticEnergy(V, m) * 2 / 3 / float64(N)
}

// TotalPotentialEnergy calculates the potential energy of the system due to pairwise particle interactions.
func TotalPotentialEnergy(Rs [][3]float64, L float64) (sum float64) {
	for i := 0; i < len(Rs)-1; i++ {
		for j := i + 1; j < len(Rs); j++ {
			sum += PairwiseLennardJonesPotential(Rs[i], Rs[j], L)
		}
	}
	return
}

// TotalEnergy calculates the total energy of the system.
func TotalEnergy(Rs, Vs [][3]float64, L, M float64) (sum float64) {
	sum += TotalKineticEnergy(Vs, M)
	sum += TotalPotentialEnergy(Rs, L)
	return
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package util

import (
    "errors"
	"fmt"
	"log"
	"os"
	"runtime"
	"runtime/debug"
	"strconv"
	"strings"
)

type MzLogger struct {
	logname  string
	pid      int32
	hostname string
	conf     *MzConfig
	tracer   bool
	filter   int64
}

// Message levels
const (
	CRITICAL = iota
	ERROR
	WARNING
	INFO
	DEBUG
)

// The fields to relay. NOTE: object reflection is VERY CPU expensive.
// I specify strings here to reduce that as much as possible. Please do
// not change this to something like map[string]interface{} since that
// can dramatically increase server load.
type Fields map[string]string

// Create a new Heka logging interface.
func NewMzLogger(conf *MzConfig) *MzLogger {
	//Preflight
	var logname string = ""
	var tracer bool = false
	var filter int64

	pid := int32(os.Getpid())

	dhost, _ := os.Hostname()
	conf.SetDefaultFlag("heka.show_caller", false)
	conf.SetDefault("logger.filter", "10")
	filter, _ = strconv.ParseInt(conf.Get("logger.filter", "10"), 0, 0)
	return &MzLogger{logname: logname,
		pid:      pid,
		hostname: conf.Get("heka.current_host", dhost),
		conf:     conf,
		tracer:   tracer,
		filter:   filter}
}

// Logging workhorse function. Chances are you're not going to call this
// directly, but via one of the helper methods. of Info() .. Critical()
// level - One of the defined logging CONST values
// mtype - Message type, Short class identifier for the message
// payload - Main error message
// fields - additional optional key/value data associated with the message.
func (self *MzLogger) Log(level int32, mtype, payload string, fields Fields) (err error) {

	var caller Fields
	// add in go language tracing. (Also CPU intensive, but REALLY helpful
	// when dev/debugging)
	if self.tracer {
		if pc, file, line, ok := runtime.Caller(2); ok {
			funk := runtime.FuncForPC(pc)
			caller = Fields{
				"file": file,
				// defaults don't appear to work.: file,
				"line": strconv.FormatInt(int64(line), 0),
				"name": funk.Name()}
		}
	}

	// Only print out the debug message if it's less than the filter.
	if int64(level) < self.filter {
		dump := fmt.Sprintf("[%d]% 7s: %s", level, mtype, payload)
		if len(fields) > 0 {
			var fld []string
			for key, val := range fields {
				fld = append(fld, key+": "+val)
			}
			dump += " {" + strings.Join(fld, ", ") + "}"
		}
		if len(caller) > 0 {
			dump += fmt.Sprintf(" [%s:%s %s]", caller["file"],
				caller["line"], caller["name"])
		}
		log.Printf(dump)

	}
	return nil
}

// record the lowest priority message
func (self *MzLogger) Info(mtype, msg string, fields Fields) (err error) {
	return self.Log(INFO, mtype, msg, fields)
}

func (self *MzLogger) Debug(mtype, msg string, fields Fields) (err error) {
	return self.Log(DEBUG, mtype, msg, fields)
}

func (self *MzLogger) Warn(mtype, msg string, fields Fields) (err error) {
	return self.Log(WARNING, mtype, msg, fields)
}

func (self *MzLogger) Error(mtype, msg string, fields Fields) (err error) {
	return self.Log(ERROR, mtype, msg, fields)
}

// record the Highest priority message, and include a printstack to STDERR
func (self *MzLogger) Critical(mtype, msg string, fields Fields) (err error) {
	return self.Log(CRITICAL, mtype, msg, fields)
	debug.PrintStack()
    log.Fatal("Fatal condition encountered")
    return errors.New("Critical Error")
}

// o4fs
// vim: set tabstab=4 softtabstop=4 shiftwidth=4 noexpandtab
<commit_msg>Tweaks to mz_config.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package util

import (
	"errors"
	"fmt"
	"log"
	"os"
	"runtime"
	"runtime/debug"
	"strconv"
	"strings"
)

type MzLogger struct {
	logname  string
	pid      int32
	hostname string
	conf     *MzConfig
	tracer   bool
	filter   int64
}

// Message levels
const (
	CRITICAL = iota
	ERROR
	WARNING
	INFO
	DEBUG
)

// The fields to relay. NOTE: object reflection is VERY CPU expensive.
// I specify strings here to reduce that as much as possible. Please do
// not change this to something like map[string]interface{} since that
// can dramatically increase server load.
type Fields map[string]string

// Create a new Heka logging interface.
func NewMzLogger(conf *MzConfig) *MzLogger {
	//Preflight
	var logname string = ""
	var tracer bool = false
	var filter int64

	pid := int32(os.Getpid())

	dhost, _ := os.Hostname()
	conf.SetDefaultFlag("heka.show_caller", false)
	conf.SetDefault("logger.filter", "10")
	filter, _ = strconv.ParseInt(conf.Get("logger.filter", "10"), 0, 0)
	return &MzLogger{
		logname:  logname,
		pid:      pid,
		hostname: conf.Get("heka.current_host", dhost),
		conf:     conf,
		tracer:   tracer,
		filter:   filter}
}

// Logging workhorse function. Chances are you're not going to call this
// directly, but via one of the helper methods. of Info() .. Critical()
// level - One of the defined logging CONST values
// mtype - Message type, Short class identifier for the message
// payload - Main error message
// fields - additional optional key/value data associated with the message.
func (self *MzLogger) Log(level int32, mtype, payload string, fields Fields) (err error) {

	var caller Fields
	// add in go language tracing. (Also CPU intensive, but REALLY helpful
	// when dev/debugging)
	if self.tracer {
		if pc, file, line, ok := runtime.Caller(2); ok {
			funk := runtime.FuncForPC(pc)
			caller = Fields{
				"file": file,
				// defaults don't appear to work.: file,
				"line": strconv.FormatInt(int64(line), 0),
				"name": funk.Name()}
		}
	}

	// Only print out the debug message if it's less than the filter.
	if int64(level) < self.filter {
		dump := fmt.Sprintf("[%d]% 7s: %s", level, mtype, payload)
		if len(fields) > 0 {
			var fld []string
			for key, val := range fields {
				fld = append(fld, key+": "+val)
			}
			dump += " {" + strings.Join(fld, ", ") + "}"
		}
		if len(caller) > 0 {
			dump += fmt.Sprintf(" [%s:%s %s]", caller["file"],
				caller["line"], caller["name"])
		}
		log.Printf(dump)

	}
	return nil
}

// record the lowest priority message
func (self *MzLogger) Info(mtype, msg string, fields Fields) (err error) {
	return self.Log(INFO, mtype, msg, fields)
}

func (self *MzLogger) Debug(mtype, msg string, fields Fields) (err error) {
	return self.Log(DEBUG, mtype, msg, fields)
}

func (self *MzLogger) Warn(mtype, msg string, fields Fields) (err error) {
	return self.Log(WARNING, mtype, msg, fields)
}

func (self *MzLogger) Error(mtype, msg string, fields Fields) (err error) {
	return self.Log(ERROR, mtype, msg, fields)
}

// record the Highest priority message, and include a printstack to STDERR
func (self *MzLogger) Critical(mtype, msg string, fields Fields) (err error) {
	return self.Log(CRITICAL, mtype, msg, fields)
	debug.PrintStack()
	log.Fatal("Fatal condition encountered")
	return errors.New("Critical Error")
}

// o4fs
// vim: set tabstab=4 softtabstop=4 shiftwidth=4 noexpandtab
<|endoftext|>


<commit_before>// Copyright 2009 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.

package net

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"internal/testenv"
	"os/exec"
	"reflect"
	"regexp"
	"sort"
	"strings"
	"testing"
)

var nslookupTestServers = []string{"mail.golang.com", "gmail.com"}
var lookupTestIPs = []string{"8.8.8.8", "1.1.1.1"}

func toJson(v interface{}) string {
	data, _ := json.Marshal(v)
	return string(data)
}

func TestNSLookupMX(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		mx, err := LookupMX(server)
		if err != nil {
			t.Error(err)
			continue
		}
		if len(mx) == 0 {
			t.Errorf("no results")
			continue
		}
		expected, err := nslookupMX(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
		}
		sort.Sort(byPrefAndHost(expected))
		sort.Sort(byPrefAndHost(mx))
		if !reflect.DeepEqual(expected, mx) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(mx))
		}
	}
}

func TestNSLookupCNAME(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		cname, err := LookupCNAME(server)
		if err != nil {
			t.Errorf("failed %s: %s", server, err)
			continue
		}
		if cname == "" {
			t.Errorf("no result %s", server)
		}
		expected, err := nslookupCNAME(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
			continue
		}
		if expected != cname {
			t.Errorf("different results %s:\texp:%v\tgot:%v", server, expected, cname)
		}
	}
}

func TestNSLookupNS(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		ns, err := LookupNS(server)
		if err != nil {
			t.Errorf("failed %s: %s", server, err)
			continue
		}
		if len(ns) == 0 {
			t.Errorf("no results")
			continue
		}
		expected, err := nslookupNS(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
			continue
		}
		sort.Sort(byHost(expected))
		sort.Sort(byHost(ns))
		if !reflect.DeepEqual(expected, ns) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", toJson(server), toJson(expected), ns)
		}
	}
}

func TestNSLookupTXT(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		txt, err := LookupTXT(server)
		if err != nil {
			t.Errorf("failed %s: %s", server, err)
			continue
		}
		if len(txt) == 0 {
			t.Errorf("no results")
			continue
		}
		expected, err := nslookupTXT(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
			continue
		}
		sort.Strings(expected)
		sort.Strings(txt)
		if !reflect.DeepEqual(expected, txt) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(txt))
		}
	}
}

func TestLookupLocalPTR(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	addr, err := localIP()
	if err != nil {
		t.Errorf("failed to get local ip: %s", err)
	}
	names, err := LookupAddr(addr.String())
	if err != nil {
		t.Errorf("failed %s: %s", addr, err)
	}
	if len(names) == 0 {
		t.Errorf("no results")
	}
	expected, err := lookupPTR(addr.String())
	if err != nil {
		t.Logf("skipping failed lookup %s test: %s", addr.String(), err)
	}
	sort.Strings(expected)
	sort.Strings(names)
	if !reflect.DeepEqual(expected, names) {
		t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names))
	}
}

func TestLookupPTR(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, addr := range lookupTestIPs {
		names, err := LookupAddr(addr)
		if err != nil {
			t.Errorf("failed %s: %s", addr, err)
		}
		if len(names) == 0 {
			t.Errorf("no results")
		}
		expected, err := lookupPTR(addr)
		if err != nil {
			t.Logf("skipping failed lookup %s test: %s", addr, err)
		}
		sort.Strings(expected)
		sort.Strings(names)
		if !reflect.DeepEqual(expected, names) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names))
		}
	}
}

type byPrefAndHost []*MX

func (s byPrefAndHost) Len() int { return len(s) }
func (s byPrefAndHost) Less(i, j int) bool {
	if s[i].Pref != s[j].Pref {
		return s[i].Pref < s[j].Pref
	}
	return s[i].Host < s[j].Host
}
func (s byPrefAndHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type byHost []*NS

func (s byHost) Len() int           { return len(s) }
func (s byHost) Less(i, j int) bool { return s[i].Host < s[j].Host }
func (s byHost) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

func nslookup(qtype, name string) (string, error) {
	var out bytes.Buffer
	var err bytes.Buffer
	cmd := exec.Command("nslookup", "-querytype="+qtype, name)
	cmd.Stdout = &out
	cmd.Stderr = &err
	if err := cmd.Run(); err != nil {
		return "", err
	}
	r := strings.ReplaceAll(out.String(), "\r\n", "\n")
	// nslookup stderr output contains also debug information such as
	// "Non-authoritative answer" and it doesn't return the correct errcode
	if strings.Contains(err.String(), "can't find") {
		return r, errors.New(err.String())
	}
	return r, nil
}

func nslookupMX(name string) (mx []*MX, err error) {
	var r string
	if r, err = nslookup("mx", name); err != nil {
		return
	}
	mx = make([]*MX, 0, 10)
	// linux nslookup syntax
	// golang.org      mail exchanger = 2 alt1.aspmx.l.google.com.
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		pref, _, _ := dtoi(ans[2])
		mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
	}
	// windows nslookup syntax
	// gmail.com       MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com
	rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		pref, _, _ := dtoi(ans[2])
		mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
	}
	return
}

func nslookupNS(name string) (ns []*NS, err error) {
	var r string
	if r, err = nslookup("ns", name); err != nil {
		return
	}
	ns = make([]*NS, 0, 10)
	// golang.org      nameserver = ns1.google.com.
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+nameserver\s*=\s*([a-z0-9.\-]+)$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		ns = append(ns, &NS{absDomainName([]byte(ans[2]))})
	}
	return
}

func nslookupCNAME(name string) (cname string, err error) {
	var r string
	if r, err = nslookup("cname", name); err != nil {
		return
	}
	// mail.golang.com canonical name = golang.org.
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+canonical name\s*=\s*([a-z0-9.\-]+)$`)
	// assumes the last CNAME is the correct one
	last := name
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		last = ans[2]
	}
	return absDomainName([]byte(last)), nil
}

func nslookupTXT(name string) (txt []string, err error) {
	var r string
	if r, err = nslookup("txt", name); err != nil {
		return
	}
	txt = make([]string, 0, 10)
	// linux
	// golang.org      text = "v=spf1 redirect=_spf.google.com"

	// windows
	// golang.org      text =
	//
	//    "v=spf1 redirect=_spf.google.com"
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+text\s*=\s*"(.*)"$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		txt = append(txt, ans[2])
	}
	return
}

func ping(name string) (string, error) {
	cmd := exec.Command("ping", "-n", "1", "-a", name)
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%v: %v", err, string(stdoutStderr))
	}
	r := strings.ReplaceAll(string(stdoutStderr), "\r\n", "\n")
	return r, nil
}

func lookupPTR(name string) (ptr []string, err error) {
	var r string
	if r, err = ping(name); err != nil {
		return
	}
	ptr = make([]string, 0, 10)
	rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		ptr = append(ptr, ans[1]+".")
	}
	return
}

func localIP() (ip IP, err error) {
	conn, err := Dial("udp", "golang.org:80")
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*UDPAddr)

	return localAddr.IP, nil
}
<commit_msg>net: use absDomainName in the Windows lookupPTR test helper<commit_after>// Copyright 2009 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.

package net

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"internal/testenv"
	"os/exec"
	"reflect"
	"regexp"
	"sort"
	"strings"
	"testing"
)

var nslookupTestServers = []string{"mail.golang.com", "gmail.com"}
var lookupTestIPs = []string{"8.8.8.8", "1.1.1.1"}

func toJson(v interface{}) string {
	data, _ := json.Marshal(v)
	return string(data)
}

func TestNSLookupMX(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		mx, err := LookupMX(server)
		if err != nil {
			t.Error(err)
			continue
		}
		if len(mx) == 0 {
			t.Errorf("no results")
			continue
		}
		expected, err := nslookupMX(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
		}
		sort.Sort(byPrefAndHost(expected))
		sort.Sort(byPrefAndHost(mx))
		if !reflect.DeepEqual(expected, mx) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(mx))
		}
	}
}

func TestNSLookupCNAME(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		cname, err := LookupCNAME(server)
		if err != nil {
			t.Errorf("failed %s: %s", server, err)
			continue
		}
		if cname == "" {
			t.Errorf("no result %s", server)
		}
		expected, err := nslookupCNAME(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
			continue
		}
		if expected != cname {
			t.Errorf("different results %s:\texp:%v\tgot:%v", server, expected, cname)
		}
	}
}

func TestNSLookupNS(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		ns, err := LookupNS(server)
		if err != nil {
			t.Errorf("failed %s: %s", server, err)
			continue
		}
		if len(ns) == 0 {
			t.Errorf("no results")
			continue
		}
		expected, err := nslookupNS(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
			continue
		}
		sort.Sort(byHost(expected))
		sort.Sort(byHost(ns))
		if !reflect.DeepEqual(expected, ns) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", toJson(server), toJson(expected), ns)
		}
	}
}

func TestNSLookupTXT(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, server := range nslookupTestServers {
		txt, err := LookupTXT(server)
		if err != nil {
			t.Errorf("failed %s: %s", server, err)
			continue
		}
		if len(txt) == 0 {
			t.Errorf("no results")
			continue
		}
		expected, err := nslookupTXT(server)
		if err != nil {
			t.Logf("skipping failed nslookup %s test: %s", server, err)
			continue
		}
		sort.Strings(expected)
		sort.Strings(txt)
		if !reflect.DeepEqual(expected, txt) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", server, toJson(expected), toJson(txt))
		}
	}
}

func TestLookupLocalPTR(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	addr, err := localIP()
	if err != nil {
		t.Errorf("failed to get local ip: %s", err)
	}
	names, err := LookupAddr(addr.String())
	if err != nil {
		t.Errorf("failed %s: %s", addr, err)
	}
	if len(names) == 0 {
		t.Errorf("no results")
	}
	expected, err := lookupPTR(addr.String())
	if err != nil {
		t.Logf("skipping failed lookup %s test: %s", addr.String(), err)
	}
	sort.Strings(expected)
	sort.Strings(names)
	if !reflect.DeepEqual(expected, names) {
		t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names))
	}
}

func TestLookupPTR(t *testing.T) {
	testenv.MustHaveExternalNetwork(t)

	for _, addr := range lookupTestIPs {
		names, err := LookupAddr(addr)
		if err != nil {
			t.Errorf("failed %s: %s", addr, err)
		}
		if len(names) == 0 {
			t.Errorf("no results")
		}
		expected, err := lookupPTR(addr)
		if err != nil {
			t.Logf("skipping failed lookup %s test: %s", addr, err)
		}
		sort.Strings(expected)
		sort.Strings(names)
		if !reflect.DeepEqual(expected, names) {
			t.Errorf("different results %s:\texp:%v\tgot:%v", addr, toJson(expected), toJson(names))
		}
	}
}

type byPrefAndHost []*MX

func (s byPrefAndHost) Len() int { return len(s) }
func (s byPrefAndHost) Less(i, j int) bool {
	if s[i].Pref != s[j].Pref {
		return s[i].Pref < s[j].Pref
	}
	return s[i].Host < s[j].Host
}
func (s byPrefAndHost) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type byHost []*NS

func (s byHost) Len() int           { return len(s) }
func (s byHost) Less(i, j int) bool { return s[i].Host < s[j].Host }
func (s byHost) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

func nslookup(qtype, name string) (string, error) {
	var out bytes.Buffer
	var err bytes.Buffer
	cmd := exec.Command("nslookup", "-querytype="+qtype, name)
	cmd.Stdout = &out
	cmd.Stderr = &err
	if err := cmd.Run(); err != nil {
		return "", err
	}
	r := strings.ReplaceAll(out.String(), "\r\n", "\n")
	// nslookup stderr output contains also debug information such as
	// "Non-authoritative answer" and it doesn't return the correct errcode
	if strings.Contains(err.String(), "can't find") {
		return r, errors.New(err.String())
	}
	return r, nil
}

func nslookupMX(name string) (mx []*MX, err error) {
	var r string
	if r, err = nslookup("mx", name); err != nil {
		return
	}
	mx = make([]*MX, 0, 10)
	// linux nslookup syntax
	// golang.org      mail exchanger = 2 alt1.aspmx.l.google.com.
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		pref, _, _ := dtoi(ans[2])
		mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
	}
	// windows nslookup syntax
	// gmail.com       MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com
	rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		pref, _, _ := dtoi(ans[2])
		mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
	}
	return
}

func nslookupNS(name string) (ns []*NS, err error) {
	var r string
	if r, err = nslookup("ns", name); err != nil {
		return
	}
	ns = make([]*NS, 0, 10)
	// golang.org      nameserver = ns1.google.com.
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+nameserver\s*=\s*([a-z0-9.\-]+)$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		ns = append(ns, &NS{absDomainName([]byte(ans[2]))})
	}
	return
}

func nslookupCNAME(name string) (cname string, err error) {
	var r string
	if r, err = nslookup("cname", name); err != nil {
		return
	}
	// mail.golang.com canonical name = golang.org.
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+canonical name\s*=\s*([a-z0-9.\-]+)$`)
	// assumes the last CNAME is the correct one
	last := name
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		last = ans[2]
	}
	return absDomainName([]byte(last)), nil
}

func nslookupTXT(name string) (txt []string, err error) {
	var r string
	if r, err = nslookup("txt", name); err != nil {
		return
	}
	txt = make([]string, 0, 10)
	// linux
	// golang.org      text = "v=spf1 redirect=_spf.google.com"

	// windows
	// golang.org      text =
	//
	//    "v=spf1 redirect=_spf.google.com"
	rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+text\s*=\s*"(.*)"$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		txt = append(txt, ans[2])
	}
	return
}

func ping(name string) (string, error) {
	cmd := exec.Command("ping", "-n", "1", "-a", name)
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%v: %v", err, string(stdoutStderr))
	}
	r := strings.ReplaceAll(string(stdoutStderr), "\r\n", "\n")
	return r, nil
}

func lookupPTR(name string) (ptr []string, err error) {
	var r string
	if r, err = ping(name); err != nil {
		return
	}
	ptr = make([]string, 0, 10)
	rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`)
	for _, ans := range rx.FindAllStringSubmatch(r, -1) {
		ptr = append(ptr, absDomainName([]byte(ans[1])))
	}
	return
}

func localIP() (ip IP, err error) {
	conn, err := Dial("udp", "golang.org:80")
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*UDPAddr)

	return localAddr.IP, nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/urfave/cli"
)

func TestCommandList(t *testing.T) {
	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		c := cli.NewContext(app, flagSet, nil)

		doList(c)
	})

	if err != nil {
		t.Errorf("error should be nil, but: %s", err)
	}
}

func TestCommandListUnique(t *testing.T) {
	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unique"})
		c := cli.NewContext(app, flagSet, nil)

		doList(c)
	})

	if err != nil {
		t.Errorf("error should be nil, but: %s", err)
	}
}

func TestCommandListUnknown(t *testing.T) {
	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unknown-flag"})
		c := cli.NewContext(app, flagSet, nil)

		doList(c)
	})

	if err != nil {
		t.Errorf("error should be nil, but: %s", err)
	}
}

func TestDoList_query(t *testing.T) {
	repos := []string{
		"github.com/motemen/ghq",
		"github.com/motemen/gobump",
		"github.com/motemen/gore",
		"github.com/Songmu/gobump",
	}
	testCases := []struct {
		name   string
		args   []string
		expect string
	}{{
		name:   "repo match",
		args:   []string{"ghq"},
		expect: "github.com/motemen/ghq\n",
	}, {
		name:   "host only doesn't match",
		args:   []string{"github.com"},
		expect: "",
	}, {
		name:   "host and user",
		args:   []string{"github.com/Songmu"},
		expect: "github.com/Songmu/gobump\n",
	}, {
		name:   "with scheme",
		args:   []string{"https://github.com/motemen/ghq"},
		expect: "github.com/motemen/ghq\n",
	}, {
		name:   "exact",
		args:   []string{"-e", "gobump"},
		expect: "github.com/Songmu/gobump\ngithub.com/motemen/gobump\n",
	}, {
		name:   "query",
		args:   []string{"men/go"},
		expect: "github.com/motemen/gobump\ngithub.com/motemen/gore\n",
	}, {
		name:   "exact query",
		args:   []string{"-e", "men/go"},
		expect: "",
	}}

	withFakeGitBackend(t, func(t *testing.T, tmproot string, _ *_cloneArgs, _ *_updateArgs) {
		for _, r := range repos {
			os.MkdirAll(filepath.Join(tmproot, r, ".git"), 0755)
		}
		for _, tc := range testCases {
			t.Run(tc.name, func(t *testing.T) {
				args := append([]string{"ghq", "list"}, tc.args...)
				out, _, _ := capture(func() {
					newApp().Run(args)
				})
				if out != tc.expect {
					t.Errorf("got:\n%s\nexpect:\n%s", out, tc.expect)
				}
				argsFull := append([]string{"ghq", "list", "--full-path"}, tc.args...)
				fullExpect := strings.ReplaceAll(tc.expect, "github.com", tmproot+"/github.com")
				out, _, _ = capture(func() {
					newApp().Run(argsFull)
				})
				if out != fullExpect {
					t.Errorf("got:\n%s\nexpect:\n%s", out, fullExpect)
				}
			})
		}
	})

}
<commit_msg>enhance testing<commit_after>package main

import (
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/urfave/cli"
)

func TestCommandList(t *testing.T) {
	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		c := cli.NewContext(app, flagSet, nil)

		doList(c)
	})

	if err != nil {
		t.Errorf("error should be nil, but: %s", err)
	}
}

func TestCommandListUnique(t *testing.T) {
	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unique"})
		c := cli.NewContext(app, flagSet, nil)

		doList(c)
	})

	if err != nil {
		t.Errorf("error should be nil, but: %s", err)
	}
}

func TestCommandListUnknown(t *testing.T) {
	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unknown-flag"})
		c := cli.NewContext(app, flagSet, nil)

		doList(c)
	})

	if err != nil {
		t.Errorf("error should be nil, but: %s", err)
	}
}

func TestDoList_query(t *testing.T) {
	repos := []string{
		"github.com/motemen/ghq",
		"github.com/motemen/gobump",
		"github.com/motemen/gore",
		"github.com/Songmu/gobump",
		"golang.org/x/crypt",
		"golang.org/x/image",
	}
	testCases := []struct {
		name   string
		args   []string
		expect string
	}{{
		name:   "repo match",
		args:   []string{"ghq"},
		expect: "github.com/motemen/ghq\n",
	}, {
		name:   "host only doesn't match",
		args:   []string{"github.com"},
		expect: "",
	}, {
		name:   "host and slash match",
		args:   []string{"golang.org/"},
		expect: "golang.org/x/crypt\ngolang.org/x/image\n",
	}, {
		name:   "host and user",
		args:   []string{"github.com/Songmu"},
		expect: "github.com/Songmu/gobump\n",
	}, {
		name:   "with scheme",
		args:   []string{"https://github.com/motemen/ghq"},
		expect: "github.com/motemen/ghq\n",
	}, {
		name:   "exact",
		args:   []string{"-e", "gobump"},
		expect: "github.com/Songmu/gobump\ngithub.com/motemen/gobump\n",
	}, {
		name:   "query",
		args:   []string{"men/go"},
		expect: "github.com/motemen/gobump\ngithub.com/motemen/gore\n",
	}, {
		name:   "exact query",
		args:   []string{"-e", "men/go"},
		expect: "",
	}}

	withFakeGitBackend(t, func(t *testing.T, tmproot string, _ *_cloneArgs, _ *_updateArgs) {
		for _, r := range repos {
			os.MkdirAll(filepath.Join(tmproot, r, ".git"), 0755)
		}
		for _, tc := range testCases {
			t.Run(tc.name, func(t *testing.T) {
				args := append([]string{"ghq", "list"}, tc.args...)
				out, _, _ := capture(func() {
					newApp().Run(args)
				})
				if out != tc.expect {
					t.Errorf("got:\n%s\nexpect:\n%s", out, tc.expect)
				}
				argsFull := append([]string{"ghq", "list", "--full-path"}, tc.args...)
				fullExpect := tc.expect
				if fullExpect != "" {
					fullExpect = tmproot + "/" + strings.TrimSpace(fullExpect)
					fullExpect = strings.ReplaceAll(fullExpect, "\n", "\n"+tmproot+"/")
					fullExpect += "\n"
				}
				out, _, _ = capture(func() {
					newApp().Run(argsFull)
				})
				if out != fullExpect {
					t.Errorf("got:\n%s\nexpect:\n%s", out, fullExpect)
				}
			})
		}
	})

}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// Package csv reads and writes comma-separated values (CSV) files.
//
// A csv file contains zero or more records of one or more fields per record.
// Each record is separated by the newline character. The final record may
// optionally be followed by a newline character.
//
//	field1,field2,field3
//
// White space is considered part of a field.
//
// Carriage returns before newline characters are silently removed.
//
// Blank lines are ignored.  A line with only whitespace characters (excluding
// the ending newline character) is not considered a blank line.
//
// Fields which start and stop with the quote character " are called
// quoted-fields.  The beginning and ending quote are not part of the
// field.
//
// The source:
//
//	normal string,"quoted-field"
//
// results in the fields
//
//	{`normal string`, `quoted-field`}
//
// Within a quoted-field a quote character followed by a second quote
// character is considered a single quote.
//
//	"the ""word"" is true","a ""quoted-field"""
//
// results in
//
//	{`the "word" is true`, `a "quoted-field"`}
//
// Newlines and commas may be included in a quoted-field
//
//	"Multi-line
//	field","comma is ,"
//
// results in
//
//	{`Multi-line
//	field`, `comma is ,`}
package csv

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"unicode"
)

// A ParseError is returned for parsing errors.
// The first line is 1.  The first column is 0.
type ParseError struct {
	Line   int   // Line where the error occurred
	Column int   // Column (rune index) where the error occurred
	Err    error // The actual error
}

func (e *ParseError) Error() string {
	return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Err)
}

// These are the errors that can be returned in ParseError.Error
var (
	ErrTrailingComma = errors.New("extra delimiter at end of line")
	ErrBareQuote     = errors.New("bare \" in non-quoted-field")
	ErrQuote         = errors.New("extraneous \" in field")
	ErrFieldCount    = errors.New("wrong number of fields in line")
)

// A Reader reads records from a CSV-encoded file.
//
// As returned by NewReader, a Reader expects input conforming to RFC 4180.
// The exported fields can be changed to customize the details before the
// first call to Read or ReadAll.
//
// Comma is the field delimiter.  It defaults to ','.
//
// Comment, if not 0, is the comment character. Lines beginning with the
// Comment character are ignored.
//
// If FieldsPerRecord is positive, Read requires each record to
// have the given number of fields.  If FieldsPerRecord is 0, Read sets it to
// the number of fields in the first record, so that future records must
// have the same field count.
//
// If LazyQuotes is true, a quote may appear in an unquoted field and a
// non-doubled quote may appear in a quoted field.
//
// If TrailingComma is true, the last field may be an unquoted empty field.
//
// If TrimLeadingSpace is true, leading white space in a field is ignored.
type Reader struct {
	Comma            rune // Field delimiter (set to ',' by NewReader)
	Comment          rune // Comment character for start of line
	FieldsPerRecord  int  // Number of expected fields per record
	LazyQuotes       bool // Allow lazy quotes
	TrailingComma    bool // Allow trailing comma
	TrimLeadingSpace bool // Trim leading space
	line             int
	column           int
	r                *bufio.Reader
	field            bytes.Buffer
}

// NewReader returns a new Reader that reads from r.
func NewReader(r io.Reader) *Reader {
	return &Reader{
		Comma: ',',
		r:     bufio.NewReader(r),
	}
}

// error creates a new ParseError based on err.
func (r *Reader) error(err error) error {
	return &ParseError{
		Line:   r.line,
		Column: r.column,
		Err:    err,
	}
}

// Read reads one record from r.  The record is a slice of strings with each
// string representing one field.
func (r *Reader) Read() (record []string, err error) {
	for {
		record, err = r.parseRecord()
		if record != nil {
			break
		}
		if err != nil {
			return nil, err
		}
	}

	if r.FieldsPerRecord > 0 {
		if len(record) != r.FieldsPerRecord {
			r.column = 0 // report at start of record
			return record, r.error(ErrFieldCount)
		}
	} else if r.FieldsPerRecord == 0 {
		r.FieldsPerRecord = len(record)
	}
	return record, nil
}

// ReadAll reads all the remaining records from r.
// Each record is a slice of fields.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read until EOF, it does not treat end of file as an error to be
// reported.
func (r *Reader) ReadAll() (records [][]string, err error) {
	for {
		record, err := r.Read()
		if err == io.EOF {
			return records, nil
		}
		if err != nil {
			return nil, err
		}
		records = append(records, record)
	}
	panic("unreachable")
}

// readRune reads one rune from r, folding \r\n to \n and keeping track
// of how far into the line we have read.  r.column will point to the start
// of this rune, not the end of this rune.
func (r *Reader) readRune() (rune, error) {
	r1, _, err := r.r.ReadRune()

	// Handle \r\n here.  We make the simplifying assumption that
	// anytime \r is followed by \n that it can be folded to \n.
	// We will not detect files which contain both \r\n and bare \n.
	if r1 == '\r' {
		r1, _, err = r.r.ReadRune()
		if err == nil {
			if r1 != '\n' {
				r.r.UnreadRune()
				r1 = '\r'
			}
		}
	}
	r.column++
	return r1, err
}

// unreadRune puts the last rune read from r back.
func (r *Reader) unreadRune() {
	r.r.UnreadRune()
	r.column--
}

// skip reads runes up to and including the rune delim or until error.
func (r *Reader) skip(delim rune) error {
	for {
		r1, err := r.readRune()
		if err != nil {
			return err
		}
		if r1 == delim {
			return nil
		}
	}
	panic("unreachable")
}

// parseRecord reads and parses a single csv record from r.
func (r *Reader) parseRecord() (fields []string, err error) {
	// Each record starts on a new line.  We increment our line
	// number (lines start at 1, not 0) and set column to -1
	// so as we increment in readRune it points to the character we read.
	r.line++
	r.column = -1

	// Peek at the first rune.  If it is an error we are done.
	// If we are support comments and it is the comment character
	// then skip to the end of line.

	r1, _, err := r.r.ReadRune()
	if err != nil {
		return nil, err
	}

	if r.Comment != 0 && r1 == r.Comment {
		return nil, r.skip('\n')
	}
	r.r.UnreadRune()

	// At this point we have at least one field.
	for {
		haveField, delim, err := r.parseField()
		if haveField {
			fields = append(fields, r.field.String())
		}
		if delim == '\n' || err == io.EOF {
			return fields, err
		} else if err != nil {
			return nil, err
		}
	}
	panic("unreachable")
}

// parseField parses the next field in the record.  The read field is
// located in r.field.  Delim is the first character not part of the field
// (r.Comma or '\n').
func (r *Reader) parseField() (haveField bool, delim rune, err error) {
	r.field.Reset()

	r1, err := r.readRune()
	if err != nil {
		// If we have EOF and are not at the start of a line
		// then we return the empty field.  We have already
		// checked for trailing commas if needed.
		if err == io.EOF && r.column != 0 {
			return true, 0, err
		}
		return false, 0, err
	}

	if r.TrimLeadingSpace {
		for r1 != '\n' && unicode.IsSpace(r1) {
			r1, err = r.readRune()
			if err != nil {
				return false, 0, err
			}
		}
	}

	switch r1 {
	case r.Comma:
		// will check below

	case '\n':
		// We are a trailing empty field or a blank line
		if r.column == 0 {
			return false, r1, nil
		}
		return true, r1, nil

	case '"':
		// quoted field
	Quoted:
		for {
			r1, err = r.readRune()
			if err != nil {
				if err == io.EOF {
					if r.LazyQuotes {
						return true, 0, err
					}
					return false, 0, r.error(ErrQuote)
				}
				return false, 0, err
			}
			switch r1 {
			case '"':
				r1, err = r.readRune()
				if err != nil || r1 == r.Comma {
					break Quoted
				}
				if r1 == '\n' {
					return true, r1, nil
				}
				if r1 != '"' {
					if !r.LazyQuotes {
						r.column--
						return false, 0, r.error(ErrQuote)
					}
					// accept the bare quote
					r.field.WriteRune('"')
				}
			case '\n':
				r.line++
				r.column = -1
			}
			r.field.WriteRune(r1)
		}

	default:
		// unquoted field
		for {
			r.field.WriteRune(r1)
			r1, err = r.readRune()
			if err != nil || r1 == r.Comma {
				break
			}
			if r1 == '\n' {
				return true, r1, nil
			}
			if !r.LazyQuotes && r1 == '"' {
				return false, 0, r.error(ErrBareQuote)
			}
		}
	}

	if err != nil {
		if err == io.EOF {
			return true, 0, err
		}
		return false, 0, err
	}

	if !r.TrailingComma {
		// We don't allow trailing commas.  See if we
		// are at the end of the line (being mindful
		// of trimming spaces).
		c := r.column
		r1, err = r.readRune()
		if r.TrimLeadingSpace {
			for r1 != '\n' && unicode.IsSpace(r1) {
				r1, err = r.readRune()
				if err != nil {
					break
				}
			}
		}
		if err == io.EOF || r1 == '\n' {
			r.column = c // report the comma
			return false, 0, r.error(ErrTrailingComma)
		}
		r.unreadRune()
	}
	return true, r1, nil
}
<commit_msg>csv: clarify what a negative FieldsPerRecord means<commit_after>// Copyright 2011 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.

// Package csv reads and writes comma-separated values (CSV) files.
//
// A csv file contains zero or more records of one or more fields per record.
// Each record is separated by the newline character. The final record may
// optionally be followed by a newline character.
//
//	field1,field2,field3
//
// White space is considered part of a field.
//
// Carriage returns before newline characters are silently removed.
//
// Blank lines are ignored.  A line with only whitespace characters (excluding
// the ending newline character) is not considered a blank line.
//
// Fields which start and stop with the quote character " are called
// quoted-fields.  The beginning and ending quote are not part of the
// field.
//
// The source:
//
//	normal string,"quoted-field"
//
// results in the fields
//
//	{`normal string`, `quoted-field`}
//
// Within a quoted-field a quote character followed by a second quote
// character is considered a single quote.
//
//	"the ""word"" is true","a ""quoted-field"""
//
// results in
//
//	{`the "word" is true`, `a "quoted-field"`}
//
// Newlines and commas may be included in a quoted-field
//
//	"Multi-line
//	field","comma is ,"
//
// results in
//
//	{`Multi-line
//	field`, `comma is ,`}
package csv

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"unicode"
)

// A ParseError is returned for parsing errors.
// The first line is 1.  The first column is 0.
type ParseError struct {
	Line   int   // Line where the error occurred
	Column int   // Column (rune index) where the error occurred
	Err    error // The actual error
}

func (e *ParseError) Error() string {
	return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Err)
}

// These are the errors that can be returned in ParseError.Error
var (
	ErrTrailingComma = errors.New("extra delimiter at end of line")
	ErrBareQuote     = errors.New("bare \" in non-quoted-field")
	ErrQuote         = errors.New("extraneous \" in field")
	ErrFieldCount    = errors.New("wrong number of fields in line")
)

// A Reader reads records from a CSV-encoded file.
//
// As returned by NewReader, a Reader expects input conforming to RFC 4180.
// The exported fields can be changed to customize the details before the
// first call to Read or ReadAll.
//
// Comma is the field delimiter.  It defaults to ','.
//
// Comment, if not 0, is the comment character. Lines beginning with the
// Comment character are ignored.
//
// If FieldsPerRecord is positive, Read requires each record to
// have the given number of fields.  If FieldsPerRecord is 0, Read sets it to
// the number of fields in the first record, so that future records must
// have the same field count.  If FieldsPerRecord is negative, no check is
// made and records may have a variable number of fields.
//
// If LazyQuotes is true, a quote may appear in an unquoted field and a
// non-doubled quote may appear in a quoted field.
//
// If TrailingComma is true, the last field may be an unquoted empty field.
//
// If TrimLeadingSpace is true, leading white space in a field is ignored.
type Reader struct {
	Comma            rune // Field delimiter (set to ',' by NewReader)
	Comment          rune // Comment character for start of line
	FieldsPerRecord  int  // Number of expected fields per record
	LazyQuotes       bool // Allow lazy quotes
	TrailingComma    bool // Allow trailing comma
	TrimLeadingSpace bool // Trim leading space
	line             int
	column           int
	r                *bufio.Reader
	field            bytes.Buffer
}

// NewReader returns a new Reader that reads from r.
func NewReader(r io.Reader) *Reader {
	return &Reader{
		Comma: ',',
		r:     bufio.NewReader(r),
	}
}

// error creates a new ParseError based on err.
func (r *Reader) error(err error) error {
	return &ParseError{
		Line:   r.line,
		Column: r.column,
		Err:    err,
	}
}

// Read reads one record from r.  The record is a slice of strings with each
// string representing one field.
func (r *Reader) Read() (record []string, err error) {
	for {
		record, err = r.parseRecord()
		if record != nil {
			break
		}
		if err != nil {
			return nil, err
		}
	}

	if r.FieldsPerRecord > 0 {
		if len(record) != r.FieldsPerRecord {
			r.column = 0 // report at start of record
			return record, r.error(ErrFieldCount)
		}
	} else if r.FieldsPerRecord == 0 {
		r.FieldsPerRecord = len(record)
	}
	return record, nil
}

// ReadAll reads all the remaining records from r.
// Each record is a slice of fields.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read until EOF, it does not treat end of file as an error to be
// reported.
func (r *Reader) ReadAll() (records [][]string, err error) {
	for {
		record, err := r.Read()
		if err == io.EOF {
			return records, nil
		}
		if err != nil {
			return nil, err
		}
		records = append(records, record)
	}
	panic("unreachable")
}

// readRune reads one rune from r, folding \r\n to \n and keeping track
// of how far into the line we have read.  r.column will point to the start
// of this rune, not the end of this rune.
func (r *Reader) readRune() (rune, error) {
	r1, _, err := r.r.ReadRune()

	// Handle \r\n here.  We make the simplifying assumption that
	// anytime \r is followed by \n that it can be folded to \n.
	// We will not detect files which contain both \r\n and bare \n.
	if r1 == '\r' {
		r1, _, err = r.r.ReadRune()
		if err == nil {
			if r1 != '\n' {
				r.r.UnreadRune()
				r1 = '\r'
			}
		}
	}
	r.column++
	return r1, err
}

// unreadRune puts the last rune read from r back.
func (r *Reader) unreadRune() {
	r.r.UnreadRune()
	r.column--
}

// skip reads runes up to and including the rune delim or until error.
func (r *Reader) skip(delim rune) error {
	for {
		r1, err := r.readRune()
		if err != nil {
			return err
		}
		if r1 == delim {
			return nil
		}
	}
	panic("unreachable")
}

// parseRecord reads and parses a single csv record from r.
func (r *Reader) parseRecord() (fields []string, err error) {
	// Each record starts on a new line.  We increment our line
	// number (lines start at 1, not 0) and set column to -1
	// so as we increment in readRune it points to the character we read.
	r.line++
	r.column = -1

	// Peek at the first rune.  If it is an error we are done.
	// If we are support comments and it is the comment character
	// then skip to the end of line.

	r1, _, err := r.r.ReadRune()
	if err != nil {
		return nil, err
	}

	if r.Comment != 0 && r1 == r.Comment {
		return nil, r.skip('\n')
	}
	r.r.UnreadRune()

	// At this point we have at least one field.
	for {
		haveField, delim, err := r.parseField()
		if haveField {
			fields = append(fields, r.field.String())
		}
		if delim == '\n' || err == io.EOF {
			return fields, err
		} else if err != nil {
			return nil, err
		}
	}
	panic("unreachable")
}

// parseField parses the next field in the record.  The read field is
// located in r.field.  Delim is the first character not part of the field
// (r.Comma or '\n').
func (r *Reader) parseField() (haveField bool, delim rune, err error) {
	r.field.Reset()

	r1, err := r.readRune()
	if err != nil {
		// If we have EOF and are not at the start of a line
		// then we return the empty field.  We have already
		// checked for trailing commas if needed.
		if err == io.EOF && r.column != 0 {
			return true, 0, err
		}
		return false, 0, err
	}

	if r.TrimLeadingSpace {
		for r1 != '\n' && unicode.IsSpace(r1) {
			r1, err = r.readRune()
			if err != nil {
				return false, 0, err
			}
		}
	}

	switch r1 {
	case r.Comma:
		// will check below

	case '\n':
		// We are a trailing empty field or a blank line
		if r.column == 0 {
			return false, r1, nil
		}
		return true, r1, nil

	case '"':
		// quoted field
	Quoted:
		for {
			r1, err = r.readRune()
			if err != nil {
				if err == io.EOF {
					if r.LazyQuotes {
						return true, 0, err
					}
					return false, 0, r.error(ErrQuote)
				}
				return false, 0, err
			}
			switch r1 {
			case '"':
				r1, err = r.readRune()
				if err != nil || r1 == r.Comma {
					break Quoted
				}
				if r1 == '\n' {
					return true, r1, nil
				}
				if r1 != '"' {
					if !r.LazyQuotes {
						r.column--
						return false, 0, r.error(ErrQuote)
					}
					// accept the bare quote
					r.field.WriteRune('"')
				}
			case '\n':
				r.line++
				r.column = -1
			}
			r.field.WriteRune(r1)
		}

	default:
		// unquoted field
		for {
			r.field.WriteRune(r1)
			r1, err = r.readRune()
			if err != nil || r1 == r.Comma {
				break
			}
			if r1 == '\n' {
				return true, r1, nil
			}
			if !r.LazyQuotes && r1 == '"' {
				return false, 0, r.error(ErrBareQuote)
			}
		}
	}

	if err != nil {
		if err == io.EOF {
			return true, 0, err
		}
		return false, 0, err
	}

	if !r.TrailingComma {
		// We don't allow trailing commas.  See if we
		// are at the end of the line (being mindful
		// of trimming spaces).
		c := r.column
		r1, err = r.readRune()
		if r.TrimLeadingSpace {
			for r1 != '\n' && unicode.IsSpace(r1) {
				r1, err = r.readRune()
				if err != nil {
					break
				}
			}
		}
		if err == io.EOF || r1 == '\n' {
			r.column = c // report the comma
			return false, 0, r.error(ErrTrailingComma)
		}
		r.unreadRune()
	}
	return true, r1, nil
}
<|endoftext|>


<commit_before>package google

import (
	"errors"
	"fmt"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGoogleComputeInstanceGroup() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceComputeInstanceGroupRead,
		Schema: map[string]*schema.Schema{
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				ConflictsWith: []string{"self_link"},
			},

			"self_link": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ConflictsWith: []string{"name", "zone"},
			},

			"zone": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ConflictsWith: []string{"self_link"},
			},

			"project": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"description": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"instances": {
				Type:     schema.TypeSet,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"named_port": {
				Type:     schema.TypeList,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": {
							Type:     schema.TypeString,
							Computed: true,
						},

						"port": {
							Type:     schema.TypeInt,
							Computed: true,
						},
					},
				},
			},

			"network": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"size": {
				Type:     schema.TypeInt,
				Computed: true,
			},
		},
	}
}

func dataSourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	if name, ok := d.GetOk("name"); ok {
		zone, err := getZone(d, config)
		if err != nil {
			return err
		}
		project, err := getProject(d, config)
		if err != nil {
			return err
		}
		d.SetId(fmt.Sprintf("projects/%s/zones/%s/instanceGroups/%s", project, zone, name.(string)))
	} else if selfLink, ok := d.GetOk("self_link"); ok {
		parsed, err := ParseInstanceGroupFieldValue(selfLink.(string), d, config)
		if err != nil {
			return err
		}
		if err := d.Set("name", parsed.Name); err != nil {
			return fmt.Errorf("Error setting name: %s", err)
		}
		if err := d.Set("zone", parsed.Zone); err != nil {
			return fmt.Errorf("Error setting zone: %s", err)
		}
		if err := d.Set("project", parsed.Project); err != nil {
			return fmt.Errorf("Error setting project: %s", err)
		}
		d.SetId(fmt.Sprintf("projects/%s/zones/%s/instanceGroups/%s", parsed.Project, parsed.Zone, parsed.Name))
	} else {
		return errors.New("Must provide either `self_link` or `zone/name`")
	}

	return resourceComputeInstanceGroupRead(d, meta)
}
<commit_msg>update to more accurate error (#5841)<commit_after>package google

import (
	"errors"
	"fmt"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGoogleComputeInstanceGroup() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceComputeInstanceGroupRead,
		Schema: map[string]*schema.Schema{
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				ConflictsWith: []string{"self_link"},
			},

			"self_link": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ConflictsWith: []string{"name", "zone"},
			},

			"zone": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ConflictsWith: []string{"self_link"},
			},

			"project": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"description": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"instances": {
				Type:     schema.TypeSet,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"named_port": {
				Type:     schema.TypeList,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": {
							Type:     schema.TypeString,
							Computed: true,
						},

						"port": {
							Type:     schema.TypeInt,
							Computed: true,
						},
					},
				},
			},

			"network": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"size": {
				Type:     schema.TypeInt,
				Computed: true,
			},
		},
	}
}

func dataSourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	if name, ok := d.GetOk("name"); ok {
		zone, err := getZone(d, config)
		if err != nil {
			return err
		}
		project, err := getProject(d, config)
		if err != nil {
			return err
		}
		d.SetId(fmt.Sprintf("projects/%s/zones/%s/instanceGroups/%s", project, zone, name.(string)))
	} else if selfLink, ok := d.GetOk("self_link"); ok {
		parsed, err := ParseInstanceGroupFieldValue(selfLink.(string), d, config)
		if err != nil {
			return fmt.Errorf("InstanceGroup name, zone or project could not be parsed from %s", selfLink)
		}
		if err := d.Set("name", parsed.Name); err != nil {
			return fmt.Errorf("Error setting name: %s", err)
		}
		if err := d.Set("zone", parsed.Zone); err != nil {
			return fmt.Errorf("Error setting zone: %s", err)
		}
		if err := d.Set("project", parsed.Project); err != nil {
			return fmt.Errorf("Error setting project: %s", err)
		}
		d.SetId(fmt.Sprintf("projects/%s/zones/%s/instanceGroups/%s", parsed.Project, parsed.Zone, parsed.Name))
	} else {
		return errors.New("Must provide either `self_link` or `zone/name`")
	}

	return resourceComputeInstanceGroupRead(d, meta)
}
<|endoftext|>


<commit_before>package mail

import (
	"mime"
	"net/textproto"
)

// A TextHeader represents a message text header.
type TextHeader struct {
	textproto.MIMEHeader
}

// NewTextHeader creates a new message text header.
func NewTextHeader() TextHeader {
	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition", "inline")
	return TextHeader{h}
}

// IsHTML checks if this text is formatted using HTML.
func (h TextHeader) IsHTML() bool {
	mediaType, _, _ := mime.ParseMediaType(h.Get("Content-Type"))
	return mediaType == "text/html"
}
<commit_msg>mail: symmetry between New{Text,Attachment}Header<commit_after>package mail

import (
	"mime"
	"net/textproto"
)

// A TextHeader represents a message text header.
type TextHeader struct {
	textproto.MIMEHeader
}

// NewTextHeader creates a new message text header.
func NewTextHeader() TextHeader {
	h := TextHeader{make(textproto.MIMEHeader)}
	h.Set("Content-Disposition", "inline")
	return h
}

// IsHTML checks if this text is formatted using HTML.
func (h TextHeader) IsHTML() bool {
	mediaType, _, _ := mime.ParseMediaType(h.Get("Content-Type"))
	return mediaType == "text/html"
}
<|endoftext|>


<commit_before>// main runs the mosaic program.
package main

import (
	"flag"
	"fmt"

	"image"
	"image/color"
	// Support reading both jpeg and png
	_ "image/jpeg"
	_ "image/png"
	//	"path/filepath"
	//	"image/gif"
	"os"
	"strings"

	"github.com/I82Much/BrickMosaic"
)

var (
	maxSizeStuds = flag.Int("studs", 40, "number of studs to have on maximum length side. The number of rows and columns will be automatically calculated")
	rows         = flag.Int("rows", -1, "number of rows. If set, will be used in preference to --studs")
	cols         = flag.Int("cols", -1, "number of columns. If set, will be used in preference to --studs")
	orientation  = flag.String("orientation", "STUDS_RIGHT", "how the grid should be oriented. Either STUDS_RIGHT, STUDS_OUT, or STUDS_TOP")
	inputPath    = flag.String("path", "", "path to input file")
	outputPath   = flag.String("output_path", "", "path to output svg file")
	palette      = flag.String("palette", "full", "comma separated list of color names, or predefined color palette name")
	dither       = flag.Bool("dither", true, "If true, use dithering when converting the imagine into a mosaic")
	solver       = flag.String("solver", "greedy", "The solver to use; either 'greedy' or 'cost'")

	orientationMap = map[string]BrickMosaic.ViewOrientation{
		"STUDS_RIGHT": BrickMosaic.StudsRight,
		"STUDS_OUT":   BrickMosaic.StudsOut,
		"STUDS_TOP":   BrickMosaic.StudsTop,
	}

	paletteMap = map[string]color.Palette{
		"gray":      BrickMosaic.GrayScalePalette,
		"gray_plus": BrickMosaic.GrayPlusPalette,
		"basic":     BrickMosaic.LimitedPalette,
		"full":      BrickMosaic.FullPalette,
		"primary":   BrickMosaic.Primary,
		"bw":        BrickMosaic.BlackAndWhite,
	}

	solverMap = map[string]BrickMosaic.GridSolver{
		"greedy":      BrickMosaic.GreedySolve,
		"symmetrical": BrickMosaic.SymmetricalGreedySolve,
		"cost":        BrickMosaic.GreedyMinCostSolve,
		"symmetricalcost": BrickMosaic.SymmetricalGreedyMinCostSolve,
	}
)

func paletteFromArg(p string) color.Palette {
	if palette, ok := paletteMap[p]; ok {
		return palette
	}
	// Treat this as comma separated list
	colorStrings := strings.Split(p, ",")
	var colors []color.Color
	for _, c := range colorStrings {
		if color := BrickMosaic.ColorForName(c); color != nil {
			colors = append(colors, *color)
		} else {
			fmt.Printf("Could not find color matching %v", c)
		}
	}
	return color.Palette(colors)
}

func main() {
	// Flag handling; fail fast if anything is amiss
	flag.Parse()
	if _, ok := orientationMap[*orientation]; !ok {
		panic("Must set --orientation to one of STUDS_RIGHT, STUDS_OUT, or STUDS_TOP")
	}
	if *inputPath == "" {
		panic("Must set --path, path to the input file")
	}
	if *outputPath == "" {
		panic("Must set --output_path, path to the output file")
	}

	path := *inputPath
	file, err := os.Open(path)
	if err != nil {
		panic(fmt.Sprintf("Couldn't load file path %q: %v", path, err))
	}
	defer file.Close()

	img, format, err := image.Decode(file)
	if err != nil {
		panic(fmt.Sprintf("Couldn't decode file %v: %v", path, err))
	}
	fmt.Printf("Image format %v\n", format)

	outputFile, err := os.Create(*outputPath)
	if err != nil {
		panic("Couldn't create output file")
	}
	// close the output file on exit and check for its returned error
	defer func() {
		if err := outputFile.Close(); err != nil {
			panic(err)
		}
	}()

	// TODO(ndunn): Expose the Palette as a command line option
	//palette := BrickMosaic.GrayPlusPalette
	palette := paletteFromArg(*palette)
	if len(palette) == 0 {
		panic("no color palette set")
	}
	viewOrientation := orientationMap[*orientation]

	var numRows, numCols int
	// Use the command line arguments directly
	if *rows > 0 && *cols > 0 {
		numRows = *rows
		numCols = *cols
	} else if *maxSizeStuds > 0 {
		imgWidth := img.Bounds().Size().X
		imgHeight := img.Bounds().Size().Y
		numRows, numCols = BrickMosaic.CalculateRowsAndColumns(imgWidth, imgHeight, *maxSizeStuds, viewOrientation)
	} else {
		panic("must set (--rows and --cols) or --studs")
	}

	// What is the ideal representation of the mosaic? Handles downsampling from many colors to few.
	var ideal BrickMosaic.Ideal
	if *dither {
		ideal = BrickMosaic.DitherPosterize(img, palette, numRows, numCols, viewOrientation)
	} else {
		ideal = BrickMosaic.EucPosterize(img, palette, numRows, numCols, viewOrientation)
	}

	var gridSolver BrickMosaic.GridSolver
	if s, ok := solverMap[*solver]; ok {
		gridSolver = s
	} else {
		panic(fmt.Sprintf("unknown solver %v; wanted one of %v", *solver, solverMap))
	}
	// How are we going to build this mosaic?
	plan := BrickMosaic.CreateGridMosaic(ideal, gridSolver)
	inventory := plan.Inventory()
	fmt.Printf("%v", inventory.DescendingUsage())
	fmt.Printf("Will cost approximately %d dollars to build", inventory.ApproximateCost()/100)

	renderer := BrickMosaic.SVGRenderer{}
	if _, err := outputFile.Write([]byte(renderer.Render(plan))); err != nil {
		panic(err)
	}

	/*
			// TODO handle this more gracefully

			for _, scalingFactor := range []float32{0.0, 0.25, 0.5, 1.0, 2.0} {
			  baseName := filepath.Base(*inputPath)
			  ditheredImg := BrickMosaic.NewDitheredBrickImage(img, numRows, numCols, palette, viewOrientation, scalingFactor)
			  gifFile, err := os.Create(fmt.Sprintf("%v_%v_%d_rows_%d_cols_%v.gif", baseName, viewOrientation, numRows, numCols, scalingFactor))
		  	if err != nil {
		  		panic("Couldn't create output file")
		  	}
		  	// close the output file on exit and check for its returned error
		  	defer func() {
		  		if err := gifFile.Close(); err != nil {
		  			panic(err)
		  		}
		  	}()
		  	// TODO fixme
		  	frames := ditheredImg.Frames
		  	var delay []int
		  	for _ = range frames {
		  	  delay = append(delay, 100)
		  	}

		    g := &gif.GIF {
		      Image: frames,
		      Delay: delay,
		      LoopCount: -1,
		    }
		    err = gif.EncodeAll(gifFile, g)
		    if err != nil {
		      panic(fmt.Sprintf("Couldn't encode gif: %v", err))
		    }
			}*/
}
<commit_msg>Gofmt<commit_after>// main runs the mosaic program.
package main

import (
	"flag"
	"fmt"

	"image"
	"image/color"
	// Support reading both jpeg and png
	_ "image/jpeg"
	_ "image/png"
	//	"path/filepath"
	//	"image/gif"
	"os"
	"strings"

	"github.com/I82Much/BrickMosaic"
)

var (
	maxSizeStuds = flag.Int("studs", 40, "number of studs to have on maximum length side. The number of rows and columns will be automatically calculated")
	rows         = flag.Int("rows", -1, "number of rows. If set, will be used in preference to --studs")
	cols         = flag.Int("cols", -1, "number of columns. If set, will be used in preference to --studs")
	orientation  = flag.String("orientation", "STUDS_RIGHT", "how the grid should be oriented. Either STUDS_RIGHT, STUDS_OUT, or STUDS_TOP")
	inputPath    = flag.String("path", "", "path to input file")
	outputPath   = flag.String("output_path", "", "path to output svg file")
	palette      = flag.String("palette", "full", "comma separated list of color names, or predefined color palette name")
	dither       = flag.Bool("dither", true, "If true, use dithering when converting the imagine into a mosaic")
	solver       = flag.String("solver", "greedy", "The solver to use; either 'greedy' or 'cost'")

	orientationMap = map[string]BrickMosaic.ViewOrientation{
		"STUDS_RIGHT": BrickMosaic.StudsRight,
		"STUDS_OUT":   BrickMosaic.StudsOut,
		"STUDS_TOP":   BrickMosaic.StudsTop,
	}

	paletteMap = map[string]color.Palette{
		"gray":      BrickMosaic.GrayScalePalette,
		"gray_plus": BrickMosaic.GrayPlusPalette,
		"basic":     BrickMosaic.LimitedPalette,
		"full":      BrickMosaic.FullPalette,
		"primary":   BrickMosaic.Primary,
		"bw":        BrickMosaic.BlackAndWhite,
	}

	solverMap = map[string]BrickMosaic.GridSolver{
		"greedy":          BrickMosaic.GreedySolve,
		"symmetrical":     BrickMosaic.SymmetricalGreedySolve,
		"cost":            BrickMosaic.GreedyMinCostSolve,
		"symmetricalcost": BrickMosaic.SymmetricalGreedyMinCostSolve,
	}
)

func paletteFromArg(p string) color.Palette {
	if palette, ok := paletteMap[p]; ok {
		return palette
	}
	// Treat this as comma separated list
	colorStrings := strings.Split(p, ",")
	var colors []color.Color
	for _, c := range colorStrings {
		if color := BrickMosaic.ColorForName(c); color != nil {
			colors = append(colors, *color)
		} else {
			fmt.Printf("Could not find color matching %v", c)
		}
	}
	return color.Palette(colors)
}

func main() {
	// Flag handling; fail fast if anything is amiss
	flag.Parse()
	if _, ok := orientationMap[*orientation]; !ok {
		panic("Must set --orientation to one of STUDS_RIGHT, STUDS_OUT, or STUDS_TOP")
	}
	if *inputPath == "" {
		panic("Must set --path, path to the input file")
	}
	if *outputPath == "" {
		panic("Must set --output_path, path to the output file")
	}

	path := *inputPath
	file, err := os.Open(path)
	if err != nil {
		panic(fmt.Sprintf("Couldn't load file path %q: %v", path, err))
	}
	defer file.Close()

	img, format, err := image.Decode(file)
	if err != nil {
		panic(fmt.Sprintf("Couldn't decode file %v: %v", path, err))
	}
	fmt.Printf("Image format %v\n", format)

	outputFile, err := os.Create(*outputPath)
	if err != nil {
		panic("Couldn't create output file")
	}
	// close the output file on exit and check for its returned error
	defer func() {
		if err := outputFile.Close(); err != nil {
			panic(err)
		}
	}()

	// TODO(ndunn): Expose the Palette as a command line option
	//palette := BrickMosaic.GrayPlusPalette
	palette := paletteFromArg(*palette)
	if len(palette) == 0 {
		panic("no color palette set")
	}
	viewOrientation := orientationMap[*orientation]

	var numRows, numCols int
	// Use the command line arguments directly
	if *rows > 0 && *cols > 0 {
		numRows = *rows
		numCols = *cols
	} else if *maxSizeStuds > 0 {
		imgWidth := img.Bounds().Size().X
		imgHeight := img.Bounds().Size().Y
		numRows, numCols = BrickMosaic.CalculateRowsAndColumns(imgWidth, imgHeight, *maxSizeStuds, viewOrientation)
	} else {
		panic("must set (--rows and --cols) or --studs")
	}

	// What is the ideal representation of the mosaic? Handles downsampling from many colors to few.
	var ideal BrickMosaic.Ideal
	if *dither {
		ideal = BrickMosaic.DitherPosterize(img, palette, numRows, numCols, viewOrientation)
	} else {
		ideal = BrickMosaic.EucPosterize(img, palette, numRows, numCols, viewOrientation)
	}

	var gridSolver BrickMosaic.GridSolver
	if s, ok := solverMap[*solver]; ok {
		gridSolver = s
	} else {
		panic(fmt.Sprintf("unknown solver %v; wanted one of %v", *solver, solverMap))
	}
	// How are we going to build this mosaic?
	plan := BrickMosaic.CreateGridMosaic(ideal, gridSolver)
	inventory := plan.Inventory()
	fmt.Printf("%v", inventory.DescendingUsage())
	fmt.Printf("Will cost approximately %d dollars to build", inventory.ApproximateCost()/100)

	renderer := BrickMosaic.SVGRenderer{}
	if _, err := outputFile.Write([]byte(renderer.Render(plan))); err != nil {
		panic(err)
	}

	/*
			// TODO handle this more gracefully

			for _, scalingFactor := range []float32{0.0, 0.25, 0.5, 1.0, 2.0} {
			  baseName := filepath.Base(*inputPath)
			  ditheredImg := BrickMosaic.NewDitheredBrickImage(img, numRows, numCols, palette, viewOrientation, scalingFactor)
			  gifFile, err := os.Create(fmt.Sprintf("%v_%v_%d_rows_%d_cols_%v.gif", baseName, viewOrientation, numRows, numCols, scalingFactor))
		  	if err != nil {
		  		panic("Couldn't create output file")
		  	}
		  	// close the output file on exit and check for its returned error
		  	defer func() {
		  		if err := gifFile.Close(); err != nil {
		  			panic(err)
		  		}
		  	}()
		  	// TODO fixme
		  	frames := ditheredImg.Frames
		  	var delay []int
		  	for _ = range frames {
		  	  delay = append(delay, 100)
		  	}

		    g := &gif.GIF {
		      Image: frames,
		      Delay: delay,
		      LoopCount: -1,
		    }
		    err = gif.EncodeAll(gifFile, g)
		    if err != nil {
		      panic(fmt.Sprintf("Couldn't encode gif: %v", err))
		    }
			}*/
}
<|endoftext|>