<commit_before>// portList.go
package main

import (
	"bytes"
	"crypto"
	_ "crypto/sha256"
	"encoding/binary"
	"reflect"
	"time"
)

type PortList struct {
	newList        []int
	current        []int
	history        [][]int
	secret         []byte
	sequenceLength int
	mask           int
	hi, lo         int
	testSequence   []int
}

func newPortList(secret []byte, sequenceLength, historyLength, hi, lo int) *PortList {
	p := &PortList{
		secret:         secret,
		sequenceLength: sequenceLength,
		hi:             hi,
		lo:             lo,
	}
	p.history = make([][]int, historyLength)
	p.testSequence = make([]int, sequenceLength)

	mask := 1
	for mask <= (hi - lo) {
		mask = mask << 1
	}
	mask -= 1
	p.mask = mask

	return p
}

func interval(t time.Time) int64 {
	return t.Unix() / int64(refreshInterval.Seconds())
}

func (p *PortList) update(intervalNum int64) {
	p.newList = make([]int, p.sequenceLength)

	hasher := crypto.SHA256.New()

	hasher.Reset()
	binary.Write(hasher, binary.LittleEndian, intervalNum)
	result := hasher.Sum(nil)

	hasher.Reset()
	hasher.Write(result)
	hasher.Write(p.secret)
	master := hasher.Sum(nil)

	n := int64(0)
	for i := range p.newList {
		p.newList[i], n = nextPort(&master, n, p)
	}

	copy(p.history[1:], p.history)
	p.history[0] = p.newList
	p.current = p.newList
	p.newList = nil
}

func nextPort(master *[]byte, n int64, p *PortList) (int, int64) {
	hasher := crypto.SHA256.New()

	port := p.hi
	for shouldRejectPort(port, p) {
		hasher.Reset()
		hasher.Write(*master)
		binary.Write(hasher, binary.LittleEndian, n)
		finalHash := hasher.Sum(nil)

		var portTmp int64
		binary.Read(bytes.NewReader(finalHash), binary.LittleEndian, &portTmp)
		port = int(portTmp)

		port &= p.mask
		port += p.lo

		n += 1
	}

	return port, n
}

func shouldRejectPort(port int, p *PortList) bool {
	if port < p.lo || port >= p.hi {
		return true
	}

	for _, oldPort := range p.newList {
		if port == oldPort {
			return true
		}
	}

	for _, list := range p.history {
		for _, oldPort := range list {
			if port == oldPort {
				return true
			}
		}
	}

	return false
}

func (p *PortList) checkFull(port int) bool {
	p.testSequence = append(p.testSequence[1:], port)

	for _, list := range p.history {
		if reflect.DeepEqual(list, p.testSequence) {
			return true
		}
	}

	return false
}
<commit_msg>Update portList.go<commit_after>// portList.go
package main

import (
	"bytes"
	"crypto"
	_ "crypto/sha256"
	"encoding/binary"
	"reflect"
	"time"
)

type PortList struct {
	newList        []int
	current        []int
	history        [][]int
	secret         []byte
	sequenceLength int
	mask           int
	hi, lo         int
	testSequence   []int
}

func newPortList(secret []byte, sequenceLength, historyLength, hi, lo int) *PortList {
	p := &PortList{
		secret:         secret,
		sequenceLength: sequenceLength,
		hi:             hi,
		lo:             lo,
	}
	p.history = make([][]int, historyLength)
	p.testSequence = make([]int, sequenceLength)

	mask := 1
	for mask <= (hi - lo) {
		mask = mask << 1
	}
	mask -= 1
	p.mask = mask

	return p
}

func interval(t time.Time) int64 {
	return t.Unix() / int64(refreshInterval.Seconds())
}

func (p *PortList) update(intervalNum int64) {
	p.newList = make([]int, p.sequenceLength)

	hasher := crypto.SHA256.New()

	hasher.Reset()
	_ = binary.Write(hasher, binary.LittleEndian, intervalNum)
	result := hasher.Sum(nil)

	hasher.Reset()
	hasher.Write(result)
	hasher.Write(p.secret)
	master := hasher.Sum(nil)

	n := int64(0)
	for i := range p.newList {
		p.newList[i], n = nextPort(master, n, p)
	}

	copy(p.history[1:], p.history)
	p.history[0] = p.newList
	p.current = p.newList
	p.newList = nil
}

func nextPort(master []byte, n int64, p *PortList) (int, int64) {
	hasher := crypto.SHA256.New()

	port := p.hi
	for shouldRejectPort(port, p) {
		hasher.Reset()
		hasher.Write(master)
		_ = binary.Write(hasher, binary.LittleEndian, n)
		finalHash := hasher.Sum(nil)

		var portTmp int64
		_ = binary.Read(bytes.NewReader(finalHash), binary.LittleEndian, &portTmp)
		port = int(portTmp)

		port &= p.mask
		port += p.lo

		n += 1
	}

	return port, n
}

func shouldRejectPort(port int, p *PortList) bool {
	if port < p.lo || port >= p.hi {
		return true
	}

	for _, oldPort := range p.newList {
		if port == oldPort {
			return true
		}
	}

	for _, list := range p.history {
		for _, oldPort := range list {
			if port == oldPort {
				return true
			}
		}
	}

	return false
}

