<commit_before>package kontrol

import (
	"errors"
	"fmt"
	"time"

	"github.com/koding/kite"
	"github.com/koding/kite/dnode"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/koding/kite/protocol"
)

func (k *Kontrol) handleRegister(r *kite.Request) (interface{}, error) {
	k.log.Info("Register request from: %s", r.Client.Kite)

	if r.Args.One().MustMap()["url"].MustString() == "" {
		return nil, errors.New("invalid url")
	}

	var args struct {
		URL string `json:"url"`
	}
	r.Args.One().MustUnmarshal(&args)
	if args.URL == "" {
		return nil, errors.New("empty url")
	}

	// Only accept requests with kiteKey because we need this info
	// for generating tokens for this kite.
	if r.Auth.Type != "kiteKey" {
		return nil, fmt.Errorf("Unexpected authentication type: %s", r.Auth.Type)
	}

	kiteURL := args.URL
	remote := r.Client

	if err := validateKiteKey(&remote.Kite); err != nil {
		return nil, err
	}

	value := &kontrolprotocol.RegisterValue{
		URL: kiteURL,
	}

	// Register first by adding the value to the storage. Return if there is
	// any error.
	if err := k.storage.Upsert(&remote.Kite, value); err != nil {
		k.log.Error("storage add '%s' error: %s", remote.Kite, err)
		return nil, errors.New("internal error - register")
	}

	// we create a new ticker which is going to update the key periodically in
	// the storage so it's always up to date.
	updater := time.NewTicker(UpdateInterval)
	updaterFunc := func() {
		for _ = range updater.C {
			k.log.Info("Kite is active, updating the value %s", remote.Kite)
			err := k.storage.Update(&remote.Kite, value)
			if err != nil {
				k.log.Error("storage update '%s' error: %s", remote.Kite, err)
			}
		}
	}

	go updaterFunc()

	// lostFunc is called when we don't get any heartbeat or we lost
	// connection. In any case, it will remove the key from the storage
	lostFunc := func(reason string) func() {
		return func() {
			k.log.Info("Kite %s. Deleting from storage %s", reason, remote.Kite)
			// stop the updater so it doesn't update it in the background
			updater.Stop()

			// delete the key immediately
			k.storage.Delete(&remote.Kite)
		}
	}

	// we are now creating a timer that is going to call the lostFunc, which
	// deletes the key from the storage and also stops the background updater
	deleteTimer := time.AfterFunc(HeartbeatInterval+HeartbeatDelay,
		lostFunc("didn't get heartbeat"))

	heartbeatArgs := []interface{}{
		HeartbeatInterval / time.Second,
		dnode.Callback(func(args *dnode.Partial) {
			// try to reset the timer every time the remote kite calls this
			// callback(sends us heartbeat). Because the timer get reset, the
			// deleteFunc above will never be fired, so the value get always
			// updated with the updater in the background according to the
			// write interval. If the kite doesn't send any heartbeat, the
			// deleteFunc is being called, which removes the key from the
			// storage.
			k.log.Info("Kite send us an heartbeat. %s", remote.Kite)
			k.clientLocks.Get(remote.Kite.ID).Lock()
			deleteTimer.Reset(HeartbeatInterval + HeartbeatDelay)
			k.clientLocks.Get(remote.Kite.ID).Unlock()
		}),
	}

	// let's ping first to see if they are alive
	_, err := remote.TellWithTimeout("kite.ping", 4*time.Second)
	if err != nil {
		return nil, err
	}

	// now trigger the remote kite so it sends us periodically an heartbeat
	remote.GoWithTimeout("kite.heartbeat", 4*time.Second, heartbeatArgs...)

	k.log.Info("Kite registered: %s", remote.Kite)

	remote.OnDisconnect(lostFunc("disconnected")) // also call it when we disconnect

	// send response back to the kite, also identify him with the new name
	return &protocol.RegisterResult{URL: args.URL}, nil
}

func (k *Kontrol) handleGetKites(r *kite.Request) (interface{}, error) {
	// This type is here until inversion branch is merged.
	// Reason: We can't use the same struct for marshaling and unmarshaling.
	// TODO use the struct in protocol
	type GetKitesArgs struct {
		Query *protocol.KontrolQuery `json:"query"`
	}

	var args GetKitesArgs
	r.Args.One().MustUnmarshal(&args)

	query := args.Query

	// audience will go into the token as "aud" claim.
	audience := getAudience(query)

	// Generate token once here because we are using the same token for every
	// kite we return and generating many tokens is really slow.
	token, err := generateToken(audience, r.Username,
		k.Kite.Kite().Username, k.privateKey)
	if err != nil {
		return nil, err
	}

	// Get kites from the storage
	kites, err := k.storage.Get(query)
	if err != nil {
		return nil, err
	}

	// Attach tokens to kites
	kites.Attach(token)

	return &protocol.GetKitesResult{
		Kites: kites,
	}, nil
}

func (k *Kontrol) handleGetToken(r *kite.Request) (interface{}, error) {
	var query *protocol.KontrolQuery
	err := r.Args.One().Unmarshal(&query)
	if err != nil {
		return nil, errors.New("Invalid query")
	}

	// check if it's exist
	kites, err := k.storage.Get(query)
	if err != nil {
		return nil, err
	}

	if len(kites) > 1 {
		return nil, errors.New("query matches more than one kite")
	}

	audience := getAudience(query)

	return generateToken(audience, r.Username, k.Kite.Kite().Username, k.privateKey)
}

func (k *Kontrol) handleMachine(r *kite.Request) (interface{}, error) {
	if k.MachineAuthenticate != nil {
		if err := k.MachineAuthenticate(r); err != nil {
			return nil, errors.New("cannot authenticate user")
		}
	}

	username := r.Args.One().MustString() // username should be send as an argument
	return k.registerUser(username)
}
<commit_msg>kontrol:  don't spam the log<commit_after>package kontrol

import (
	"errors"
	"fmt"
	"time"

	"github.com/koding/kite"
	"github.com/koding/kite/dnode"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/koding/kite/protocol"
)

func (k *Kontrol) handleRegister(r *kite.Request) (interface{}, error) {
	k.log.Info("Register request from: %s", r.Client.Kite)

	if r.Args.One().MustMap()["url"].MustString() == "" {
		return nil, errors.New("invalid url")
	}

	var args struct {
		URL string `json:"url"`
	}
	r.Args.One().MustUnmarshal(&args)
	if args.URL == "" {
		return nil, errors.New("empty url")
	}

	// Only accept requests with kiteKey because we need this info
	// for generating tokens for this kite.
	if r.Auth.Type != "kiteKey" {
		return nil, fmt.Errorf("Unexpected authentication type: %s", r.Auth.Type)
	}

	kiteURL := args.URL
	remote := r.Client

	if err := validateKiteKey(&remote.Kite); err != nil {
		return nil, err
	}

	value := &kontrolprotocol.RegisterValue{
		URL: kiteURL,
	}

	// Register first by adding the value to the storage. Return if there is
	// any error.
	if err := k.storage.Upsert(&remote.Kite, value); err != nil {
		k.log.Error("storage add '%s' error: %s", remote.Kite, err)
		return nil, errors.New("internal error - register")
	}

	// we create a new ticker which is going to update the key periodically in
	// the storage so it's always up to date.
	updater := time.NewTicker(UpdateInterval)
	updaterFunc := func() {
		for _ = range updater.C {
			k.log.Debug("Kite is active, updating the value %s", remote.Kite)
			err := k.storage.Update(&remote.Kite, value)
			if err != nil {
				k.log.Error("storage update '%s' error: %s", remote.Kite, err)
			}
		}
	}

	go updaterFunc()

	// lostFunc is called when we don't get any heartbeat or we lost
	// connection. In any case, it will remove the key from the storage
	lostFunc := func(reason string) func() {
		return func() {
			k.log.Info("Kite %s. Deleting from storage %s", reason, remote.Kite)
			// stop the updater so it doesn't update it in the background
			updater.Stop()

			// delete the key immediately
			k.storage.Delete(&remote.Kite)
		}
	}

	// we are now creating a timer that is going to call the lostFunc, which
	// deletes the key from the storage and also stops the background updater
	deleteTimer := time.AfterFunc(HeartbeatInterval+HeartbeatDelay,
		lostFunc("didn't get heartbeat"))

	heartbeatArgs := []interface{}{
		HeartbeatInterval / time.Second,
		dnode.Callback(func(args *dnode.Partial) {
			// try to reset the timer every time the remote kite calls this
			// callback(sends us heartbeat). Because the timer get reset, the
			// deleteFunc above will never be fired, so the value get always
			// updated with the updater in the background according to the
			// write interval. If the kite doesn't send any heartbeat, the
			// deleteFunc is being called, which removes the key from the
			// storage.
			k.log.Debug("Kite send us an heartbeat. %s", remote.Kite)
			k.clientLocks.Get(remote.Kite.ID).Lock()
			deleteTimer.Reset(HeartbeatInterval + HeartbeatDelay)
			k.clientLocks.Get(remote.Kite.ID).Unlock()
		}),
	}

	// let's ping first to see if they are alive
	_, err := remote.TellWithTimeout("kite.ping", 4*time.Second)
	if err != nil {
		return nil, err
	}

	// now trigger the remote kite so it sends us periodically an heartbeat
	remote.GoWithTimeout("kite.heartbeat", 4*time.Second, heartbeatArgs...)

	k.log.Info("Kite registered: %s", remote.Kite)

	remote.OnDisconnect(lostFunc("disconnected")) // also call it when we disconnect

	// send response back to the kite, also identify him with the new name
	return &protocol.RegisterResult{URL: args.URL}, nil
}

func (k *Kontrol) handleGetKites(r *kite.Request) (interface{}, error) {
	// This type is here until inversion branch is merged.
	// Reason: We can't use the same struct for marshaling and unmarshaling.
	// TODO use the struct in protocol
	type GetKitesArgs struct {
		Query *protocol.KontrolQuery `json:"query"`
	}

	var args GetKitesArgs
	r.Args.One().MustUnmarshal(&args)

	query := args.Query

	// audience will go into the token as "aud" claim.
	audience := getAudience(query)

	// Generate token once here because we are using the same token for every
	// kite we return and generating many tokens is really slow.
	token, err := generateToken(audience, r.Username,
		k.Kite.Kite().Username, k.privateKey)
	if err != nil {
		return nil, err
	}

	// Get kites from the storage
	kites, err := k.storage.Get(query)
	if err != nil {
		return nil, err
	}

	// Attach tokens to kites
	kites.Attach(token)

	return &protocol.GetKitesResult{
		Kites: kites,
	}, nil
}

func (k *Kontrol) handleGetToken(r *kite.Request) (interface{}, error) {
	var query *protocol.KontrolQuery
	err := r.Args.One().Unmarshal(&query)
	if err != nil {
		return nil, errors.New("Invalid query")
	}

	// check if it's exist
	kites, err := k.storage.Get(query)
	if err != nil {
		return nil, err
	}

	if len(kites) > 1 {
		return nil, errors.New("query matches more than one kite")
	}

	audience := getAudience(query)

	return generateToken(audience, r.Username, k.Kite.Kite().Username, k.privateKey)
}

func (k *Kontrol) handleMachine(r *kite.Request) (interface{}, error) {
	if k.MachineAuthenticate != nil {
		if err := k.MachineAuthenticate(r); err != nil {
			return nil, errors.New("cannot authenticate user")
		}
	}

	username := r.Args.One().MustString() // username should be send as an argument
	return k.registerUser(username)
}
<|endoftext|>


<commit_before>package diff

import (
	"context"
	"image"
	"image/color"
	"image/draw"
	"math"
	"unsafe"

	"go.skia.org/infra/go/metrics2"
	"go.skia.org/infra/go/paramtools"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/golden/go/types"
)

