<commit_before>package oauth2

import (
	"net/http"
	"net/url"
)

// A TokenRequest is typically returned by ParseTokenRequest and holds all
// information necessary to handle a token request.
type TokenRequest struct {
	GrantType    string
	Scope        Scope
	ClientID     string
	ClientSecret string
	Username     string
	Password     string
	RefreshToken string
	RedirectURI  string
	Code         string

	HTTP *http.Request
}

// ParseTokenRequest parses an incoming request and returns a TokenRequest.
// The functions validates basic constraints given by the OAuth2 spec.
//
// Note: Obtaining the client id and secret from the request body (form data)
// is not implemented by default due to security considerations.
func ParseTokenRequest(r *http.Request) (*TokenRequest, error) {
	// check method
	if r.Method != "POST" {
		return nil, InvalidRequest("invalid HTTP method")
	}

	// parse query params and body params to form
	err := r.ParseForm()
	if err != nil {
		return nil, InvalidRequest("malformed query parameters or body form")
	}

	// get grant type
	grantType := r.PostForm.Get("grant_type")
	if grantType == "" {
		return nil, InvalidRequest("missing grant type")
	}

	// get scope
	scope := ParseScope(r.PostForm.Get("scope"))

	// get client id and secret
	clientID, clientSecret, ok := r.BasicAuth()
	if !ok {
		return nil, InvalidRequest("missing or invalid HTTP authorization header")
	}

	// get username and password
	username := r.PostForm.Get("username")
	password := r.PostForm.Get("password")

	// get refresh token
	refreshToken := r.PostForm.Get("refresh_token")

	// get redirect uri
	redirectURIString, err := url.QueryUnescape(r.Form.Get("redirect_uri"))
	if err != nil {
		return nil, InvalidRequest("invalid redirect URI")
	}

	// validate redirect uri if present
	if redirectURIString != "" {
		redirectURI, err := url.ParseRequestURI(redirectURIString)
		if err != nil || redirectURI.Fragment != "" {
			return nil, InvalidRequest("invalid redirect URI")
		}
	}

	// get code
	code := r.PostForm.Get("code")

	return &TokenRequest{
		GrantType:    grantType,
		Scope:        scope,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Username:     username,
		Password:     password,
		RefreshToken: refreshToken,
		RedirectURI:  redirectURIString,
		Code:         code,
		HTTP:         r,
	}, nil
}

// A AuthorizationRequest is typically returned by ParseAuthorizationRequest and
// holds all information necessary to handle an authorization request.
type AuthorizationRequest struct {
	ResponseType string
	Scope        Scope
	ClientID     string
	RedirectURI  string
	State        string

	HTTP *http.Request
}

// ParseAuthorizationRequest parses an incoming request and returns an
// AuthorizationRequest. The functions validates basic constraints given by the
// OAuth2 spec.
func ParseAuthorizationRequest(r *http.Request) (*AuthorizationRequest, error) {
	// check method
	if r.Method != "GET" && r.Method != "POST" {
		return nil, InvalidRequest("invalid HTTP method")
	}

	// parse query params and body params to form
	err := r.ParseForm()
	if err != nil {
		return nil, InvalidRequest("malformed query parameters or form data")
	}

	// get state
	state := r.Form.Get("state")

	// get response type
	responseType := r.Form.Get("response_type")
	if responseType == "" {
		return nil, InvalidRequest("missing response type")
	}

	// get scope
	scope := ParseScope(r.Form.Get("scope"))

	// get client id
	clientID := r.Form.Get("client_id")
	if clientID == "" {
		return nil, InvalidRequest("missing client ID")
	}

	// get redirect uri
	redirectURIString, err := url.QueryUnescape(r.Form.Get("redirect_uri"))
	if err != nil || redirectURIString == "" {
		return nil, InvalidRequest("missing redirect URI")
	}

	// parse redirect uri
	redirectURI, err := url.ParseRequestURI(redirectURIString)
	if err != nil || redirectURI.Fragment != "" {
		return nil, InvalidRequest("invalid redirect URI")
	}

	return &AuthorizationRequest{
		ResponseType: responseType,
		Scope:        scope,
		ClientID:     clientID,
		RedirectURI:  redirectURIString,
		State:        state,
		HTTP:         r,
	}, nil
}
<commit_msg>only read from post body<commit_after>package oauth2

import (
	"net/http"
	"net/url"
)

// A TokenRequest is typically returned by ParseTokenRequest and holds all
// information necessary to handle a token request.
type TokenRequest struct {
	GrantType    string
	Scope        Scope
	ClientID     string
	ClientSecret string
	Username     string
	Password     string
	RefreshToken string
	RedirectURI  string
	Code         string

	HTTP *http.Request
}

// ParseTokenRequest parses an incoming request and returns a TokenRequest.
// The functions validates basic constraints given by the OAuth2 spec.
//
// Note: Obtaining the client id and secret from the request body (form data)
// is not implemented by default due to security considerations.
func ParseTokenRequest(r *http.Request) (*TokenRequest, error) {
	// check method
	if r.Method != "POST" {
		return nil, InvalidRequest("invalid HTTP method")
	}

	// parse query params and body params to form
	err := r.ParseForm()
	if err != nil {
		return nil, InvalidRequest("malformed query parameters or body form")
	}

	// get grant type
	grantType := r.PostForm.Get("grant_type")
	if grantType == "" {
		return nil, InvalidRequest("missing grant type")
	}

	// get scope
	scope := ParseScope(r.PostForm.Get("scope"))

	// get client id and secret
	clientID, clientSecret, ok := r.BasicAuth()
	if !ok {
		return nil, InvalidRequest("missing or invalid HTTP authorization header")
	}

	// get username and password
	username := r.PostForm.Get("username")
	password := r.PostForm.Get("password")

	// get refresh token
	refreshToken := r.PostForm.Get("refresh_token")

	// get redirect uri
	redirectURIString, err := url.QueryUnescape(r.PostForm.Get("redirect_uri"))
	if err != nil {
		return nil, InvalidRequest("invalid redirect URI")
	}

	// validate redirect uri if present
	if redirectURIString != "" {
		redirectURI, err := url.ParseRequestURI(redirectURIString)
		if err != nil || redirectURI.Fragment != "" {
			return nil, InvalidRequest("invalid redirect URI")
		}
	}

	// get code
	code := r.PostForm.Get("code")

	return &TokenRequest{
		GrantType:    grantType,
		Scope:        scope,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Username:     username,
		Password:     password,
		RefreshToken: refreshToken,
		RedirectURI:  redirectURIString,
		Code:         code,
		HTTP:         r,
	}, nil
}

// A AuthorizationRequest is typically returned by ParseAuthorizationRequest and
// holds all information necessary to handle an authorization request.
type AuthorizationRequest struct {
	ResponseType string
	Scope        Scope
	ClientID     string
	RedirectURI  string
	State        string

	HTTP *http.Request
}

// ParseAuthorizationRequest parses an incoming request and returns an
// AuthorizationRequest. The functions validates basic constraints given by the
// OAuth2 spec.
func ParseAuthorizationRequest(r *http.Request) (*AuthorizationRequest, error) {
	// check method
	if r.Method != "GET" && r.Method != "POST" {
		return nil, InvalidRequest("invalid HTTP method")
	}

	// parse query params and body params to form
	err := r.ParseForm()
	if err != nil {
		return nil, InvalidRequest("malformed query parameters or form data")
	}

	// get state
	state := r.Form.Get("state")

	// get response type
	responseType := r.Form.Get("response_type")
	if responseType == "" {
		return nil, InvalidRequest("missing response type")
	}

	// get scope
	scope := ParseScope(r.Form.Get("scope"))

	// get client id
	clientID := r.Form.Get("client_id")
	if clientID == "" {
		return nil, InvalidRequest("missing client ID")
	}

	// get redirect uri
	redirectURIString, err := url.QueryUnescape(r.Form.Get("redirect_uri"))
	if err != nil || redirectURIString == "" {
		return nil, InvalidRequest("missing redirect URI")
	}

	// parse redirect uri
	redirectURI, err := url.ParseRequestURI(redirectURIString)
	if err != nil || redirectURI.Fragment != "" {
		return nil, InvalidRequest("invalid redirect URI")
	}

	return &AuthorizationRequest{
		ResponseType: responseType,
		Scope:        scope,
		ClientID:     clientID,
		RedirectURI:  redirectURIString,
		State:        state,
		HTTP:         r,
	}, nil
}
<|endoftext|>


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

// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle

// ConstantTimeCompare returns 1 iff the two equal length slices, x
// and y, have equal contents. The time taken is a function of the length of
// the slices and is independent of the contents.
func ConstantTimeCompare(x, y []byte) int {
	var v byte

	for i := 0; i < len(x); i++ {
		v |= x[i] ^ y[i]
	}

	return ConstantTimeByteEq(v, 0)
}

// ConstantTimeSelect returns x if v is 1 and y if v is 0.
// Its behavior is undefined if v takes any other value.
func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }

// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
func ConstantTimeByteEq(x, y uint8) int {
	z := ^(x ^ y)
	z &= z >> 4
	z &= z >> 2
	z &= z >> 1

	return int(z)
}

// ConstantTimeEq returns 1 if x == y and 0 otherwise.
func ConstantTimeEq(x, y int32) int {
	z := ^(x ^ y)
	z &= z >> 16
	z &= z >> 8
	z &= z >> 4
	z &= z >> 2
	z &= z >> 1

	return int(z & 1)
}

// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged.
// Its behavior is undefined if v takes any other value.
func ConstantTimeCopy(v int, x, y []byte) {
	xmask := byte(v - 1)
	ymask := byte(^(v - 1))
	for i := 0; i < len(x); i++ {
		x[i] = x[i]&xmask | y[i]&ymask
	}
	return
}

// ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
// Its behavior is undefined if x or y are negative or > 2**31 - 1.
func ConstantTimeLessOrEq(x, y int) int {
	x32 := int32(x)
	y32 := int32(y)
	return int(((x32 - y32 - 1) >> 31) & 1)
}
<commit_msg>crypto/subtle: panic if slices of different lengths are passed to ConstantTimeCompare.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle

// ConstantTimeCompare returns 1 iff the two equal length slices, x
// and y, have equal contents. The time taken is a function of the length of
// the slices and is independent of the contents.
func ConstantTimeCompare(x, y []byte) int {
	if len(x) != len(y) {
		panic("subtle: slices have different lengths")
	}

	var v byte

	for i := 0; i < len(x); i++ {
		v |= x[i] ^ y[i]
	}

	return ConstantTimeByteEq(v, 0)
}

// ConstantTimeSelect returns x if v is 1 and y if v is 0.
// Its behavior is undefined if v takes any other value.
func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }

// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
func ConstantTimeByteEq(x, y uint8) int {
	z := ^(x ^ y)
	z &= z >> 4
	z &= z >> 2
	z &= z >> 1

	return int(z)
}

// ConstantTimeEq returns 1 if x == y and 0 otherwise.
func ConstantTimeEq(x, y int32) int {
	z := ^(x ^ y)
	z &= z >> 16
	z &= z >> 8
	z &= z >> 4
	z &= z >> 2
	z &= z >> 1

	return int(z & 1)
}

// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged.
// Its behavior is undefined if v takes any other value.
func ConstantTimeCopy(v int, x, y []byte) {
	xmask := byte(v - 1)
	ymask := byte(^(v - 1))
	for i := 0; i < len(x); i++ {
		x[i] = x[i]&xmask | y[i]&ymask
	}
	return
}

// ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
// Its behavior is undefined if x or y are negative or > 2**31 - 1.
func ConstantTimeLessOrEq(x, y int) int {
	x32 := int32(x)
	y32 := int32(y)
	return int(((x32 - y32 - 1) >> 31) & 1)
}
<|endoftext|>


<commit_before>package parser

import (
	"github.com/fxnn/gowatch/logentry"
	"github.com/gemsi/grok"
	"log"
	"time"
)