func (p *PortList) checkFull(port int) bool {
	p.testSequence = append(p.testSequence[1:], port)

	for _, list := range p.history {
		if reflect.DeepEqual(list, p.testSequence) {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package shamir

import (
	"crypto/rand"
	"fmt"
)

// polynomial represents a polynomial of arbitrary degree
type polynomial struct {
	coefficients []uint8
}

// makePolynomial constructs a random polynomial of the given
// degree but with the provided intercept value.
func makePolynomial(intercept, degree uint8) (polynomial, error) {
	// Create a wrapper
	p := polynomial{
		coefficients: make([]byte, degree+1),
	}

	// Ensure the intercept is set
	p.coefficients[0] = intercept

	// Assign random co-efficients to the polynomial, ensuring
	// the highest order co-efficient is non-zero
	for p.coefficients[degree] == 0 {
		if _, err := rand.Read(p.coefficients[1:]); err != nil {
			return p, err
		}
	}
	return p, nil
}

// evaluate returns the value of the polynomial for the given x
func (p *polynomial) evaluate(x uint8) uint8 {
	// Special case the origin
	if x == 0 {
		return p.coefficients[0]
	}

	// Compute the polynomial value using Horner's method.
	degree := len(p.coefficients) - 1
	out := p.coefficients[degree]
	for i := degree - 1; i >= 0; i-- {
		coeff := p.coefficients[i]
		out = add(mult(out, x), coeff)
	}
	return out
}

// interpolatePolynomial takes N sample points and returns
// the value at a given x using a lagrange interpolation.
func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 {
	limit := len(x_samples)
	var result, basis uint8
	for i := 0; i < limit; i++ {
		basis = 1
		for j := 0; j < limit; j++ {
			if i == j {
				continue
			}
			num := add(x, x_samples[j])
			denom := add(x_samples[i], x_samples[j])
			term := div(num, denom)
			basis = mult(basis, term)
			//println(fmt.Sprintf("Num: %d Denom: %d Term: %d Basis: %d",
			//    num, denom, term, basis))
		}
		group := mult(y_samples[i], basis)
		//println(fmt.Sprintf("Group: %d", group))
		result = add(result, group)
	}
	return result
}

// div divides two numbers in GF(2^8)
func div(a, b uint8) uint8 {
	if b == 0 {
		panic("divide by zero")
	}
	if a == 0 {
		return 0
	}

	log_a := logTable[a]
	log_b := logTable[b]
	diff := (int(log_a) - int(log_b)) % 255
	if diff < 0 {
		diff += 255
	}
	return expTable[diff]
}

// mult multiplies two numbers in GF(2^8)
func mult(a, b uint8) (out uint8) {
	if a == 0 || b == 0 {
		return 0
	}
	log_a := logTable[a]
	log_b := logTable[b]
	sum := (int(log_a) + int(log_b)) % 255
	return expTable[sum]
}

// add combines two numbers in GF(2^8)
// This can also be used for subtraction since it is symmetric.
func add(a, b uint8) uint8 {
	return a ^ b
}

// Split takes an arbitrarily long secret and generates a `parts`
// number of shares, `threshold` of which are required to reconstruct
// the secret. The parts and threshold must be at least 2, and less
// than 256. The returned shares are each one byte longer than the secret
// as they attach a tag used to reconstruct the secret.
func Split(secret []byte, parts, threshold int) ([][]byte, error) {
	// Sanity check the input
	if parts < threshold {
		return nil, fmt.Errorf("parts cannot be less than threshold")
	}
	if parts > 255 {
		return nil, fmt.Errorf("parts cannot exceed 255")
	}
	if threshold < 2 {
		return nil, fmt.Errorf("threshold must be at least 2")
	}
	if threshold > 255 {
		return nil, fmt.Errorf("threshold cannot exceed 255")
	}
	if len(secret) == 0 {
		return nil, fmt.Errorf("cannot split an empty secret")
	}

	// Allocate the output array, initialize the final byte
	// of the output with the offset. The representation of each
	// output is {y1, y2, .., yN, x}.
	out := make([][]byte, parts)
	for idx := range out {
		out[idx] = make([]byte, len(secret)+1)
		out[idx][len(secret)] = uint8(idx) + 1
	}

	// Construct a random polynomial for each byte of the secret.
	// Because we are using a field of size 256, we can only represent
	// a single byte as the intercept of the polynomial, so we must
	// use a new polynomial for each byte.
	for idx, val := range secret {
		p, err := makePolynomial(val, uint8(threshold-1))
		if err != nil {
			return nil, fmt.Errorf("failed to generate polynomial: %v", err)
		}

		// Generate a `parts` number of (x,y) pairs
		// We cheat by encoding the x value once as the final index,
		// so that it only needs to be stored once.
		for i := 0; i < parts; i++ {
			x := uint8(i) + 1
			y := p.evaluate(x)
			out[i][idx] = y
		}
	}

	// Return the encoded secrets
	return out, nil
}

// Combine is used to reverse a Split and reconstruct a secret
// once a `threshold` number of parts are available.
func Combine(parts [][]byte) ([]byte, error) {
	// Verify enough parts provided
	if len(parts) < 2 {
		return nil, fmt.Errorf("less than two parts cannot be used to reconstruct the secret")
	}

	// Verify the parts are all the same length
	firstPartLen := len(parts[0])
	if firstPartLen < 2 {
		return nil, fmt.Errorf("parts must be at least two bytes")
	}
	for i := 1; i < len(parts); i++ {
		if len(parts[i]) != firstPartLen {
			return nil, fmt.Errorf("all parts must be the same length")
		}
	}

	// Create a buffer to store the reconstructed secret
	secret := make([]byte, firstPartLen-1)

	// Buffer to store the samples
	x_samples := make([]uint8, len(parts))
	y_samples := make([]uint8, len(parts))

	// Set the x value for each sample
	for i, part := range parts {
		x_samples[i] = part[firstPartLen-1]
	}

	// Reconstruct each byte
	for idx := range secret {
		// Set the y value for each sample
		for i, part := range parts {
			y_samples[i] = part[idx]
		}

		// Interpolte the polynomial and compute the value at 0
		println(fmt.Sprintf("byte: %d x: %v y: %v", idx, x_samples, y_samples))
		val := interpolatePolynomial(x_samples, y_samples, 0)
		println(fmt.Sprintf("byte: %d out: %v", idx, val))

		// Evaluate the 0th value to get the intercept
		secret[idx] = val
	}
	return secret, nil
}
<commit_msg>shamir: Remove debug statements<commit_after>package shamir

import (
	"crypto/rand"
	"fmt"
)

// polynomial represents a polynomial of arbitrary degree
type polynomial struct {
	coefficients []uint8
}

// makePolynomial constructs a random polynomial of the given
// degree but with the provided intercept value.
func makePolynomial(intercept, degree uint8) (polynomial, error) {
	// Create a wrapper
	p := polynomial{
		coefficients: make([]byte, degree+1),
	}

	// Ensure the intercept is set
	p.coefficients[0] = intercept

	// Assign random co-efficients to the polynomial, ensuring
	// the highest order co-efficient is non-zero
	for p.coefficients[degree] == 0 {
		if _, err := rand.Read(p.coefficients[1:]); err != nil {
			return p, err
		}
	}
	return p, nil
}

// evaluate returns the value of the polynomial for the given x
func (p *polynomial) evaluate(x uint8) uint8 {
	// Special case the origin
	if x == 0 {
		return p.coefficients[0]
	}

	// Compute the polynomial value using Horner's method.
	degree := len(p.coefficients) - 1
	out := p.coefficients[degree]
	for i := degree - 1; i >= 0; i-- {
		coeff := p.coefficients[i]
		out = add(mult(out, x), coeff)
	}
	return out
}

// interpolatePolynomial takes N sample points and returns
// the value at a given x using a lagrange interpolation.
func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 {
	limit := len(x_samples)
	var result, basis uint8
	for i := 0; i < limit; i++ {
		basis = 1
		for j := 0; j < limit; j++ {
			if i == j {
				continue
			}
			num := add(x, x_samples[j])
			denom := add(x_samples[i], x_samples[j])
			term := div(num, denom)
			basis = mult(basis, term)
		}
		group := mult(y_samples[i], basis)
		result = add(result, group)
	}
	return result
}

// div divides two numbers in GF(2^8)
func div(a, b uint8) uint8 {
	if b == 0 {
		panic("divide by zero")
	}
	if a == 0 {
		return 0
	}

	log_a := logTable[a]
	log_b := logTable[b]
	diff := (int(log_a) - int(log_b)) % 255
	if diff < 0 {
		diff += 255
	}
	return expTable[diff]
}

// mult multiplies two numbers in GF(2^8)
func mult(a, b uint8) (out uint8) {
	if a == 0 || b == 0 {
		return 0
	}
	log_a := logTable[a]
	log_b := logTable[b]
	sum := (int(log_a) + int(log_b)) % 255
	return expTable[sum]
}

// add combines two numbers in GF(2^8)
// This can also be used for subtraction since it is symmetric.
func add(a, b uint8) uint8 {
	return a ^ b
}

// Split takes an arbitrarily long secret and generates a `parts`
// number of shares, `threshold` of which are required to reconstruct
// the secret. The parts and threshold must be at least 2, and less
// than 256. The returned shares are each one byte longer than the secret
// as they attach a tag used to reconstruct the secret.
func Split(secret []byte, parts, threshold int) ([][]byte, error) {
	// Sanity check the input
	if parts < threshold {
		return nil, fmt.Errorf("parts cannot be less than threshold")
	}
	if parts > 255 {
		return nil, fmt.Errorf("parts cannot exceed 255")
	}
	if threshold < 2 {
		return nil, fmt.Errorf("threshold must be at least 2")
	}
	if threshold > 255 {
		return nil, fmt.Errorf("threshold cannot exceed 255")
	}
	if len(secret) == 0 {
		return nil, fmt.Errorf("cannot split an empty secret")
	}

	// Allocate the output array, initialize the final byte
	// of the output with the offset. The representation of each
	// output is {y1, y2, .., yN, x}.
	out := make([][]byte, parts)
	for idx := range out {
		out[idx] = make([]byte, len(secret)+1)
		out[idx][len(secret)] = uint8(idx) + 1
	}

	// Construct a random polynomial for each byte of the secret.
	// Because we are using a field of size 256, we can only represent
	// a single byte as the intercept of the polynomial, so we must
	// use a new polynomial for each byte.
	for idx, val := range secret {
		p, err := makePolynomial(val, uint8(threshold-1))
		if err != nil {
			return nil, fmt.Errorf("failed to generate polynomial: %v", err)
		}

		// Generate a `parts` number of (x,y) pairs
		// We cheat by encoding the x value once as the final index,
		// so that it only needs to be stored once.
		for i := 0; i < parts; i++ {
			x := uint8(i) + 1
			y := p.evaluate(x)
			out[i][idx] = y
		}
	}

	// Return the encoded secrets
	return out, nil
}

// Combine is used to reverse a Split and reconstruct a secret
// once a `threshold` number of parts are available.
func Combine(parts [][]byte) ([]byte, error) {
	// Verify enough parts provided
	if len(parts) < 2 {
		return nil, fmt.Errorf("less than two parts cannot be used to reconstruct the secret")
	}

	// Verify the parts are all the same length
	firstPartLen := len(parts[0])
	if firstPartLen < 2 {
		return nil, fmt.Errorf("parts must be at least two bytes")
	}
	for i := 1; i < len(parts); i++ {
		if len(parts[i]) != firstPartLen {
			return nil, fmt.Errorf("all parts must be the same length")
		}
	}

	// Create a buffer to store the reconstructed secret
	secret := make([]byte, firstPartLen-1)

	// Buffer to store the samples
	x_samples := make([]uint8, len(parts))
	y_samples := make([]uint8, len(parts))

	// Set the x value for each sample
	for i, part := range parts {
		x_samples[i] = part[firstPartLen-1]
	}

	// Reconstruct each byte
	for idx := range secret {
		// Set the y value for each sample
		for i, part := range parts {
			y_samples[i] = part[idx]
		}

		// Interpolte the polynomial and compute the value at 0
		val := interpolatePolynomial(x_samples, y_samples, 0)

		// Evaluate the 0th value to get the intercept
		secret[idx] = val
	}
	return secret, nil
}
<|endoftext|>


<commit_before>package signalfx

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/signalfx/golib/datapoint"
	"github.com/signalfx/golib/datapoint/dpsink"
	"github.com/signalfx/golib/event"
	"github.com/signalfx/golib/sfxclient"
	"github.com/sirupsen/logrus"
	"github.com/stripe/veneur/protocol/dogstatsd"
	"github.com/stripe/veneur/samplers"
	"github.com/stripe/veneur/sinks"
	"github.com/stripe/veneur/ssf"
	"github.com/stripe/veneur/trace"
)

// collection is a structure that aggregates signalfx data points
// per-endpoint. It takes care of collecting the metrics by the tag
// values that identify where to send them, and
type collection struct {
	sink        *SignalFxSink
	points      []*datapoint.Datapoint
	pointsByKey map[string][]*datapoint.Datapoint
}

func (c *collection) addPoint(key string, point *datapoint.Datapoint) {
	if c.sink.clientsByTagValue != nil {
		if _, ok := c.sink.clientsByTagValue[key]; ok {
			c.pointsByKey[key] = append(c.pointsByKey[key], point)
			return
		}
	}
	c.points = append(c.points, point)
}

func (c *collection) submit(ctx context.Context, cl *trace.Client) error {
	wg := &sync.WaitGroup{}
	errorCh := make(chan error, len(c.pointsByKey)+1)

	submitOne := func(client dpsink.Sink, points []*datapoint.Datapoint) {
		span, _ := trace.StartSpanFromContext(ctx, "")
		defer span.ClientFinish(cl)
		err := client.AddDatapoints(ctx, points)
		if err != nil {
			span.Error(err)
			errorCh <- err
		}
		wg.Done()
	}

	wg.Add(1)
	go submitOne(c.sink.defaultClient, c.points)
	for key, points := range c.pointsByKey {
		wg.Add(1)
		go submitOne(c.sink.client(key), points)
	}
	wg.Wait()
	close(errorCh)
	errors := []error{}
	for err := range errorCh {
		errors = append(errors, err)
	}
	if len(errors) > 0 {
		return fmt.Errorf("Could not submit to all sfx sinks: %v", errors)
	}
	return nil
}

// SignalFxSink is a MetricsSink implementation.
type SignalFxSink struct {
	defaultClient     DPClient
	clientsByTagValue map[string]DPClient
	keyClients        map[string]dpsink.Sink
	varyBy            string
	hostnameTag       string
	hostname          string
	commonDimensions  map[string]string
	log               *logrus.Logger
	traceClient       *trace.Client
	excludedTags      map[string]struct{}
}

// A DPClient is a client that can be used to submit signalfx data
// points to an upstream consumer. It wraps the dpsink.Sink interface.
type DPClient dpsink.Sink

// NewClient constructs a new signalfx HTTP client for the given
// endpoint and API token.
func NewClient(endpoint, apiKey string) DPClient {
	httpSink := sfxclient.NewHTTPSink()
	httpSink.AuthToken = apiKey
	httpSink.DatapointEndpoint = fmt.Sprintf("%s/v2/datapoint", endpoint)
	httpSink.EventEndpoint = fmt.Sprintf("%s/v2/event", endpoint)
	return httpSink
}

// NewSignalFxSink creates a new SignalFx sink for metrics.
func NewSignalFxSink(hostnameTag string, hostname string, commonDimensions map[string]string, log *logrus.Logger, client DPClient, varyBy string, perTagClients map[string]DPClient) (*SignalFxSink, error) {
	return &SignalFxSink{
		defaultClient:     client,
		clientsByTagValue: perTagClients,
		hostnameTag:       hostnameTag,
		hostname:          hostname,
		commonDimensions:  commonDimensions,
		log:               log,
		varyBy:            varyBy,
	}, nil
}

// Name returns the name of this sink.
func (sfx *SignalFxSink) Name() string {
	return "signalfx"
}

// Start begins the sink. For SignalFx this is a noop.
func (sfx *SignalFxSink) Start(traceClient *trace.Client) error {
	sfx.traceClient = traceClient
	return nil
}

// client returns a client that can be used to submit to vary-by tag's
// value. If no client is specified for that tag value, the default
// client is returned.
func (sfx *SignalFxSink) client(key string) DPClient {
	if cl, ok := sfx.clientsByTagValue[key]; ok {
		return cl
	}
	return sfx.defaultClient
}

// newPointCollection creates an empty collection object and returns it
func (sfx *SignalFxSink) newPointCollection() *collection {
	return &collection{
		sink:        sfx,
		points:      []*datapoint.Datapoint{},
		pointsByKey: map[string][]*datapoint.Datapoint{},
	}
}

// Flush sends metrics to SignalFx
func (sfx *SignalFxSink) Flush(ctx context.Context, interMetrics []samplers.InterMetric) error {
	span, _ := trace.StartSpanFromContext(ctx, "")
	defer span.ClientFinish(sfx.traceClient)

	flushStart := time.Now()
	coll := sfx.newPointCollection()
	numPoints := 0

	for _, metric := range interMetrics {
		if !sinks.IsAcceptableMetric(metric, sfx) {
			continue
		}
		dims := map[string]string{}
		// Set the hostname as a tag, since SFx doesn't have a first-class hostname field
		dims[sfx.hostnameTag] = sfx.hostname
		for _, tag := range metric.Tags {
			kv := strings.SplitN(tag, ":", 2)
			key := kv[0]

			if len(kv) == 1 {
				dims[key] = ""
			} else {
				dims[key] = kv[1]
			}
		}
		// Copy common dimensions
		for k, v := range sfx.commonDimensions {
			dims[k] = v
		}
		metricKey := ""
		if sfx.varyBy != "" {
			if val, ok := dims[sfx.varyBy]; ok {
				metricKey = val
			}
		}

		for k := range sfx.excludedTags {
			delete(dims, k)
		}

		var point *datapoint.Datapoint
		if metric.Type == samplers.GaugeMetric {
			point = sfxclient.GaugeF(metric.Name, dims, metric.Value)
		} else if metric.Type == samplers.CounterMetric {
			// TODO I am not certain if this should be a Counter or a Cumulative
			point = sfxclient.Counter(metric.Name, dims, int64(metric.Value))
		}
		coll.addPoint(metricKey, point)
		numPoints++
	}
	err := coll.submit(ctx, sfx.traceClient)
	if err != nil {
		span.Error(err)
	}
	tags := map[string]string{"sink": "signalfx"}
	span.Add(ssf.Timing(sinks.MetricKeyMetricFlushDuration, time.Since(flushStart), time.Nanosecond, tags))
	span.Add(ssf.Count(sinks.MetricKeyTotalMetricsFlushed, float32(numPoints), tags))
	sfx.log.WithField("metrics", len(interMetrics)).Info("Completed flush to SignalFx")

	return err
}

// FlushEventsChecks sends events to SignalFx. It does not support checks.
func (sfx *SignalFxSink) FlushOtherSamples(ctx context.Context, samples []ssf.SSFSample) {
	span, _ := trace.StartSpanFromContext(ctx, "")
	defer span.ClientFinish(sfx.traceClient)

	for _, sample := range samples {

		if _, ok := sample.Tags[dogstatsd.EventIdentifierKey]; !ok {
			// This isn't an event, just continue
			continue
		}

		dims := map[string]string{}

		// Copy common dimensions in
		for k, v := range sfx.commonDimensions {
			dims[k] = v
		}
		// And hostname
		dims[sfx.hostnameTag] = sfx.hostname

		for k, v := range sample.Tags {
			if k == dogstatsd.EventIdentifierKey {
				// Don't copy this tag
				continue
			}
			dims[k] = v
		}

		for k := range sfx.excludedTags {
			delete(dims, k)
		}

		ev := event.Event{
			EventType:  sample.Name,
			Category:   event.USERDEFINED,
			Dimensions: dims,
			Timestamp:  time.Unix(sample.Timestamp, 0),
			Properties: map[string]interface{}{
				"description": sample.Message,
			},
		}
		// TODO: Split events out the same way as points
		sfx.defaultClient.AddEvents(ctx, []*event.Event{&ev})
	}
}

// SetTagExcludes sets the excluded tag names. Any tags with the
// provided key (name) will be excluded.
func (sfx *SignalFxSink) SetExcludedTags(excludes []string) {

	tagsSet := map[string]struct{}{}
	for _, tag := range excludes {
		tagsSet[tag] = struct{}{}
	}
	sfx.excludedTags = tagsSet
}
<commit_msg>Ensure we don't send long event types<commit_after>package signalfx

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/signalfx/golib/datapoint"
	"github.com/signalfx/golib/datapoint/dpsink"
	"github.com/signalfx/golib/event"
	"github.com/signalfx/golib/sfxclient"
	"github.com/sirupsen/logrus"
	"github.com/stripe/veneur/protocol/dogstatsd"
	"github.com/stripe/veneur/samplers"
	"github.com/stripe/veneur/sinks"
	"github.com/stripe/veneur/ssf"
	"github.com/stripe/veneur/trace"
)

const EVENT_NAME_MAX_LENGTH = 256

// collection is a structure that aggregates signalfx data points
// per-endpoint. It takes care of collecting the metrics by the tag
// values that identify where to send them, and
type collection struct {
	sink        *SignalFxSink
	points      []*datapoint.Datapoint
	pointsByKey map[string][]*datapoint.Datapoint
}

func (c *collection) addPoint(key string, point *datapoint.Datapoint) {
	if c.sink.clientsByTagValue != nil {
		if _, ok := c.sink.clientsByTagValue[key]; ok {
			c.pointsByKey[key] = append(c.pointsByKey[key], point)
			return
		}
	}
	c.points = append(c.points, point)
}

func (c *collection) submit(ctx context.Context, cl *trace.Client) error {
	wg := &sync.WaitGroup{}
	errorCh := make(chan error, len(c.pointsByKey)+1)

	submitOne := func(client dpsink.Sink, points []*datapoint.Datapoint) {
		span, _ := trace.StartSpanFromContext(ctx, "")
		defer span.ClientFinish(cl)
		err := client.AddDatapoints(ctx, points)
		if err != nil {
			span.Error(err)
			errorCh <- err
		}
		wg.Done()
	}

	wg.Add(1)
	go submitOne(c.sink.defaultClient, c.points)
	for key, points := range c.pointsByKey {
		wg.Add(1)
		go submitOne(c.sink.client(key), points)
	}
	wg.Wait()
	close(errorCh)
	errors := []error{}
	for err := range errorCh {
		errors = append(errors, err)
	}
	if len(errors) > 0 {
		return fmt.Errorf("Could not submit to all sfx sinks: %v", errors)
	}
	return nil
}

// SignalFxSink is a MetricsSink implementation.
type SignalFxSink struct {
	defaultClient     DPClient
	clientsByTagValue map[string]DPClient
	keyClients        map[string]dpsink.Sink
	varyBy            string
	hostnameTag       string
	hostname          string
	commonDimensions  map[string]string
	log               *logrus.Logger
	traceClient       *trace.Client
	excludedTags      map[string]struct{}
}

// A DPClient is a client that can be used to submit signalfx data
// points to an upstream consumer. It wraps the dpsink.Sink interface.
type DPClient dpsink.Sink

// NewClient constructs a new signalfx HTTP client for the given
// endpoint and API token.
func NewClient(endpoint, apiKey string) DPClient {
	httpSink := sfxclient.NewHTTPSink()
	httpSink.AuthToken = apiKey
	httpSink.DatapointEndpoint = fmt.Sprintf("%s/v2/datapoint", endpoint)
	httpSink.EventEndpoint = fmt.Sprintf("%s/v2/event", endpoint)
	return httpSink
}

// NewSignalFxSink creates a new SignalFx sink for metrics.
func NewSignalFxSink(hostnameTag string, hostname string, commonDimensions map[string]string, log *logrus.Logger, client DPClient, varyBy string, perTagClients map[string]DPClient) (*SignalFxSink, error) {
	return &SignalFxSink{
		defaultClient:     client,
		clientsByTagValue: perTagClients,
		hostnameTag:       hostnameTag,
		hostname:          hostname,
		commonDimensions:  commonDimensions,
		log:               log,
		varyBy:            varyBy,
	}, nil
}

// Name returns the name of this sink.
func (sfx *SignalFxSink) Name() string {
	return "signalfx"
}

// Start begins the sink. For SignalFx this is a noop.
func (sfx *SignalFxSink) Start(traceClient *trace.Client) error {
	sfx.traceClient = traceClient
	return nil
}

// client returns a client that can be used to submit to vary-by tag's
// value. If no client is specified for that tag value, the default
// client is returned.
func (sfx *SignalFxSink) client(key string) DPClient {
	if cl, ok := sfx.clientsByTagValue[key]; ok {
		return cl
	}
	return sfx.defaultClient
}

// newPointCollection creates an empty collection object and returns it
func (sfx *SignalFxSink) newPointCollection() *collection {
	return &collection{
		sink:        sfx,
		points:      []*datapoint.Datapoint{},
		pointsByKey: map[string][]*datapoint.Datapoint{},
	}
}

// Flush sends metrics to SignalFx
func (sfx *SignalFxSink) Flush(ctx context.Context, interMetrics []samplers.InterMetric) error {
	span, _ := trace.StartSpanFromContext(ctx, "")
	defer span.ClientFinish(sfx.traceClient)

	flushStart := time.Now()
	coll := sfx.newPointCollection()
	numPoints := 0

	for _, metric := range interMetrics {
		if !sinks.IsAcceptableMetric(metric, sfx) {
			continue
		}
		dims := map[string]string{}
		// Set the hostname as a tag, since SFx doesn't have a first-class hostname field
		dims[sfx.hostnameTag] = sfx.hostname
		for _, tag := range metric.Tags {
			kv := strings.SplitN(tag, ":", 2)
			key := kv[0]

			if len(kv) == 1 {
				dims[key] = ""
			} else {
				dims[key] = kv[1]
			}
		}
		// Copy common dimensions
		for k, v := range sfx.commonDimensions {
			dims[k] = v
		}
		metricKey := ""
		if sfx.varyBy != "" {
			if val, ok := dims[sfx.varyBy]; ok {
				metricKey = val
			}
		}

		for k := range sfx.excludedTags {
			delete(dims, k)
		}

		var point *datapoint.Datapoint
		if metric.Type == samplers.GaugeMetric {
			point = sfxclient.GaugeF(metric.Name, dims, metric.Value)
		} else if metric.Type == samplers.CounterMetric {
			// TODO I am not certain if this should be a Counter or a Cumulative
			point = sfxclient.Counter(metric.Name, dims, int64(metric.Value))
		}
		coll.addPoint(metricKey, point)
		numPoints++
	}
	err := coll.submit(ctx, sfx.traceClient)
	if err != nil {
		span.Error(err)
	}
	tags := map[string]string{"sink": "signalfx"}
	span.Add(ssf.Timing(sinks.MetricKeyMetricFlushDuration, time.Since(flushStart), time.Nanosecond, tags))
	span.Add(ssf.Count(sinks.MetricKeyTotalMetricsFlushed, float32(numPoints), tags))
	sfx.log.WithField("metrics", len(interMetrics)).Info("Completed flush to SignalFx")

	return err
}

// FlushEventsChecks sends events to SignalFx. It does not support checks.
func (sfx *SignalFxSink) FlushOtherSamples(ctx context.Context, samples []ssf.SSFSample) {
	span, _ := trace.StartSpanFromContext(ctx, "")
	defer span.ClientFinish(sfx.traceClient)

	for _, sample := range samples {

		if _, ok := sample.Tags[dogstatsd.EventIdentifierKey]; !ok {
			// This isn't an event, just continue
			continue
		}

		dims := map[string]string{}

		// Copy common dimensions in
		for k, v := range sfx.commonDimensions {
			dims[k] = v
		}
		// And hostname
		dims[sfx.hostnameTag] = sfx.hostname

		for k, v := range sample.Tags {
			if k == dogstatsd.EventIdentifierKey {
				// Don't copy this tag
				continue
			}
			dims[k] = v
		}

		for k := range sfx.excludedTags {
			delete(dims, k)
		}
		name := sample.Name
		if len(name) > EVENT_NAME_MAX_LENGTH {
			name = name[0:EVENT_NAME_MAX_LENGTH]
		}

		ev := event.Event{
			EventType:  name,
			Category:   event.USERDEFINED,
			Dimensions: dims,
			Timestamp:  time.Unix(sample.Timestamp, 0),
			Properties: map[string]interface{}{
				"description": sample.Message,
			},
		}
		// TODO: Split events out the same way as points
		sfx.defaultClient.AddEvents(ctx, []*event.Event{&ev})
	}
}

// SetTagExcludes sets the excluded tag names. Any tags with the
// provided key (name) will be excluded.
func (sfx *SignalFxSink) SetExcludedTags(excludes []string) {

	tagsSet := map[string]struct{}{}
	for _, tag := range excludes {
		tagsSet[tag] = struct{}{}
	}
	sfx.excludedTags = tagsSet
}
<|endoftext|>


<commit_before>package progress

type HandlerFunc func(current, total, expected int64)

var DefaultHandle = HandlerFunc(func(c, t, e int64) {})

func New() *Progress {
	return &Progress{Progress: DefaultHandle}
}

type Progress struct {
	Current     int64
	Total       int64
	Expected    int64
	Progress    HandlerFunc
	Finished    bool
	IgnoreTotal bool
}

func (p *Progress) Read(b []byte) (n int, err error) {
	return p.handle(b)
}

func (p *Progress) Write(b []byte) (n int, err error) {
	return p.handle(b)
}

func (p *Progress) handle(b []byte) (n int, err error) {
	n = len(b)
	if p.Finished || n == 0 {
		return
	}
	p.calculate(int64(n))
	p.Progress(p.Current, p.Total, p.Expected)
	return
}

func (p *Progress) calculate(n int64) {
	p.Current += n
	p.Expected = p.Total - p.Current
	if !p.IgnoreTotal && p.Expected < 0 {
		p.Current = p.Total
		p.Expected = 0
		p.Finished = true
	}
}
<commit_msg>cleanup<commit_after>package progress

type HandlerFunc func(current, total, expected int64)

var DefaultHandle = HandlerFunc(func(c, t, e int64) {})

func New() *Progress {
	return &Progress{Progress: DefaultHandle}
}

type Progress struct {
	Current     int64
	Total       int64
	Expected    int64
	Finished    bool
	IgnoreTotal bool
	Progress    HandlerFunc
}

func (p *Progress) Read(b []byte) (n int, err error) {
	return p.handle(b)
}

func (p *Progress) Write(b []byte) (n int, err error) {
	return p.handle(b)
}

func (p *Progress) handle(b []byte) (n int, err error) {
	n = len(b)
	if p.Finished || n == 0 {
		return
	}
	p.calculate(int64(n))
	p.Progress(p.Current, p.Total, p.Expected)
	return
}

func (p *Progress) calculate(n int64) {
	p.Current += n
	p.Expected = p.Total - p.Current
	if !p.IgnoreTotal && p.Expected < 0 {
		p.Current = p.Total
		p.Expected = 0
		p.Finished = true
	}
}
<|endoftext|>


<commit_before><commit_msg>fix linter<commit_after><|endoftext|>


<commit_before>package plugins

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"sort"
	"strings"

	"github.com/servehub/serve/manifest"
	"github.com/servehub/utils/gabs"
)