var (
	pixelMatchColor = color.Transparent

	// Orange gradient.
	//
	// These are non-premultiplied RGBA values.
	pixelDiffColor = [][]uint8{
		{0xfd, 0xd0, 0xa2, 0xff},
		{0xfd, 0xae, 0x6b, 0xff},
		{0xfd, 0x8d, 0x3c, 0xff},
		{0xf1, 0x69, 0x13, 0xff},
		{0xd9, 0x48, 0x01, 0xff},
		{0xa6, 0x36, 0x03, 0xff},
		{0x7f, 0x27, 0x04, 0xff},
	}

	// Blue gradient.
	//
	// These are non-premultiplied RGBA values.
	pixelAlphaDiffColor = [][]uint8{
		{0xc6, 0xdb, 0xef, 0xff},
		{0x9e, 0xca, 0xe1, 0xff},
		{0x6b, 0xae, 0xd6, 0xff},
		{0x42, 0x92, 0xc6, 0xff},
		{0x21, 0x71, 0xb5, 0xff},
		{0x08, 0x51, 0x9c, 0xff},
		{0x08, 0x30, 0x6b, 0xff},
	}
)

// Returns the offset into the color slices (pixelDiffColor,
// or pixelAlphaDiffColor) based on the delta passed in.
//
// The number passed in is the difference between two colors,
// on a scale from 1 to 1024.
func deltaOffset(n int) int {
	ret := int(math.Ceil(math.Log(float64(n))/math.Log(3) + 0.5))
	if ret < 1 || ret > 7 {
		sklog.Fatalf("Input: %d", n)
	}
	return ret - 1
}

// DiffMetrics contains the diff information between two images.
type DiffMetrics struct {
	// NumDiffPixels is the absolute number of pixels that are different.
	NumDiffPixels int

	// CombinedMetric is a value in [0, 10] that represents how large the diff is between two
	// images. It is based off the MaxRGBADiffs and PixelDiffPercent.
	CombinedMetric float32

	// PixelDiffPercent is the percentage of pixels that are different. The denominator here is
	// (maximum width of the two images) * (maximum height of the two images).
	PixelDiffPercent float32

	// MaxRGBADiffs contains the maximum difference of each channel.
	MaxRGBADiffs [4]int

	// DimDiffer is true if the dimensions between the two images are different.
	DimDiffer bool
}

// ComputeDiffMetrics computes and returns the diff metrics between two given images.
func ComputeDiffMetrics(leftImg *image.NRGBA, rightImg *image.NRGBA) *DiffMetrics {
	defer metrics2.FuncTimer().Stop()
	ret, _ := PixelDiff(leftImg, rightImg)
	ret.CombinedMetric = CombinedDiffMetric(ret.MaxRGBADiffs, ret.PixelDiffPercent)
	return ret
}

// CombinedDiffMetric returns a value in [0, 10] that represents how large
// the diff is between two images. Implements the MetricFn signature.
func CombinedDiffMetric(channelDiffs [4]int, pixelDiffPercent float32) float32 {
	// Turn maxRGBA into a percent by taking the root mean square difference from
	// [0, 0, 0, 0].
	sum := 0.0
	for _, c := range channelDiffs {
		sum += float64(c) * float64(c)
	}
	normalizedRGBA := math.Sqrt(sum/float64(len(channelDiffs))) / 255.0
	// We take the sqrt of (pixelDiffPercent * normalizedRGBA) to straighten out
	// the curve, i.e. think about what a plot of x^2 would look like in the
	// range [0, 1].
	return float32(math.Sqrt(float64(pixelDiffPercent) * normalizedRGBA))
}

// getPixelDiffPercent returns the percentage of pixels that differ, as a float between 0 and 100
// (inclusive).
func getPixelDiffPercent(numDiffPixels, totalPixels int) float32 {
	return (float32(numDiffPixels) * 100) / float32(totalPixels)
}

func uint8ToColor(c []uint8) color.Color {
	return color.NRGBA{R: c[0], G: c[1], B: c[2], A: c[3]}
}

// diffColors compares two color values and returns a color to indicate the
// difference. If the colors differ it updates maxRGBADiffs to contain the
// maximum difference over multiple calls.
// If the RGB channels are identical, but the alpha differ then
// pixelAlphaDiffColor is returned. This allows to distinguish pixels that
// render the same, but have different alpha values.
func diffColors(color1, color2 color.Color, maxRGBADiffs *[4]int) color.Color {
	// We compare them before normalizing to non-premultiplied. If one of the
	// original images did not have an alpha channel (but the other did) the
	// equality will be false.
	if color1 == color2 {
		return pixelMatchColor
	}

	// Treat all colors as non-premultiplied.
	c1 := color.NRGBAModel.Convert(color1).(color.NRGBA)
	c2 := color.NRGBAModel.Convert(color2).(color.NRGBA)

	rDiff := util.AbsInt(int(c1.R) - int(c2.R))
	gDiff := util.AbsInt(int(c1.G) - int(c2.G))
	bDiff := util.AbsInt(int(c1.B) - int(c2.B))
	aDiff := util.AbsInt(int(c1.A) - int(c2.A))
	maxRGBADiffs[0] = util.MaxInt(maxRGBADiffs[0], rDiff)
	maxRGBADiffs[1] = util.MaxInt(maxRGBADiffs[1], gDiff)
	maxRGBADiffs[2] = util.MaxInt(maxRGBADiffs[2], bDiff)
	maxRGBADiffs[3] = util.MaxInt(maxRGBADiffs[3], aDiff)

	// If the color channels differ we mark with the diff color.
	if (c1.R != c2.R) || (c1.G != c2.G) || (c1.B != c2.B) {
		// We use the Manhattan metric for color difference.
		return uint8ToColor(pixelDiffColor[deltaOffset(rDiff+gDiff+bDiff+aDiff)])
	}

	// If only the alpha channel differs we mark it with the alpha diff color.
	//
	if aDiff > 0 {
		return uint8ToColor(pixelAlphaDiffColor[deltaOffset(aDiff)])
	}

	return pixelMatchColor
}

// recode creates a new NRGBA image from the given image.
func recode(img image.Image) *image.NRGBA {
	ret := image.NewNRGBA(img.Bounds())
	draw.Draw(ret, img.Bounds(), img, image.Pt(0, 0), draw.Src)
	return ret
}

// GetNRGBA converts the image to an *image.NRGBA in an efficient manner.
func GetNRGBA(img image.Image) *image.NRGBA {
	switch t := img.(type) {
	case *image.NRGBA:
		return t
	case *image.RGBA:
		for i := 0; i < len(t.Pix); i += 4 {
			if t.Pix[i+3] != 0xff {
				sklog.Warning("Unexpected premultiplied image!")
				return recode(img)
			}
		}
		// If every alpha is 0xff then t.Pix is already in NRGBA format, simply
		// share Pix between the RGBA and NRGBA structs.
		return &image.NRGBA{
			Pix:    t.Pix,
			Stride: t.Stride,
			Rect:   t.Rect,
		}
	default:
		// TODO(mtklein): does it make sense we're getting other types, or a DM bug?
		return recode(img)
	}
}

// PixelDiff is a utility function that calculates the DiffMetrics and the image of the
// difference for the provided images.
func PixelDiff(img1, img2 image.Image) (*DiffMetrics, *image.NRGBA) {
	defer metrics2.FuncTimer().Stop()
	img1Bounds := img1.Bounds()
	img2Bounds := img2.Bounds()

	// Get the bounds we want to compare.
	cmpWidth := util.MinInt(img1Bounds.Dx(), img2Bounds.Dx())
	cmpHeight := util.MinInt(img1Bounds.Dy(), img2Bounds.Dy())

	// Get the bounds of the resulting image. If they dimensions match they
	// will be identical to the result bounds. Fill the image with black pixels.
	resultWidth := util.MaxInt(img1Bounds.Dx(), img2Bounds.Dx())
	resultHeight := util.MaxInt(img1Bounds.Dy(), img2Bounds.Dy())
	resultImg := image.NewNRGBA(image.Rect(0, 0, resultWidth, resultHeight))
	totalPixels := resultWidth * resultHeight

	// Loop through all points and compare. We start assuming all pixels are
	// wrong. This takes care of the case where the images have different sizes
	// and there is an area not inspected by the loop.
	numDiffPixels := totalPixels
	maxRGBADiffs := [4]int{0, 0, 0, 0}

	// Pix is a []uint8 rotating through R, G, B, A, R, G, B, A, ...
	p1 := GetNRGBA(img1).Pix
	p2 := GetNRGBA(img2).Pix
	// Compare the bounds, if they are the same then use this fast path.
	// We cast to uint64 to compare 2 pixels at a time, so we also require
	// an even number of pixels here.  If that's a big deal, we can easily
	// fix that up, handling the straggler pixel separately at the end.
	if img1Bounds.Eq(img2Bounds) && len(p1)%8 == 0 {
		numDiffPixels = 0
		// Note the += 8.  We're checking two pixels at a time here.
		for i := 0; i < len(p1); i += 8 {
			// Most pixels we compare will be the same, so from here to
			// the 'continue' is the hot path in all this code.
			rgba_2x := (*uint64)(unsafe.Pointer(&p1[i]))
			RGBA_2x := (*uint64)(unsafe.Pointer(&p2[i]))
			if *rgba_2x == *RGBA_2x {
				continue
			}

			// When off == 0, we check the first pixel of the pair; when 4, the second.
			for off := 0; off <= 4; off += 4 {
				r, g, b, a := p1[off+i+0], p1[off+i+1], p1[off+i+2], p1[off+i+3]
				R, G, B, A := p2[off+i+0], p2[off+i+1], p2[off+i+2], p2[off+i+3]
				if r != R || g != G || b != B || a != A {
					numDiffPixels++
					dr := util.AbsInt(int(r) - int(R))
					dg := util.AbsInt(int(g) - int(G))
					db := util.AbsInt(int(b) - int(B))
					da := util.AbsInt(int(a) - int(A))
					maxRGBADiffs[0] = util.MaxInt(dr, maxRGBADiffs[0])
					maxRGBADiffs[1] = util.MaxInt(dg, maxRGBADiffs[1])
					maxRGBADiffs[2] = util.MaxInt(db, maxRGBADiffs[2])
					maxRGBADiffs[3] = util.MaxInt(da, maxRGBADiffs[3])
					if dr+dg+db > 0 {
						copy(resultImg.Pix[off+i:], pixelDiffColor[deltaOffset(dr+dg+db+da)])
					} else {
						copy(resultImg.Pix[off+i:], pixelAlphaDiffColor[deltaOffset(da)])
					}
				}
			}
		}
	} else {
		// Set pixels outside of the comparison area with the maximum diff color.
		maxDiffColor := uint8ToColor(pixelDiffColor[deltaOffset(1024)])
		for x := 0; x < resultWidth; x++ {
			for y := 0; y < resultHeight; y++ {
				if x < cmpWidth && y < cmpHeight {
					color1 := img1.At(x, y)
					color2 := img2.At(x, y)

					dc := diffColors(color1, color2, &maxRGBADiffs)
					if dc == pixelMatchColor {
						numDiffPixels--
					}
					resultImg.Set(x, y, dc)
				} else {
					resultImg.Set(x, y, maxDiffColor)
				}
			}
		}
	}

	return &DiffMetrics{
		NumDiffPixels:    numDiffPixels,
		PixelDiffPercent: getPixelDiffPercent(numDiffPixels, totalPixels),
		MaxRGBADiffs:     maxRGBADiffs,
		DimDiffer:        (cmpWidth != resultWidth) || (cmpHeight != resultHeight)}, resultImg
}

type Calculator interface {
	// CalculateDiffs recomputes all diffs for the current grouping, including any digests provided.
	CalculateDiffs(ctx context.Context, grouping paramtools.Params, additional []types.Digest) error
}
<commit_msg>[gold] Add logging to diff<commit_after>package diff

import (
	"context"
	"image"
	"image/color"
	"image/draw"
	"math"
	"unsafe"

	"go.skia.org/infra/go/metrics2"
	"go.skia.org/infra/go/paramtools"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/golden/go/types"
)