type GrokParser struct {
	linesource LineSource
	grok       *grok.Grok
	pattern    string
	predicate  logentry.Predicate
	timeLayout string
}

func NewGrokParser(linesource LineSource, pattern string, timeLayout string, predicate logentry.Predicate) (p *GrokParser) {
	return &GrokParser{
		grok:       grok.New(),
		linesource: linesource,
		pattern:    pattern,
		timeLayout: timeLayout,
		predicate:  predicate}
}

func (p *GrokParser) AddPattern(name string, pattern string) {
	p.grok.AddPattern(name, pattern, pattern)
}

func (p *GrokParser) Parse() <-chan logentry.LogEntry {
	return parse(p.linesource, p.predicate, p.lineToLogEntry)
}

func (p *GrokParser) lineToLogEntry(line string, entry *logentry.LogEntry) {
	matches, err := p.grok.ParseToMultiMap(p.pattern, line)
	if err != nil {
		log.Print(err)
		return
	}

	for field, values := range matches {
		for _, value := range values {
			if entry.IsTimestamp(field) {
				timestamp, err := time.Parse(p.timeLayout, value)
				if err != nil {
					log.Fatalf("Error on parsing with time layout \"%s\": %s", p.timeLayout, err)
				}
				entry.Timestamp = timestamp
			} else if err := entry.AssignValue(field, value); err != nil {
				log.Fatal(err)
			}
		}
	}
}
<commit_msg>Fix after change in gemsi/grok<commit_after>package parser

import (
	"github.com/fxnn/gowatch/logentry"
	"github.com/gemsi/grok"
	"log"
	"time"
)

type GrokParser struct {
	linesource LineSource
	grok       *grok.Grok
	pattern    string
	predicate  logentry.Predicate
	timeLayout string
}

func NewGrokParser(linesource LineSource, pattern string, timeLayout string, predicate logentry.Predicate) (p *GrokParser) {
	return &GrokParser{
		grok:       grok.New(),
		linesource: linesource,
		pattern:    pattern,
		timeLayout: timeLayout,
		predicate:  predicate}
}

func (p *GrokParser) AddPattern(name string, pattern string) {
	p.grok.AddPattern(name, pattern)
}

func (p *GrokParser) Parse() <-chan logentry.LogEntry {
	return parse(p.linesource, p.predicate, p.lineToLogEntry)
}