func init() {
	manifest.PluginRegestry.Add("gocd.pipeline.create", goCdPipelineCreate{})
}

/**
 * plugin for manifest section "goCd.pipeline.create"
 * section structure:
 *
 * goCd.pipeline.create:
 *   api-url: goCd_URL
 *   environment: ENV
 *   branch: BRANCH
 *   allowed-branches: [BRANCH, ...]
 *   pipeline:
 *     group: GROUP
 *     pipeline:
 *       according to the description: https://api.go.cd/current/#the-pipeline-config-object
 */

type goCdCredents struct {
	Login    string `json:"login"`
	Password string `json:"password"`
}

type goCdPipelineCreate struct{}

func (p goCdPipelineCreate) Run(data manifest.Manifest) error {
	if suffix := data.GetString("name-suffix"); suffix != "" {
		data.Set("pipeline.pipeline.name", data.GetString("pipeline.pipeline.name")+suffix)
		data.Set("pipeline.pipeline.envs.SERVE_EXTRA_ARGS.value", data.GetStringOr("pipeline.pipeline.envs.SERVE_EXTRA_ARGS.value", "")+" --var name-suffix="+suffix)
	}

	name := data.GetString("pipeline.pipeline.name")
	url := data.GetString("api-url")
	if data.GetString("pipeline.pipeline.template") == "" {
		data.DelTree("pipeline.pipeline.template")
	}

	replaceMapWithArray(data, "pipeline.pipeline.envs", "pipeline.pipeline.environment_variables")
	replaceMapWithArray(data, "pipeline.pipeline.params", "pipeline.pipeline.parameters")

	depends := []string{}
	if !data.Has("pipeline.pipeline.materials") {
		data.Set("pipeline.pipeline.materials", []interface{}{})
	}
	for _, dep := range data.GetArray("depends") {
		pipeline := dep.GetString("pipeline")
		depends = append(depends, pipeline)
		data.ArrayAppend("pipeline.pipeline.materials",
			map[string]interface{}{"type": "dependency",
				"attributes": map[string]interface{}{
					"name":        dep.GetStringOr("name", pipeline),
					"pipeline":    pipeline,
					"stage":       data.GetStringOr("stage", "Build"),
					"auto_update": true}})
	}

	body := data.GetTree("pipeline").String()
	branch := data.GetString("branch")

	m := false
	for _, b := range data.GetArray("allowed-branches") {
		re := b.Unwrap().(string)
		if re == "*" || re == branch {
			m = true
			break
		} else if m, _ = regexp.MatchString(re, branch); m {
			break
		}
	}

	if !m {
		log.Println("branch ", branch, " not in ", data.GetString("allowed-branches"))
		return nil
	}

	if data.GetBool("purge") {
		return goCdDelete(name, data.GetString("environment"), url,
			map[string]string{"Accept": "application/vnd.go.cd.v5+json"})
	}

	exist, err := goCdRequest("GET", url+"/go/api/admin/pipelines/"+name, "",
		map[string]string{"Accept": "application/vnd.go.cd.v5+json"})
	if err != nil {
		return err
	}

	if exist.StatusCode == http.StatusOK {
		err = goCdUpdate(name, data.GetString("environment"), url, body,
			map[string]string{"If-Match": exist.Header.Get("ETag"), "Accept": "application/vnd.go.cd.v5+json"}, depends)
	} else if exist.StatusCode == http.StatusNotFound {
		err = goCdCreate(name, data.GetString("environment"), url, body,
			map[string]string{"Accept": "application/vnd.go.cd.v5+json"})
	} else {
		return fmt.Errorf("Operation error: %s", exist.Status)
	}

	if err != nil {
		return err
	}

	return nil
}