var (
	pixelMatchColor = color.Transparent

	// Orange gradient.
	//
	// These are non-premultiplied RGBA values.
	pixelDiffColor = [][]uint8{
		{0xfd, 0xd0, 0xa2, 0xff},
		{0xfd, 0xae, 0x6b, 0xff},
		{0xfd, 0x8d, 0x3c, 0xff},
		{0xf1, 0x69, 0x13, 0xff},
		{0xd9, 0x48, 0x01, 0xff},
		{0xa6, 0x36, 0x03, 0xff},
		{0x7f, 0x27, 0x04, 0xff},
	}

	// Blue gradient.
	//
	// These are non-premultiplied RGBA values.
	pixelAlphaDiffColor = [][]uint8{
		{0xc6, 0xdb, 0xef, 0xff},
		{0x9e, 0xca, 0xe1, 0xff},
		{0x6b, 0xae, 0xd6, 0xff},
		{0x42, 0x92, 0xc6, 0xff},
		{0x21, 0x71, 0xb5, 0xff},
		{0x08, 0x51, 0x9c, 0xff},
		{0x08, 0x30, 0x6b, 0xff},
	}
)

// Returns the offset into the color slices (pixelDiffColor,
// or pixelAlphaDiffColor) based on the delta passed in.
//
// The number passed in is the difference between two colors,
// on a scale from 1 to 1024.
func deltaOffset(n int) int {
	ret := int(math.Ceil(math.Log(float64(n))/math.Log(3) + 0.5))
	if ret < 1 || ret > 7 {
		sklog.Fatalf("Input: %d", n)
	}
	return ret - 1
}

// DiffMetrics contains the diff information between two images.
type DiffMetrics struct {
	// NumDiffPixels is the absolute number of pixels that are different.
	NumDiffPixels int

	// CombinedMetric is a value in [0, 10] that represents how large the diff is between two
	// images. It is based off the MaxRGBADiffs and PixelDiffPercent.
	CombinedMetric float32

	// PixelDiffPercent is the percentage of pixels that are different. The denominator here is
	// (maximum width of the two images) * (maximum height of the two images).
	PixelDiffPercent float32

	// MaxRGBADiffs contains the maximum difference of each channel.
	MaxRGBADiffs [4]int

	// DimDiffer is true if the dimensions between the two images are different.
	DimDiffer bool
}

// ComputeDiffMetrics computes and returns the diff metrics between two given images.
func ComputeDiffMetrics(leftImg *image.NRGBA, rightImg *image.NRGBA) *DiffMetrics {
	defer metrics2.FuncTimer().Stop()
	ret, _ := PixelDiff(leftImg, rightImg)
	ret.CombinedMetric = CombinedDiffMetric(ret.MaxRGBADiffs, ret.PixelDiffPercent)
	return ret
}

// CombinedDiffMetric returns a value in [0, 10] that represents how large
// the diff is between two images. Implements the MetricFn signature.
func CombinedDiffMetric(channelDiffs [4]int, pixelDiffPercent float32) float32 {
	// Turn maxRGBA into a percent by taking the root mean square difference from
	// [0, 0, 0, 0].
	sum := 0.0
	for _, c := range channelDiffs {
		sum += float64(c) * float64(c)
	}
	normalizedRGBA := math.Sqrt(sum/float64(len(channelDiffs))) / 255.0
	// We take the sqrt of (pixelDiffPercent * normalizedRGBA) to straighten out
	// the curve, i.e. think about what a plot of x^2 would look like in the
	// range [0, 1].
	return float32(math.Sqrt(float64(pixelDiffPercent) * normalizedRGBA))
}

// getPixelDiffPercent returns the percentage of pixels that differ, as a float between 0 and 100
// (inclusive).
func getPixelDiffPercent(numDiffPixels, totalPixels int) float32 {
	return (float32(numDiffPixels) * 100) / float32(totalPixels)
}

func uint8ToColor(c []uint8) color.Color {
	return color.NRGBA{R: c[0], G: c[1], B: c[2], A: c[3]}
}

// diffColors compares two color values and returns a color to indicate the
// difference. If the colors differ it updates maxRGBADiffs to contain the
// maximum difference over multiple calls.
// If the RGB channels are identical, but the alpha differ then
// pixelAlphaDiffColor is returned. This allows to distinguish pixels that
// render the same, but have different alpha values.
func diffColors(color1, color2 color.Color, maxRGBADiffs *[4]int) color.Color {
	// We compare them before normalizing to non-premultiplied. If one of the
	// original images did not have an alpha channel (but the other did) the
	// equality will be false.
	if color1 == color2 {
		return pixelMatchColor
	}

	// Treat all colors as non-premultiplied.
	c1 := color.NRGBAModel.Convert(color1).(color.NRGBA)
	c2 := color.NRGBAModel.Convert(color2).(color.NRGBA)

	rDiff := util.AbsInt(int(c1.R) - int(c2.R))
	gDiff := util.AbsInt(int(c1.G) - int(c2.G))
	bDiff := util.AbsInt(int(c1.B) - int(c2.B))
	aDiff := util.AbsInt(int(c1.A) - int(c2.A))
	maxRGBADiffs[0] = util.MaxInt(maxRGBADiffs[0], rDiff)
	maxRGBADiffs[1] = util.MaxInt(maxRGBADiffs[1], gDiff)
	maxRGBADiffs[2] = util.MaxInt(maxRGBADiffs[2], bDiff)
	maxRGBADiffs[3] = util.MaxInt(maxRGBADiffs[3], aDiff)

	// If the color channels differ we mark with the diff color.
	if (c1.R != c2.R) || (c1.G != c2.G) || (c1.B != c2.B) {
		// We use the Manhattan metric for color difference.
		return uint8ToColor(pixelDiffColor[deltaOffset(rDiff+gDiff+bDiff+aDiff)])
	}

	// If only the alpha channel differs we mark it with the alpha diff color.
	//
	if aDiff > 0 {
		return uint8ToColor(pixelAlphaDiffColor[deltaOffset(aDiff)])
	}

	return pixelMatchColor
}

// recode creates a new NRGBA image from the given image.
func recode(img image.Image) *image.NRGBA {
	ret := image.NewNRGBA(img.Bounds())
	draw.Draw(ret, img.Bounds(), img, image.Pt(0, 0), draw.Src)
	return ret
}

// GetNRGBA converts the image to an *image.NRGBA in an efficient manner.
func GetNRGBA(img image.Image) *image.NRGBA {
	switch t := img.(type) {
	case *image.NRGBA:
		return t
	case *image.RGBA:
		for i := 0; i < len(t.Pix); i += 4 {
			if t.Pix[i+3] != 0xff {
				sklog.Warning("Unexpected premultiplied image!")
				return recode(img)
			}
		}
		// If every alpha is 0xff then t.Pix is already in NRGBA format, simply
		// share Pix between the RGBA and NRGBA structs.
		return &image.NRGBA{
			Pix:    t.Pix,
			Stride: t.Stride,
			Rect:   t.Rect,
		}
	default:
		// TODO(kjlubick): does it make sense we're getting other types, or a DM bug?
		sklog.Errorf("Unexpected image type %T", img)
		return recode(img)
	}
}

// PixelDiff is a utility function that calculates the DiffMetrics and the image of the
// difference for the provided images.
func PixelDiff(img1, img2 image.Image) (*DiffMetrics, *image.NRGBA) {
	defer metrics2.FuncTimer().Stop()
	img1Bounds := img1.Bounds()
	img2Bounds := img2.Bounds()

	// Get the bounds we want to compare.
	cmpWidth := util.MinInt(img1Bounds.Dx(), img2Bounds.Dx())
	cmpHeight := util.MinInt(img1Bounds.Dy(), img2Bounds.Dy())

	// Get the bounds of the resulting image. If they dimensions match they
	// will be identical to the result bounds. Fill the image with black pixels.
	resultWidth := util.MaxInt(img1Bounds.Dx(), img2Bounds.Dx())
	resultHeight := util.MaxInt(img1Bounds.Dy(), img2Bounds.Dy())
	resultImg := image.NewNRGBA(image.Rect(0, 0, resultWidth, resultHeight))
	totalPixels := resultWidth * resultHeight

	// Loop through all points and compare. We start assuming all pixels are
	// wrong. This takes care of the case where the images have different sizes
	// and there is an area not inspected by the loop.
	numDiffPixels := totalPixels
	maxRGBADiffs := [4]int{0, 0, 0, 0}

	// Pix is a []uint8 rotating through R, G, B, A, R, G, B, A, ...
	p1 := GetNRGBA(img1).Pix
	p2 := GetNRGBA(img2).Pix
	// Compare the bounds, if they are the same then use this fast path.
	// We cast to uint64 to compare 2 pixels at a time, so we also require
	// an even number of pixels here.  If that's a big deal, we can easily
	// fix that up, handling the straggler pixel separately at the end.
	if img1Bounds.Eq(img2Bounds) && len(p1)%8 == 0 {
		numDiffPixels = 0
		// Note the += 8.  We're checking two pixels at a time here.
		for i := 0; i < len(p1); i += 8 {
			// Most pixels we compare will be the same, so from here to
			// the 'continue' is the hot path in all this code.
			rgba_2x := (*uint64)(unsafe.Pointer(&p1[i]))
			RGBA_2x := (*uint64)(unsafe.Pointer(&p2[i]))
			if *rgba_2x == *RGBA_2x {
				continue
			}

			// When off == 0, we check the first pixel of the pair; when 4, the second.
			for off := 0; off <= 4; off += 4 {
				r, g, b, a := p1[off+i+0], p1[off+i+1], p1[off+i+2], p1[off+i+3]
				R, G, B, A := p2[off+i+0], p2[off+i+1], p2[off+i+2], p2[off+i+3]
				if r != R || g != G || b != B || a != A {
					numDiffPixels++
					dr := util.AbsInt(int(r) - int(R))
					dg := util.AbsInt(int(g) - int(G))
					db := util.AbsInt(int(b) - int(B))
					da := util.AbsInt(int(a) - int(A))
					maxRGBADiffs[0] = util.MaxInt(dr, maxRGBADiffs[0])
					maxRGBADiffs[1] = util.MaxInt(dg, maxRGBADiffs[1])
					maxRGBADiffs[2] = util.MaxInt(db, maxRGBADiffs[2])
					maxRGBADiffs[3] = util.MaxInt(da, maxRGBADiffs[3])
					if dr+dg+db > 0 {
						copy(resultImg.Pix[off+i:], pixelDiffColor[deltaOffset(dr+dg+db+da)])
					} else {
						copy(resultImg.Pix[off+i:], pixelAlphaDiffColor[deltaOffset(da)])
					}
				}
			}
		}
	} else {
		// Set pixels outside of the comparison area with the maximum diff color.
		maxDiffColor := uint8ToColor(pixelDiffColor[deltaOffset(1024)])
		for x := 0; x < resultWidth; x++ {
			for y := 0; y < resultHeight; y++ {
				if x < cmpWidth && y < cmpHeight {
					color1 := img1.At(x, y)
					color2 := img2.At(x, y)

					dc := diffColors(color1, color2, &maxRGBADiffs)
					if dc == pixelMatchColor {
						numDiffPixels--
					}
					resultImg.Set(x, y, dc)
				} else {
					resultImg.Set(x, y, maxDiffColor)
				}
			}
		}
	}

	return &DiffMetrics{
		NumDiffPixels:    numDiffPixels,
		PixelDiffPercent: getPixelDiffPercent(numDiffPixels, totalPixels),
		MaxRGBADiffs:     maxRGBADiffs,
		DimDiffer:        (cmpWidth != resultWidth) || (cmpHeight != resultHeight)}, resultImg
}

type Calculator interface {
	// CalculateDiffs recomputes all diffs for the current grouping, including any digests provided.
	CalculateDiffs(ctx context.Context, grouping paramtools.Params, additional []types.Digest) error
}
<|endoftext|>


<commit_before>package gqt_test

import (
	"github.com/cloudfoundry-incubator/guardian/gqt/runner"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Garden API", func() {
	var (
		client *runner.RunningGarden
	)

	BeforeEach(func() {
		client = startGarden()
	})

	AfterEach(func() {
		client.DestroyAndStop()
	})

	Describe("Capacity", func() {
		It("returns json representing capacity", func() {
			result, err := client.Capacity()
			Expect(err).NotTo(HaveOccurred())

			Expect(result.MemoryInBytes).To(BeNumerically(">", 0))
			Expect(result.DiskInBytes).To(BeNumerically(">", 0))
			Expect(result.MaxContainers).To(BeNumerically(">", 0))
		})
	})
})
<commit_msg>Add capacity test<commit_after>package gqt_test