func (p *GrokParser) lineToLogEntry(line string, entry *logentry.LogEntry) {
	matches, err := p.grok.ParseToMultiMap(p.pattern, line)
	if err != nil {
		log.Print(err)
		return
	}

	for field, values := range matches {
		for _, value := range values {
			if entry.IsTimestamp(field) {
				timestamp, err := time.Parse(p.timeLayout, value)
				if err != nil {
					log.Fatalf("Error on parsing with time layout \"%s\": %s", p.timeLayout, err)
				}
				entry.Timestamp = timestamp
			} else if err := entry.AssignValue(field, value); err != nil {
				log.Fatal(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package grayt

import (
	"image"
	"image/color"
	"log"
	"math"
	"time"
)

type Light struct {
	Location  Vect
	Intensity float64
}

type Scene struct {
	Camera     Camera
	Geometries []Geometry
	Lights     []Light
}

func TraceImage(s Scene) image.Image {

	const pxWide = 640
	const pxHigh = 480

	startTime := time.Now()
	defer func() {
		totalTime := time.Since(startTime)
		pxCount := pxWide * pxHigh
		timePerPixel := time.Duration(int(totalTime) / pxCount)

		log.Printf("Dimensions=%dx%d PxCount=%d TotalTime=%s TimePerPixel=%s",
			pxWide, pxHigh, pxCount, totalTime, timePerPixel)
	}()

	img := image.NewGray(image.Rect(0, 0, pxWide, pxHigh))

	for pxX := 0; pxX < pxWide; pxX++ {
		for pxY := 0; pxY < pxHigh; pxY++ {

			pxPitch := 2.0 / float64(pxWide)
			x := (float64(pxX-pxWide/2) + 0.5) * pxPitch
			y := (float64(pxY-pxHigh/2) + 0.5) * pxPitch * -1.0

			r := s.Camera.MakeRay(x, y)
			r.Dir = r.Dir.Unit()
			img.Set(pxX, pxY, traceRay(s, r))
		}
	}

	return img
}

// traceRay is a recursive function to find the colour from a single ray into a
// scene. It's a precondition that r.Dir must be a unit vector.
func traceRay(s Scene, r Ray) color.Color {

	// Assert that r.Dir is a unit vector.
	if ulpDiff(1.0, r.Dir.Length2()) > 50 {
		panic("precondition not met: r.Dir not a unit vector")
	}

	// Establish the hit point.
	hr, ok := closestHit(s.Geometries, r)
	if !ok {
		// Missed everything, shade black.
		return color.Gray{Y: 0x00}
	}

	hitLoc := r.At(hr.Distance * 0.999999) // XXX move by several ULPs

	var colour float64

	// Calculate the colour at the hit point.
	for _, light := range s.Lights {

		// Vector from hit location to the light.
		fromHitToLight := light.Location.Sub(hitLoc)
		unitFromHitToLight := fromHitToLight.Unit()
		attenuation := fromHitToLight.Length2()

		// Test if anything obscures the light.
		if tmpHR, ok := closestHit(
			s.Geometries,
			Ray{Start: hitLoc, Dir: fromHitToLight},
		); !ok || tmpHR.Distance > 1.0 {

			// Lambert shading.
			lambertCoef := unitFromHitToLight.Dot(hr.UnitNormal)

			// Add shading to the colour.
			colour += math.Abs(lambertCoef) * light.Intensity / attenuation
		}
	}

	var colourUint8 uint8
	if colour >= 1.0 {
		colourUint8 = 0xff
	} else if colour < 0.0 {
		colourUint8 = 0x00
	} else {
		colourUint8 = uint8(colour * 256)
	}
	return color.Gray{Y: colourUint8}
}

func closestHit(gs []Geometry, r Ray) (Intersection, bool) {
	isHit := false
	var closest Intersection
	for _, geometry := range gs {
		tmpHR, ok := geometry.Intersect(r)
		if ok && (!isHit || tmpHR.Distance < closest.Distance) {
			closest = tmpHR
			isHit = true
		}
	}
	return closest, isHit
}

func ulpDiff(a, b float64) uint64 {

	ulpA := math.Float64bits(a)
	ulpB := math.Float64bits(b)

	if ulpA > ulpB {
		return ulpA - ulpB
	} else {
		return ulpB - ulpA
	}
}
<commit_msg>Rename `TraceImage` to `RayTraceImage`<commit_after>package grayt

import (
	"image"
	"image/color"
	"log"
	"math"
	"time"
)

type Light struct {
	Location  Vect
	Intensity float64
}

type Scene struct {
	Camera     Camera
	Geometries []Geometry
	Lights     []Light
}

func RayTraceImage(s Scene) image.Image {

	const pxWide = 640
	const pxHigh = 480

	startTime := time.Now()
	defer func() {
		totalTime := time.Since(startTime)
		pxCount := pxWide * pxHigh
		timePerPixel := time.Duration(int(totalTime) / pxCount)

		log.Printf("Dimensions=%dx%d PxCount=%d TotalTime=%s TimePerPixel=%s",
			pxWide, pxHigh, pxCount, totalTime, timePerPixel)
	}()

	img := image.NewGray(image.Rect(0, 0, pxWide, pxHigh))

	for pxX := 0; pxX < pxWide; pxX++ {
		for pxY := 0; pxY < pxHigh; pxY++ {

			pxPitch := 2.0 / float64(pxWide)
			x := (float64(pxX-pxWide/2) + 0.5) * pxPitch
			y := (float64(pxY-pxHigh/2) + 0.5) * pxPitch * -1.0

			r := s.Camera.MakeRay(x, y)
			r.Dir = r.Dir.Unit()
			img.Set(pxX, pxY, traceRay(s, r))
		}
	}

	return img
}

// traceRay is a recursive function to find the colour from a single ray into a
// scene. It's a precondition that r.Dir must be a unit vector.
func traceRay(s Scene, r Ray) color.Color {

	// Assert that r.Dir is a unit vector.
	if ulpDiff(1.0, r.Dir.Length2()) > 50 {
		panic("precondition not met: r.Dir not a unit vector")
	}

	// Establish the hit point.
	hr, ok := closestHit(s.Geometries, r)
	if !ok {
		// Missed everything, shade black.
		return color.Gray{Y: 0x00}
	}

	hitLoc := r.At(hr.Distance * 0.999999) // XXX move by several ULPs

	var colour float64

	// Calculate the colour at the hit point.
	for _, light := range s.Lights {

		// Vector from hit location to the light.
		fromHitToLight := light.Location.Sub(hitLoc)
		unitFromHitToLight := fromHitToLight.Unit()
		attenuation := fromHitToLight.Length2()

		// Test if anything obscures the light.
		if tmpHR, ok := closestHit(
			s.Geometries,
			Ray{Start: hitLoc, Dir: fromHitToLight},
		); !ok || tmpHR.Distance > 1.0 {

			// Lambert shading.
			lambertCoef := unitFromHitToLight.Dot(hr.UnitNormal)

			// Add shading to the colour.
			colour += math.Abs(lambertCoef) * light.Intensity / attenuation
		}
	}

	var colourUint8 uint8
	if colour >= 1.0 {
		colourUint8 = 0xff
	} else if colour < 0.0 {
		colourUint8 = 0x00
	} else {
		colourUint8 = uint8(colour * 256)
	}
	return color.Gray{Y: colourUint8}
}

func closestHit(gs []Geometry, r Ray) (Intersection, bool) {
	isHit := false
	var closest Intersection
	for _, geometry := range gs {
		tmpHR, ok := geometry.Intersect(r)
		if ok && (!isHit || tmpHR.Distance < closest.Distance) {
			closest = tmpHR
			isHit = true
		}
	}
	return closest, isHit
}

func ulpDiff(a, b float64) uint64 {

	ulpA := math.Float64bits(a)
	ulpB := math.Float64bits(b)

	if ulpA > ulpB {
		return ulpA - ulpB
	} else {
		return ulpB - ulpA
	}
}
<|endoftext|>


<commit_before>// Package tracer implements a Dapper-style tracing system. It is
// compatible with the Open Tracing specification.
package tracer

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/hex"
	"io"
	"strings"
	"time"

	"github.com/opentracing/opentracing-go"
)

type Joiner func(carrier interface{}) (traceID, parentID, spanID uint64, baggage map[string]string, err error)
type Injecter func(sp *Span, carrier interface{}) error

var joiners = map[interface{}]Joiner{
	opentracing.TextMap: textJoiner,
	opentracing.Binary:  binaryJoiner,
}

var injecters = map[interface{}]Injecter{
	opentracing.TextMap: textInjecter,
	opentracing.Binary:  binaryInjecter,
}

func RegisterJoiner(format interface{}, joiner Joiner) {
	joiners[format] = joiner
}

func RegisterInjecter(format interface{}, injecter Injecter) {
	injecters[format] = injecter
}

func textInjecter(sp *Span, carrier interface{}) error {
	w, ok := carrier.(opentracing.TextMapWriter)
	if !ok {
		return opentracing.ErrInvalidCarrier
	}
	w.Set("X-B3-TraceId", idToHex(sp.TraceID))
	w.Set("X-B3-SpanId", idToHex(sp.SpanID))
	w.Set("X-B3-ParentSpanId", idToHex(sp.ParentID))
	for k, v := range sp.Baggage {
		w.Set("X-B3-Baggage-"+k, v)
	}
	return nil
}

func textJoiner(carrier interface{}) (traceID, parentID, spanID uint64, baggage map[string]string, err error) {
	r, ok := carrier.(opentracing.TextMapReader)
	if !ok {
		return 0, 0, 0, nil, opentracing.ErrInvalidCarrier
	}
	baggage = map[string]string{}
	err = r.ForeachKey(func(key string, val string) error {
		switch key {
		case "X-B3-TraceId":
			traceID = idFromHex(val)
		case "X-B3-SpanId":
			spanID = idFromHex(val)
		case "X-B3-ParentSpanId":
			parentID = idFromHex(val)
		default:
			if strings.HasPrefix(key, "X-B3-Baggage-") {
				key = key[len("X-B3-Baggage-"):]
				baggage[key] = val
			}
		}
		return nil
	})
	if traceID == 0 {
		return 0, 0, 0, nil, opentracing.ErrTraceNotFound
	}
	return traceID, parentID, spanID, baggage, err
}

func binaryInjecter(sp *Span, carrier interface{}) error {
	w, ok := carrier.(io.Writer)
	if !ok {
		return opentracing.ErrInvalidCarrier
	}
	b := make([]byte, 24)
	binary.BigEndian.PutUint64(b, sp.TraceID)
	binary.BigEndian.PutUint64(b[8:], sp.TraceID)
	binary.BigEndian.PutUint64(b[16:], sp.TraceID)
	_, err := w.Write(b)
	return err
}

func binaryJoiner(carrier interface{}) (traceID, parentID, spanID uint64, baggage map[string]string, err error) {
	r, ok := carrier.(io.Reader)
	if !ok {
		return 0, 0, 0, nil, opentracing.ErrInvalidCarrier
	}
	b := make([]byte, 24)
	if _, err := io.ReadFull(r, b); err != nil {
		if err == io.ErrUnexpectedEOF {
			return 0, 0, 0, nil, opentracing.ErrTraceNotFound
		}
		return 0, 0, 0, nil, err
	}
	traceID = binary.BigEndian.Uint64(b)
	spanID = binary.BigEndian.Uint64(b[8:])
	parentID = binary.BigEndian.Uint64(b[16:])
	return traceID, parentID, spanID, nil, err
}

// Span is an implementation of the Open Tracing Span interface.
type Span struct {
	tracer *Tracer

	SpanID        uint64
	ParentID      uint64
	TraceID       uint64
	OperationName string
	StartTime     time.Time
	FinishTime    time.Time

	Tags    map[string]interface{}
	Baggage map[string]string
	Logs    []opentracing.LogData
}

func (sp *Span) SetOperationName(name string) opentracing.Span {
	sp.OperationName = name
	return sp
}

func (sp *Span) SetTag(key string, value interface{}) opentracing.Span {
	if sp.Tags == nil {
		sp.Tags = map[string]interface{}{}
	}
	sp.Tags[key] = value
	return sp
}

func (sp *Span) Finish() {
	sp.FinishWithOptions(opentracing.FinishOptions{})
}

func (sp *Span) FinishWithOptions(opts opentracing.FinishOptions) {
	if opts.FinishTime.IsZero() {
		opts.FinishTime = time.Now()
	}
	sp.FinishTime = opts.FinishTime
	for _, log := range opts.BulkLogData {
		sp.Log(log)
	}
	sp.tracer.storer.Store(sp)
}

func (sp *Span) LogEvent(event string) {
	sp.Log(opentracing.LogData{
		Event: event,
	})
}

func (sp *Span) LogEventWithPayload(event string, payload interface{}) {
	sp.Log(opentracing.LogData{
		Event:   event,
		Payload: payload,
	})
}

func (sp *Span) Log(data opentracing.LogData) {
	if data.Timestamp.IsZero() {
		data.Timestamp = time.Now()
	}
	sp.Logs = append(sp.Logs, data)
}

func (sp *Span) SetBaggageItem(key, value string) opentracing.Span {
	sp.Baggage[key] = value
	return sp

}
func (sp *Span) BaggageItem(key string) string {
	return sp.Baggage[key]
}

func (sp *Span) Tracer() opentracing.Tracer {
	return sp.tracer
}

// Tracer is an implementation of the Open Tracing Tracer interface.
type Tracer struct {
	storer      Storer
	idGenerator IDGenerator
}

func NewTracer(storer Storer, idGenerator IDGenerator) *Tracer {
	return &Tracer{storer, idGenerator}
}

func (tr *Tracer) StartSpan(operationName string) opentracing.Span {
	return tr.StartSpanWithOptions(opentracing.StartSpanOptions{
		OperationName: operationName,
	})
}

func (tr *Tracer) StartSpanWithOptions(opts opentracing.StartSpanOptions) opentracing.Span {
	if opts.StartTime.IsZero() {
		opts.StartTime = time.Now()
	}
	var traceID uint64
	var parentID uint64
	if opts.Parent != nil {
		parent, ok := opts.Parent.(*Span)
		if !ok {
			panic("parent span must be of type *Span")
		}
		parentID = parent.SpanID
		traceID = parent.TraceID
	}
	if traceID == 0 {
		traceID = tr.idGenerator.GenerateID()
	}
	id := tr.idGenerator.GenerateID()
	sp := &Span{
		tracer:        tr,
		OperationName: opts.OperationName,
		SpanID:        id,
		ParentID:      parentID,
		TraceID:       traceID,
		StartTime:     opts.StartTime,
	}
	return sp
}

func idToHex(id uint64) string {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, id)
	return hex.EncodeToString(b)
}

func idFromHex(s string) uint64 {
	b, _ := hex.DecodeString(s)
	return binary.BigEndian.Uint64(b)
}

func (tr *Tracer) Inject(sp opentracing.Span, format interface{}, carrier interface{}) error {
	// TODO(dh): support sampling
	span, ok := sp.(*Span)
	if !ok {
		return opentracing.ErrInvalidSpan
	}
	injecter, ok := injecters[format]
	if !ok {
		return opentracing.ErrUnsupportedFormat
	}
	return injecter(span, carrier)
}

func (tr *Tracer) Join(operationName string, format interface{}, carrier interface{}) (opentracing.Span, error) {
	// TODO(dh): support sampling
	joiner, ok := joiners[format]
	if !ok {
		return nil, opentracing.ErrUnsupportedFormat
	}
	traceID, parentID, spanID, baggage, err := joiner(carrier)
	if err != nil {
		return nil, err
	}

	return &Span{
		tracer:   tr,
		TraceID:  traceID,
		SpanID:   spanID,
		ParentID: parentID,
		Baggage:  baggage,
	}, nil
}

// IDGenerator generates IDs for traces and spans. The ID with value 0
// is reserved to mean "no parent span" and should not be generated.
type IDGenerator interface {
	GenerateID() uint64
}

// A Storer stores a finished span. "Storing" a span may either mean
// saving it in a storage engine, or sending it to a remote
// collector.
//
// If a span with the same ID and the same trace ID already exists,
// the existing and new spans should be merged into one span.
//
// Because spans are only stored once they're done, children will be
// stored before their parents.
type Storer interface {
	Store(sp *Span)
}

type Queryer interface {
	SpanWithID(id uint64) (*Span, bool)
}

// RandomID generates random IDs by using crypto/rand.
type RandomID struct{}

// GenerateID generates an ID.
func (RandomID) GenerateID() uint64 {
	b := make([]byte, 8)
	for {
		_, _ = rand.Read(b)
		x := binary.BigEndian.Uint64(b)
		if x != 0 {
			return x
		}
	}
}
<commit_msg>Look for lowercase keys in TextMap<commit_after>// Package tracer implements a Dapper-style tracing system. It is
// compatible with the Open Tracing specification.
package tracer

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/hex"
	"io"
	"strings"
	"time"

	"github.com/opentracing/opentracing-go"
)

type Joiner func(carrier interface{}) (traceID, parentID, spanID uint64, baggage map[string]string, err error)
type Injecter func(sp *Span, carrier interface{}) error

var joiners = map[interface{}]Joiner{
	opentracing.TextMap: textJoiner,
	opentracing.Binary:  binaryJoiner,
}

var injecters = map[interface{}]Injecter{
	opentracing.TextMap: textInjecter,
	opentracing.Binary:  binaryInjecter,
}

func RegisterJoiner(format interface{}, joiner Joiner) {
	joiners[format] = joiner
}

func RegisterInjecter(format interface{}, injecter Injecter) {
	injecters[format] = injecter
}

func textInjecter(sp *Span, carrier interface{}) error {
	w, ok := carrier.(opentracing.TextMapWriter)
	if !ok {
		return opentracing.ErrInvalidCarrier
	}
	w.Set("X-B3-TraceId", idToHex(sp.TraceID))
	w.Set("X-B3-SpanId", idToHex(sp.SpanID))
	w.Set("X-B3-ParentSpanId", idToHex(sp.ParentID))
	for k, v := range sp.Baggage {
		w.Set("X-B3-Baggage-"+k, v)
	}
	return nil
}

func textJoiner(carrier interface{}) (traceID, parentID, spanID uint64, baggage map[string]string, err error) {
	r, ok := carrier.(opentracing.TextMapReader)
	if !ok {
		return 0, 0, 0, nil, opentracing.ErrInvalidCarrier
	}
	baggage = map[string]string{}
	err = r.ForeachKey(func(key string, val string) error {
		lower := strings.ToLower(key)
		switch lower {
		case "x-b3-traceid":
			traceID = idFromHex(val)
		case "x-b3-spanid":
			spanID = idFromHex(val)
		case "x-b3-parentspanid":
			parentID = idFromHex(val)
		default:
			if strings.HasPrefix(lower, "x-b3-baggage-") {
				key = key[len("X-B3-Baggage-"):]
				baggage[key] = val
			}
		}
		return nil
	})
	if traceID == 0 {
		return 0, 0, 0, nil, opentracing.ErrTraceNotFound
	}
	return traceID, parentID, spanID, baggage, err
}

func binaryInjecter(sp *Span, carrier interface{}) error {
	w, ok := carrier.(io.Writer)
	if !ok {
		return opentracing.ErrInvalidCarrier
	}
	b := make([]byte, 24)
	binary.BigEndian.PutUint64(b, sp.TraceID)
	binary.BigEndian.PutUint64(b[8:], sp.TraceID)
	binary.BigEndian.PutUint64(b[16:], sp.TraceID)
	_, err := w.Write(b)
	return err
}

func binaryJoiner(carrier interface{}) (traceID, parentID, spanID uint64, baggage map[string]string, err error) {
	r, ok := carrier.(io.Reader)
	if !ok {
		return 0, 0, 0, nil, opentracing.ErrInvalidCarrier
	}
	b := make([]byte, 24)
	if _, err := io.ReadFull(r, b); err != nil {
		if err == io.ErrUnexpectedEOF {
			return 0, 0, 0, nil, opentracing.ErrTraceNotFound
		}
		return 0, 0, 0, nil, err
	}
	traceID = binary.BigEndian.Uint64(b)
	spanID = binary.BigEndian.Uint64(b[8:])
	parentID = binary.BigEndian.Uint64(b[16:])
	return traceID, parentID, spanID, nil, err
}

// Span is an implementation of the Open Tracing Span interface.
type Span struct {
	tracer *Tracer

	SpanID        uint64
	ParentID      uint64
	TraceID       uint64
	OperationName string
	StartTime     time.Time
	FinishTime    time.Time

	Tags    map[string]interface{}
	Baggage map[string]string
	Logs    []opentracing.LogData
}

func (sp *Span) SetOperationName(name string) opentracing.Span {
	sp.OperationName = name
	return sp
}

func (sp *Span) SetTag(key string, value interface{}) opentracing.Span {
	if sp.Tags == nil {
		sp.Tags = map[string]interface{}{}
	}
	sp.Tags[key] = value
	return sp
}

func (sp *Span) Finish() {
	sp.FinishWithOptions(opentracing.FinishOptions{})
}

func (sp *Span) FinishWithOptions(opts opentracing.FinishOptions) {
	if opts.FinishTime.IsZero() {
		opts.FinishTime = time.Now()
	}
	sp.FinishTime = opts.FinishTime
	for _, log := range opts.BulkLogData {
		sp.Log(log)
	}
	sp.tracer.storer.Store(sp)
}

func (sp *Span) LogEvent(event string) {
	sp.Log(opentracing.LogData{
		Event: event,
	})
}

func (sp *Span) LogEventWithPayload(event string, payload interface{}) {
	sp.Log(opentracing.LogData{
		Event:   event,
		Payload: payload,
	})
}

func (sp *Span) Log(data opentracing.LogData) {
	if data.Timestamp.IsZero() {
		data.Timestamp = time.Now()
	}
	sp.Logs = append(sp.Logs, data)
}

func (sp *Span) SetBaggageItem(key, value string) opentracing.Span {
	sp.Baggage[key] = value
	return sp

}
func (sp *Span) BaggageItem(key string) string {
	return sp.Baggage[key]
}

func (sp *Span) Tracer() opentracing.Tracer {
	return sp.tracer
}

// Tracer is an implementation of the Open Tracing Tracer interface.
type Tracer struct {
	storer      Storer
	idGenerator IDGenerator
}

func NewTracer(storer Storer, idGenerator IDGenerator) *Tracer {
	return &Tracer{storer, idGenerator}
}

func (tr *Tracer) StartSpan(operationName string) opentracing.Span {
	return tr.StartSpanWithOptions(opentracing.StartSpanOptions{
		OperationName: operationName,
	})
}

func (tr *Tracer) StartSpanWithOptions(opts opentracing.StartSpanOptions) opentracing.Span {
	if opts.StartTime.IsZero() {
		opts.StartTime = time.Now()
	}
	var traceID uint64
	var parentID uint64
	if opts.Parent != nil {
		parent, ok := opts.Parent.(*Span)
		if !ok {
			panic("parent span must be of type *Span")
		}
		parentID = parent.SpanID
		traceID = parent.TraceID
	}
	if traceID == 0 {
		traceID = tr.idGenerator.GenerateID()
	}
	id := tr.idGenerator.GenerateID()
	sp := &Span{
		tracer:        tr,
		OperationName: opts.OperationName,
		SpanID:        id,
		ParentID:      parentID,
		TraceID:       traceID,
		StartTime:     opts.StartTime,
	}
	return sp
}

func idToHex(id uint64) string {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, id)
	return hex.EncodeToString(b)
}

func idFromHex(s string) uint64 {
	b, _ := hex.DecodeString(s)
	return binary.BigEndian.Uint64(b)
}

func (tr *Tracer) Inject(sp opentracing.Span, format interface{}, carrier interface{}) error {
	// TODO(dh): support sampling
	span, ok := sp.(*Span)
	if !ok {
		return opentracing.ErrInvalidSpan
	}
	injecter, ok := injecters[format]
	if !ok {
		return opentracing.ErrUnsupportedFormat
	}
	return injecter(span, carrier)
}

func (tr *Tracer) Join(operationName string, format interface{}, carrier interface{}) (opentracing.Span, error) {
	// TODO(dh): support sampling
	joiner, ok := joiners[format]
	if !ok {
		return nil, opentracing.ErrUnsupportedFormat
	}
	traceID, parentID, spanID, baggage, err := joiner(carrier)
	if err != nil {
		return nil, err
	}

	return &Span{
		tracer:   tr,
		TraceID:  traceID,
		SpanID:   spanID,
		ParentID: parentID,
		Baggage:  baggage,
	}, nil
}

// IDGenerator generates IDs for traces and spans. The ID with value 0
// is reserved to mean "no parent span" and should not be generated.
type IDGenerator interface {
	GenerateID() uint64
}

// A Storer stores a finished span. "Storing" a span may either mean
// saving it in a storage engine, or sending it to a remote
// collector.
//
// If a span with the same ID and the same trace ID already exists,
// the existing and new spans should be merged into one span.
//
// Because spans are only stored once they're done, children will be
// stored before their parents.
type Storer interface {
	Store(sp *Span)
}

type Queryer interface {
	SpanWithID(id uint64) (*Span, bool)
}

// RandomID generates random IDs by using crypto/rand.
type RandomID struct{}

// GenerateID generates an ID.
func (RandomID) GenerateID() uint64 {
	b := make([]byte, 8)
	for {
		_, _ = rand.Read(b)
		x := binary.BigEndian.Uint64(b)
		if x != 0 {
			return x
		}
	}
}
<|endoftext|>


<commit_before>package tracer

import (
	"crypto/rand"
	"encoding/binary"
	"time"

	"github.com/opentracing/opentracing-go"
)

type Span struct {
	tracer *Tracer

	SpanID        uint64
	ParentID      uint64
	TraceID       uint64
	OperationName string
	StartTime     time.Time
	Tags          opentracing.Tags
}

func (sp *Span) SetOperationName(name string) opentracing.Span {
	sp.tracer.storer.SetOperationName(sp, name)
	sp.OperationName = name
	return sp
}

func (sp *Span) SetTag(key string, value interface{}) opentracing.Span {
	sp.tracer.storer.SetTag(sp, key, value)
	return sp
}

func (sp *Span) Finish() {
	sp.FinishWithOptions(opentracing.FinishOptions{})
}

func (sp *Span) FinishWithOptions(opts opentracing.FinishOptions) {
	if opts.FinishTime.IsZero() {
		opts.FinishTime = time.Now()
	}
	sp.tracer.storer.FinishWithOptions(sp, opts)
}

func (sp *Span) LogEvent(event string) {
	sp.Log(opentracing.LogData{
		Event: event,
	})
}

func (sp *Span) LogEventWithPayload(event string, payload interface{}) {
	sp.Log(opentracing.LogData{
		Event:   event,
		Payload: payload,
	})
}

func (sp *Span) Log(data opentracing.LogData) {
	if data.Timestamp.IsZero() {
		data.Timestamp = time.Now()
	}
	sp.tracer.storer.Log(sp, data)
}

func (sp *Span) SetBaggageItem(key, value string) opentracing.Span {
	// TODO implement
	return sp

}
func (sp *Span) BaggageItem(key string) string {
	// TODO implement
	return ""
}

func (sp *Span) Tracer() opentracing.Tracer {
	return sp.tracer
}

type Tracer struct {
	storer      Storer
	idGenerator IDGenerator
}

func NewTracer(storer Storer, idGenerator IDGenerator) *Tracer {
	return &Tracer{storer, idGenerator}
}

func (tr *Tracer) StartSpan(operationName string) opentracing.Span {
	return tr.StartSpanWithOptions(opentracing.StartSpanOptions{
		OperationName: operationName,
	})
}

func (tr *Tracer) StartSpanWithOptions(opts opentracing.StartSpanOptions) opentracing.Span {
	if opts.StartTime.IsZero() {
		opts.StartTime = time.Now()
	}
	var traceID uint64
	var parentID uint64
	if opts.Parent != nil {
		parent, ok := opts.Parent.(*Span)
		if !ok {
			panic("parent span must be of type *Span")
		}
		parentID = parent.SpanID
		traceID = parent.TraceID
	}
	if traceID == 0 {
		traceID = tr.idGenerator.GenerateID()
	}
	id := tr.idGenerator.GenerateID()
	sp := &Span{
		tracer:        tr,
		OperationName: opts.OperationName,
		SpanID:        id,
		ParentID:      parentID,
		TraceID:       traceID,
		StartTime:     opts.StartTime,
	}
	tr.storer.AddSpan(sp)
	return sp
}

func (tr *Tracer) Inject(sp opentracing.Span, format interface{}, carrier interface{}) error {
	// TODO implement
	return nil
}

func (tr *Tracer) Join(operationName string, format interface{}, carrier interface{}) (opentracing.Span, error) {
	// TODO implement
	return nil, nil
}

type IDGenerator interface {
	GenerateID() uint64
}

type Storer interface {
	AddSpan(sp *Span)
	SetOperationName(sp *Span, name string)
	SetTag(sp *Span, key string, value interface{})
	FinishWithOptions(sp *Span, opts opentracing.FinishOptions)
	Log(sp *Span, data opentracing.LogData)
}

type Queryer interface {
	SpanWithID(id uint64) (*Span, bool)
}

// RandomID generates random IDs by using crypto/rand.
type RandomID struct{}

func (RandomID) GenerateID() uint64 {
	b := make([]byte, 8)
	_, _ = rand.Read(b)
	return binary.BigEndian.Uint64(b)
}
<commit_msg>Add support for opentracing.TextMapReader injection and joining<commit_after>package tracer

import (
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"time"

	"github.com/opentracing/opentracing-go"
)

type Span struct {
	tracer *Tracer

	SpanID        uint64
	ParentID      uint64
	TraceID       uint64
	OperationName string
	StartTime     time.Time
	Tags          opentracing.Tags
}

func (sp *Span) SetOperationName(name string) opentracing.Span {
	sp.tracer.storer.SetOperationName(sp, name)
	sp.OperationName = name
	return sp
}

func (sp *Span) SetTag(key string, value interface{}) opentracing.Span {
	sp.tracer.storer.SetTag(sp, key, value)
	return sp
}

func (sp *Span) Finish() {
	sp.FinishWithOptions(opentracing.FinishOptions{})
}

func (sp *Span) FinishWithOptions(opts opentracing.FinishOptions) {
	if opts.FinishTime.IsZero() {
		opts.FinishTime = time.Now()
	}
	sp.tracer.storer.FinishWithOptions(sp, opts)
}

func (sp *Span) LogEvent(event string) {
	sp.Log(opentracing.LogData{
		Event: event,
	})
}

func (sp *Span) LogEventWithPayload(event string, payload interface{}) {
	sp.Log(opentracing.LogData{
		Event:   event,
		Payload: payload,
	})
}

func (sp *Span) Log(data opentracing.LogData) {
	if data.Timestamp.IsZero() {
		data.Timestamp = time.Now()
	}
	sp.tracer.storer.Log(sp, data)
}

func (sp *Span) SetBaggageItem(key, value string) opentracing.Span {
	// TODO implement
	return sp

}
func (sp *Span) BaggageItem(key string) string {
	// TODO implement
	return ""
}

func (sp *Span) Tracer() opentracing.Tracer {
	return sp.tracer
}

type Tracer struct {
	storer      Storer
	idGenerator IDGenerator
}

func NewTracer(storer Storer, idGenerator IDGenerator) *Tracer {
	return &Tracer{storer, idGenerator}
}

func (tr *Tracer) StartSpan(operationName string) opentracing.Span {
	return tr.StartSpanWithOptions(opentracing.StartSpanOptions{
		OperationName: operationName,
	})
}

func (tr *Tracer) StartSpanWithOptions(opts opentracing.StartSpanOptions) opentracing.Span {
	if opts.StartTime.IsZero() {
		opts.StartTime = time.Now()
	}
	var traceID uint64
	var parentID uint64
	if opts.Parent != nil {
		parent, ok := opts.Parent.(*Span)
		if !ok {
			panic("parent span must be of type *Span")
		}
		parentID = parent.SpanID
		traceID = parent.TraceID
	}
	if traceID == 0 {
		traceID = tr.idGenerator.GenerateID()
	}
	id := tr.idGenerator.GenerateID()
	sp := &Span{
		tracer:        tr,
		OperationName: opts.OperationName,
		SpanID:        id,
		ParentID:      parentID,
		TraceID:       traceID,
		StartTime:     opts.StartTime,
	}
	tr.storer.AddSpan(sp)
	return sp
}

func (tr *Tracer) Inject(sp opentracing.Span, format interface{}, carrier interface{}) error {
	switch format {
	case opentracing.TextMap:
		w := carrier.(opentracing.TextMapWriter)
		w.Set("X-B3-TraceId", fmt.Sprintf("%016x", sp.(*Span).TraceID))
		w.Set("X-B3-SpanId", fmt.Sprintf("%016x", sp.(*Span).SpanID))
		w.Set("X-B3-ParentSpanId", fmt.Sprintf("%016x", sp.(*Span).ParentID))
		// TODO(dh): support sampling
	case opentracing.Binary:
		// TODO implement
	default:
		return opentracing.ErrUnsupportedFormat
	}
	return nil
}

func (tr *Tracer) Join(operationName string, format interface{}, carrier interface{}) (opentracing.Span, error) {
	switch format {
	case opentracing.TextMap:
		w := carrier.(opentracing.TextMapReader)
		sp := &Span{tracer: tr}
		err := w.ForeachKey(func(key string, val string) error {
			var id uint64
			switch key {
			case "X-B3-TraceId":
				if _, err := fmt.Sscanf(val, "%016x", &id); err != nil {
					return err
				}
				sp.TraceID = id
			case "X-B3-SpanId":
				if _, err := fmt.Sscanf(val, "%016x", &id); err != nil {
					return err
				}
				sp.SpanID = id
			case "X-B3-ParentSpanId":
				if _, err := fmt.Sscanf(val, "%016x", &id); err != nil {
					return err
				}
				sp.ParentID = id
			}
			return nil
		})
		return sp, err
	case opentracing.Binary:
		// TODO implement
	default:
		return nil, opentracing.ErrUnsupportedFormat
	}
	return nil, nil
}

type IDGenerator interface {
	GenerateID() uint64
}

type Storer interface {
	AddSpan(sp *Span)
	SetOperationName(sp *Span, name string)
	SetTag(sp *Span, key string, value interface{})
	FinishWithOptions(sp *Span, opts opentracing.FinishOptions)
	Log(sp *Span, data opentracing.LogData)
}

type Queryer interface {
	SpanWithID(id uint64) (*Span, bool)
}

// RandomID generates random IDs by using crypto/rand.
type RandomID struct{}

func (RandomID) GenerateID() uint64 {
	b := make([]byte, 8)
	_, _ = rand.Read(b)
	return binary.BigEndian.Uint64(b)
}
<|endoftext|>


<commit_before>package proxy

import "runtime"

// Outputter is what is used by the tracing proxy created via `NewTraceProxy`.
// Anything that implements a `log.Logger` style `Output` method will satisfy
// this interface.
type Outputter interface {
	Output(calldepth int, s string) error
}

// Filter is used by the tracing proxy for skipping database libraries (e.g. O/R mapper).
type Filter interface {
	DoOutput(packageName string) bool
}

// PackageFilter is an implementation of Filter.
type PackageFilter map[string]struct{}

// DoOutput returns false if the package is in the ignored list.
func (f PackageFilter) DoOutput(packageName string) bool {
	_, ok := f[packageName]
	return !ok
}

// Ignore add the package into the ignored list.
func (f PackageFilter) Ignore(packageName string) {
	f[packageName] = struct{}{}
}

// DefaultPackageFilter ignores some database util package.
var DefaultPackageFilter = PackageFilter{
	"database/sql":                       struct{}{},
	"github.com/shogo82148/txmanager":    struct{}{},
	"github.com/shogo82148/go-sql-proxy": struct{}{},
}

func findCaller(f Filter) int {
	// skip starts 4. 0: Callers, 1: findCaller, 2: hooks, 3: proxy-funcs, 4: database/sql, and equals or greater than 5: user-funcs
	skip := 5
	for {
		var rpc [8]uintptr
		n := runtime.Callers(skip, rpc[:])

		for i, pc := range rpc[:n] {
			// http://stackoverflow.com/questions/25262754/how-to-get-name-of-current-package-in-go
			name := runtime.FuncForPC(pc).Name()
			dotIdx := 0
			for j := len(name) - 1; j >= 0; j-- {
				if name[j] == '.' {
					dotIdx = j
				} else if name[j] == '/' {
					break
				}
			}
			packageName := name[:dotIdx]
			if f.DoOutput(packageName) {
				// -1 because the meaning of skip differs between Caller and Callers.
				return skip + i - 1
			}
		}
		if n < len(rpc) {
			break
		}
		skip += n
	}
	return 0
}
<commit_msg>fix #16 use runtime.CallersFrames instead of runtime.FuncForPC<commit_after>package proxy

import "runtime"

// Outputter is what is used by the tracing proxy created via `NewTraceProxy`.
// Anything that implements a `log.Logger` style `Output` method will satisfy
// this interface.
type Outputter interface {
	Output(calldepth int, s string) error
}

// Filter is used by the tracing proxy for skipping database libraries (e.g. O/R mapper).
type Filter interface {
	DoOutput(packageName string) bool
}

// PackageFilter is an implementation of Filter.
type PackageFilter map[string]struct{}

// DoOutput returns false if the package is in the ignored list.
func (f PackageFilter) DoOutput(packageName string) bool {
	_, ok := f[packageName]
	return !ok
}

// Ignore add the package into the ignored list.
func (f PackageFilter) Ignore(packageName string) {
	f[packageName] = struct{}{}
}

// DefaultPackageFilter ignores some database util package.
var DefaultPackageFilter = PackageFilter{
	"database/sql":                       struct{}{},
	"github.com/shogo82148/txmanager":    struct{}{},
	"github.com/shogo82148/go-sql-proxy": struct{}{},
}

func findCaller(f Filter) int {
	// skip starts 4. 0: Callers, 1: findCaller, 2: hooks, 3: proxy-funcs, 4: database/sql, and equals or greater than 5: user-funcs
	skip := 5
	for {
		var rpc [8]uintptr
		n := runtime.Callers(skip, rpc[:])
		frames := runtime.CallersFrames(rpc[:])

		for i := 0; ; i++ {
			// http://stackoverflow.com/questions/25262754/how-to-get-name-of-current-package-in-go
			frame, more := frames.Next()
			name := frame.Func.Name()
			dotIdx := 0
			for j := len(name) - 1; j >= 0; j-- {
				if name[j] == '.' {
					dotIdx = j
				} else if name[j] == '/' {
					break
				}
			}
			packageName := name[:dotIdx]
			if f.DoOutput(packageName) {
				// -1 because the meaning of skip differs between Caller and Callers.
				return skip + i - 1
			}
			if !more {
				break
			}
		}
		if n < len(rpc) {
			break
		}
		skip += n
	}
	return 0
}
<|endoftext|>


<commit_before>package simpletable

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"
)