func goCdCreate(name string, env string, resource string, body string, headers map[string]string) error {
	if resp, err := goCdRequest("POST", resource+"/go/api/admin/pipelines", body, headers); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		defer resp.Body.Close()
		if body, err := ioutil.ReadAll(resp.Body); err == nil {
			log.Printf("Operation body: %s", body)
		}
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	if err := gocdChangeEnv(resource, env, map[string]interface{}{"add": []string{name}}); err != nil {
		return err
	}

	return goCdUnpause(resource + "/go/api/pipelines/" + name)
}

func goCdUnpause(resource string) error {
	if resp, err := goCdRequest("POST", resource+"/unpause", "",
		map[string]string{"Confirm": "true"}); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		if body, err := ioutil.ReadAll(resp.Body); err == nil {
			log.Printf("Operation error body: %s", body)

			if strings.Contains(string(body), "is already unpaused") {
				return nil
			}
		}

		return fmt.Errorf("Operation error: %s", resp.Status)
	}
	return nil
}

func goCdUpdate(name string, env string, resource string, body string, headers map[string]string, depends []string) error {
	if resp, err := goCdRequest("PUT", resource+"/go/api/admin/pipelines/"+name, body, headers); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		defer resp.Body.Close()
		if body, err := ioutil.ReadAll(resp.Body); err == nil {
			log.Printf("Operation body: %s", body)
		}
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	if currentEnv, err := goCdFindEnv(resource, name, depends); err == nil {
		if env != currentEnv {
			if currentEnv != "" {
				if err := gocdChangeEnv(resource, currentEnv, map[string]interface{}{"remove": []string{name}}); err != nil {
					return err
				}
			}

			if err := gocdChangeEnv(resource, env, map[string]interface{}{"add": []string{name}}); err != nil {
				return err
			}
		}
	} else {
		return err
	}

	return nil
}

func goCdDelete(name string, env string, resource string, headers map[string]string) error {
	if err := gocdChangeEnv(resource, env, map[string]interface{}{"remove": []string{name}}); err != nil {
		log.Println("Error on remove pipeline from env: ", err)
	}

	if resp, err := goCdRequest("DELETE", resource+"/go/api/admin/pipelines/"+name, "", headers); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	return nil
}

func gocdChangeEnv(apiUrl string, env string, actions map[string]interface{}) error {
	body, _ := json.Marshal(map[string]interface{}{
		"pipelines": actions,
	})

	resp, err := goCdRequest("PATCH", apiUrl+"/go/api/admin/environments/"+env, string(body),
		map[string]string{"Accept": "application/vnd.go.cd.v2+json"})
	if err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	return nil
}

func goCdFindEnv(resource string, pipeline string, depends []string) (string, error) {
	resp, err := goCdRequest("GET", resource+"/go/api/admin/environments", "",
		map[string]string{"Accept": "application/vnd.go.cd.v2+json"})
	if err != nil {
		return "", err
	} else if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("Operation error: %s", resp.Status)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	tree, err := gabs.ParseJSON(body)
	if err != nil {
		return "", err
	}

	sort.Strings(depends)
	envs, _ := tree.Path("_embedded.environments").Children()
	curEnvName := ""
	for _, env := range envs {
		envName := env.Path("name").Data().(string)
		pipelines, _ := env.Path("pipelines").Children()

		if len(depends) > 0 {
			if i := sort.SearchStrings(depends, envName); i != len(depends) {
				depends = append(depends[:i], depends[i+1:]...)
			}
		} else {
			if curEnvName != "" {
				break
			}
		}

		for _, pline := range pipelines {
			if pline.Path("name").Data().(string) == pipeline {
				curEnvName = envName
			}
		}
	}

	if len(depends) != 0 {
		return curEnvName, fmt.Errorf("not found depends: %v", depends)
	}

	return curEnvName, nil
}

var httpClient = &http.Client{Transport: &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}}

var goCdRequest = func(method string, resource string, body string, headers map[string]string) (*http.Response, error) {
	req, _ := http.NewRequest(method, resource, bytes.NewReader([]byte(body)))

	for k, v := range headers {
		req.Header.Set(k, v)
	}

	req.Header.Set("Content-Type", "application/json")

	data, err := ioutil.ReadFile("/etc/serve/gocd_credentials")
	if err != nil {
		return nil, fmt.Errorf("Credentias file error: %v", err)
	}

	creds := &goCdCredents{}
	json.Unmarshal(data, creds)

	req.SetBasicAuth(creds.Login, creds.Password)

	log.Printf(" --> %s %s:\n%s\n%s\n\n", method, resource, req.Header, body)

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	log.Printf("<-- %s\n", resp.Status)
	return resp, nil
}

func replaceMapWithArray(data manifest.Manifest, mapPath string, arrPath string) {
	arrs := make([]interface{}, 0)
	for k, v := range data.GetMap(mapPath) {
		v.Set("name", k)
		arrs = append(arrs, v.Unwrap())
	}
	data.Set(arrPath, arrs)
	data.DelTree(mapPath)
}
<commit_msg>gocd: fix api for new gocd version<commit_after>package plugins

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"sort"
	"strings"

	"github.com/servehub/serve/manifest"
	"github.com/servehub/utils/gabs"
)

func init() {
	manifest.PluginRegestry.Add("gocd.pipeline.create", goCdPipelineCreate{})
}

/**
 * plugin for manifest section "goCd.pipeline.create"
 * section structure:
 *
 * goCd.pipeline.create:
 *   api-url: goCd_URL
 *   environment: ENV
 *   branch: BRANCH
 *   allowed-branches: [BRANCH, ...]
 *   pipeline:
 *     group: GROUP
 *     pipeline:
 *       according to the description: https://api.go.cd/current/#the-pipeline-config-object
 */

type goCdCredents struct {
	Login    string `json:"login"`
	Password string `json:"password"`
}

type goCdPipelineCreate struct{}

func (p goCdPipelineCreate) Run(data manifest.Manifest) error {
	if suffix := data.GetString("name-suffix"); suffix != "" {
		data.Set("pipeline.pipeline.name", data.GetString("pipeline.pipeline.name")+suffix)
		data.Set("pipeline.pipeline.envs.SERVE_EXTRA_ARGS.value", data.GetStringOr("pipeline.pipeline.envs.SERVE_EXTRA_ARGS.value", "")+" --var name-suffix="+suffix)
	}

	name := data.GetString("pipeline.pipeline.name")
	url := data.GetString("api-url")
	if data.GetString("pipeline.pipeline.template") == "" {
		data.DelTree("pipeline.pipeline.template")
	}

	replaceMapWithArray(data, "pipeline.pipeline.envs", "pipeline.pipeline.environment_variables")
	replaceMapWithArray(data, "pipeline.pipeline.params", "pipeline.pipeline.parameters")

	depends := []string{}
	if !data.Has("pipeline.pipeline.materials") {
		data.Set("pipeline.pipeline.materials", []interface{}{})
	}
	for _, dep := range data.GetArray("depends") {
		pipeline := dep.GetString("pipeline")
		depends = append(depends, pipeline)
		data.ArrayAppend("pipeline.pipeline.materials",
			map[string]interface{}{"type": "dependency",
				"attributes": map[string]interface{}{
					"name":        dep.GetStringOr("name", pipeline),
					"pipeline":    pipeline,
					"stage":       data.GetStringOr("stage", "Build"),
					"auto_update": true}})
	}

	body := data.GetTree("pipeline").String()
	branch := data.GetString("branch")

	m := false
	for _, b := range data.GetArray("allowed-branches") {
		re := b.Unwrap().(string)
		if re == "*" || re == branch {
			m = true
			break
		} else if m, _ = regexp.MatchString(re, branch); m {
			break
		}
	}

	if !m {
		log.Println("branch ", branch, " not in ", data.GetString("allowed-branches"))
		return nil
	}

	if data.GetBool("purge") {
		return goCdDelete(name, data.GetString("environment"), url,
			map[string]string{"Accept": "application/vnd.go.cd.v6+json"})
	}

	exist, err := goCdRequest("GET", url+"/go/api/admin/pipelines/"+name, "",
		map[string]string{"Accept": "application/vnd.go.cd.v6+json"})
	if err != nil {
		return err
	}

	if exist.StatusCode == http.StatusOK {
		err = goCdUpdate(name, data.GetString("environment"), url, body,
			map[string]string{"If-Match": exist.Header.Get("ETag"), "Accept": "application/vnd.go.cd.v6+json"}, depends)
	} else if exist.StatusCode == http.StatusNotFound {
		err = goCdCreate(name, data.GetString("environment"), url, body,
			map[string]string{"Accept": "application/vnd.go.cd.v6+json"})
	} else {
		return fmt.Errorf("Operation error: %s", exist.Status)
	}

	if err != nil {
		return err
	}

	return nil
}

func goCdCreate(name string, env string, resource string, body string, headers map[string]string) error {
	if resp, err := goCdRequest("POST", resource+"/go/api/admin/pipelines", body, headers); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		defer resp.Body.Close()
		if body, err := ioutil.ReadAll(resp.Body); err == nil {
			log.Printf("Operation body: %s", body)
		}
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	if err := gocdChangeEnv(resource, env, map[string]interface{}{"add": []string{name}}); err != nil {
		return err
	}

	return goCdUnpause(resource + "/go/api/pipelines/" + name)
}

func goCdUnpause(resource string) error {
	if resp, err := goCdRequest("POST", resource+"/unpause", "",
		map[string]string{"Confirm": "true"}); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		if body, err := ioutil.ReadAll(resp.Body); err == nil {
			log.Printf("Operation error body: %s", body)

			if strings.Contains(string(body), "is already unpaused") {
				return nil
			}
		}

		return fmt.Errorf("Operation error: %s", resp.Status)
	}
	return nil
}