import (
	"github.com/cloudfoundry-incubator/guardian/gqt/runner"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Garden API", func() {
	var (
		args   []string
		client *runner.RunningGarden
	)

	BeforeEach(func() {
		args = []string{}
	})

	JustBeforeEach(func() {
		client = startGarden(args...)
	})

	AfterEach(func() {
		client.DestroyAndStop()
	})

	Describe("Capacity", func() {
		It("returns json representing capacity", func() {
			result, err := client.Capacity()
			Expect(err).NotTo(HaveOccurred())

			Expect(result.MemoryInBytes).To(BeNumerically(">", 0))
			Expect(result.DiskInBytes).To(BeNumerically(">", 0))
			Expect(result.MaxContainers).To(BeNumerically(">", 0))
		})

		Context("when the network pool is /24", func() {
			BeforeEach(func() {
				args = append(args, "--networkPool", "10.254.0.0/24")
			})

			It("returns the capacity of the subnet pool", func() {
				capacity, err := client.Capacity()
				Expect(err).ToNot(HaveOccurred())
				Expect(capacity.MaxContainers).To(Equal(uint64(64)))
			})
		})
	})
})
<|endoftext|>


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

/*  Filename:    lexer.go
 *  Author:      Bryan Matsuo <bryan.matsuo [at] gmail.com>
 *  Created:     2012-11-02 22:10:59.782356 -0700 PDT
 *  Description: Main source file in go-lexer
 */

/*
Package lexer provides a simple scanner and types for handrolling lexers.
The implementation is based on Rob Pike's talk.

	http://www.youtube.com/watch?v=HxaD_trXwRE

Two APIs

The Lexer type has two APIs, one is used byte StateFn types.  The other is
called by the parser. These APIs are called the scanner and the parser APIs
here.

The parser API

The only function the parser calls on the lexer is Next to retreive the next
token from the input stream.  Eventually an item with type ItemEOF is returned
at which point there are no more tokens in the stream.

The scanner API

Common lexer methods used in a scanner are fhe Accept[Run][Range] family of
methods.  Accept* methods take a set and advance the lexer if incoming runes
are in the set. The AcceptRun subfamily advance the lexer as far as possible.

For scanning known sequences of bytes (e.g. keywords) the AcceptString method
avoids a lot of branching that would be incurred using methods that match
character classes.
*/
package lexer

import (
	"container/list"
	"fmt"
	"math"
	"strings"
	"unicode"
	"unicode/utf8"
)

const EOF rune = 0x04

// IsEOF returns true if n is zero.
func IsEOF(c rune, n int) bool {
	return n == 0
}

// IsInvalid returns true if c is utf8.RuneInvalid and n is 1.
func IsInvalid(c rune, n int) bool {
	return c == utf8.RuneError && n == 1
}

// A state function that scans runes from the lexer's input and emits items.
// The state functions are responsible for emitting ItemEOF.
type StateFn func(*Lexer) StateFn

// A type for building lexers.
type Lexer struct {
	input string     // string being scanned
	start int        // start position for the current lexeme
	pos   int        // current position
	width int        // length of the last rune read
	last  rune       // the last rune read
	state StateFn    // the current state
	items *list.List // Buffer of lexed items
}

// Create a new lexer. Must be given a non-nil state.
func New(start StateFn, input string) *Lexer {
	if start == nil {
		panic("nil start state")
	}
	return &Lexer{
		state: start,
		input: input,
		items: list.New(),
	}
}

// The starting position of the current item.
func (l *Lexer) Start() int {
	return l.start
}

// The position following the last read rune.
func (l *Lexer) Pos() int {
	return l.pos
}

// The contents of the item currently being lexed.
func (l *Lexer) Current() string {
	return l.input[l.start:l.pos]
}

// The last rune read from the input stream.
func (l *Lexer) Last() (r rune, width int) {
	return l.last, l.width
}

// Add one rune of the input stream to the current lexeme. Invalid UTF-8
// codepoints cause the current call and all subsequent calls to return
// (utf8.RuneError, 1).  If l is at the end of its input stream the returned
// size is zero.
func (l *Lexer) Advance() (rune, int) {
	if l.pos >= len(l.input) {
		l.width = 0
		return EOF, l.width
	}
	l.last, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	if l.last == utf8.RuneError && l.width == 1 {
		return l.last, l.width
	}
	l.pos += l.width
	return l.last, l.width
}

// Remove the last rune from the current lexeme and place back in the stream.
func (l *Lexer) Backup() {
	l.pos -= l.width
}

// Returns the next rune in the input stream without adding it to the current lexeme.
func (l *Lexer) Peek() (c rune, width int) {
	defer func() { l.Backup() }()
	return l.Advance()
}

// Throw away the current lexeme (do not call Emit).
func (l *Lexer) Ignore() {
	l.start = l.pos
}

func (l *Lexer) Accept(valid string) (ok bool) {
	r, _ := l.Advance()
	ok = strings.IndexRune(valid, r) >= 0
	if !ok {
		l.Backup()
	}
	return
}

// AcceptRange advances l's position if the current rune is in tab.
func (l *Lexer) AcceptRange(tab *unicode.RangeTable) (ok bool) {
	r, _ := l.Advance()
	ok = unicode.Is(tab, r)
	if !ok {
		l.Backup()
	}
	return
}

// AcceptRun advances l's position as long as the current rune is in valid.
func (l *Lexer) AcceptRun(valid string) (n int) {
	for l.Accept(valid) {
		n++
	}
	return
}

// AcceptRunRange advances l's possition as long as the current rune is in tab.
func (l *Lexer) AcceptRunRange(tab *unicode.RangeTable) (n int) {
	for l.AcceptRange(tab) {
		n++
	}
	return
}

// AcceptString advances the lexer len(s) bytes if the next len(s) bytes equal
// s. AcceptString returns true if l advanced.
func (l *Lexer) AcceptString(s string) (ok bool) {
	if strings.HasPrefix(l.input[l.pos:], s) {
		l.pos += len(s)
		return true
	}
	return false
}

// Emit an error from the Lexer.
func (l *Lexer) Errorf(format string, args ...interface{}) StateFn {
	l.enqueue(&Item{
		ItemError,
		l.start,
		fmt.Sprintf(format, args...),
	})
	return nil
}

// Emit the current value as an Item with the specified type.
func (l *Lexer) Emit(t ItemType) {
	l.enqueue(&Item{
		t,
		l.start,
		l.input[l.start:l.pos],
	})
	l.start = l.pos
}

// The method by which items are extracted from the input.
// Returns nil if the lexer has entered a nil state.
func (l *Lexer) Next() (i *Item) {
	for {
		if head := l.dequeue(); head != nil {
			return head
		}
		if l.state == nil {
			return &Item{ItemEOF, l.start, ""}
		}
		l.state = l.state(l)
	}
	panic("unreachable")
}

func (l *Lexer) enqueue(i *Item) {
	l.items.PushBack(i)
}

func (l *Lexer) dequeue() *Item {
	head := l.items.Front()
	if head == nil {
		return nil
	}
	return l.items.Remove(head).(*Item)
}

// A type for all the types of items in the language being lexed.
type ItemType uint16

// Special item types.
const (
	ItemEOF ItemType = math.MaxUint16 - iota
	ItemError
)

// An individual scanned item (a lexeme).
type Item struct {
	Type  ItemType
	Pos   int
	Value string
}

func (i *Item) Err() error {
	if i.Type == ItemError {
		return (*Error)(i)
	}
	return nil
}

func (i *Item) String() string {
	switch i.Type {
	case ItemError:
		return i.Value
	case ItemEOF:
		return "EOF"
	}
	if len(i.Value) > 10 {
		return fmt.Sprintf("%.10q...", i.Value)
	}
	return i.Value
}

type Error Item

func (err *Error) Error() string {
	return (*Item)(err).String()
}
<commit_msg>godoc<commit_after>// Copyright 2012, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*  Filename:    lexer.go
 *  Author:      Bryan Matsuo <bryan.matsuo [at] gmail.com>
 *  Created:     2012-11-02 22:10:59.782356 -0700 PDT
 *  Description: Main source file in go-lexer
 */

/*
Package lexer provides a simple scanner and types for handrolling lexers.
The implementation is based on Rob Pike's talk.

	http://www.youtube.com/watch?v=HxaD_trXwRE

Two APIs

The Lexer type has two APIs, one is used byte StateFn types.  The other is
called by the parser. These APIs are called the scanner and the parser APIs
here.

The parser API

The only function the parser calls on the lexer is Next to retreive the next
token from the input stream.  Eventually an item with type ItemEOF is returned
at which point there are no more tokens in the stream.

The scanner API

Common lexer methods used in a scanner are fhe Accept[Run][Range] family of
methods.  Accept* methods take a set and advance the lexer if incoming runes
are in the set. The AcceptRun subfamily advance the lexer as far as possible.

For scanning known sequences of bytes (e.g. keywords) the AcceptString method
avoids a lot of branching that would be incurred using methods that match
character classes.
*/
package lexer

import (
	"container/list"
	"fmt"
	"math"
	"strings"
	"unicode"
	"unicode/utf8"
)

const EOF rune = 0x04

// IsEOF returns true if n is zero.
func IsEOF(c rune, n int) bool {
	return n == 0
}

// IsInvalid returns true if c is utf8.RuneInvalid and n is 1.
func IsInvalid(c rune, n int) bool {
	return c == utf8.RuneError && n == 1
}

// A state function that scans runes from the lexer's input and emits items.
// The state functions are responsible for emitting ItemEOF.
type StateFn func(*Lexer) StateFn

// A type for building lexers.
type Lexer struct {
	input string     // string being scanned
	start int        // start position for the current lexeme
	pos   int        // current position
	width int        // length of the last rune read
	last  rune       // the last rune read
	state StateFn    // the current state
	items *list.List // Buffer of lexed items
}

// Create a new lexer. Must be given a non-nil state.
func New(start StateFn, input string) *Lexer {
	if start == nil {
		panic("nil start state")
	}
	return &Lexer{
		state: start,
		input: input,
		items: list.New(),
	}
}

// The starting position of the current item.
func (l *Lexer) Start() int {
	return l.start
}

// The position following the last read rune.
func (l *Lexer) Pos() int {
	return l.pos
}

// The contents of the item currently being lexed.
func (l *Lexer) Current() string {
	return l.input[l.start:l.pos]
}

// The last rune read from the input stream.
func (l *Lexer) Last() (r rune, width int) {
	return l.last, l.width
}

// Add one rune of input to the current lexeme. Invalid UTF-8 codepoints cause
// the current call and all subsequent calls to return (utf8.RuneError, 1).  If
// there is no input the returned size is zero.
func (l *Lexer) Advance() (rune, int) {
	if l.pos >= len(l.input) {
		l.width = 0
		return EOF, l.width
	}
	l.last, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	if l.last == utf8.RuneError && l.width == 1 {
		return l.last, l.width
	}
	l.pos += l.width
	return l.last, l.width
}

// Remove the last rune from the current lexeme and place back in the stream.
func (l *Lexer) Backup() {
	l.pos -= l.width
}

// Returns the next rune in the input stream without adding it to the current
// lexeme.
func (l *Lexer) Peek() (c rune, width int) {
	defer func() { l.Backup() }()
	return l.Advance()
}

// Ignore throws away the current lexeme.
func (l *Lexer) Ignore() {
	l.start = l.pos
}

// Accept advances the lexer if the next rune is in valid.
func (l *Lexer) Accept(valid string) (ok bool) {
	r, _ := l.Advance()
	ok = strings.IndexRune(valid, r) >= 0
	if !ok {
		l.Backup()
	}
	return
}

// AcceptRange advances l's position if the current rune is in tab.
func (l *Lexer) AcceptRange(tab *unicode.RangeTable) (ok bool) {
	r, _ := l.Advance()
	ok = unicode.Is(tab, r)
	if !ok {
		l.Backup()
	}
	return
}