// stripAnsiEscapeRegexp is a regular expression to clean ANSI Control sequences
// feat https://stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python#33925425
var stripAnsiEscapeRegexp = regexp.MustCompile(`(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]`)

// content is a cell content
type content struct {
	c  []string // content lines (trimmed)
	mw int      // maximal content width (f.e, for multilines columns)
	w  int      // meta content width
}

// width returns content width
func (c *content) width() int {
	m := c.mw
	if m > c.w {
		return m
	}

	return c.w
}

// setWidth sets content block width
func (c *content) setWidth(w int) {
	c.w = w
}

// height returns content height
func (c *content) height() int {
	return len(c.c)
}

// setHeigth sets content height
func (c *content) setHeight(h int) {
	l := c.height()
	if h <= l {
		return
	}

	for i := 0; i < h-l; i++ {
		c.c = append(c.c, "")
	}
}

// lines returns content as string slice
func (c *content) lines(a int) []string {
	r := []string{}

	for _, l := range c.c {
		r = append(r, c.line(l, a))
	}

	return r
}

// line formats content line
func (c *content) line(l string, a int) string {
	len := c.width() - utf8.RuneCountInString(stripAnsiEscape(l))
	if len <= 0 {
		return l
	}

	switch a {
	case AlignLeft:
		l = fmt.Sprintf("%s%s", l, strings.Repeat(" ", len))

	case AlignCenter:
		lft := len / 2
		rgt := len - lft

		left := strings.Repeat(" ", lft)
		right := strings.Repeat(" ", rgt)

		l = fmt.Sprintf("%s%s%s", left, l, right)

	case AlignRight:
		l = fmt.Sprintf("%s%s", strings.Repeat(" ", len), l)
	}

	return l
}