func goCdUpdate(name string, env string, resource string, body string, headers map[string]string, depends []string) error {
	if resp, err := goCdRequest("PUT", resource+"/go/api/admin/pipelines/"+name, body, headers); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		defer resp.Body.Close()
		if body, err := ioutil.ReadAll(resp.Body); err == nil {
			log.Printf("Operation body: %s", body)
		}
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	if currentEnv, err := goCdFindEnv(resource, name, depends); err == nil {
		if env != currentEnv {
			if currentEnv != "" {
				if err := gocdChangeEnv(resource, currentEnv, map[string]interface{}{"remove": []string{name}}); err != nil {
					return err
				}
			}

			if err := gocdChangeEnv(resource, env, map[string]interface{}{"add": []string{name}}); err != nil {
				return err
			}
		}
	} else {
		return err
	}

	return nil
}

func goCdDelete(name string, env string, resource string, headers map[string]string) error {
	if err := gocdChangeEnv(resource, env, map[string]interface{}{"remove": []string{name}}); err != nil {
		log.Println("Error on remove pipeline from env: ", err)
	}

	if resp, err := goCdRequest("DELETE", resource+"/go/api/admin/pipelines/"+name, "", headers); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	return nil
}

func gocdChangeEnv(apiUrl string, env string, actions map[string]interface{}) error {
	body, _ := json.Marshal(map[string]interface{}{
		"pipelines": actions,
	})

	resp, err := goCdRequest("PATCH", apiUrl+"/go/api/admin/environments/"+env, string(body),
		map[string]string{"Accept": "application/vnd.go.cd.v2+json"})
	if err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Operation error: %s", resp.Status)
	}

	return nil
}

func goCdFindEnv(resource string, pipeline string, depends []string) (string, error) {
	resp, err := goCdRequest("GET", resource+"/go/api/admin/environments", "",
		map[string]string{"Accept": "application/vnd.go.cd.v2+json"})
	if err != nil {
		return "", err
	} else if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("Operation error: %s", resp.Status)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	tree, err := gabs.ParseJSON(body)
	if err != nil {
		return "", err
	}

	sort.Strings(depends)
	envs, _ := tree.Path("_embedded.environments").Children()
	curEnvName := ""
	for _, env := range envs {
		envName := env.Path("name").Data().(string)
		pipelines, _ := env.Path("pipelines").Children()

		if len(depends) > 0 {
			if i := sort.SearchStrings(depends, envName); i != len(depends) {
				depends = append(depends[:i], depends[i+1:]...)
			}
		} else {
			if curEnvName != "" {
				break
			}
		}

		for _, pline := range pipelines {
			if pline.Path("name").Data().(string) == pipeline {
				curEnvName = envName
			}
		}
	}

	if len(depends) != 0 {
		return curEnvName, fmt.Errorf("not found depends: %v", depends)
	}

	return curEnvName, nil
}

var httpClient = &http.Client{Transport: &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}}

var goCdRequest = func(method string, resource string, body string, headers map[string]string) (*http.Response, error) {
	req, _ := http.NewRequest(method, resource, bytes.NewReader([]byte(body)))

	for k, v := range headers {
		req.Header.Set(k, v)
	}

	req.Header.Set("Content-Type", "application/json")

	data, err := ioutil.ReadFile("/etc/serve/gocd_credentials")
	if err != nil {
		return nil, fmt.Errorf("Credentias file error: %v", err)
	}

	creds := &goCdCredents{}
	json.Unmarshal(data, creds)

	req.SetBasicAuth(creds.Login, creds.Password)

	log.Printf(" --> %s %s:\n%s\n%s\n\n", method, resource, req.Header, body)

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	log.Printf("<-- %s\n", resp.Status)
	return resp, nil
}

func replaceMapWithArray(data manifest.Manifest, mapPath string, arrPath string) {
	arrs := make([]interface{}, 0)
	for k, v := range data.GetMap(mapPath) {
		v.Set("name", k)
		arrs = append(arrs, v.Unwrap())
	}
	data.Set(arrPath, arrs)
	data.DelTree(mapPath)
}
<|endoftext|>


<commit_before><commit_msg>profiler: make benchmark API address configurable<commit_after><|endoftext|>


<commit_before>/*
   Copyright 2014 CoreOS, Inc.

   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 raft

import (
	"fmt"
	"log"

	pb "github.com/coreos/etcd/raft/raftpb"
)

type raftLog struct {
	// storage contains all stable entries since the last snapshot.
	storage Storage
	// unstableEnts contains all entries that have not yet been written
	// to storage.
	unstableEnts []pb.Entry
	// unstableEnts[i] has raft log position i+unstable.  Note that
	// unstable may be less than the highest log position in storage;
	// this means that the next write to storage will truncate the log
	// before persisting unstableEnts.
	unstable uint64
	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	// Invariant: committed < unstable
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	applied uint64
}

func newLog(storage Storage) *raftLog {
	if storage == nil {
		log.Panic("storage must not be nil")
	}
	log := &raftLog{
		storage: storage,
	}
	firstIndex, err := storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	lastIndex, err := storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	log.unstable = lastIndex + 1
	// Initialize our committed and applied pointers to the time of the last compaction.
	log.committed = firstIndex - 1
	log.applied = firstIndex - 1

	return log
}

func (l *raftLog) String() string {
	return fmt.Sprintf("unstable=%d committed=%d applied=%d", l.unstable, l.committed, l.applied)
}

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
	lastnewi = index + uint64(len(ents))
	if l.matchTerm(index, logTerm) {
		from := index + 1
		ci := l.findConflict(from, ents)
		switch {
		case ci == 0:
		case ci <= l.committed:
			panic("conflict with committed entry")
		default:
			l.append(ci-1, ents[ci-from:]...)
		}
		l.commitTo(min(committed, lastnewi))
		return lastnewi, true
	}
	return 0, false
}

func (l *raftLog) append(after uint64, ents ...pb.Entry) uint64 {
	if after < l.committed {
		log.Panicf("after(%d) out of range [committed(%d)]", after, l.committed)
	}
	if after < l.unstable {
		// The log is being truncated to before our current unstable
		// portion, so discard it and reset unstable.
		l.unstableEnts = nil
		l.unstable = after + 1
	}
	// Truncate any unstable entries that are being replaced, then
	// append the new ones.
	l.unstableEnts = append(l.unstableEnts[0:1+after-l.unstable], ents...)
	l.unstable = min(l.unstable, after+1)
	return l.lastIndex()
}

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The first entry MUST have an index equal to the argument 'from'.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 {
	// TODO(xiangli): validate the index of ents
	for i, ne := range ents {
		if oe := l.at(from + uint64(i)); oe == nil || oe.Term != ne.Term {
			return from + uint64(i)
		}
	}
	return 0
}

func (l *raftLog) unstableEntries() []pb.Entry {
	if len(l.unstableEnts) == 0 {
		return nil
	}
	return append([]pb.Entry(nil), l.unstableEnts...)
}

// nextEnts returns all the available entries for execution.
// If applied is smaller than the index of snapshot, it returns all committed
// entries after the index of snapshot.
func (l *raftLog) nextEnts() (ents []pb.Entry) {
	off := max(l.applied+1, l.firstIndex())
	if l.committed+1 > off {
		return l.slice(off, l.committed+1)
	}
	return nil
}

func (l *raftLog) firstIndex() uint64 {
	index, err := l.storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) lastIndex() uint64 {
	if len(l.unstableEnts) > 0 {
		return l.unstable + uint64(len(l.unstableEnts)) - 1
	}
	index, err := l.storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) commitTo(tocommit uint64) {
	// never decrease commit
	if l.committed < tocommit {
		if l.lastIndex() < tocommit {
			log.Panicf("tocommit(%d) is out of range [lastIndex(%d)]", tocommit, l.lastIndex())
		}
		l.committed = tocommit
	}
}

func (l *raftLog) appliedTo(i uint64) {
	if i == 0 {
		return
	}
	if l.committed < i || i < l.applied {
		log.Panicf("applied(%d) is out of range [prevApplied(%d), committed(%d)]", i, l.applied, l.committed)
	}
	l.applied = i
}

func (l *raftLog) stableTo(i uint64) {
	if i < l.unstable || i+1-l.unstable > uint64(len(l.unstableEnts)) {
		log.Panicf("stableTo(%d) is out of range [unstable(%d), len(unstableEnts)(%d)]",
			i, l.unstable, len(l.unstableEnts))
	}
	l.unstableEnts = l.unstableEnts[i+1-l.unstable:]
	l.unstable = i + 1
}

func (l *raftLog) lastTerm() uint64 {
	return l.term(l.lastIndex())
}

func (l *raftLog) term(i uint64) uint64 {
	if i < l.unstable {
		t, err := l.storage.Term(i)
		if err == ErrCompacted {
			return 0
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}
		return t
	}
	if i >= l.unstable+uint64(len(l.unstableEnts)) {
		return 0
	}
	return l.unstableEnts[i-l.unstable].Term
}

func (l *raftLog) entries(i uint64) []pb.Entry {
	return l.slice(i, l.lastIndex()+1)
}

// allEntries returns all entries in the log.
func (l *raftLog) allEntries() []pb.Entry {
	return l.entries(l.firstIndex())
}

// isUpToDate determines if the given (lastIndex,term) log is more up-to-date
// by comparing the index and term of the last entries in the existing logs.
// If the logs have last entries with different terms, then the log with the
// later term is more up-to-date. If the logs end with the same term, then
// whichever log has the larger lastIndex is more up-to-date. If the logs are
// the same, the given log is up-to-date.
func (l *raftLog) isUpToDate(lasti, term uint64) bool {
	return term > l.lastTerm() || (term == l.lastTerm() && lasti >= l.lastIndex())
}

func (l *raftLog) matchTerm(i, term uint64) bool {
	return l.term(i) == term
}

func (l *raftLog) maybeCommit(maxIndex, term uint64) bool {
	if maxIndex > l.committed && l.term(maxIndex) == term {
		l.commitTo(maxIndex)
		return true
	}
	return false
}

func (l *raftLog) restore(s pb.Snapshot) {
	err := l.storage.ApplySnapshot(s)
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	l.committed = s.Metadata.Index
	l.applied = s.Metadata.Index
	l.unstable = l.committed + 1
	l.unstableEnts = nil
}

func (l *raftLog) at(i uint64) *pb.Entry {
	ents := l.slice(i, i+1)
	if len(ents) == 0 {
		return nil
	}
	return &ents[0]
}

// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo uint64, hi uint64) []pb.Entry {
	if lo >= hi {
		return nil
	}
	if l.isOutOfBounds(lo) || l.isOutOfBounds(hi-1) {
		return nil
	}
	var ents []pb.Entry
	if lo < l.unstable {
		storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable))
		if err == ErrCompacted {
			return nil
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}
		ents = append(ents, storedEnts...)
	}
	if len(l.unstableEnts) > 0 && hi > l.unstable {
		firstUnstable := max(lo, l.unstable)
		ents = append(ents, l.unstableEnts[firstUnstable-l.unstable:hi-l.unstable]...)
	}
	return ents
}

func (l *raftLog) isOutOfBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.lastIndex() {
		return true
	}
	return false
}

func (l *raftLog) isOutOfAppliedBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.applied {
		return true
	}
	return false
}

func min(a, b uint64) uint64 {
	if a > b {
		return b
	}
	return a
}

func max(a, b uint64) uint64 {
	if a > b {
		return a
	}
	return b
}
<commit_msg>raft: use empty slice in unstableEntries in log.go<commit_after>/*
   Copyright 2014 CoreOS, Inc.

   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 raft

import (
	"fmt"
	"log"

	pb "github.com/coreos/etcd/raft/raftpb"
)

type raftLog struct {
	// storage contains all stable entries since the last snapshot.
	storage Storage
	// unstableEnts contains all entries that have not yet been written
	// to storage.
	unstableEnts []pb.Entry
	// unstableEnts[i] has raft log position i+unstable.  Note that
	// unstable may be less than the highest log position in storage;
	// this means that the next write to storage will truncate the log
	// before persisting unstableEnts.
	unstable uint64
	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	// Invariant: committed < unstable
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	applied uint64
}

func newLog(storage Storage) *raftLog {
	if storage == nil {
		log.Panic("storage must not be nil")
	}
	log := &raftLog{
		storage: storage,
	}
	firstIndex, err := storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	lastIndex, err := storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	log.unstable = lastIndex + 1
	// Initialize our committed and applied pointers to the time of the last compaction.
	log.committed = firstIndex - 1
	log.applied = firstIndex - 1

	return log
}

func (l *raftLog) String() string {
	return fmt.Sprintf("unstable=%d committed=%d applied=%d", l.unstable, l.committed, l.applied)
}

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
	lastnewi = index + uint64(len(ents))
	if l.matchTerm(index, logTerm) {
		from := index + 1
		ci := l.findConflict(from, ents)
		switch {
		case ci == 0:
		case ci <= l.committed:
			panic("conflict with committed entry")
		default:
			l.append(ci-1, ents[ci-from:]...)
		}
		l.commitTo(min(committed, lastnewi))
		return lastnewi, true
	}
	return 0, false
}

func (l *raftLog) append(after uint64, ents ...pb.Entry) uint64 {
	if after < l.committed {
		log.Panicf("after(%d) out of range [committed(%d)]", after, l.committed)
	}
	if after < l.unstable {
		// The log is being truncated to before our current unstable
		// portion, so discard it and reset unstable.
		l.unstableEnts = nil
		l.unstable = after + 1
	}
	// Truncate any unstable entries that are being replaced, then
	// append the new ones.
	l.unstableEnts = append(l.unstableEnts[0:1+after-l.unstable], ents...)
	l.unstable = min(l.unstable, after+1)
	return l.lastIndex()
}

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The first entry MUST have an index equal to the argument 'from'.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 {
	// TODO(xiangli): validate the index of ents
	for i, ne := range ents {
		if oe := l.at(from + uint64(i)); oe == nil || oe.Term != ne.Term {
			return from + uint64(i)
		}
	}
	return 0
}

func (l *raftLog) unstableEntries() []pb.Entry {
	if len(l.unstableEnts) == 0 {
		return nil
	}
	return append([]pb.Entry{}, l.unstableEnts...)
}

// nextEnts returns all the available entries for execution.
// If applied is smaller than the index of snapshot, it returns all committed
// entries after the index of snapshot.
func (l *raftLog) nextEnts() (ents []pb.Entry) {
	off := max(l.applied+1, l.firstIndex())
	if l.committed+1 > off {
		return l.slice(off, l.committed+1)
	}
	return nil
}

func (l *raftLog) firstIndex() uint64 {
	index, err := l.storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) lastIndex() uint64 {
	if len(l.unstableEnts) > 0 {
		return l.unstable + uint64(len(l.unstableEnts)) - 1
	}
	index, err := l.storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) commitTo(tocommit uint64) {
	// never decrease commit
	if l.committed < tocommit {
		if l.lastIndex() < tocommit {
			log.Panicf("tocommit(%d) is out of range [lastIndex(%d)]", tocommit, l.lastIndex())
		}
		l.committed = tocommit
	}
}

func (l *raftLog) appliedTo(i uint64) {
	if i == 0 {
		return
	}
	if l.committed < i || i < l.applied {
		log.Panicf("applied(%d) is out of range [prevApplied(%d), committed(%d)]", i, l.applied, l.committed)
	}
	l.applied = i
}

func (l *raftLog) stableTo(i uint64) {
	if i < l.unstable || i+1-l.unstable > uint64(len(l.unstableEnts)) {
		log.Panicf("stableTo(%d) is out of range [unstable(%d), len(unstableEnts)(%d)]",
			i, l.unstable, len(l.unstableEnts))
	}
	l.unstableEnts = l.unstableEnts[i+1-l.unstable:]
	l.unstable = i + 1
}

func (l *raftLog) lastTerm() uint64 {
	return l.term(l.lastIndex())
}

func (l *raftLog) term(i uint64) uint64 {
	if i < l.unstable {
		t, err := l.storage.Term(i)
		if err == ErrCompacted {
			return 0
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}
		return t
	}
	if i >= l.unstable+uint64(len(l.unstableEnts)) {
		return 0
	}
	return l.unstableEnts[i-l.unstable].Term
}

func (l *raftLog) entries(i uint64) []pb.Entry {
	return l.slice(i, l.lastIndex()+1)
}

// allEntries returns all entries in the log.
func (l *raftLog) allEntries() []pb.Entry {
	return l.entries(l.firstIndex())
}

// isUpToDate determines if the given (lastIndex,term) log is more up-to-date
// by comparing the index and term of the last entries in the existing logs.
// If the logs have last entries with different terms, then the log with the
// later term is more up-to-date. If the logs end with the same term, then
// whichever log has the larger lastIndex is more up-to-date. If the logs are
// the same, the given log is up-to-date.
func (l *raftLog) isUpToDate(lasti, term uint64) bool {
	return term > l.lastTerm() || (term == l.lastTerm() && lasti >= l.lastIndex())
}

func (l *raftLog) matchTerm(i, term uint64) bool {
	return l.term(i) == term
}

func (l *raftLog) maybeCommit(maxIndex, term uint64) bool {
	if maxIndex > l.committed && l.term(maxIndex) == term {
		l.commitTo(maxIndex)
		return true
	}
	return false
}

func (l *raftLog) restore(s pb.Snapshot) {
	err := l.storage.ApplySnapshot(s)
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	l.committed = s.Metadata.Index
	l.applied = s.Metadata.Index
	l.unstable = l.committed + 1
	l.unstableEnts = nil
}

func (l *raftLog) at(i uint64) *pb.Entry {
	ents := l.slice(i, i+1)
	if len(ents) == 0 {
		return nil
	}
	return &ents[0]
}

// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo uint64, hi uint64) []pb.Entry {
	if lo >= hi {
		return nil
	}
	if l.isOutOfBounds(lo) || l.isOutOfBounds(hi-1) {
		return nil
	}
	var ents []pb.Entry
	if lo < l.unstable {
		storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable))
		if err == ErrCompacted {
			return nil
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}
		ents = append(ents, storedEnts...)
	}
	if len(l.unstableEnts) > 0 && hi > l.unstable {
		firstUnstable := max(lo, l.unstable)
		ents = append(ents, l.unstableEnts[firstUnstable-l.unstable:hi-l.unstable]...)
	}
	return ents
}

func (l *raftLog) isOutOfBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.lastIndex() {
		return true
	}
	return false
}

func (l *raftLog) isOutOfAppliedBounds(i uint64) bool {
	if i < l.firstIndex() || i > l.applied {
		return true
	}
	return false
}

func min(a, b uint64) uint64 {
	if a > b {
		return b
	}
	return a
}

func max(a, b uint64) uint64 {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>// +build !windows,!darwin,!plan9

// 17 february 2014

package ui

import (
	"unsafe"
)

/*
GTK+ 3.10 introduces a dedicated GtkListView type for simple listboxes like our Listbox. Unfortunately, since I want to target at least GTK+ 3.4, I need to do things the old, long, and hard way: manually with a GtkTreeView and GtkListStore model.

You are not expected to understand this.

if you must though:
GtkTreeViews are model/view. We use a GtkListStore as a model.
GtkTreeViews also separate selections into another type, but the GtkTreeView creates the selection object for us.
GtkTreeViews can scroll, but do not draw scrollbars or borders; we need to use a GtkScrolledWindow to hold the GtkTreeView to do so. We return the GtkScrolledWindow and get its control out when we want to access the GtkTreeView.
Like with Windows, there's a difference between signle-selection and multi-selection GtkTreeViews when it comes to getting the list of selections that we can exploit. The GtkTreeSelection class hands us an iterator and the model (for some reason). We pull a GtkTreePath out of the iterator, which we can then use to get the indices or text data.

For more information, read
	https://developer.gnome.org/gtk3/3.4/TreeWidget.html
	http://ubuntuforums.org/showthread.php?t=1208655
	http://scentric.net/tutorial/sec-treemodel-remove-row.html
	http://gtk.10911.n7.nabble.com/Scrollbars-in-a-GtkTreeView-td58076.html
	http://stackoverflow.com/questions/11407447/gtk-treeview-get-current-row-index-in-python (I think; I don't remember if I wound up using this one as a reference or not; I know after that I found the ubuntuforums link above)
and the GTK+ reference documentation.
*/