// AcceptRun advances l's position as long as the current rune is in valid.
func (l *Lexer) AcceptRun(valid string) (n int) {
	for l.Accept(valid) {
		n++
	}
	return
}

// AcceptRunRange advances l's possition as long as the current rune is in tab.
func (l *Lexer) AcceptRunRange(tab *unicode.RangeTable) (n int) {
	for l.AcceptRange(tab) {
		n++
	}
	return
}

// AcceptString advances the lexer len(s) bytes if the next len(s) bytes equal
// s. AcceptString returns true if l advanced.
func (l *Lexer) AcceptString(s string) (ok bool) {
	if strings.HasPrefix(l.input[l.pos:], s) {
		l.pos += len(s)
		return true
	}
	return false
}

// Emit an error from the Lexer.
func (l *Lexer) Errorf(format string, args ...interface{}) StateFn {
	l.enqueue(&Item{
		ItemError,
		l.start,
		fmt.Sprintf(format, args...),
	})
	return nil
}

// Emit the current value as an Item with the specified type.
func (l *Lexer) Emit(t ItemType) {
	l.enqueue(&Item{
		t,
		l.start,
		l.input[l.start:l.pos],
	})
	l.start = l.pos
}

// The method by which items are extracted from the input.
// Returns nil if the lexer has entered a nil state.
func (l *Lexer) Next() (i *Item) {
	for {
		if head := l.dequeue(); head != nil {
			return head
		}
		if l.state == nil {
			return &Item{ItemEOF, l.start, ""}
		}
		l.state = l.state(l)
	}
	panic("unreachable")
}

func (l *Lexer) enqueue(i *Item) {
	l.items.PushBack(i)
}

func (l *Lexer) dequeue() *Item {
	head := l.items.Front()
	if head == nil {
		return nil
	}
	return l.items.Remove(head).(*Item)
}

// A type for all the types of items in the language being lexed.
type ItemType uint16

// Special item types.
const (
	ItemEOF ItemType = math.MaxUint16 - iota
	ItemError
)

// An individual scanned item (a lexeme).
type Item struct {
	Type  ItemType
	Pos   int
	Value string
}

func (i *Item) Err() error {
	if i.Type == ItemError {
		return (*Error)(i)
	}
	return nil
}

func (i *Item) String() string {
	switch i.Type {
	case ItemError:
		return i.Value
	case ItemEOF:
		return "EOF"
	}
	if len(i.Value) > 10 {
		return fmt.Sprintf("%.10q...", i.Value)
	}
	return i.Value
}

type Error Item

func (err *Error) Error() string {
	return (*Item)(err).String()
}
<|endoftext|>


<commit_before><commit_msg>gobuilder: increase log limit<commit_after><|endoftext|>


<commit_before>package editor

import (
	"github.com/gdamore/tcell"
	"github.com/rivo/tview"
	"io/ioutil"
	"os"
	"path/filepath"
)

func isDir(name string) bool {
	if fi, err := os.Stat(name); !os.IsNotExist(err) {
		return fi.IsDir()
	}
	if _, err := os.Stat(name); os.IsNotExist(err) {
		os.OpenFile(name, os.O_RDONLY|os.O_CREATE, 0666)
	}
	return false
}

func (e *Editor) newFileselector(rootDir string) *tview.TreeView {
	if !isDir(rootDir) {
		rootDir = "."
	}
	root := tview.NewTreeNode(rootDir).
		SetColor(tcell.ColorRed)
	tree := tview.NewTreeView().
		SetRoot(root).
		SetCurrentNode(root)

	add := func(target *tview.TreeNode, path string) {
		files, err := ioutil.ReadDir(path)
		if err != nil {
			panic(err)
		}
		for _, file := range files {
			node := tview.NewTreeNode(file.Name()).
				SetReference(filepath.Join(path, file.Name())).
				SetSelectable(true)
			if file.IsDir() {
				node.SetColor(tcell.ColorGreen)
			}
			target.AddChild(node)
		}
	}

	add(root, rootDir)

	tree.SetSelectedFunc(func(node *tview.TreeNode) {
		reference := node.GetReference()
		if reference == nil {
			return // Selecting the root node does nothing.
		}
		children := node.GetChildren()
		if len(children) == 0 {
			// Load and show files in this directory.
			path := reference.(string)
			if isDir(path) {
				add(node, path)
			} else {
				e.OpenFile(path)
				e.focusMain()
			}
		} else {
			// Collapse if visible, expand if collapsed.
			node.SetExpanded(!node.IsExpanded())
		}
	})
	tree.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		switch key := event.Key(); key {
		case tcell.KeyRight:
			e.fileSelector_width++
			e.application.Draw()
			return nil
		case tcell.KeyLeft:
			e.fileSelector_width--
			e.application.Draw()
			return nil
		}
		return event
	})
	return tree
}
<commit_msg>Guard for resize<commit_after>package editor

import (
	"github.com/gdamore/tcell"
	"github.com/rivo/tview"
	"io/ioutil"
	"os"
	"path/filepath"
)

func isDir(name string) bool {
	if fi, err := os.Stat(name); !os.IsNotExist(err) {
		return fi.IsDir()
	}
	if _, err := os.Stat(name); os.IsNotExist(err) {
		os.OpenFile(name, os.O_RDONLY|os.O_CREATE, 0666)
	}
	return false
}

func (e *Editor) newFileselector(rootDir string) *tview.TreeView {
	if !isDir(rootDir) {
		rootDir = "."
	}
	root := tview.NewTreeNode(rootDir).
		SetColor(tcell.ColorRed)
	tree := tview.NewTreeView().
		SetRoot(root).
		SetCurrentNode(root)

	add := func(target *tview.TreeNode, path string) {
		files, err := ioutil.ReadDir(path)
		if err != nil {
			panic(err)
		}
		for _, file := range files {
			node := tview.NewTreeNode(file.Name()).
				SetReference(filepath.Join(path, file.Name())).
				SetSelectable(true)
			if file.IsDir() {
				node.SetColor(tcell.ColorGreen)
			}
			target.AddChild(node)
		}
	}

	add(root, rootDir)

	tree.SetSelectedFunc(func(node *tview.TreeNode) {
		reference := node.GetReference()
		if reference == nil {
			return // Selecting the root node does nothing.
		}
		children := node.GetChildren()
		if len(children) == 0 {
			// Load and show files in this directory.
			path := reference.(string)
			if isDir(path) {
				add(node, path)
			} else {
				e.OpenFile(path)
				e.focusMain()
			}
		} else {
			// Collapse if visible, expand if collapsed.
			node.SetExpanded(!node.IsExpanded())
		}
	})
	tree.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		switch key := event.Key(); key {
		case tcell.KeyRight:
			if e.fileSelector_width < 200 {
				e.fileSelector_width++
			}
			e.application.Draw()
			return nil
		case tcell.KeyLeft:
			if e.fileSelector_width > 3 {
				e.fileSelector_width--
			}
			e.application.Draw()
			return nil
		}
		return event
	})
	return tree
}
<|endoftext|>


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

package gremlin

// Builds a new Gremlin environment pointing at a session.

import (
	"sync"

	"github.com/barakmich/glog"
	"github.com/robertkrimen/otto"

	"github.com/google/cayley/graph"
)

type worker struct {
	qs  graph.QuadStore
	env *otto.Otto
	sync.Mutex

	results chan interface{}
	shape   map[string]interface{}

	count int
	limit int

	kill <-chan struct{}
}

func newWorker(qs graph.QuadStore) *worker {
	env := otto.New()
	wk := &worker{
		qs:    qs,
		env:   env,
		limit: -1,
	}
	graph, _ := env.Object("graph = {}")
	env.Run("g = graph")

	graph.Set("Vertex", func(call otto.FunctionCall) otto.Value {
		call.Otto.Run("var out = {}")
		out, err := call.Otto.Object("out")
		if err != nil {
			glog.Error(err.Error())
			return otto.TrueValue()
		}
		out.Set("_gremlin_type", "vertex")
		args := argsOf(call)
		if len(args) > 0 {
			out.Set("string_args", args)
		}
		wk.embedTraversals(env, out)
		wk.embedFinals(env, out)
		return out.Value()
	})
	env.Run("graph.V = graph.Vertex")

	graph.Set("Morphism", func(call otto.FunctionCall) otto.Value {
		call.Otto.Run("var out = {}")
		out, _ := call.Otto.Object("out")
		out.Set("_gremlin_type", "morphism")
		wk.embedTraversals(env, out)
		return out.Value()
	})
	env.Run("graph.M = graph.Morphism")

	graph.Set("Emit", func(call otto.FunctionCall) otto.Value {
		value := call.Argument(0)
		if value.IsDefined() {
			wk.send(&Result{val: &value})
		}
		return otto.NullValue()
	})

	return wk
}

func (wk *worker) wantShape() bool {
	return wk.shape != nil
}

func argsOf(call otto.FunctionCall) []string {
	var out []string
	for _, arg := range call.ArgumentList {
		if arg.IsString() {
			out = append(out, arg.String())
		}
		if arg.IsObject() && arg.Class() == "Array" {
			obj, _ := arg.Export()
			for _, x := range obj.([]string) {
				out = append(out, x)
			}
		}
	}
	return out
}

func isVertexChain(obj *otto.Object) bool {
	val, _ := obj.Get("_gremlin_type")
	if val.String() == "vertex" {
		return true
	}
	val, _ = obj.Get("_gremlin_prev")
	if val.IsObject() {
		return isVertexChain(val.Object())
	}
	return false
}
<commit_msg>Fix interface conversion<commit_after>// Copyright 2014 The Cayley Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gremlin

// Builds a new Gremlin environment pointing at a session.

import (
	"fmt"
	"sync"

	"github.com/barakmich/glog"
	"github.com/robertkrimen/otto"

	"github.com/google/cayley/graph"
)

type worker struct {
	qs  graph.QuadStore
	env *otto.Otto
	sync.Mutex

	results chan interface{}
	shape   map[string]interface{}

	count int
	limit int

	kill <-chan struct{}
}

func newWorker(qs graph.QuadStore) *worker {
	env := otto.New()
	wk := &worker{
		qs:    qs,
		env:   env,
		limit: -1,
	}
	graph, _ := env.Object("graph = {}")
	env.Run("g = graph")

	graph.Set("Vertex", func(call otto.FunctionCall) otto.Value {
		call.Otto.Run("var out = {}")
		out, err := call.Otto.Object("out")
		if err != nil {
			glog.Error(err.Error())
			return otto.TrueValue()
		}
		out.Set("_gremlin_type", "vertex")
		args := argsOf(call)
		if len(args) > 0 {
			out.Set("string_args", args)
		}
		wk.embedTraversals(env, out)
		wk.embedFinals(env, out)
		return out.Value()
	})
	env.Run("graph.V = graph.Vertex")

	graph.Set("Morphism", func(call otto.FunctionCall) otto.Value {
		call.Otto.Run("var out = {}")
		out, _ := call.Otto.Object("out")
		out.Set("_gremlin_type", "morphism")
		wk.embedTraversals(env, out)
		return out.Value()
	})
	env.Run("graph.M = graph.Morphism")

	graph.Set("Emit", func(call otto.FunctionCall) otto.Value {
		value := call.Argument(0)
		if value.IsDefined() {
			wk.send(&Result{val: &value})
		}
		return otto.NullValue()
	})

	return wk
}

func (wk *worker) wantShape() bool {
	return wk.shape != nil
}

func argsOf(call otto.FunctionCall) []string {
	var out []string
	for _, arg := range call.ArgumentList {
		if arg.IsString() {
			out = append(out, arg.String())
		}
		if arg.IsObject() && arg.Class() == "Array" {
			obj, _ := arg.Export()
			switch o := obj.(type) {
			case []interface{}:
				for _, x := range o {
					out = append(out, x.(string))
				}
			case []string:
				for _, x := range o {
					out = append(out, x)
				}
			default:
				panic(fmt.Errorf("unexpected type: %T", obj))
			}
		}
	}
	return out
}