// newContent returns new content object
func newContent(s string) *content {
	c := strings.Split(s, "\n")
	mw := 0

	for i, v := range c {
		c[i] = strings.TrimSpace(v)
		w := realLength(c[i])

		if w > mw {
			mw = w
		}
	}

	return &content{
		c:  c,
		mw: mw,
	}
}

// stripAnsiEscape returns string without ANSI escape sequences (colors etc)
func stripAnsiEscape(s string) string {
	return stripAnsiEscapeRegexp.ReplaceAllString(s, "")
}

// realWidth returns real string length (without ANSI escape sequences)
func realLength(s string) int {
	return utf8.RuneCountInString(stripAnsiEscape(s))
}
<commit_msg>Wrote func and forgot to use it... shame..<commit_after>package simpletable

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"
)

// stripAnsiEscapeRegexp is a regular expression to clean ANSI Control sequences
// feat https://stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python#33925425
var stripAnsiEscapeRegexp = regexp.MustCompile(`(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]`)

// content is a cell content
type content struct {
	c  []string // content lines (trimmed)
	mw int      // maximal content width (f.e, for multilines columns)
	w  int      // meta content width
}

// width returns content width
func (c *content) width() int {
	m := c.mw
	if m > c.w {
		return m
	}

	return c.w
}

// setWidth sets content block width
func (c *content) setWidth(w int) {
	c.w = w
}

// height returns content height
func (c *content) height() int {
	return len(c.c)
}

// setHeigth sets content height
func (c *content) setHeight(h int) {
	l := c.height()
	if h <= l {
		return
	}

	for i := 0; i < h-l; i++ {
		c.c = append(c.c, "")
	}
}

// lines returns content as string slice
func (c *content) lines(a int) []string {
	r := []string{}

	for _, l := range c.c {
		r = append(r, c.line(l, a))
	}

	return r
}

// line formats content line
func (c *content) line(l string, a int) string {
	len := c.width() - realLength(l)
	if len <= 0 {
		return l
	}

	switch a {
	case AlignLeft:
		l = fmt.Sprintf("%s%s", l, strings.Repeat(" ", len))

	case AlignCenter:
		lft := len / 2
		rgt := len - lft

		left := strings.Repeat(" ", lft)
		right := strings.Repeat(" ", rgt)

		l = fmt.Sprintf("%s%s%s", left, l, right)

	case AlignRight:
		l = fmt.Sprintf("%s%s", strings.Repeat(" ", len), l)
	}

	return l
}

// newContent returns new content object
func newContent(s string) *content {
	c := strings.Split(s, "\n")
	mw := 0

	for i, v := range c {
		c[i] = strings.TrimSpace(v)
		w := realLength(c[i])

		if w > mw {
			mw = w
		}
	}

	return &content{
		c:  c,
		mw: mw,
	}
}

// stripAnsiEscape returns string without ANSI escape sequences (colors etc)
func stripAnsiEscape(s string) string {
	return stripAnsiEscapeRegexp.ReplaceAllString(s, "")
}

// realWidth returns real string length (without ANSI escape sequences)
func realLength(s string) int {
	return utf8.RuneCountInString(stripAnsiEscape(s))
}
<|endoftext|>


<commit_before>package ak

import (
	"encoding/json"
	"log"
	"net/http"
	"path"
	"reflect"
	"strconv"
)

//定义方法类型
type actionFunc func(*Context)

//请求上下文
type Context struct {
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	Params         map[string]string
	Data           map[string]interface{} //返回参数定义
	server         *Server
	Session        *Session
	closed         bool
}

//返回json
func (ctx *Context) WriteJson(content interface{}) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Header().Set("Content-Type", "application/json;charset=UTF-8")
	cv := reflect.ValueOf(content)
	log.Println("cv = ", cv.Type().Kind())
	if cv.Type().Kind() == reflect.String {
		ctx.ResponseWriter.Write([]byte(cv.String()))
	} else if cv.Type().Kind() == reflect.Struct || cv.Type().Kind() == reflect.Slice || cv.Type().Kind() == reflect.Ptr || cv.Type().Kind() == reflect.Map {
		jsonData, err := json.Marshal(content)
		if err != nil {
			panic(err)
		}
		ctx.ResponseWriter.Write(jsonData)
	}
	ctx.closed = true
}

//字符流
func (ctx *Context) WriteStream(filename string, contentType string, data []byte) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Header().Add("Content-Disposition", "attachment;filename="+filename)
	ctx.ResponseWriter.Header().Set("Content-Type", contentType)
	ctx.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(len(data)))
	ctx.ResponseWriter.Write(data)
	ctx.closed = true
}