// #cgo pkg-config: gtk+-3.0
// #include "gtk_unix.h"
// /* because cgo seems to choke on ... */
// void gtkTreeModelGet(GtkTreeModel *model, GtkTreeIter *iter, gchar **gs)
// {
// 	/* 0 is the column #; we only have one column here */
// 	gtk_tree_model_get(model, iter, 0, gs, -1);
// }
// GtkListStore *gtkListStoreNew(void)
// {
// 	/* 1 column that stores strings */
// 	return gtk_list_store_new(1, G_TYPE_STRING);
// }
// void gtkListStoreSet(GtkListStore *ls, GtkTreeIter *iter, char *gs)
// {
// 	/* same parameters as in gtkTreeModelGet() */
// 	gtk_list_store_set(ls, iter, 0, (gchar *) gs, -1);
// }
// GtkTreeViewColumn *gtkTreeViewColumnNewWithAttributes(GtkCellRenderer *renderer)
// {
// 	/* "" is the column header; "text" associates the text of the column with column 0 */
// 	return gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
// }
import "C"

func fromgtktreemodel(x *C.GtkTreeModel) *C.GtkWidget {
	return (*C.GtkWidget)(unsafe.Pointer(x))
}

func togtktreemodel(what *C.GtkWidget) *C.GtkTreeModel {
	return (*C.GtkTreeModel)(unsafe.Pointer(what))
}

func fromgtktreeview(x *C.GtkTreeView) *C.GtkWidget {
	return (*C.GtkWidget)(unsafe.Pointer(x))
}

func togtktreeview(what *C.GtkWidget) *C.GtkTreeView {
	return (*C.GtkTreeView)(unsafe.Pointer(what))
}

func gListboxNew(multisel bool) *C.GtkWidget {
	store := C.gtkListStoreNew()
	widget := C.gtk_tree_view_new_with_model((*C.GtkTreeModel)(unsafe.Pointer(store)))
	tv := (*C.GtkTreeView)(unsafe.Pointer(widget))
	column := C.gtkTreeViewColumnNewWithAttributes(C.gtk_cell_renderer_text_new())
	// TODO set AUTOSIZE?
	C.gtk_tree_view_append_column(tv, column)
	C.gtk_tree_view_set_headers_visible(tv, C.FALSE)
	sel := C.GTK_SELECTION_SINGLE
	if multisel {
		sel = C.GTK_SELECTION_MULTIPLE
	}
	C.gtk_tree_selection_set_mode(C.gtk_tree_view_get_selection(tv), C.GtkSelectionMode(sel))
	scrollarea := C.gtk_scrolled_window_new((*C.GtkAdjustment)(nil), (*C.GtkAdjustment)(nil))
	// thanks to jlindgren in irc.gimp.net/#gtk+
	C.gtk_scrolled_window_set_shadow_type((*C.GtkScrolledWindow)(unsafe.Pointer(scrollarea)), C.GTK_SHADOW_IN)
	C.gtk_container_add((*C.GtkContainer)(unsafe.Pointer(scrollarea)), widget)
	return scrollarea
}

func gListboxNewSingle() *C.GtkWidget {
	return gListboxNew(false)
}

func gListboxNewMulti() *C.GtkWidget {
	return gListboxNew(true)
}

func getTreeViewFrom(widget *C.GtkWidget) *C.GtkTreeView {
	wid := C.gtk_bin_get_child((*C.GtkBin)(unsafe.Pointer(widget)))
	return (*C.GtkTreeView)(unsafe.Pointer(wid))
}

func gListboxText(widget *C.GtkWidget) string {
	var model *C.GtkTreeModel
	var iter C.GtkTreeIter
	var gs *C.gchar

	tv := getTreeViewFrom(widget)
	sel := C.gtk_tree_view_get_selection(tv)
	if !fromgbool(C.gtk_tree_selection_get_selected(sel, &model, &iter)) {
		return ""
	}
	C.gtkTreeModelGet(model, &iter, &gs)
	return fromgstr(gs)
}

func gListboxAppend(widget *C.GtkWidget, what string) {
	var iter C.GtkTreeIter

	tv := getTreeViewFrom(widget)
	ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv)))
	C.gtk_list_store_append(ls, &iter)
	cwhat := C.CString(what)
	defer C.free(unsafe.Pointer(cwhat))
	C.gtkListStoreSet(ls, &iter, cwhat)
}

func gListboxInsert(widget *C.GtkWidget, index int, what string) {
	var iter C.GtkTreeIter

	tv := getTreeViewFrom(widget)
	ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv)))
	C.gtk_list_store_insert(ls, &iter, C.gint(index))
	cwhat := C.CString(what)
	defer C.free(unsafe.Pointer(cwhat))
	C.gtkListStoreSet(ls, &iter, cwhat)
}