func isVertexChain(obj *otto.Object) bool {
	val, _ := obj.Get("_gremlin_type")
	if val.String() == "vertex" {
		return true
	}
	val, _ = obj.Get("_gremlin_prev")
	if val.IsObject() {
		return isVertexChain(val.Object())
	}
	return false
}
<|endoftext|>


<commit_before>package xcassets

import (
	"encoding/json"
	"errors"
	"fmt"
	"image/png"
	"log"
	"os"
	"strings"

	"github.com/nfnt/resize"
)

func resizePNG(source, dest string, dim uint) (err error) {
	file, err := os.Open(source)
	if err != nil {
		log.Fatal(err)
	}
	// decode png into image.Image
	img, err := png.Decode(file)
	if err != nil {
		log.Fatal(err)
	}
	file.Close()
	m := resize.Thumbnail(dim, dim, img, resize.Lanczos3)
	out, err := os.Create(dest)
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()
	// write new image to file
	png.Encode(out, m)
	return nil
}

//GenerateAppIconSet takes a source file and a dest Images.xcassets filepath, and overwrites the containing AppIcon.appiconset with a new one containing all the image formats in targets.
func GenerateAppIconSet(source, dest string, targets []Image) error {
	dir, err := os.Getwd()
	if err != nil {
		fmt.Println("Can't get working dir:", err)
		os.Exit(-1)
	}
	if source[:2] == "./" {
		source = strings.Replace(source, "./", dir, 1)
	}
	if dest[:2] == "./" {
		dest = strings.Replace(dest, "./", dir, 1)
	}
	//Have we been given a valid input icon?
	if _, err := os.Stat(source); os.IsNotExist(err) {
		return errors.New(fmt.Sprint("Can't find the source file:", source))
	}
	//Are we in (or given the correct path of) the Gleepost project dir?
	if _, err := os.Stat(dest); os.IsNotExist(err) {
		return errors.New(fmt.Sprint("You didn't specify the project directory correctly -- can't find Images.xcassets here:", dest))
	}
	destDir := dest + "/AppIcon.appiconset"
	//Delete the existing icon if it exists
	if _, err := os.Stat(destDir); err == nil {
		err = os.RemoveAll(destDir)
		if err != nil {
			return errors.New(fmt.Sprint("Error deleting existing icon:", err))
		}
	}
	//Create base dir
	err = os.MkdirAll(destDir, 0755)
	if err != nil {
		return errors.New(fmt.Sprint("Error creating appiconset:", err))
	}

	contents := NewContents()
	for i, t := range targets {
		skip := false
		for _, before := range targets[:i] {
			if before.Px() == t.Px() {
				fmt.Sprint("Already generated this resolution, skipping:", t.Px())
				skip = true
				break
			}
		}
		if !skip {
			fmt.Println("Generating icon for resolution:", t.Px())
			err := resizePNG(source, destDir+"/"+t.Filename, t.Px())
			if err != nil {
				return errors.New(fmt.Sprint("Error resizing icon:", err))
			}
		}
	}
	contents.Images = targets
	f, err := os.Create(destDir + "/Contents.json")
	if err != nil {
		return errors.New(fmt.Sprint("Error creating contents file:", err))
	}
	defer f.Close()
	enc := json.NewEncoder(f)
	err = enc.Encode(contents)
	if err != nil {
		return errors.New(fmt.Sprint("Error writing contents file:", err))
	}
	return nil
}
<commit_msg>resizePNG should return errors<commit_after>package xcassets

import (
	"encoding/json"
	"errors"
	"fmt"
	"image/png"
	"os"
	"strings"

	"github.com/nfnt/resize"
)

func resizePNG(source, dest string, dim uint) (err error) {
	file, err := os.Open(source)
	if err != nil {
		return
	}
	// decode png into image.Image
	img, err := png.Decode(file)
	if err != nil {
		return
	}
	file.Close()
	m := resize.Thumbnail(dim, dim, img, resize.Lanczos3)
	out, err := os.Create(dest)
	if err != nil {
		return
	}
	defer out.Close()
	// write new image to file
	err = png.Encode(out, m)
	return
}