//返回html
func (ctx *Context) WriteHtml(html string) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Write([]byte(html))
	ctx.closed = true
}

//返回模板
func (ctx *Context) WriteTpl(tplName string) {
	if ctx.closed {
		return
	}
	tplPath := path.Join(ctx.server.config.tplPath, tplName)
	if !fileExists(tplPath) {
		ctx.Abort(404, tplName+" not fond")
	}
	parseTpl(ctx.ResponseWriter, tplPath, ctx.Data, ctx.server.config.leftDelim, ctx.server.config.rightDelim)
	//	s := parseTmplateToStr(tplPath)
	//	t, err := template.New("index").Funcs(template.FuncMap{"include": includeTmplate}).Parse(s)
	//	tpl, err := template.ParseFiles(tplPath)
	//	if err != nil {
	//		panic(err.Error())
	//	}
	//	t.Execute(ctx.ResponseWriter, ctx.Data)
	ctx.closed = true
}

//重定向 3xx
func (ctx *Context) Redirect(url_ string) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Header().Set("Location", url_)
	ctx.ResponseWriter.WriteHeader(301)
	ctx.ResponseWriter.Write([]byte("Redirecting to: " + url_))
	ctx.closed = true
}

//错误信息
func (ctx *Context) Abort(status int, body string) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.WriteHeader(status)
	ctx.ResponseWriter.Write([]byte(body))
	ctx.closed = true
}

//将请求数据的json格式信息转换成结构
func (ctx *Context) ParseReqBodyJson(obj interface{}) error {
	decoder := json.NewDecoder(ctx.Request.Body)
	k := reflect.ValueOf(obj).Type().Kind()
	var err error
	switch k {
	case reflect.Struct:
		err = decoder.Decode(&obj)
	case reflect.Ptr:
		err = decoder.Decode(obj)
	case reflect.Array:
		err = decoder.Decode(obj)
	case reflect.String:
		err = decoder.Decode(&obj)
	}
	return err
}
<commit_msg>fix type().Kind()<commit_after>package ak

import (
	"encoding/json"
	"net/http"
	"path"
	"reflect"
	"strconv"
)

//定义方法类型
type actionFunc func(*Context)

//请求上下文
type Context struct {
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	Params         map[string]string
	Data           map[string]interface{} //返回参数定义
	server         *Server
	Session        *Session
	closed         bool
}

//返回json
func (ctx *Context) WriteJson(content interface{}) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Header().Set("Content-Type", "application/json;charset=UTF-8")
	cv := reflect.ValueOf(content)
	vkind := cv.Type().Kind()
	if vkind == reflect.String {
		ctx.ResponseWriter.Write([]byte(cv.String()))
	} else if vkind == reflect.Struct || vkind == reflect.Slice || vkind == reflect.Ptr || vkind == reflect.Map {
		jsonData, err := json.Marshal(content)
		if err != nil {
			panic(err)
		}
		ctx.ResponseWriter.Write(jsonData)
	}
	ctx.closed = true
}

//字符流
func (ctx *Context) WriteStream(filename string, contentType string, data []byte) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Header().Add("Content-Disposition", "attachment;filename="+filename)
	ctx.ResponseWriter.Header().Set("Content-Type", contentType)
	ctx.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(len(data)))
	ctx.ResponseWriter.Write(data)
	ctx.closed = true
}

//返回html
func (ctx *Context) WriteHtml(html string) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Write([]byte(html))
	ctx.closed = true
}

//返回模板
func (ctx *Context) WriteTpl(tplName string) {
	if ctx.closed {
		return
	}
	tplPath := path.Join(ctx.server.config.tplPath, tplName)
	if !fileExists(tplPath) {
		ctx.Abort(404, tplName+" not fond")
	}
	parseTpl(ctx.ResponseWriter, tplPath, ctx.Data, ctx.server.config.leftDelim, ctx.server.config.rightDelim)
	//	s := parseTmplateToStr(tplPath)
	//	t, err := template.New("index").Funcs(template.FuncMap{"include": includeTmplate}).Parse(s)
	//	tpl, err := template.ParseFiles(tplPath)
	//	if err != nil {
	//		panic(err.Error())
	//	}
	//	t.Execute(ctx.ResponseWriter, ctx.Data)
	ctx.closed = true
}

//重定向 3xx
func (ctx *Context) Redirect(url_ string) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.Header().Set("Location", url_)
	ctx.ResponseWriter.WriteHeader(301)
	ctx.ResponseWriter.Write([]byte("Redirecting to: " + url_))
	ctx.closed = true
}

//错误信息
func (ctx *Context) Abort(status int, body string) {
	if ctx.closed {
		return
	}
	ctx.ResponseWriter.WriteHeader(status)
	ctx.ResponseWriter.Write([]byte(body))
	ctx.closed = true
}

//将请求数据的json格式信息转换成结构
func (ctx *Context) ParseReqBodyJson(obj interface{}) error {
	decoder := json.NewDecoder(ctx.Request.Body)
	k := reflect.ValueOf(obj).Type().Kind()
	var err error
	switch k {
	case reflect.Struct:
		err = decoder.Decode(&obj)
	case reflect.Ptr:
		err = decoder.Decode(obj)
	case reflect.Array:
		err = decoder.Decode(obj)
	case reflect.String:
		err = decoder.Decode(&obj)
	}
	return err
}
<|endoftext|>


<commit_before>package air

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"time"

	"golang.org/x/net/context"
)

// Context represents the context of the current HTTP request. It holds request and
// response objects, path, path parameters, data and registered handler.
type Context struct {
	goContext context.Context

	Request    *Request
	Response   *Response
	Path       string
	ParamNames []string
	Params     map[string]string
	Handler    HandlerFunc
	StatusCode int
	Data       map[string]interface{}
	Air        *Air
}

// newContext returns a new instance of `Context`.
func newContext(a *Air) *Context {
	return &Context{
		goContext:  context.Background(),
		Params:     make(map[string]string),
		Handler:    NotFoundHandler,
		StatusCode: http.StatusOK,
		Data:       make(map[string]interface{}),
		Air:        a,
	}
}

// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
func (c *Context) Deadline() (deadline time.Time, ok bool) {
	return c.goContext.Deadline()
}

// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
func (c *Context) Done() <-chan struct{} {
	return c.goContext.Done()
}

// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
func (c *Context) Err() error {
	return c.goContext.Err()
}

// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
func (c *Context) Value(key interface{}) interface{} {
	return c.goContext.Value(key)
}

// SetValue sets request-scoped value into the context.
func (c *Context) SetValue(key interface{}, val interface{}) {
	c.goContext = context.WithValue(c.goContext, key, val)
}

// QueryParam returns the query param for the provided name. It is an alias
// for `URI#QueryParam()`.
func (c *Context) QueryParam(name string) string {
	return c.Request.URI.QueryParam(name)
}

// QueryParams returns the query parameters as map. It is an alias for
// `URI#QueryParams()`.
func (c *Context) QueryParams() map[string][]string {
	return c.Request.URI.QueryParams()
}

// FormValue returns the form field value for the provided name. It is an
// alias for `Request#FormValue()`.
func (c *Context) FormValue(name string) string {
	return c.Request.FormValue(name)
}

// FormParams returns the form parameters as map.
// It is an alias for `Request#FormParams()`.
func (c *Context) FormParams() map[string][]string {
	return c.Request.FormParams()
}

// FormFile returns the multipart form file for the provided name. It is an
// alias for `Request#FormFile()`.
func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
	return c.Request.FormFile(name)
}

// MultipartForm returns the multipart form.
// It is an alias for `Request#MultipartForm()`.
func (c *Context) MultipartForm() (*multipart.Form, error) {
	return c.Request.MultipartForm()
}

// Cookie returns the named cookie provided in the request.
// It is an alias for `Request#Cookie()`.
func (c *Context) Cookie(name string) (Cookie, error) {
	return c.Request.Cookie(name)
}

// SetCookie adds a "Set-Cookie" header in HTTP response.
// It is an alias for `Response#SetCookie()`.
func (c *Context) SetCookie(cookie Cookie) {
	c.Response.SetCookie(cookie)
}

// Cookies returns the HTTP cookies sent with the request. It is an alias
// for `Request#Cookies()`.
func (c *Context) Cookies() []Cookie {
	return c.Request.Cookies()
}

// Bind binds the request body into provided type i. The default binder doe
// it based on "Content-Type" header.
func (c *Context) Bind(i interface{}) error {
	return c.Air.binder.bind(i, c)
}

// Render renders a template with `Context#Data` and `Context#Data["template"]`
// and sends a "text/html" response with `Context#StatusCode`.
func (c *Context) Render() (err error) {
	t, ok := c.Data["template"]
	if !ok || reflect.ValueOf(t).Kind() != reflect.String {
		return errors.New("c.Data[\"template\"] Not Setted")
	}
	buf := new(bytes.Buffer)
	if err = c.Air.renderer.render(buf, t.(string), c); err != nil {
		return
	}
	c.Response.Header.Set(HeaderContentType, MIMETextHTML)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write(buf.Bytes())
	return
}

// HTML sends an HTTP response with `Context#StatusCode` and `Context#Data["html"]`.
func (c *Context) HTML() (err error) {
	h, ok := c.Data["html"]
	if !ok || reflect.ValueOf(h).Kind() != reflect.String {
		return errors.New("c.Data[\"html\"] Not Setted")
	}
	c.Response.Header.Set(HeaderContentType, MIMETextHTML)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write([]byte(h.(string)))
	return
}

// String sends a string response with `Context#StatusCode` and `Context#Data["string"]`.
func (c *Context) String() (err error) {
	s, ok := c.Data["string"]
	if !ok || reflect.ValueOf(s).Kind() != reflect.String {
		return errors.New("c.Data[\"string\"] Not Setted")
	}
	c.Response.Header.Set(HeaderContentType, MIMETextPlain)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write([]byte(s.(string)))
	return
}