func gListboxSelectedMulti(widget *C.GtkWidget) (indices []int) {
	var model *C.GtkTreeModel

	tv := getTreeViewFrom(widget)
	sel := C.gtk_tree_view_get_selection(tv)
	rows := C.gtk_tree_selection_get_selected_rows(sel, &model)
	defer C.g_list_free_full(rows, C.GDestroyNotify(unsafe.Pointer(C.gtk_tree_path_free)))
	// TODO needed?
	len := C.g_list_length(rows)
	if len == 0 {
		return nil
	}
	indices = make([]int, len)
	for i := C.guint(0); i < len; i++ {
		path := (*C.GtkTreePath)(unsafe.Pointer(rows.data))
		idx := C.gtk_tree_path_get_indices(path)
		indices[i] = int(*idx)
		rows = rows.next
	}
	return indices
}

func gListboxSelMultiTexts(widget *C.GtkWidget) (texts []string) {
	var model *C.GtkTreeModel
	var iter C.GtkTreeIter
	var gs *C.gchar

	tv := getTreeViewFrom(widget)
	sel := C.gtk_tree_view_get_selection(tv)
	rows := C.gtk_tree_selection_get_selected_rows(sel, &model)
	defer C.g_list_free_full(rows, C.GDestroyNotify(unsafe.Pointer(C.gtk_tree_path_free)))
	len := C.g_list_length(rows)
	if len == 0 {
		return nil
	}
	texts = make([]string, len)
	for i := C.guint(0); i < len; i++ {
		path := (*C.GtkTreePath)(unsafe.Pointer(rows.data))
		if !fromgbool(C.gtk_tree_model_get_iter(model, &iter, path)) {
			// TODO
			return
		}
		C.gtkTreeModelGet(model, &iter, &gs)
		texts[i] = fromgstr(gs)
		rows = rows.next
	}
	return texts
}

func gListboxDelete(widget *C.GtkWidget, index int) {
	var iter C.GtkTreeIter

	tv := getTreeViewFrom(widget)
	ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv)))
	if !fromgbool(C.gtk_tree_model_iter_nth_child((*C.GtkTreeModel)(unsafe.Pointer(ls)), &iter, (*C.GtkTreeIter)(nil), C.gint(index))) {		// no such index
		// TODO
		return
	}
	C.gtk_list_store_remove(ls, &iter)
}

// this is a separate function because Combobox uses it too
func gtkTreeModelListLen(model *C.GtkTreeModel) int {
	// "As a special case, if iter is NULL, then the number of toplevel nodes is returned."
	return int(C.gtk_tree_model_iter_n_children(model, (*C.GtkTreeIter)(nil)))
}

func gListboxLen(widget *C.GtkWidget) int {
	tv := getTreeViewFrom(widget)
	model := C.gtk_tree_view_get_model(tv)
	return gtkTreeModelListLen(model)
}
<commit_msg>Made Listbox's column autoresizing on GTK+.<commit_after>// +build !windows,!darwin,!plan9

// 17 february 2014

package ui

import (
	"unsafe"
)

/*
GTK+ 3.10 introduces a dedicated GtkListView type for simple listboxes like our Listbox. Unfortunately, since I want to target at least GTK+ 3.4, I need to do things the old, long, and hard way: manually with a GtkTreeView and GtkListStore model.

You are not expected to understand this.

if you must though:
GtkTreeViews are model/view. We use a GtkListStore as a model.
GtkTreeViews also separate selections into another type, but the GtkTreeView creates the selection object for us.
GtkTreeViews can scroll, but do not draw scrollbars or borders; we need to use a GtkScrolledWindow to hold the GtkTreeView to do so. We return the GtkScrolledWindow and get its control out when we want to access the GtkTreeView.
Like with Windows, there's a difference between signle-selection and multi-selection GtkTreeViews when it comes to getting the list of selections that we can exploit. The GtkTreeSelection class hands us an iterator and the model (for some reason). We pull a GtkTreePath out of the iterator, which we can then use to get the indices or text data.

For more information, read
	https://developer.gnome.org/gtk3/3.4/TreeWidget.html
	http://ubuntuforums.org/showthread.php?t=1208655
	http://scentric.net/tutorial/sec-treemodel-remove-row.html
	http://gtk.10911.n7.nabble.com/Scrollbars-in-a-GtkTreeView-td58076.html
	http://stackoverflow.com/questions/11407447/gtk-treeview-get-current-row-index-in-python (I think; I don't remember if I wound up using this one as a reference or not; I know after that I found the ubuntuforums link above)
and the GTK+ reference documentation.
*/

// #cgo pkg-config: gtk+-3.0
// #include "gtk_unix.h"
// /* because cgo seems to choke on ... */
// void gtkTreeModelGet(GtkTreeModel *model, GtkTreeIter *iter, gchar **gs)
// {
// 	/* 0 is the column #; we only have one column here */
// 	gtk_tree_model_get(model, iter, 0, gs, -1);
// }
// GtkListStore *gtkListStoreNew(void)
// {
// 	/* 1 column that stores strings */
// 	return gtk_list_store_new(1, G_TYPE_STRING);
// }
// void gtkListStoreSet(GtkListStore *ls, GtkTreeIter *iter, char *gs)
// {
// 	/* same parameters as in gtkTreeModelGet() */
// 	gtk_list_store_set(ls, iter, 0, (gchar *) gs, -1);
// }
// GtkTreeViewColumn *gtkTreeViewColumnNewWithAttributes(GtkCellRenderer *renderer)
// {
// 	/* "" is the column header; "text" associates the text of the column with column 0 */
// 	return gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
// }
import "C"

func fromgtktreemodel(x *C.GtkTreeModel) *C.GtkWidget {
	return (*C.GtkWidget)(unsafe.Pointer(x))
}

func togtktreemodel(what *C.GtkWidget) *C.GtkTreeModel {
	return (*C.GtkTreeModel)(unsafe.Pointer(what))
}

func fromgtktreeview(x *C.GtkTreeView) *C.GtkWidget {
	return (*C.GtkWidget)(unsafe.Pointer(x))
}

func togtktreeview(what *C.GtkWidget) *C.GtkTreeView {
	return (*C.GtkTreeView)(unsafe.Pointer(what))
}

func gListboxNew(multisel bool) *C.GtkWidget {
	store := C.gtkListStoreNew()
	widget := C.gtk_tree_view_new_with_model((*C.GtkTreeModel)(unsafe.Pointer(store)))
	tv := (*C.GtkTreeView)(unsafe.Pointer(widget))
	column := C.gtkTreeViewColumnNewWithAttributes(C.gtk_cell_renderer_text_new())
	C.gtk_tree_view_column_set_sizing(column, C.GTK_TREE_VIEW_COLUMN_AUTOSIZE)
	C.gtk_tree_view_column_set_resizable(column, C.FALSE)		// not resizeable by the user; just autoresize
	C.gtk_tree_view_append_column(tv, column)
	C.gtk_tree_view_set_headers_visible(tv, C.FALSE)
	sel := C.GTK_SELECTION_SINGLE
	if multisel {
		sel = C.GTK_SELECTION_MULTIPLE
	}
	C.gtk_tree_selection_set_mode(C.gtk_tree_view_get_selection(tv), C.GtkSelectionMode(sel))
	scrollarea := C.gtk_scrolled_window_new((*C.GtkAdjustment)(nil), (*C.GtkAdjustment)(nil))
	// thanks to jlindgren in irc.gimp.net/#gtk+
	C.gtk_scrolled_window_set_shadow_type((*C.GtkScrolledWindow)(unsafe.Pointer(scrollarea)), C.GTK_SHADOW_IN)
	C.gtk_container_add((*C.GtkContainer)(unsafe.Pointer(scrollarea)), widget)
	return scrollarea
}

func gListboxNewSingle() *C.GtkWidget {
	return gListboxNew(false)
}

func gListboxNewMulti() *C.GtkWidget {
	return gListboxNew(true)
}

func getTreeViewFrom(widget *C.GtkWidget) *C.GtkTreeView {
	wid := C.gtk_bin_get_child((*C.GtkBin)(unsafe.Pointer(widget)))
	return (*C.GtkTreeView)(unsafe.Pointer(wid))
}

func gListboxText(widget *C.GtkWidget) string {
	var model *C.GtkTreeModel
	var iter C.GtkTreeIter
	var gs *C.gchar

	tv := getTreeViewFrom(widget)
	sel := C.gtk_tree_view_get_selection(tv)
	if !fromgbool(C.gtk_tree_selection_get_selected(sel, &model, &iter)) {
		return ""
	}
	C.gtkTreeModelGet(model, &iter, &gs)
	return fromgstr(gs)
}

func gListboxAppend(widget *C.GtkWidget, what string) {
	var iter C.GtkTreeIter

	tv := getTreeViewFrom(widget)
	ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv)))
	C.gtk_list_store_append(ls, &iter)
	cwhat := C.CString(what)
	defer C.free(unsafe.Pointer(cwhat))
	C.gtkListStoreSet(ls, &iter, cwhat)
}

func gListboxInsert(widget *C.GtkWidget, index int, what string) {
	var iter C.GtkTreeIter

	tv := getTreeViewFrom(widget)
	ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv)))
	C.gtk_list_store_insert(ls, &iter, C.gint(index))
	cwhat := C.CString(what)
	defer C.free(unsafe.Pointer(cwhat))
	C.gtkListStoreSet(ls, &iter, cwhat)
}

func gListboxSelectedMulti(widget *C.GtkWidget) (indices []int) {
	var model *C.GtkTreeModel

	tv := getTreeViewFrom(widget)
	sel := C.gtk_tree_view_get_selection(tv)
	rows := C.gtk_tree_selection_get_selected_rows(sel, &model)
	defer C.g_list_free_full(rows, C.GDestroyNotify(unsafe.Pointer(C.gtk_tree_path_free)))
	// TODO needed?
	len := C.g_list_length(rows)
	if len == 0 {
		return nil
	}
	indices = make([]int, len)
	for i := C.guint(0); i < len; i++ {
		path := (*C.GtkTreePath)(unsafe.Pointer(rows.data))
		idx := C.gtk_tree_path_get_indices(path)
		indices[i] = int(*idx)
		rows = rows.next
	}
	return indices
}

func gListboxSelMultiTexts(widget *C.GtkWidget) (texts []string) {
	var model *C.GtkTreeModel
	var iter C.GtkTreeIter
	var gs *C.gchar

	tv := getTreeViewFrom(widget)
	sel := C.gtk_tree_view_get_selection(tv)
	rows := C.gtk_tree_selection_get_selected_rows(sel, &model)
	defer C.g_list_free_full(rows, C.GDestroyNotify(unsafe.Pointer(C.gtk_tree_path_free)))
	len := C.g_list_length(rows)
	if len == 0 {
		return nil
	}
	texts = make([]string, len)
	for i := C.guint(0); i < len; i++ {
		path := (*C.GtkTreePath)(unsafe.Pointer(rows.data))
		if !fromgbool(C.gtk_tree_model_get_iter(model, &iter, path)) {
			// TODO
			return
		}
		C.gtkTreeModelGet(model, &iter, &gs)
		texts[i] = fromgstr(gs)
		rows = rows.next
	}
	return texts
}

func gListboxDelete(widget *C.GtkWidget, index int) {
	var iter C.GtkTreeIter

	tv := getTreeViewFrom(widget)
	ls := (*C.GtkListStore)(unsafe.Pointer(C.gtk_tree_view_get_model(tv)))
	if !fromgbool(C.gtk_tree_model_iter_nth_child((*C.GtkTreeModel)(unsafe.Pointer(ls)), &iter, (*C.GtkTreeIter)(nil), C.gint(index))) {		// no such index
		// TODO
		return
	}
	C.gtk_list_store_remove(ls, &iter)
}

// this is a separate function because Combobox uses it too
func gtkTreeModelListLen(model *C.GtkTreeModel) int {
	// "As a special case, if iter is NULL, then the number of toplevel nodes is returned."
	return int(C.gtk_tree_model_iter_n_children(model, (*C.GtkTreeIter)(nil)))
}

func gListboxLen(widget *C.GtkWidget) int {
	tv := getTreeViewFrom(widget)
	model := C.gtk_tree_view_get_model(tv)
	return gtkTreeModelListLen(model)
}
<|endoftext|>


<commit_before>// Simple Radius server inspired on net/http.
package radius

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"radiusd/config"
)

var handlers map[string]func(io.Writer, *Packet)

func init() {
	handlers = make(map[string]func(io.Writer, *Packet))
}