//GenerateAppIconSet takes a source file and a dest Images.xcassets filepath, and overwrites the containing AppIcon.appiconset with a new one containing all the image formats in targets.
func GenerateAppIconSet(source, dest string, targets []Image) error {
	dir, err := os.Getwd()
	if err != nil {
		fmt.Println("Can't get working dir:", err)
		os.Exit(-1)
	}
	if source[:2] == "./" {
		source = strings.Replace(source, "./", dir, 1)
	}
	if dest[:2] == "./" {
		dest = strings.Replace(dest, "./", dir, 1)
	}
	//Have we been given a valid input icon?
	if _, err := os.Stat(source); os.IsNotExist(err) {
		return errors.New(fmt.Sprint("Can't find the source file:", source))
	}
	//Are we in (or given the correct path of) the Gleepost project dir?
	if _, err := os.Stat(dest); os.IsNotExist(err) {
		return errors.New(fmt.Sprint("You didn't specify the project directory correctly -- can't find Images.xcassets here:", dest))
	}
	destDir := dest + "/AppIcon.appiconset"
	//Delete the existing icon if it exists
	if _, err := os.Stat(destDir); err == nil {
		err = os.RemoveAll(destDir)
		if err != nil {
			return errors.New(fmt.Sprint("Error deleting existing icon:", err))
		}
	}
	//Create base dir
	err = os.MkdirAll(destDir, 0755)
	if err != nil {
		return errors.New(fmt.Sprint("Error creating appiconset:", err))
	}

	contents := NewContents()
	for i, t := range targets {
		skip := false
		for _, before := range targets[:i] {
			if before.Px() == t.Px() {
				fmt.Sprint("Already generated this resolution, skipping:", t.Px())
				skip = true
				break
			}
		}
		if !skip {
			fmt.Println("Generating icon for resolution:", t.Px())
			err := resizePNG(source, destDir+"/"+t.Filename, t.Px())
			if err != nil {
				return errors.New(fmt.Sprint("Error resizing icon:", err))
			}
		}
	}
	contents.Images = targets
	f, err := os.Create(destDir + "/Contents.json")
	if err != nil {
		return errors.New(fmt.Sprint("Error creating contents file:", err))
	}
	defer f.Close()
	enc := json.NewEncoder(f)
	err = enc.Encode(contents)
	if err != nil {
		return errors.New(fmt.Sprint("Error writing contents file:", err))
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum 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 optimize

import (
	"math"
	"time"

	"github.com/gonum/floats"
)

// Local finds a local minimum of a function using a sequential algorithm.
// In order to maximize a function, multiply the output by -1.
//
// The first argument is of Function type representing the function to be minimized.
// Type switching is used to see if the function implements Gradient, FunctionGradient
// and Statuser.
//
// The second argument is the initial location at which to start the minimization.
// The initial location must be supplied, and must have a length equal to the
// problem dimension.
//
// The third argument contains the settings for the minimization. It is here that
// gradient tolerance, etc. are specified. The DefaultSettings() function
// can be called for a Settings struct with the default values initialized.
// If settings == nil, the default settings are used. Please see the documentation
// for the Settings structure for more information. The optimization Method used
// may also contain settings, see documentation for the appropriate optimizer.
//
// The final argument is the optimization method to use. If method == nil, then
// an appropriate default is chosen based on the properties of the other arguments
// (dimension, gradient-free or gradient-based, etc.). The optimization
// methods in this package are designed such that reasonable defaults occur
// if options are not specified explicitly. For example, the code
//  method := &Bfgs{}
// creates a pointer to a new Bfgs struct. When minimize is called, the settings
// in the method will be populated with default values. The methods are also
// designed such that they can be reused in future calls to method.
//
// Local returns a Result struct and any error that occurred. Please see the
// documentation of Result for more information.
//
// Please be aware that the default behavior of Local is to find the minimum.
// For certain functions and optimization methods, this process can take many
// function evaluations. If you would like to put limits on this, for example
// maximum runtime or maximum function evaluations, please modify the Settings
// input struct.
func Local(f Function, initX []float64, settings *Settings, method Method) (*Result, error) {
	if len(initX) == 0 {
		panic("local: initial X has zero length")
	}

	startTime := time.Now()

	funcs, funcStat := findFunctionStats(f)

	if method == nil {
		method = getDefaultMethod(funcStat)
	}

	if settings == nil {
		settings = DefaultSettings()
	}

	location, err := setStartingLocation(f, funcs, funcStat, initX, settings)
	if err != nil {
		return nil, err
	}

	stats := &Stats{}
	optLoc := &Location{}
	// update stats (grad norm, function value, etc.) so that things are
	// initialized for the first convergence check
	update(location, optLoc, stats, funcStat, NoEvaluation, NoIteration, startTime)

	if settings.Recorder != nil {
		err = settings.Recorder.Init(funcStat)
		if err != nil {
			return &Result{Status: Failure}, err
		}
	}

	// actually perform the minimization
	status, err := minimize(settings, location, method, funcStat, stats, funcs, optLoc, startTime)

	// cleanup at exit
	if settings.Recorder != nil && err == nil {
		err = settings.Recorder.Record(*optLoc, NoEvaluation, PostIteration, stats)
	}
	stats.Runtime = time.Since(startTime)
	return &Result{
		Stats:    *stats,
		Location: *optLoc,
		Status:   status,
	}, err
}

func minimize(settings *Settings, location Location, method Method, funcStat *FunctionInfo, stats *Stats, funcs functions, optLoc *Location, startTime time.Time) (status Status, err error) {
	methodStatus, methodIsStatuser := method.(Statuser)
	xNext := make([]float64, len(location.X))

	evalType, iterType, err := method.Init(location, funcStat, xNext)
	if err != nil {
		return Failure, err
	}
	copyLocation(optLoc, location)

	for {
		if settings.Recorder != nil {
			err = settings.Recorder.Record(location, evalType, iterType, stats)
			if err != nil {
				status = Failure
				return
			}
		}

		status = checkConvergence(location, iterType, stats, settings)
		if status != NotTerminated {
			return
		}

		if funcStat.IsStatuser {
			status, err = funcs.status.Status()
			if err != nil || status != NotTerminated {
				return
			}
		}

		if methodIsStatuser {
			status, err = methodStatus.Status()
			if err != nil || status != NotTerminated {
				return
			}
		}

		// Compute the new function and update the statistics
		err = evaluate(funcs, funcStat, evalType, xNext, &location)
		if err != nil {
			status = Failure
			return
		}
		update(location, optLoc, stats, funcStat, evalType, iterType, startTime)

		// Find the next location
		evalType, iterType, err = method.Iterate(location, xNext)
		if err != nil {
			status = Failure
			return
		}
	}
	panic("unreachable")
}

func copyLocation(dst *Location, src Location) {
	dst.X = resize(dst.X, len(src.X))
	copy(dst.X, src.X)

	dst.F = src.F

	dst.Gradient = resize(dst.Gradient, len(src.Gradient))
	copy(dst.Gradient, src.Gradient)
}

func findFunctionStats(f Function) (functions, *FunctionInfo) {
	// Not sure how/if we want to compute timing to be used with functions
	gradient, isGradient := f.(Gradient)
	gradFunc, isFunGrad := f.(FunctionGradient)

	status, isStatuser := f.(Statuser)

	stats := &FunctionInfo{
		IsGradient:         isGradient,
		IsFunctionGradient: isFunGrad,
		IsStatuser:         isStatuser,
	}
	funcs := functions{
		function: f,
		gradient: gradient,
		gradFunc: gradFunc,
		status:   status,
	}

	return funcs, stats
}

func getDefaultMethod(f *FunctionInfo) Method {
	if f.IsFunctionGradient {
		return &BFGS{}
	}
	// TODO: Implement a gradient-free method
	panic("optimize: gradient-free methods not yet coded")
}

// Combine location and stats because maybe in the future we'll add evaluation times
// to functionStats?
func setStartingLocation(f Function, funcs functions, stats *FunctionInfo, initX []float64, settings *Settings) (Location, error) {
	var l Location

	l.X = make([]float64, len(initX))
	copy(l.X, initX)

	if settings.UseInitialData {
		initF := settings.InitialFunctionValue
		// Do we allow Inf initial function value?
		if math.IsNaN(initF) {
			return l, ErrNaN
		}
		if math.IsInf(initF, 1) {
			return l, ErrInf
		}
		l.F = initF

		initG := settings.InitialGradient
		if stats.IsGradient {
			if len(initX) != len(initG) {
				panic("local: initial location size mismatch")
			}

			l.Gradient = make([]float64, len(initG))
			copy(l.Gradient, initG)
		}
		return l, nil
	}

	// Compute missing information in the initial state.
	if stats.IsFunctionGradient {
		l.Gradient = make([]float64, len(initX))
		l.F = funcs.gradFunc.FDf(initX, l.Gradient)
		return l, nil
	}
	l.F = funcs.function.F(l.X)
	if math.IsNaN(l.F) {
		return l, ErrNaN
	}
	if math.IsInf(l.F, 1) {
		return l, ErrInf
	}
	return l, nil
}

func checkConvergence(loc Location, itertype IterationType, stats *Stats, settings *Settings) Status {
	if itertype == MajorIteration && loc.Gradient != nil {
		if stats.GradientNorm <= settings.GradientAbsTol {
			return GradientAbsoluteConvergence
		}
	}

	if itertype == MajorIteration && loc.F < settings.FunctionAbsTol {
		return FunctionAbsoluteConvergence
	}

	// Check every step for negative infinity because it could break the
	// linesearches and -inf is the best you can do anyway.
	if math.IsInf(loc.F, -1) {
		return FunctionNegativeInfinity
	}

	if settings.FunctionEvals > 0 {
		totalFun := stats.FunctionEvals + stats.FunctionGradientEvals
		if totalFun >= settings.FunctionEvals {
			return FunctionEvaluationLimit
		}
	}

	if settings.GradientEvals > 0 {
		totalGrad := stats.GradientEvals + stats.FunctionGradientEvals
		if totalGrad >= settings.GradientEvals {
			return GradientEvaluationLimit
		}
	}

	if settings.Runtime > 0 {
		if stats.Runtime >= settings.Runtime {
			return RuntimeLimit
		}
	}

	if itertype == MajorIteration && settings.MajorIterations > 0 {
		if stats.MajorIterations >= settings.MajorIterations {
			return IterationLimit
		}
	}
	return NotTerminated
}

// evaluate evaluates the function and stores the answer in place
func evaluate(funcs functions, funcStat *FunctionInfo, evalType EvaluationType, xNext []float64, location *Location) error {
	copy(location.X, xNext)
	switch evalType {
	case FunctionEval:
		location.F = funcs.function.F(xNext)
		for i := range location.Gradient {
			location.Gradient[i] = math.NaN()
		}
		return nil
	case GradientEval:
		location.F = math.NaN()
		if funcStat.IsGradient {
			funcs.gradient.Df(location.X, location.Gradient)
			return nil
		}
		if funcStat.IsFunctionGradient {
			location.F = funcs.gradFunc.FDf(location.X, location.Gradient)
			return nil
		}
		return ErrMismatch{Type: evalType}
	case FunctionAndGradientEval:
		if funcStat.IsFunctionGradient {
			location.F = funcs.gradFunc.FDf(xNext, location.Gradient)
			return nil
		}
		if funcStat.IsGradient {
			location.F = funcs.function.F(xNext)
			funcs.gradient.Df(xNext, location.Gradient)
			return nil
		}
		return ErrMismatch{Type: evalType}
	default:
		panic("unreachable")
	}
}

// update updates the stats given the new evaluation
func update(location Location, optLoc *Location, stats *Stats, funcStat *FunctionInfo, evalType EvaluationType, iterType IterationType, startTime time.Time) {
	switch evalType {
	case FunctionEval:
		stats.FunctionEvals++
	case GradientEval:
		if funcStat.IsGradient {
			stats.GradientEvals++
		}
		if funcStat.IsFunctionGradient {
			stats.FunctionGradientEvals++
		}
	case FunctionAndGradientEval:
		if funcStat.IsFunctionGradient {
			stats.FunctionGradientEvals++
		}
		if funcStat.IsGradient {
			stats.FunctionEvals++
			stats.FunctionGradientEvals++
		}
	}
	if iterType == MajorIteration {
		stats.MajorIterations++
	}
	if location.F < optLoc.F {
		copyLocation(optLoc, location)
	}
	stats.Runtime = time.Since(startTime)
	if location.Gradient != nil {
		stats.GradientNorm = floats.Norm(location.Gradient, 2) / math.Sqrt(float64(len(location.Gradient)))
	}
}
<commit_msg>Rename some variables for consistency<commit_after>// Copyright ©2014 The gonum 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 optimize

import (
	"math"
	"time"

	"github.com/gonum/floats"
)

// Local finds a local minimum of a function using a sequential algorithm.
// In order to maximize a function, multiply the output by -1.
//
// The first argument is of Function type representing the function to be minimized.
// Type switching is used to see if the function implements Gradient, FunctionGradient
// and Statuser.
//
// The second argument is the initial location at which to start the minimization.
// The initial location must be supplied, and must have a length equal to the
// problem dimension.
//
// The third argument contains the settings for the minimization. It is here that
// gradient tolerance, etc. are specified. The DefaultSettings() function
// can be called for a Settings struct with the default values initialized.
// If settings == nil, the default settings are used. Please see the documentation
// for the Settings structure for more information. The optimization Method used
// may also contain settings, see documentation for the appropriate optimizer.
//
// The final argument is the optimization method to use. If method == nil, then
// an appropriate default is chosen based on the properties of the other arguments
// (dimension, gradient-free or gradient-based, etc.). The optimization
// methods in this package are designed such that reasonable defaults occur
// if options are not specified explicitly. For example, the code
//  method := &Bfgs{}
// creates a pointer to a new Bfgs struct. When minimize is called, the settings
// in the method will be populated with default values. The methods are also
// designed such that they can be reused in future calls to method.
//
// Local returns a Result struct and any error that occurred. Please see the
// documentation of Result for more information.
//
// Please be aware that the default behavior of Local is to find the minimum.
// For certain functions and optimization methods, this process can take many
// function evaluations. If you would like to put limits on this, for example
// maximum runtime or maximum function evaluations, please modify the Settings
// input struct.
func Local(f Function, initX []float64, settings *Settings, method Method) (*Result, error) {
	if len(initX) == 0 {
		panic("local: initial X has zero length")
	}

	startTime := time.Now()

	funcs, funcInfo := findFunctionStats(f)

	if method == nil {
		method = getDefaultMethod(funcInfo)
	}

	if settings == nil {
		settings = DefaultSettings()
	}

	location, err := setStartingLocation(f, funcs, funcInfo, initX, settings)
	if err != nil {
		return nil, err
	}

	stats := &Stats{}
	optLoc := &Location{}
	// update stats (grad norm, function value, etc.) so that things are
	// initialized for the first convergence check
	update(location, optLoc, stats, funcInfo, NoEvaluation, NoIteration, startTime)

	if settings.Recorder != nil {
		err = settings.Recorder.Init(funcInfo)
		if err != nil {
			return &Result{Status: Failure}, err
		}
	}

	// actually perform the minimization
	status, err := minimize(settings, location, method, funcInfo, stats, funcs, optLoc, startTime)

	// cleanup at exit
	if settings.Recorder != nil && err == nil {
		err = settings.Recorder.Record(*optLoc, NoEvaluation, PostIteration, stats)
	}
	stats.Runtime = time.Since(startTime)
	return &Result{
		Stats:    *stats,
		Location: *optLoc,
		Status:   status,
	}, err
}

func minimize(settings *Settings, location Location, method Method, funcInfo *FunctionInfo, stats *Stats, funcs functions, optLoc *Location, startTime time.Time) (status Status, err error) {
	methodStatus, methodIsStatuser := method.(Statuser)
	xNext := make([]float64, len(location.X))

	evalType, iterType, err := method.Init(location, funcInfo, xNext)
	if err != nil {
		return Failure, err
	}
	copyLocation(optLoc, location)

	for {
		if settings.Recorder != nil {
			err = settings.Recorder.Record(location, evalType, iterType, stats)
			if err != nil {
				status = Failure
				return
			}
		}

		status = checkConvergence(location, iterType, stats, settings)
		if status != NotTerminated {
			return
		}

		if funcInfo.IsStatuser {
			status, err = funcs.status.Status()
			if err != nil || status != NotTerminated {
				return
			}
		}

		if methodIsStatuser {
			status, err = methodStatus.Status()
			if err != nil || status != NotTerminated {
				return
			}
		}

		// Compute the new function and update the statistics
		err = evaluate(funcs, funcInfo, evalType, xNext, &location)
		if err != nil {
			status = Failure
			return
		}
		update(location, optLoc, stats, funcInfo, evalType, iterType, startTime)

		// Find the next location
		evalType, iterType, err = method.Iterate(location, xNext)
		if err != nil {
			status = Failure
			return
		}
	}
	panic("unreachable")
}

func copyLocation(dst *Location, src Location) {
	dst.X = resize(dst.X, len(src.X))
	copy(dst.X, src.X)

	dst.F = src.F

	dst.Gradient = resize(dst.Gradient, len(src.Gradient))
	copy(dst.Gradient, src.Gradient)
}

func findFunctionStats(f Function) (functions, *FunctionInfo) {
	// Not sure how/if we want to compute timing to be used with functions
	gradient, isGradient := f.(Gradient)
	gradFunc, isFunGrad := f.(FunctionGradient)

	status, isStatuser := f.(Statuser)

	funcInfo := &FunctionInfo{
		IsGradient:         isGradient,
		IsFunctionGradient: isFunGrad,
		IsStatuser:         isStatuser,
	}
	funcs := functions{
		function: f,
		gradient: gradient,
		gradFunc: gradFunc,
		status:   status,
	}

	return funcs, funcInfo
}

func getDefaultMethod(funcInfo *FunctionInfo) Method {
	if funcInfo.IsFunctionGradient {
		return &BFGS{}
	}
	// TODO: Implement a gradient-free method
	panic("optimize: gradient-free methods not yet coded")
}

// Combine location and stats because maybe in the future we'll add evaluation times
// to functionStats?
func setStartingLocation(f Function, funcs functions, funcInfo *FunctionInfo, initX []float64, settings *Settings) (Location, error) {
	var l Location

	l.X = make([]float64, len(initX))
	copy(l.X, initX)

	if settings.UseInitialData {
		initF := settings.InitialFunctionValue
		// Do we allow Inf initial function value?
		if math.IsNaN(initF) {
			return l, ErrNaN
		}
		if math.IsInf(initF, 1) {
			return l, ErrInf
		}
		l.F = initF

		initG := settings.InitialGradient
		if funcInfo.IsGradient {
			if len(initX) != len(initG) {
				panic("local: initial location size mismatch")
			}

			l.Gradient = make([]float64, len(initG))
			copy(l.Gradient, initG)
		}
		return l, nil
	}

	// Compute missing information in the initial state.
	if funcInfo.IsFunctionGradient {
		l.Gradient = make([]float64, len(initX))
		l.F = funcs.gradFunc.FDf(initX, l.Gradient)
		return l, nil
	}
	l.F = funcs.function.F(l.X)
	if math.IsNaN(l.F) {
		return l, ErrNaN
	}
	if math.IsInf(l.F, 1) {
		return l, ErrInf
	}
	return l, nil
}

func checkConvergence(loc Location, itertype IterationType, stats *Stats, settings *Settings) Status {
	if itertype == MajorIteration && loc.Gradient != nil {
		if stats.GradientNorm <= settings.GradientAbsTol {
			return GradientAbsoluteConvergence
		}
	}

	if itertype == MajorIteration && loc.F < settings.FunctionAbsTol {
		return FunctionAbsoluteConvergence
	}

	// Check every step for negative infinity because it could break the
	// linesearches and -inf is the best you can do anyway.
	if math.IsInf(loc.F, -1) {
		return FunctionNegativeInfinity
	}

	if settings.FunctionEvals > 0 {
		totalFun := stats.FunctionEvals + stats.FunctionGradientEvals
		if totalFun >= settings.FunctionEvals {
			return FunctionEvaluationLimit
		}
	}

	if settings.GradientEvals > 0 {
		totalGrad := stats.GradientEvals + stats.FunctionGradientEvals
		if totalGrad >= settings.GradientEvals {
			return GradientEvaluationLimit
		}
	}

	if settings.Runtime > 0 {
		if stats.Runtime >= settings.Runtime {
			return RuntimeLimit
		}
	}

	if itertype == MajorIteration && settings.MajorIterations > 0 {
		if stats.MajorIterations >= settings.MajorIterations {
			return IterationLimit
		}
	}
	return NotTerminated
}

// evaluate evaluates the function and stores the answer in place
func evaluate(funcs functions, funcInfo *FunctionInfo, evalType EvaluationType, xNext []float64, location *Location) error {
	copy(location.X, xNext)
	switch evalType {
	case FunctionEval:
		location.F = funcs.function.F(location.X)
		for i := range location.Gradient {
			location.Gradient[i] = math.NaN()
		}
		return nil
	case GradientEval:
		location.F = math.NaN()
		if funcInfo.IsGradient {
			funcs.gradient.Df(location.X, location.Gradient)
			return nil
		}
		if funcInfo.IsFunctionGradient {
			location.F = funcs.gradFunc.FDf(location.X, location.Gradient)
			return nil
		}
		return ErrMismatch{Type: evalType}
	case FunctionAndGradientEval:
		if funcInfo.IsFunctionGradient {
			location.F = funcs.gradFunc.FDf(location.X, location.Gradient)
			return nil
		}
		if funcInfo.IsGradient {
			location.F = funcs.function.F(location.X)
			funcs.gradient.Df(location.X, location.Gradient)
			return nil
		}
		return ErrMismatch{Type: evalType}
	default:
		panic("unreachable")
	}
}

// update updates the stats given the new evaluation
func update(location Location, optLoc *Location, stats *Stats, funcInfo *FunctionInfo, evalType EvaluationType, iterType IterationType, startTime time.Time) {
	switch evalType {
	case FunctionEval:
		stats.FunctionEvals++
	case GradientEval:
		if funcInfo.IsGradient {
			stats.GradientEvals++
		}
		if funcInfo.IsFunctionGradient {
			stats.FunctionGradientEvals++
		}
	case FunctionAndGradientEval:
		if funcInfo.IsFunctionGradient {
			stats.FunctionGradientEvals++
		}
		if funcInfo.IsGradient {
			stats.FunctionEvals++
			stats.FunctionGradientEvals++
		}
	}
	if iterType == MajorIteration {
		stats.MajorIterations++
	}
	if location.F < optLoc.F {
		copyLocation(optLoc, location)
	}
	stats.Runtime = time.Since(startTime)
	if location.Gradient != nil {
		stats.GradientNorm = floats.Norm(location.Gradient, 2) / math.Sqrt(float64(len(location.Gradient)))
	}
}
<|endoftext|>


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

// +build !appengine

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"

	"code.google.com/p/go.net/websocket"
)

const socketPresent = true

func HandleSocket(path string) {
	http.Handle(path, websocket.Handler(socketHandler))
}

const msgLimit = 1000 // max number of messages to send per session

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()
}

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id   string // client-provided unique id for the process
	Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body string
}