// JSON sends a JSON response with `Context#StatusCode` and `Context#Data["json"]`.
func (c *Context) JSON() (err error) {
	j, ok := c.Data["json"]
	if !ok {
		return errors.New("c.Data[\"json\"] Not Setted")
	}
	b, err := json.Marshal(j)
	if c.Air.Config.DebugMode {
		b, err = json.MarshalIndent(j, "", "\t")
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(b)
}

// JSONBlob sends a JSON blob response with `Context#StatusCode`.
func (c *Context) JSONBlob(b []byte) (err error) {
	c.Response.Header.Set(HeaderContentType, MIMEApplicationJSON)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write(b)
	return
}

// JSONP sends a JSONP response with `Context#StatusCode` and `Context#Data["jsonp"]`.
// It uses `Context#Data["callback"]` to construct the JSONP payload.
func (c *Context) JSONP() (err error) {
	j, jok := c.Data["jsonp"]
	cb, cbok := c.Data["callback"]
	if !jok {
		return errors.New("c.Data[\"jsonp\"] Not Setted")
	} else if !cbok || reflect.ValueOf(cb).Kind() != reflect.String {
		return errors.New("c.Data[\"callback\"] Not Setted")
	}
	b, err := json.Marshal(j)
	if err != nil {
		return err
	}
	c.Response.Header.Set(HeaderContentType, MIMEApplicationJavaScript)
	c.Response.WriteHeader(c.StatusCode)
	if _, err = c.Response.Write([]byte(cb.(string) + "(")); err != nil {
		return
	}
	if _, err = c.Response.Write(b); err != nil {
		return
	}
	_, err = c.Response.Write([]byte(");"))
	return
}

// XML sends an XML response with `Context#StatusCode` and `Context#Data["xml"]`.
func (c *Context) XML() (err error) {
	x, ok := c.Data["xml"]
	if !ok {
		return errors.New("c.Data[\"xml\"] Not Setted")
	}
	b, err := xml.Marshal(x)
	if c.Air.Config.DebugMode {
		b, err = xml.MarshalIndent(x, "", "\t")
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(b)
}

// XMLBlob sends a XML blob response with `Context#StatusCode`.
func (c *Context) XMLBlob(b []byte) (err error) {
	c.Response.Header.Set(HeaderContentType, MIMEApplicationXML)
	c.Response.WriteHeader(c.StatusCode)
	if _, err = c.Response.Write([]byte(xml.Header)); err != nil {
		return
	}
	_, err = c.Response.Write(b)
	return
}

// File sends a response with the content of the file.
func (c *Context) File(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return ErrNotFound
	}
	defer f.Close()

	fi, _ := f.Stat()
	if fi.IsDir() {
		file = filepath.Join(file, "index.html")
		f, err = os.Open(file)
		if err != nil {
			return ErrNotFound
		}
		if fi, err = f.Stat(); err != nil {
			return err
		}
	}
	return c.ServeContent(f, fi.Name(), fi.ModTime())
}

// Attachment sends a response from `io.ReaderSeeker` as attachment, prompting
// client to save the file.
func (c *Context) Attachment(r io.ReadSeeker, name string) (err error) {
	c.Response.Header.Set(HeaderContentType, contentTypeByExtension(name))
	c.Response.Header.Set(HeaderContentDisposition, "attachment; filename="+name)
	c.Response.WriteHeader(http.StatusOK)
	_, err = io.Copy(c.Response, r)
	return
}

// NoContent sends a response with no body and a `Context#StatusCode`.
func (c *Context) NoContent() error {
	c.Response.WriteHeader(c.StatusCode)
	return nil
}

// Redirect redirects the request with `Context#StatusCode`.
func (c *Context) Redirect(uri string) error {
	if c.StatusCode < http.StatusMultipleChoices || c.StatusCode > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	c.Response.Header.Set(HeaderLocation, uri)
	c.Response.WriteHeader(c.StatusCode)
	return nil
}

// ServeContent sends static content from `io.Reader` and handles caching
// via "If-Modified-Since" request header. It automatically sets "Content-Type"
// and "Last-Modified" response headers.
func (c *Context) ServeContent(content io.ReadSeeker, name string, modtime time.Time) error {
	req := c.Request
	res := c.Response

	if t, err := time.Parse(http.TimeFormat, req.Header.Get(HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
		res.Header.Del(HeaderContentType)
		res.Header.Del(HeaderContentLength)
		c.StatusCode = http.StatusNotModified
		return c.NoContent()
	}

	res.Header.Set(HeaderContentType, contentTypeByExtension(name))
	res.Header.Set(HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
	res.WriteHeader(http.StatusOK)
	_, err := io.Copy(res, content)
	return err
}

// reset resets the instance of `Context`.
func (c *Context) reset() {
	c.goContext = context.Background()
	c.Request = nil
	c.Response = nil
	c.Path = ""
	c.ParamNames = c.ParamNames[:0]
	for k := range c.Params {
		delete(c.Params, k)
	}
	c.Handler = NotFoundHandler
	c.StatusCode = http.StatusOK
	for k := range c.Data {
		delete(c.Data, k)
	}
}

// contentTypeByExtension returns the MIME type associated with the file based
// on its extension. It returns "application/octet-stream" incase MIME type is
// not found.
func contentTypeByExtension(name string) (t string) {
	if t = mime.TypeByExtension(filepath.Ext(name)); t == "" {
		t = MIMEOctetStream
	}
	return
}
<commit_msg>refactor: use go1.7's new built-in package `context`<commit_after>package air

import (
	"bytes"
	"context"
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"time"
)

// Context represents the context of the current HTTP request. It holds request and
// response objects, path, path parameters, data and registered handler.
type Context struct {
	goContext context.Context

	Request    *Request
	Response   *Response
	Path       string
	ParamNames []string
	Params     map[string]string
	Handler    HandlerFunc
	StatusCode int
	Data       map[string]interface{}
	Air        *Air
}

// newContext returns a new instance of `Context`.
func newContext(a *Air) *Context {
	return &Context{
		goContext:  context.Background(),
		Params:     make(map[string]string),
		Handler:    NotFoundHandler,
		StatusCode: http.StatusOK,
		Data:       make(map[string]interface{}),
		Air:        a,
	}
}

// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
func (c *Context) Deadline() (deadline time.Time, ok bool) {
	return c.goContext.Deadline()
}

// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
func (c *Context) Done() <-chan struct{} {
	return c.goContext.Done()
}

// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
func (c *Context) Err() error {
	return c.goContext.Err()
}

// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
func (c *Context) Value(key interface{}) interface{} {
	return c.goContext.Value(key)
}

// SetValue sets request-scoped value into the context.
func (c *Context) SetValue(key interface{}, val interface{}) {
	c.goContext = context.WithValue(c.goContext, key, val)
}

// QueryParam returns the query param for the provided name. It is an alias
// for `URI#QueryParam()`.
func (c *Context) QueryParam(name string) string {
	return c.Request.URI.QueryParam(name)
}

// QueryParams returns the query parameters as map. It is an alias for
// `URI#QueryParams()`.
func (c *Context) QueryParams() map[string][]string {
	return c.Request.URI.QueryParams()
}

// FormValue returns the form field value for the provided name. It is an
// alias for `Request#FormValue()`.
func (c *Context) FormValue(name string) string {
	return c.Request.FormValue(name)
}

// FormParams returns the form parameters as map.
// It is an alias for `Request#FormParams()`.
func (c *Context) FormParams() map[string][]string {
	return c.Request.FormParams()
}

// FormFile returns the multipart form file for the provided name. It is an
// alias for `Request#FormFile()`.
func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
	return c.Request.FormFile(name)
}

// MultipartForm returns the multipart form.
// It is an alias for `Request#MultipartForm()`.
func (c *Context) MultipartForm() (*multipart.Form, error) {
	return c.Request.MultipartForm()
}

// Cookie returns the named cookie provided in the request.
// It is an alias for `Request#Cookie()`.
func (c *Context) Cookie(name string) (Cookie, error) {
	return c.Request.Cookie(name)
}

// SetCookie adds a "Set-Cookie" header in HTTP response.
// It is an alias for `Response#SetCookie()`.
func (c *Context) SetCookie(cookie Cookie) {
	c.Response.SetCookie(cookie)
}

// Cookies returns the HTTP cookies sent with the request. It is an alias
// for `Request#Cookies()`.
func (c *Context) Cookies() []Cookie {
	return c.Request.Cookies()
}

// Bind binds the request body into provided type i. The default binder doe
// it based on "Content-Type" header.
func (c *Context) Bind(i interface{}) error {
	return c.Air.binder.bind(i, c)
}

// Render renders a template with `Context#Data` and `Context#Data["template"]`
// and sends a "text/html" response with `Context#StatusCode`.
func (c *Context) Render() (err error) {
	t, ok := c.Data["template"]
	if !ok || reflect.ValueOf(t).Kind() != reflect.String {
		return errors.New("c.Data[\"template\"] Not Setted")
	}
	buf := new(bytes.Buffer)
	if err = c.Air.renderer.render(buf, t.(string), c); err != nil {
		return
	}
	c.Response.Header.Set(HeaderContentType, MIMETextHTML)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write(buf.Bytes())
	return
}

// HTML sends an HTTP response with `Context#StatusCode` and `Context#Data["html"]`.
func (c *Context) HTML() (err error) {
	h, ok := c.Data["html"]
	if !ok || reflect.ValueOf(h).Kind() != reflect.String {
		return errors.New("c.Data[\"html\"] Not Setted")
	}
	c.Response.Header.Set(HeaderContentType, MIMETextHTML)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write([]byte(h.(string)))
	return
}

// String sends a string response with `Context#StatusCode` and `Context#Data["string"]`.
func (c *Context) String() (err error) {
	s, ok := c.Data["string"]
	if !ok || reflect.ValueOf(s).Kind() != reflect.String {
		return errors.New("c.Data[\"string\"] Not Setted")
	}
	c.Response.Header.Set(HeaderContentType, MIMETextPlain)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write([]byte(s.(string)))
	return
}

// JSON sends a JSON response with `Context#StatusCode` and `Context#Data["json"]`.
func (c *Context) JSON() (err error) {
	j, ok := c.Data["json"]
	if !ok {
		return errors.New("c.Data[\"json\"] Not Setted")
	}
	b, err := json.Marshal(j)
	if c.Air.Config.DebugMode {
		b, err = json.MarshalIndent(j, "", "\t")
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(b)
}

// JSONBlob sends a JSON blob response with `Context#StatusCode`.
func (c *Context) JSONBlob(b []byte) (err error) {
	c.Response.Header.Set(HeaderContentType, MIMEApplicationJSON)
	c.Response.WriteHeader(c.StatusCode)
	_, err = c.Response.Write(b)
	return
}

// JSONP sends a JSONP response with `Context#StatusCode` and `Context#Data["jsonp"]`.
// It uses `Context#Data["callback"]` to construct the JSONP payload.
func (c *Context) JSONP() (err error) {
	j, jok := c.Data["jsonp"]
	cb, cbok := c.Data["callback"]
	if !jok {
		return errors.New("c.Data[\"jsonp\"] Not Setted")
	} else if !cbok || reflect.ValueOf(cb).Kind() != reflect.String {
		return errors.New("c.Data[\"callback\"] Not Setted")
	}
	b, err := json.Marshal(j)
	if err != nil {
		return err
	}
	c.Response.Header.Set(HeaderContentType, MIMEApplicationJavaScript)
	c.Response.WriteHeader(c.StatusCode)
	if _, err = c.Response.Write([]byte(cb.(string) + "(")); err != nil {
		return
	}
	if _, err = c.Response.Write(b); err != nil {
		return
	}
	_, err = c.Response.Write([]byte(");"))
	return
}

// XML sends an XML response with `Context#StatusCode` and `Context#Data["xml"]`.
func (c *Context) XML() (err error) {
	x, ok := c.Data["xml"]
	if !ok {
		return errors.New("c.Data[\"xml\"] Not Setted")
	}
	b, err := xml.Marshal(x)
	if c.Air.Config.DebugMode {
		b, err = xml.MarshalIndent(x, "", "\t")
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(b)
}

// XMLBlob sends a XML blob response with `Context#StatusCode`.
func (c *Context) XMLBlob(b []byte) (err error) {
	c.Response.Header.Set(HeaderContentType, MIMEApplicationXML)
	c.Response.WriteHeader(c.StatusCode)
	if _, err = c.Response.Write([]byte(xml.Header)); err != nil {
		return
	}
	_, err = c.Response.Write(b)
	return
}

// File sends a response with the content of the file.
func (c *Context) File(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return ErrNotFound
	}
	defer f.Close()

	fi, _ := f.Stat()
	if fi.IsDir() {
		file = filepath.Join(file, "index.html")
		f, err = os.Open(file)
		if err != nil {
			return ErrNotFound
		}
		if fi, err = f.Stat(); err != nil {
			return err
		}
	}
	return c.ServeContent(f, fi.Name(), fi.ModTime())
}

// Attachment sends a response from `io.ReaderSeeker` as attachment, prompting
// client to save the file.
func (c *Context) Attachment(r io.ReadSeeker, name string) (err error) {
	c.Response.Header.Set(HeaderContentType, contentTypeByExtension(name))
	c.Response.Header.Set(HeaderContentDisposition, "attachment; filename="+name)
	c.Response.WriteHeader(http.StatusOK)
	_, err = io.Copy(c.Response, r)
	return
}

// NoContent sends a response with no body and a `Context#StatusCode`.
func (c *Context) NoContent() error {
	c.Response.WriteHeader(c.StatusCode)
	return nil
}

// Redirect redirects the request with `Context#StatusCode`.
func (c *Context) Redirect(uri string) error {
	if c.StatusCode < http.StatusMultipleChoices || c.StatusCode > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	c.Response.Header.Set(HeaderLocation, uri)
	c.Response.WriteHeader(c.StatusCode)
	return nil
}

// ServeContent sends static content from `io.Reader` and handles caching
// via "If-Modified-Since" request header. It automatically sets "Content-Type"
// and "Last-Modified" response headers.
func (c *Context) ServeContent(content io.ReadSeeker, name string, modtime time.Time) error {
	req := c.Request
	res := c.Response

	if t, err := time.Parse(http.TimeFormat, req.Header.Get(HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
		res.Header.Del(HeaderContentType)
		res.Header.Del(HeaderContentLength)
		c.StatusCode = http.StatusNotModified
		return c.NoContent()
	}

	res.Header.Set(HeaderContentType, contentTypeByExtension(name))
	res.Header.Set(HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
	res.WriteHeader(http.StatusOK)
	_, err := io.Copy(res, content)
	return err
}

// reset resets the instance of `Context`.
func (c *Context) reset() {
	c.goContext = context.Background()
	c.Request = nil
	c.Response = nil
	c.Path = ""
	c.ParamNames = c.ParamNames[:0]
	for k := range c.Params {
		delete(c.Params, k)
	}
	c.Handler = NotFoundHandler
	c.StatusCode = http.StatusOK
	for k := range c.Data {
		delete(c.Data, k)
	}
}

// contentTypeByExtension returns the MIME type associated with the file based
// on its extension. It returns "application/octet-stream" incase MIME type is
// not found.
func contentTypeByExtension(name string) (t string) {
	if t = mime.TypeByExtension(filepath.Ext(name)); t == "" {
		t = MIMEOctetStream
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"net/textproto"
	"strings"
)

// TCPServer simple tcp server for commands
func TCPServer() (ret int) {
	ln, err := net.Listen("tcp", ":"+TCPPort)
	if err != nil {
		log.Println("Error listening:", err.Error())
		return 1
	}
	log.Printf("Listening to port %s for connections...", TCPPort)
	defer ln.Close()

	for {
		conn, err := ln.Accept()
		bot := NewBot()
		bot.inconn = conn
		if err != nil {
			fmt.Println("Error accepting: ", err.Error())
			return 1
		}
		go handleRequest(conn, bot)
	}
}

// Start reading packets that are sent to the given connection
func handleRequest(conn net.Conn, bot *Bot) {
	// XXX(pajlada): Not sure if this is where we should close the connection or not
	// Perhaps in bot.ListenToConnection()?
	defer conn.Close()

	reader := bufio.NewReader(conn)
	tp := textproto.NewReader(reader)
	for {
		line, err := tp.ReadLine()

		if err != nil {
			fmt.Println("Read error:", err)
			fmt.Fprintf(conn, "Read error: %s", err)
			conn.Close()
			return
		}
		handleMessage(line, bot)
	}
}

// Handle an IRC received from a bot
func handleMessage(message string, bot *Bot) {
	remoteAddr := bot.inconn.RemoteAddr().String()
	remoteAddrIP := strings.Split(remoteAddr, ":")

	if strings.Contains(message, "JOIN ") {
		joinComm := strings.Split(message, "JOIN ")
		bot.join(joinComm[1])
	} else if strings.Contains(message, "PASS ") {
		passComm := strings.Split(message, "PASS ")
		passwordParts := strings.Split(passComm[1], ";")
		if passwordParts[0] == TCPPass {
			bot.oauth = passwordParts[1]
			log.Printf("Authenticated! %s\n", remoteAddrIP)
		} else {
			log.Printf("Invalid broker pass! %s\n", remoteAddrIP)
			bot.inconn.Close()
			return
		}
	} else if strings.Contains(message, "NICK ") {
		nickComm := strings.Split(message, "NICK ")
		bot.nick = nickComm[1]

		if bot.oauth != "" {
			bot.CreateConnection()
			bot.CreateGroupConnection()
		}
	} else if strings.Contains(message, "USER ") {
		if bot.nick != "" {
			nickComm := strings.Split(message, "USER ")
			bot.nick = nickComm[1]

			if bot.oauth != "" {
				bot.CreateConnection()
				bot.CreateGroupConnection()
			}
		}
	} else if strings.Contains(message, "PRIVMSG #jtv :/w ") {
		privmsgComm := strings.Split(message, "PRIVMSG #jtv :")
		bot.Whisper(privmsgComm[1])
	} else if strings.Contains(message, "PRIVMSG ") {
		privmsgComm := strings.Split(message, "PRIVMSG ")
		remainingString := strings.Split(privmsgComm[1], " :")
		channel := remainingString[0]
		message := remainingString[1]
		bot.Message(channel, message)
	} else {
		log.Printf("Unhandled message: '%s'\n", message)
	}
}
<commit_msg>log for incoming messages<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"net/textproto"
	"strings"
)

// TCPServer simple tcp server for commands
func TCPServer() (ret int) {
	ln, err := net.Listen("tcp", ":"+TCPPort)
	if err != nil {
		log.Println("Error listening:", err.Error())
		return 1
	}
	log.Printf("Listening to port %s for connections...", TCPPort)
	defer ln.Close()

	for {
		conn, err := ln.Accept()
		bot := NewBot()
		bot.inconn = conn
		if err != nil {
			fmt.Println("Error accepting: ", err.Error())
			return 1
		}
		go handleRequest(conn, bot)
	}
}

// Start reading packets that are sent to the given connection
func handleRequest(conn net.Conn, bot *Bot) {
	// XXX(pajlada): Not sure if this is where we should close the connection or not
	// Perhaps in bot.ListenToConnection()?
	defer conn.Close()

	reader := bufio.NewReader(conn)
	tp := textproto.NewReader(reader)
	for {
		line, err := tp.ReadLine()

		if err != nil {
			fmt.Println("Read error:", err)
			fmt.Fprintf(conn, "Read error: %s", err)
			conn.Close()
			return
		}
		log.Println(line)
		handleMessage(line, bot)
	}
}

// Handle an IRC received from a bot
func handleMessage(message string, bot *Bot) {
	remoteAddr := bot.inconn.RemoteAddr().String()
	remoteAddrIP := strings.Split(remoteAddr, ":")

	if strings.Contains(message, "JOIN ") {
		joinComm := strings.Split(message, "JOIN ")
		bot.join(joinComm[1])
	} else if strings.Contains(message, "PASS ") {
		passComm := strings.Split(message, "PASS ")
		passwordParts := strings.Split(passComm[1], ";")
		if passwordParts[0] == TCPPass {
			bot.oauth = passwordParts[1]
			log.Printf("Authenticated! %s\n", remoteAddrIP)
		} else {
			log.Printf("Invalid broker pass! %s\n", remoteAddrIP)
			bot.inconn.Close()
			return
		}
	} else if strings.Contains(message, "NICK ") {
		nickComm := strings.Split(message, "NICK ")
		bot.nick = nickComm[1]

		if bot.oauth != "" {
			bot.CreateConnection()
			bot.CreateGroupConnection()
		}
	} else if strings.Contains(message, "USER ") {
		if bot.nick != "" {
			nickComm := strings.Split(message, "USER ")
			bot.nick = nickComm[1]

			if bot.oauth != "" {
				bot.CreateConnection()
				bot.CreateGroupConnection()
			}
		}
	} else if strings.Contains(message, "PRIVMSG #jtv :/w ") {
		privmsgComm := strings.Split(message, "PRIVMSG #jtv :")
		bot.Whisper(privmsgComm[1])
	} else if strings.Contains(message, "PRIVMSG ") {
		privmsgComm := strings.Split(message, "PRIVMSG ")
		remainingString := strings.Split(privmsgComm[1], " :")
		channel := remainingString[0]
		message := remainingString[1]
		bot.Message(channel, message)
	} else {
		log.Printf("Unhandled message: '%s'\n", message)
	}
}
<|endoftext|>


<commit_before>package decor

import (
	"fmt"
	"math"
	"time"
	"unicode/utf8"
)

const (
	// DidentRight specifies identation direction.
	// |foo   |b     | With DidentRight
	// |   foo|     b| Without DidentRight
	DidentRight = 1 << iota

	// DwidthSync will auto sync max width
	DwidthSync

	// DextraSpace adds extra space, makes sence with DwidthSync only.
	// When DidentRight bit set, the space will be added to the right,
	// otherwise to the left.
	DextraSpace

	DSyncSpace = DwidthSync | DextraSpace
)

// Statistics represents statistics of the progress bar.
// Cantains: Total, Current, TimeElapsed, TimePerItemEstimate
type Statistics struct {
	ID                  int
	Completed           bool
	Aborted             bool
	Total               int64
	Current             int64
	StartTime           time.Time
	TimeElapsed         time.Duration
	TimePerItemEstimate time.Duration
}

// Eta returns exponential-weighted-moving-average ETA estimator
func (s *Statistics) Eta() time.Duration {
	return time.Duration(s.Total-s.Current) * s.TimePerItemEstimate
}

// DecoratorFunc is a function that can be prepended and appended to the progress bar
type DecoratorFunc func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string

func Name(name string, minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(name)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), name)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), name)
	}
}