func HandleFunc(code PacketCode, statusType int, handler func(io.Writer, *Packet)) {
	key := fmt.Sprintf("%d-%d", code, statusType)
	if _, inuse := handlers[key]; inuse {
		panic(fmt.Errorf("DevErr: HandleFunc-add for already assigned code=%d", code))
	}
	handlers[key] = handler
}

func ListenAndServe(addr string, secret string, cidrs []string) error {
	var whitelist []*net.IPNet

	for _, cidr := range cidrs {
		_, net, e := net.ParseCIDR(cidr)
		if e != nil {
			return e
		}
		whitelist = append(whitelist, net)
	}

	udpAddr, e := net.ResolveUDPAddr("udp", addr)
	if e != nil {
		return e
	}
	conn, e := net.ListenUDP("udp", udpAddr)
	if e != nil {
		return e
	}

	buf := make([]byte, 1024)
	readBuf := new(bytes.Buffer)
	for {
		n, client, e := conn.ReadFromUDP(buf)
		if e != nil {
			// TODO: Silently ignore?
			return e
		}
		ok := false
		for _, cidr := range whitelist {
			if cidr.Contains(client.IP) {
				ok = true
				break
			}
		}
		if !ok {
			config.Log.Printf("Request dropped for invalid IP=" + client.String())
			continue
		}

		p, e := decode(buf, n, secret)
		if e != nil {
			// TODO: Silently ignore decode?
			return e
		}
		if !validate(p) {
			// TODO: Silently ignore invalidate package?
			return fmt.Errorf("Invalid MessageAuthenticator")
		}

		statusType := uint32(0)
		if attr, ok := p.Attrs[AcctStatusType]; ok {
			statusType = binary.BigEndian.Uint32(attr.Value)
		}

		key := fmt.Sprintf("%d-%d", p.Code, statusType)
		handle, ok := handlers[key]
		if ok {
			handle(readBuf, p)
			if _, e := conn.WriteTo(readBuf.Bytes(), client); e != nil {
				// TODO: ignore clients that gone away?
				panic(e)
			}
		} else {
			fmt.Println(fmt.Sprintf("Drop packet with code=%d, statusType=%d", p.Code, statusType))
		}

		readBuf.Reset()
	}
}
<commit_msg>Bugfix. Only reply if we got something to send<commit_after>// Simple Radius server inspired on net/http.
package radius

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"radiusd/config"
)

var handlers map[string]func(io.Writer, *Packet)

func init() {
	handlers = make(map[string]func(io.Writer, *Packet))
}

func HandleFunc(code PacketCode, statusType int, handler func(io.Writer, *Packet)) {
	key := fmt.Sprintf("%d-%d", code, statusType)
	if _, inuse := handlers[key]; inuse {
		panic(fmt.Errorf("DevErr: HandleFunc-add for already assigned code=%d", code))
	}
	handlers[key] = handler
}

func ListenAndServe(addr string, secret string, cidrs []string) error {
	var whitelist []*net.IPNet

	for _, cidr := range cidrs {
		_, net, e := net.ParseCIDR(cidr)
		if e != nil {
			return e
		}
		whitelist = append(whitelist, net)
	}

	udpAddr, e := net.ResolveUDPAddr("udp", addr)
	if e != nil {
		return e
	}
	conn, e := net.ListenUDP("udp", udpAddr)
	if e != nil {
		return e
	}

	buf := make([]byte, 1024)
	readBuf := new(bytes.Buffer)
	for {
		n, client, e := conn.ReadFromUDP(buf)
		if e != nil {
			// TODO: Silently ignore?
			return e
		}
		ok := false
		for _, cidr := range whitelist {
			if cidr.Contains(client.IP) {
				ok = true
				break
			}
		}
		if !ok {
			config.Log.Printf("Request dropped for invalid IP=" + client.String())
			continue
		}

		p, e := decode(buf, n, secret)
		if e != nil {
			// TODO: Silently ignore decode?
			return e
		}
		if !validate(p) {
			// TODO: Silently ignore invalidate package?
			return fmt.Errorf("Invalid MessageAuthenticator")
		}

		statusType := uint32(0)
		if attr, ok := p.Attrs[AcctStatusType]; ok {
			statusType = binary.BigEndian.Uint32(attr.Value)
		}

		key := fmt.Sprintf("%d-%d", p.Code, statusType)
		handle, ok := handlers[key]
		if ok {
			handle(readBuf, p)
			if len(readBuf.Bytes()) != 0 {
				// Only send a packet if we got anything
				if _, e := conn.WriteTo(readBuf.Bytes(), client); e != nil {
					// TODO: ignore clients that gone away?
					panic(e)
				}
			}
		} else {
			fmt.Println(fmt.Sprintf("Drop packet with code=%d, statusType=%d", p.Code, statusType))
		}

		readBuf.Reset()
	}
}
<|endoftext|>


<commit_before>// Package prompter is utility for easy prompting
package prompter

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/mattn/go-isatty"
	"golang.org/x/crypto/ssh/terminal"
)

// Prompter is object for prompting
type Prompter struct {
	Message string
	// choices of answer
	Choices    []string
	IgnoreCase bool
	Default    string
	// specify answer pattern by regexp. When both Choices and Regexp are specified, Regexp takes a priority.
	Regexp *regexp.Regexp
	// for passwords and so on.
	NoEcho     bool
	UseDefault bool
	reg        *regexp.Regexp
}

// Prompt displays a prompt and returns answer
func (p *Prompter) Prompt() string {
	fmt.Print(p.msg())
	if p.UseDefault || skip() {
		return p.Default
	}

	input := ""
	for {
		if p.NoEcho {
			b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
			if err == nil {
				input = string(b)
			}
			fmt.Print("\n")
		} else {
			scanner := bufio.NewScanner(os.Stdin)
			ok := scanner.Scan()
			if ok {
				input = strings.TrimRight(scanner.Text(), "\r\n")
			}
		}
		if input == "" {
			input = p.Default
		}
		if p.inputIsValid(input) {
			break
		}
		fmt.Println(p.errorMsg())
		fmt.Print(p.msg())
	}
	return input
}

func skip() bool {
	if os.Getenv("GO_PROMPTER_USE_DEFAULT") != "" {
		return true
	}
	return !isatty.IsTerminal(os.Stdin.Fd()) || !isatty.IsTerminal(os.Stdout.Fd())
}

func (p *Prompter) msg() string {
	msg := p.Message
	if p.Choices != nil && len(p.Choices) > 0 {
		msg += fmt.Sprintf(" (%s)", strings.Join(p.Choices, "/"))
	}
	if p.Default != "" {
		msg += " [" + p.Default + "]"
	}
	return msg + ": "
}

func (p *Prompter) errorMsg() string {
	if p.Regexp != nil {
		return fmt.Sprintf("# Answer should match /%s/", p.Regexp)
	}
	if p.Choices != nil && len(p.Choices) > 0 {
		if len(p.Choices) == 1 {
			return fmt.Sprintf("# Enter `%s`", p.Choices[0])
		}
		choices := make([]string, len(p.Choices)-1)
		for i, v := range p.Choices[:len(p.Choices)-1] {
			choices[i] = "`" + v + "`"
		}
		return fmt.Sprintf("# Enter %s or `%s`", strings.Join(choices, ", "), p.Choices[len(p.Choices)-1])
	}
	return ""
}

func (p *Prompter) inputIsValid(input string) bool {
	if p.IgnoreCase {
		input = strings.ToLower(input)
	}
	return p.regexp().MatchString(input)
}

var allReg = regexp.MustCompile(`.*`)

func (p *Prompter) regexp() *regexp.Regexp {
	if p.Regexp != nil {
		return p.Regexp
	}
	if p.reg != nil {
		return p.reg
	}
	if p.Choices == nil || len(p.Choices) == 0 {
		p.reg = allReg
		return p.reg
	}

	choices := make([]string, len(p.Choices))
	for i, v := range p.Choices {
		choice := regexp.QuoteMeta(v)
		if p.IgnoreCase {
			choice = strings.ToLower(choice)
		}
		choices[i] = choice
	}
	regStr := fmt.Sprintf(`\A(?:%s)\z`, strings.Join(choices, "|"))
	p.reg = regexp.MustCompile(regStr)
	return p.reg
}
<commit_msg>fix ignore case handling<commit_after>// Package prompter is utility for easy prompting
package prompter

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/mattn/go-isatty"
	"golang.org/x/crypto/ssh/terminal"
)

// Prompter is object for prompting
type Prompter struct {
	Message string
	// choices of answer
	Choices    []string
	IgnoreCase bool
	Default    string
	// specify answer pattern by regexp. When both Choices and Regexp are specified, Regexp takes a priority.
	Regexp *regexp.Regexp
	// for passwords and so on.
	NoEcho     bool
	UseDefault bool
	reg        *regexp.Regexp
}

// Prompt displays a prompt and returns answer
func (p *Prompter) Prompt() string {
	fmt.Print(p.msg())
	if p.UseDefault || skip() {
		return p.Default
	}

	input := ""
	for {
		if p.NoEcho {
			b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
			if err == nil {
				input = string(b)
			}
			fmt.Print("\n")
		} else {
			scanner := bufio.NewScanner(os.Stdin)
			ok := scanner.Scan()
			if ok {
				input = strings.TrimRight(scanner.Text(), "\r\n")
			}
		}
		if input == "" {
			input = p.Default
		}
		if p.inputIsValid(input) {
			break
		}
		fmt.Println(p.errorMsg())
		fmt.Print(p.msg())
	}
	return input
}

func skip() bool {
	if os.Getenv("GO_PROMPTER_USE_DEFAULT") != "" {
		return true
	}
	return !isatty.IsTerminal(os.Stdin.Fd()) || !isatty.IsTerminal(os.Stdout.Fd())
}

func (p *Prompter) msg() string {
	msg := p.Message
	if p.Choices != nil && len(p.Choices) > 0 {
		msg += fmt.Sprintf(" (%s)", strings.Join(p.Choices, "/"))
	}
	if p.Default != "" {
		msg += " [" + p.Default + "]"
	}
	return msg + ": "
}

func (p *Prompter) errorMsg() string {
	if p.Regexp != nil {
		return fmt.Sprintf("# Answer should match /%s/", p.Regexp)
	}
	if p.Choices != nil && len(p.Choices) > 0 {
		if len(p.Choices) == 1 {
			return fmt.Sprintf("# Enter `%s`", p.Choices[0])
		}
		choices := make([]string, len(p.Choices)-1)
		for i, v := range p.Choices[:len(p.Choices)-1] {
			choices[i] = "`" + v + "`"
		}
		return fmt.Sprintf("# Enter %s or `%s`", strings.Join(choices, ", "), p.Choices[len(p.Choices)-1])
	}
	return ""
}

func (p *Prompter) inputIsValid(input string) bool {
	return p.regexp().MatchString(input)
}

var allReg = regexp.MustCompile(`.*`)

func (p *Prompter) regexp() *regexp.Regexp {
	if p.Regexp != nil {
		return p.Regexp
	}
	if p.reg != nil {
		return p.reg
	}
	if p.Choices == nil || len(p.Choices) == 0 {
		p.reg = allReg
		return p.reg
	}

	choices := make([]string, len(p.Choices))
	for i, v := range p.Choices {
		choices[i] = regexp.QuoteMeta(v)
	}
	ignoreReg := ""
	if p.IgnoreCase {
		ignoreReg = "(?i)"
	}
	p.reg = regexp.MustCompile(fmt.Sprintf(`%s\A(?:%s)\z`, ignoreReg, strings.Join(choices, "|")))
	return p.reg
}
<|endoftext|>


<commit_before>//this file contains several examples by Golang
package main

import (
	"fmt"
)

func main() {

	checkNumberIsEvenOrOdd()

}

func checkNumberIsEvenOrOdd() {

	fmt.Print("Enter a number: ")
	var number int
	fmt.Scanf("%d", &number)

	if (number % 2 == 0) {
		fmt.Printf("%d is even number\n", number)
	} else {
		fmt.Printf("%d is odd number\n", number)
	}

}
<commit_msg>Init a function to convertFehrenheitToCelsius<commit_after>//this file contains several examples by Golang
package main

import (
	"fmt"
)

func main() {

	checkNumberIsEvenOrOdd()

}

func checkNumberIsEvenOrOdd() {

	fmt.Print("Enter a number: ")
	var number int
	fmt.Scanf("%d", &number)

	if (number % 2 == 0) {
		fmt.Printf("%d is even number\n", number)
	} else {
		fmt.Printf("%d is odd number\n", number)
	}

}

func convertFehrenheitToCelsius() {

}<|endoftext|>