// socketHandler handles the websocket connection for a given present session.
// It constructs a new Client and handles transcoding Messages to and from JSON
// format, sending and receiving those messages on the Client's in and out
// channels.
func socketHandler(c *websocket.Conn) {
	proc := make(map[string]*Process)
	in, out := make(chan *Message), make(chan *Message)
	errc := make(chan error, 1)

	// Decode messages from client and take the relevant action.
	go func() {
		dec := json.NewDecoder(c)
		for {
			var m Message
			if err := dec.Decode(&m); err != nil {
				errc <- err
				return
			}
			in <- &m
		}
	}()

	// Receive messages from the out channel and encode to the client.
	go func() {
		enc := json.NewEncoder(c)
		for m := range out {
			if err := enc.Encode(m); err != nil {
				errc <- err
				return
			}
		}
	}()

	// Handle input.
	for {
		select {
		case m := <-in:
			switch m.Kind {
			case "run":
				proc[m.Id].Kill()
				lOut := limiter(in, out)
				proc[m.Id] = StartProcess(m.Id, m.Body, lOut)
			case "kill":
				proc[m.Id].Kill()
			}
		case err := <-errc:
			// A encode or decode has failed; bail.
			log.Println(err)
			// Shut down any running processes.
			for _, p := range proc {
				p.Kill()
			}
			return
		}
	}
}

// Process represents a running process.
type Process struct {
	id   string
	out  chan<- *Message
	done chan struct{} // closed when wait completes
	run  *exec.Cmd
}

// StartProcess builds and runs the given program, sending its output
// and end event as Messages on the provided channel.
func StartProcess(id, body string, out chan<- *Message) *Process {
	p := &Process{
		id:   id,
		out:  out,
		done: make(chan struct{}),
	}
	cmd, err := p.start(body)
	if err != nil {
		p.end(err)
		return nil
	}
	p.run = cmd
	go p.wait(cmd)
	return p
}

// Kill stops the process if it is running and waits for it to exit.
func (p *Process) Kill() {
	if p == nil {
		return
	}
	if p.run != nil {
		p.run.Process.Kill()
	}
	<-p.done
}

// start builds and starts the given program, sending its output to p.out,
// and returns the associated *exec.Cmd.
func (p *Process) start(body string) (*exec.Cmd, error) {
	// x is the base name for .go and executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// write body to x.go
	defer os.Remove(src)
	if err := ioutil.WriteFile(src, []byte(body), 0666); err != nil {
		return nil, err
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	err := p.cmd(dir, "go", "build", "-o", bin, file).Run()
	defer os.Remove(bin)
	if err != nil {
		return nil, err
	}

	// run x
	cmd := p.cmd("", bin)
	if err = cmd.Start(); err != nil {
		return nil, err
	}
	return cmd, nil
}

// Wait waits for the running process to complete and returns its error state.
func (p *Process) wait(cmd *exec.Cmd) {
	defer close(p.done)
	p.end(cmd.Wait())
}

// end sends an "end" message to the client, containing the process id and the
// given error value.
func (p *Process) end(err error) {
	m := &Message{Id: p.id, Kind: "end"}
	if err != nil {
		m.Body = err.Error()
	}
	p.out <- m
}

// cmd builds an *exec.Cmd that writes its standard output and error to the
// Process' output channel.
func (p *Process) cmd(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &messageWriter{p.id, "stdout", p.out}
	cmd.Stderr = &messageWriter{p.id, "stderr", p.out}
	return cmd
}

// messageWriter is an io.Writer that converts all writes to Message sends on
// the out channel with the specified id and kind.
type messageWriter struct {
	id, kind string
	out      chan<- *Message
}

func (w *messageWriter) Write(b []byte) (n int, err error) {
	w.out <- &Message{Id: w.id, Kind: w.kind, Body: string(b)}
	return len(b), nil
}

// limiter returns a channel that wraps dest. Messages sent to the channel are
// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
// is sent to the kill channel, and only "end" messages are passed.
func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
	ch := make(chan *Message)
	go func() {
		n := 0
		for m := range ch {
			switch {
			case n < msgLimit || m.Kind == "end":
				dest <- m
				if m.Kind == "end" {
					return
				}
			case n == msgLimit:
				// Process produced too much output. Kill it.
				kill <- &Message{Id: m.Id, Kind: "kill"}
			}
			n++
		}
	}()
	return ch
}

var tmpdir string

func init() {
	// find real path to temporary directory
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>go.talks/present: amend some comments<commit_after>// Copyright 2012 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.

// +build !appengine

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"

	"code.google.com/p/go.net/websocket"
)

const socketPresent = true

func HandleSocket(path string) {
	http.Handle(path, websocket.Handler(socketHandler))
}

const msgLimit = 1000 // max number of messages to send per session

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()
}

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id   string // client-provided unique id for the process
	Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body string
}

// socketHandler handles the websocket connection for a given present session.
// It handles transcoding Messages to and from JSON format, and starting
// and killing Processes.
func socketHandler(c *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	errc := make(chan error, 1)

	// Decode messages from client and send to the in channel.
	go func() {
		dec := json.NewDecoder(c)
		for {
			var m Message
			if err := dec.Decode(&m); err != nil {
				errc <- err
				return
			}
			in <- &m
		}
	}()

	// Receive messages from the out channel and encode to the client.
	go func() {
		enc := json.NewEncoder(c)
		for m := range out {
			if err := enc.Encode(m); err != nil {
				errc <- err
				return
			}
		}
	}()

	// Start and kill Processes and handle errors.
	proc := make(map[string]*Process)
	for {
		select {
		case m := <-in:
			switch m.Kind {
			case "run":
				proc[m.Id].Kill()
				lOut := limiter(in, out)
				proc[m.Id] = StartProcess(m.Id, m.Body, lOut)
			case "kill":
				proc[m.Id].Kill()
			}
		case err := <-errc:
			// A encode or decode has failed; bail.
			log.Println(err)
			// Shut down any running processes.
			for _, p := range proc {
				p.Kill()
			}
			return
		}
	}
}

// Process represents a running process.
type Process struct {
	id   string
	out  chan<- *Message
	done chan struct{} // closed when wait completes
	run  *exec.Cmd
}

// StartProcess builds and runs the given program, sending its output
// and end event as Messages on the provided channel.
func StartProcess(id, body string, out chan<- *Message) *Process {
	p := &Process{
		id:   id,
		out:  out,
		done: make(chan struct{}),
	}
	cmd, err := p.start(body)
	if err != nil {
		p.end(err)
		return nil
	}
	p.run = cmd
	go p.wait(cmd)
	return p
}

// Kill stops the process if it is running and waits for it to exit.
func (p *Process) Kill() {
	if p == nil {
		return
	}
	if p.run != nil {
		p.run.Process.Kill()
	}
	<-p.done
}

// start builds and starts the given program, sending its output to p.out,
// and returns the associated *exec.Cmd.
func (p *Process) start(body string) (*exec.Cmd, error) {
	// x is the base name for .go and executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// write body to x.go
	defer os.Remove(src)
	if err := ioutil.WriteFile(src, []byte(body), 0666); err != nil {
		return nil, err
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	err := p.cmd(dir, "go", "build", "-o", bin, file).Run()
	defer os.Remove(bin)
	if err != nil {
		return nil, err
	}

	// run x
	cmd := p.cmd("", bin)
	if err = cmd.Start(); err != nil {
		return nil, err
	}
	return cmd, nil
}

// wait waits for the running process to complete and returns its error state.
func (p *Process) wait(cmd *exec.Cmd) {
	defer close(p.done)
	p.end(cmd.Wait())
}

// end sends an "end" message to the client, containing the process id and the
// given error value.
func (p *Process) end(err error) {
	m := &Message{Id: p.id, Kind: "end"}
	if err != nil {
		m.Body = err.Error()
	}
	p.out <- m
}

// cmd builds an *exec.Cmd that writes its standard output and error to the
// Process' output channel.
func (p *Process) cmd(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &messageWriter{p.id, "stdout", p.out}
	cmd.Stderr = &messageWriter{p.id, "stderr", p.out}
	return cmd
}

// messageWriter is an io.Writer that converts all writes to Message sends on
// the out channel with the specified id and kind.
type messageWriter struct {
	id, kind string
	out      chan<- *Message
}

func (w *messageWriter) Write(b []byte) (n int, err error) {
	w.out <- &Message{Id: w.id, Kind: w.kind, Body: string(b)}
	return len(b), nil
}

// limiter returns a channel that wraps dest. Messages sent to the channel are
// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
// is sent to the kill channel, and only "end" messages are passed.
func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
	ch := make(chan *Message)
	go func() {
		n := 0
		for m := range ch {
			switch {
			case n < msgLimit || m.Kind == "end":
				dest <- m
				if m.Kind == "end" {
					return
				}
			case n == msgLimit:
				// Process produced too much output. Kill it.
				kill <- &Message{Id: m.Id, Kind: "kill"}
			}
			n++
		}
	}()
	return ch
}

var tmpdir string

func init() {
	// find real path to temporary directory
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>