func Counters(pairFormat string, unit Units, minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		current := Format(s.Current).To(unit)
		total := Format(s.Total).To(unit)
		str := fmt.Sprintf(pairFormat, current, total)
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func ETA(minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		str := fmt.Sprint(time.Duration(s.Eta().Seconds()) * time.Second)
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func Elapsed(minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		str := fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func Percentage(minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		str := fmt.Sprintf("%d %%", CalcPercentage(s.Total, s.Current, 100))
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func CalcPercentage(total, current int64, width int) int {
	if total == 0 || current > total {
		return 0
	}
	num := float64(width) * float64(current) / float64(total)
	ceil := math.Ceil(num)
	diff := ceil - num
	// num = 2.34 will return 2
	// num = 2.44 will return 3
	if math.Max(diff, 0.6) == diff {
		return int(num)
	}
	return int(ceil)
}
<commit_msg>DSyncSpace public comment<commit_after>package decor

import (
	"fmt"
	"math"
	"time"
	"unicode/utf8"
)

const (
	// DidentRight specifies identation direction.
	// |foo   |b     | With DidentRight
	// |   foo|     b| Without DidentRight
	DidentRight = 1 << iota

	// DwidthSync will auto sync max width
	DwidthSync

	// DextraSpace adds extra space, makes sence with DwidthSync only.
	// When DidentRight bit set, the space will be added to the right,
	// otherwise to the left.
	DextraSpace

	// DSyncSpace is shortcut for DwidthSync|DextraSpace
	DSyncSpace = DwidthSync | DextraSpace
)

// Statistics represents statistics of the progress bar.
// Cantains: Total, Current, TimeElapsed, TimePerItemEstimate
type Statistics struct {
	ID                  int
	Completed           bool
	Aborted             bool
	Total               int64
	Current             int64
	StartTime           time.Time
	TimeElapsed         time.Duration
	TimePerItemEstimate time.Duration
}

// Eta returns exponential-weighted-moving-average ETA estimator
func (s *Statistics) Eta() time.Duration {
	return time.Duration(s.Total-s.Current) * s.TimePerItemEstimate
}

// DecoratorFunc is a function that can be prepended and appended to the progress bar
type DecoratorFunc func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string

func Name(name string, minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(name)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), name)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), name)
	}
}

func Counters(pairFormat string, unit Units, minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		current := Format(s.Current).To(unit)
		total := Format(s.Total).To(unit)
		str := fmt.Sprintf(pairFormat, current, total)
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func ETA(minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		str := fmt.Sprint(time.Duration(s.Eta().Seconds()) * time.Second)
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func Elapsed(minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		str := fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func Percentage(minWidth int, conf byte) DecoratorFunc {
	format := "%%"
	if (conf & DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
		str := fmt.Sprintf("%d %%", CalcPercentage(s.Total, s.Current, 100))
		if (conf & DwidthSync) != 0 {
			myWidth <- utf8.RuneCountInString(str)
			max := <-maxWidth
			if (conf & DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func CalcPercentage(total, current int64, width int) int {
	if total == 0 || current > total {
		return 0
	}
	num := float64(width) * float64(current) / float64(total)
	ceil := math.Ceil(num)
	diff := ceil - num
	// num = 2.34 will return 2
	// num = 2.44 will return 3
	if math.Max(diff, 0.6) == diff {
		return int(num)
	}
	return int(ceil)
}
<|endoftext|>