<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`fmt`
	`math/rand`
	`time`
)

type Globals struct {
	Log   bool // Enable logging.
	Trace bool // Trace evaluation scores.
	Fancy bool // Represent pieces as UTF-8 characters.
}

var Settings Globals

// Returns row number for the given bit index.
func Row(n int) int {
	return n >> 3 // n / 8
}

// Returns column number for the given bit index.
func Col(n int) int {
	return n & 7 // n % 8
}

// Returns row and column numbers for the given bit index.
func Coordinate(n int) (int, int) {
	return Row(n), Col(n)
}

func RelRow(square, color int) int {
	return Row(square) ^ (color * 7)
}

// Returns 0..63 square number for the given row/column coordinate.
func Square(row, column int) int {
	return (row << 3) + column
}

func Flip(color, square int) int {
	if color == White {
		return square ^ 56
	}
	return square
}

// Returns bitmask with light or dark squares set, based on color of the square.
func Same(square int) Bitmask {
	return (bit[square] & maskDark) | (bit[square] & ^maskDark)
}

func IsBetween(from, to, between int) bool {
	return ((maskStraight[from][to] | maskDiagonal[from][to]) & bit[between]) != 0
}

func Ply() int {
	return node - rootNode
}

// Integer version of math/abs.
func Abs(n int) int {
	if n < 0 {
		return -n
	}
	return n
}

func Min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func Max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

// Returns, as an integer, a non-negative pseudo-random number
// in [0, limit) range. It panics if limit <= 0.
func Random(limit int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(limit)
}

func C(color int) string {
	return [2]string{`white`, `black`}[color]
}

//
//   noWe         nort         noEa
//           +7    +8    +9
//               \  |  /
//   west    -1 <-  0 -> +1    east
//               /  |  \
//           -9    -8    -7
//   soWe         sout         soEa
//
func Rose(direction int) int {
	return [8]int{8, 9, 1, -7, -8, -9, -1, 7}[direction]
}

func Summary(metrics map[string]interface{}) {
	phase := metrics[`Phase`].(int)
	tally := metrics[`PST`].(Score)
	final := metrics[`Final`].(Score)

	fmt.Println()
	fmt.Printf("Metric              MidGame        |        EndGame        | Blended\n")
	fmt.Printf("                W      B     W-B   |    W      B     W-B   |  (%d)  \n", phase)
	fmt.Printf("-----------------------------------+-----------------------+--------\n")
	fmt.Printf("%-12s    -      -    %5.2f  |    -      -    %5.2f  >  %5.2f\n", `PST`,
		float32(tally.midgame)/100.0, float32(tally.endgame)/100.0, float32(tally.blended(phase))/100.0)

	for _, tag := range([]string{`Tempo`, `Pawns`, `+Pieces`, `-Knights`, `-Bishops`, `-Rooks`, `-Queens`, `+King`, `-Cover`, `-Danger`, `Initiative`}) {
		white := metrics[tag].(Total).white
		black := metrics[tag].(Total).black

		var score Score
		score.add(white).subtract(black)

		if tag[0:1] == `+` {
			tag = tag[1:]
		} else if tag[0:1] == `-` {
			tag = `  ` + tag[1:]
		}

		fmt.Printf("%-12s  %5.2f  %5.2f  %5.2f  |  %5.2f  %5.2f  %5.2f  >  %5.2f\n", tag,
			float32(white.midgame)/100.0, float32(black.midgame)/100.0, float32(score.midgame)/100.0,
			float32(white.endgame)/100.0, float32(black.endgame)/100.0, float32(score.endgame)/100.0,
			float32(score.blended(phase))/100.0)
	}
	fmt.Printf("%-12s    -      -    %5.2f  |    -      -    %5.2f  >  %5.2f\n\n", `Final Score`,
		float32(final.midgame)/100.0, float32(final.endgame)/100.0, float32(final.blended(phase))/100.0)
}

func SummaryAlt(metrics map[string]interface{}) {
	phase := metrics[`Phase`].(int)
	tally := metrics[`PST`].(Score)
	final := metrics[`Final`].(Score)

	fmt.Println()
	fmt.Printf("Metric            White     |     Black     |     Total     | Blended \n")
	fmt.Printf("                mid   end   |   mid   end   |   mid   end   |  (%d)  \n", phase)
	fmt.Printf("----------------------------+---------------+---------------+---------\n")
	fmt.Printf("%-12s     -     -    |    -     -    | %5.2f  %5.2f  > %5.2f\n", `PST`,
		float32(tally.midgame)/100.0, float32(tally.endgame)/100.0,
		float32(tally.blended(phase))/100.0)

	for _, tag := range([]string{`Tempo`, `Pawns`, `+Pieces`, `-Knights`, `-Bishops`, `-Rooks`, `-Queens`, `+King`, `-Cover`, `-Danger`, `Initiative`}) {
		white := metrics[tag].(Total).white
		black := metrics[tag].(Total).black

		var score Score
		score.add(white).subtract(black)

		if tag[0:1] == `+` {
			tag = tag[1:]
		} else if tag[0:1] == `-` {
			tag = `  ` + tag[1:]
		}

		fmt.Printf("%-12s  %5.2f  %5.2f  | %5.2f  %5.2f  | %5.2f  %5.2f  > %5.2f\n", tag,
			float32(white.midgame)/100.0, float32(white.endgame)/100.0,
			float32(black.midgame)/100.0, float32(black.endgame)/100.0,
			float32(score.midgame)/100.0, float32(score.endgame)/100.0,
			float32(score.blended(phase))/100.0)
	}
	fmt.Printf("%-12s     -     -    |    -     -    | %5.2f  %5.2f  > %5.2f\n\n", `Final Score`,
		float32(final.midgame)/100.0, float32(final.endgame)/100.0,
		float32(final.blended(phase))/100.0)
}

// Logging wrapper around fmt.Printf() that could be turned on as needed. Typical
// usage is Log(true); defer Log(false) in tests.
func Log(args ...interface{}) {
	switch len(args) {
	case 0:
		// Calling Log() with no arguments flips the logging setting.
		Settings.Log = !Settings.Log
		Settings.Fancy = !Settings.Fancy
	case 1:
		switch args[0].(type) {
		case bool:
			Settings.Log = args[0].(bool)
			Settings.Fancy = args[0].(bool)
		default:
			if Settings.Log {
				fmt.Println(args...)
			}
		}
	default:
		if Settings.Log {
			fmt.Printf(args[0].(string), args[1:]...)
		}
	}
}
<commit_msg>Added threat metrics to evaluation summary<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`fmt`
	`math/rand`
	`time`
)

type Globals struct {
	Log   bool // Enable logging.
	Trace bool // Trace evaluation scores.
	Fancy bool // Represent pieces as UTF-8 characters.
}

var Settings Globals

// Returns row number for the given bit index.
func Row(n int) int {
	return n >> 3 // n / 8
}

// Returns column number for the given bit index.
func Col(n int) int {
	return n & 7 // n % 8
}

// Returns row and column numbers for the given bit index.
func Coordinate(n int) (int, int) {
	return Row(n), Col(n)
}

func RelRow(square, color int) int {
	return Row(square) ^ (color * 7)
}

// Returns 0..63 square number for the given row/column coordinate.
func Square(row, column int) int {
	return (row << 3) + column
}

func Flip(color, square int) int {
	if color == White {
		return square ^ 56
	}
	return square
}

// Returns bitmask with light or dark squares set, based on color of the square.
func Same(square int) Bitmask {
	return (bit[square] & maskDark) | (bit[square] & ^maskDark)
}

func IsBetween(from, to, between int) bool {
	return ((maskStraight[from][to] | maskDiagonal[from][to]) & bit[between]) != 0
}

func Ply() int {
	return node - rootNode
}

// Integer version of math/abs.
func Abs(n int) int {
	if n < 0 {
		return -n
	}
	return n
}

func Min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func Max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

// Returns, as an integer, a non-negative pseudo-random number
// in [0, limit) range. It panics if limit <= 0.
func Random(limit int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(limit)
}

func C(color int) string {
	return [2]string{`white`, `black`}[color]
}

//
//   noWe         nort         noEa
//           +7    +8    +9
//               \  |  /
//   west    -1 <-  0 -> +1    east
//               /  |  \
//           -9    -8    -7
//   soWe         sout         soEa
//
func Rose(direction int) int {
	return [8]int{8, 9, 1, -7, -8, -9, -1, 7}[direction]
}

func Summary(metrics map[string]interface{}) {
	phase := metrics[`Phase`].(int)
	tally := metrics[`PST`].(Score)
	final := metrics[`Final`].(Score)

	fmt.Println()
	fmt.Printf("Metric              MidGame        |        EndGame        | Blended\n")
	fmt.Printf("                W      B     W-B   |    W      B     W-B   |  (%d)  \n", phase)
	fmt.Printf("-----------------------------------+-----------------------+--------\n")
	fmt.Printf("%-12s    -      -    %5.2f  |    -      -    %5.2f  >  %5.2f\n", `PST`,
		float32(tally.midgame)/100.0, float32(tally.endgame)/100.0, float32(tally.blended(phase))/100.0)

	for _, tag := range([]string{`Tempo`, `Threats`, `Pawns`, `+Pieces`, `-Knights`, `-Bishops`, `-Rooks`, `-Queens`, `+King`, `-Cover`, `-Safety`}) {
		white := metrics[tag].(Total).white
		black := metrics[tag].(Total).black

		var score Score
		score.add(white).subtract(black)

		if tag[0:1] == `+` {
			tag = tag[1:]
		} else if tag[0:1] == `-` {
			tag = `  ` + tag[1:]
		}

		fmt.Printf("%-12s  %5.2f  %5.2f  %5.2f  |  %5.2f  %5.2f  %5.2f  >  %5.2f\n", tag,
			float32(white.midgame)/100.0, float32(black.midgame)/100.0, float32(score.midgame)/100.0,
			float32(white.endgame)/100.0, float32(black.endgame)/100.0, float32(score.endgame)/100.0,
			float32(score.blended(phase))/100.0)
	}
	fmt.Printf("%-12s    -      -    %5.2f  |    -      -    %5.2f  >  %5.2f\n\n", `Final Score`,
		float32(final.midgame)/100.0, float32(final.endgame)/100.0, float32(final.blended(phase))/100.0)
}

func SummaryAlt(metrics map[string]interface{}) {
	phase := metrics[`Phase`].(int)
	tally := metrics[`PST`].(Score)
	final := metrics[`Final`].(Score)

	fmt.Println()
	fmt.Printf("Metric            White     |     Black     |     Total     | Blended \n")
	fmt.Printf("                mid   end   |   mid   end   |   mid   end   |  (%d)  \n", phase)
	fmt.Printf("----------------------------+---------------+---------------+---------\n")
	fmt.Printf("%-12s     -     -    |    -     -    | %5.2f  %5.2f  > %5.2f\n", `PST`,
		float32(tally.midgame)/100.0, float32(tally.endgame)/100.0,
		float32(tally.blended(phase))/100.0)

	for _, tag := range([]string{`Tempo`, `Threats`, `Pawns`, `+Pieces`, `-Knights`, `-Bishops`, `-Rooks`, `-Queens`, `+King`, `-Cover`, `-Safety`}) {
		white := metrics[tag].(Total).white
		black := metrics[tag].(Total).black

		var score Score
		score.add(white).subtract(black)

		if tag[0:1] == `+` {
			tag = tag[1:]
		} else if tag[0:1] == `-` {
			tag = `  ` + tag[1:]
		}

		fmt.Printf("%-12s  %5.2f  %5.2f  | %5.2f  %5.2f  | %5.2f  %5.2f  > %5.2f\n", tag,
			float32(white.midgame)/100.0, float32(white.endgame)/100.0,
			float32(black.midgame)/100.0, float32(black.endgame)/100.0,
			float32(score.midgame)/100.0, float32(score.endgame)/100.0,
			float32(score.blended(phase))/100.0)
	}
	fmt.Printf("%-12s     -     -    |    -     -    | %5.2f  %5.2f  > %5.2f\n\n", `Final Score`,
		float32(final.midgame)/100.0, float32(final.endgame)/100.0,
		float32(final.blended(phase))/100.0)
}

// Logging wrapper around fmt.Printf() that could be turned on as needed. Typical
// usage is Log(true); defer Log(false) in tests.
func Log(args ...interface{}) {
	switch len(args) {
	case 0:
		// Calling Log() with no arguments flips the logging setting.
		Settings.Log = !Settings.Log
		Settings.Fancy = !Settings.Fancy
	case 1:
		switch args[0].(type) {
		case bool:
			Settings.Log = args[0].(bool)
			Settings.Fancy = args[0].(bool)
		default:
			if Settings.Log {
				fmt.Println(args...)
			}
		}
	default:
		if Settings.Log {
			fmt.Printf(args[0].(string), args[1:]...)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os"
	"regexp"
)

func getIP(uuid string) string {
	nameRe := regexp.MustCompile(`.*name=([A-F0-9\-]+)`)
	ipRe := regexp.MustCompile(`.*ip_address=([0-9\.]+)`)

	file, err := os.Open("/var/db/dhcpd_leases")
	if err != nil {
		log.Fatalln(err)
	}

	defer file.Close()
	leases, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatalln(err)
	}

	lines := string(leases)
	names := nameRe.FindStringSubmatch(lines)
	ips := ipRe.FindStringSubmatch(lines)
	for i, name := range names {
		log.Println("name", name)
		if name == uuid {
			return ips[i]
		}
	}

	return ""
}
<commit_msg>remove extra file<commit_after><|endoftext|>


<commit_before>package gift

import (
	"image"
	"image/draw"
	"math"
	"runtime"
	"sync"
	"sync/atomic"
)

// parallelize parallelizes the data processing if enabled is true.
func parallelize(enabled bool, datamin, datamax int, fn func(pmin, pmax int)) {
	datasize := datamax - datamin
	partsize := datasize

	numGoroutines := 1
	if enabled {
		numProcs := runtime.GOMAXPROCS(0)
		if numProcs > 1 {
			numGoroutines = numProcs
			partsize = partsize / (numGoroutines * 10)
			if partsize < 1 {
				partsize = 1
			}
		}
	}

	if numGoroutines == 1 {
		fn(datamin, datamax)
	} else {
		var wg sync.WaitGroup
		wg.Add(numGoroutines)
		idx := int64(datamin)

		for p := 0; p < numGoroutines; p++ {
			go func() {
				defer wg.Done()
				for {
					pmin := int(atomic.AddInt64(&idx, int64(partsize))) - partsize
					if pmin >= datamax {
						break
					}
					pmax := pmin + partsize
					if pmax > datamax {
						pmax = datamax
					}
					fn(pmin, pmax)
				}
			}()
		}

		wg.Wait()
	}
}

func absf32(x float32) float32 {
	if x < 0 {
		return -x
	}
	return x
}

func minf32(x, y float32) float32 {
	if x < y {
		return x
	}
	return y
}

func maxf32(x, y float32) float32 {
	if x > y {
		return x
	}
	return y
}

func powf32(x, y float32) float32 {
	return float32(math.Pow(float64(x), float64(y)))
}

func logf32(x float32) float32 {
	return float32(math.Log(float64(x)))
}

func expf32(x float32) float32 {
	return float32(math.Exp(float64(x)))
}

func sincosf32(a float32) (float32, float32) {
	sin, cos := math.Sincos(math.Pi * float64(a) / 180)
	return float32(sin), float32(cos)
}

func floorf32(x float32) float32 {
	return float32(math.Floor(float64(x)))
}

func sqrtf32(x float32) float32 {
	return float32(math.Sqrt(float64(x)))
}

func minint(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func maxint(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func sort(data []float32) {
	n := len(data)

	if n < 2 {
		return
	}

	if n <= 20 {
		for i := 1; i < n; i++ {
			x := data[i]
			j := i - 1
			for ; j >= 0 && data[j] > x; j-- {
				data[j+1] = data[j]
			}
			data[j+1] = x
		}
		return
	}

	i := 0
	j := n - 1
	x := data[n/2]
	for i <= j {
		for data[i] < x {
			i++
		}
		for data[j] > x {
			j--
		}
		if i <= j {
			data[i], data[j] = data[j], data[i]
			i++
			j--
		}
	}
	if j > 0 {
		sort(data[:j+1])
	}
	if i < n-1 {
		sort(data[i:])
	}
}

// createTempImage creates a temporary image.
func createTempImage(r image.Rectangle) draw.Image {
	return image.NewNRGBA64(r)
}

// isOpaque checks if the given image is opaque.
func isOpaque(img image.Image) bool {
	switch img := img.(type) {
	case *image.NRGBA:
		return img.Opaque()
	case *image.NRGBA64:
		return img.Opaque()
	case *image.RGBA:
		return img.Opaque()
	case *image.RGBA64:
		return img.Opaque()
	case *image.Gray:
		return true
	case *image.Gray16:
		return true
	case *image.YCbCr:
		return true
	case *image.Paletted:
		return img.Opaque()
	}
	return false
}

// genDisk generates a disk-shaped kernel.
func genDisk(ksize int) []float32 {
	if ksize%2 == 0 {
		ksize--
	}
	if ksize < 1 {
		return []float32{}
	}
	disk := make([]float32, ksize*ksize)
	kcenter := ksize / 2
	for i := 0; i < ksize; i++ {
		for j := 0; j < ksize; j++ {
			x := kcenter - i
			y := kcenter - j
			r := math.Sqrt(float64(x*x + y*y))
			if r <= float64(ksize/2) {
				disk[j*ksize+i] = 1
			}
		}
	}
	return disk
}

// copyimage copies an image from src to dst.
func copyimage(dst draw.Image, src image.Image, options *Options) {
	if options == nil {
		options = &defaultOptions
	}

	srcb := src.Bounds()
	dstb := dst.Bounds()
	pixGetter := newPixelGetter(src)
	pixSetter := newPixelSetter(dst)

	parallelize(options.Parallelization, srcb.Min.Y, srcb.Max.Y, func(pmin, pmax int) {
		for srcy := pmin; srcy < pmax; srcy++ {
			for srcx := srcb.Min.X; srcx < srcb.Max.X; srcx++ {
				dstx := dstb.Min.X + srcx - srcb.Min.X
				dsty := dstb.Min.Y + srcy - srcb.Min.Y
				pixSetter.setPixel(dstx, dsty, pixGetter.getPixel(srcx, srcy))
			}
		}
	})
}

type copyimageFilter struct{}

func (p *copyimageFilter) Bounds(srcBounds image.Rectangle) (dstBounds image.Rectangle) {
	dstBounds = image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy())
	return
}

func (p *copyimageFilter) Draw(dst draw.Image, src image.Image, options *Options) {
	copyimage(dst, src, options)
}
<commit_msg>parallelize: use one data partition per goroutine<commit_after>package gift

import (
	"image"
	"image/draw"
	"math"
	"runtime"
	"sync"
	"sync/atomic"
)

// parallelize parallelizes the data processing if enabled is true.
func parallelize(enabled bool, datamin, datamax int, fn func(pmin, pmax int)) {
	datasize := datamax - datamin
	partsize := datasize

	numGoroutines := 1
	if enabled {
		numProcs := runtime.GOMAXPROCS(0)
		if numProcs > 1 {
			numGoroutines = numProcs
			partsize = partsize / numGoroutines
			if partsize < 1 {
				partsize = 1
			}
		}
	}

	if numGoroutines == 1 {
		fn(datamin, datamax)
	} else {
		var wg sync.WaitGroup
		wg.Add(numGoroutines)
		idx := int64(datamin)

		for p := 0; p < numGoroutines; p++ {
			go func() {
				defer wg.Done()
				for {
					pmin := int(atomic.AddInt64(&idx, int64(partsize))) - partsize
					if pmin >= datamax {
						break
					}
					pmax := pmin + partsize
					if pmax > datamax {
						pmax = datamax
					}
					fn(pmin, pmax)
				}
			}()
		}

		wg.Wait()
	}
}

func absf32(x float32) float32 {
	if x < 0 {
		return -x
	}
	return x
}

func minf32(x, y float32) float32 {
	if x < y {
		return x
	}
	return y
}

func maxf32(x, y float32) float32 {
	if x > y {
		return x
	}
	return y
}

func powf32(x, y float32) float32 {
	return float32(math.Pow(float64(x), float64(y)))
}

func logf32(x float32) float32 {
	return float32(math.Log(float64(x)))
}

func expf32(x float32) float32 {
	return float32(math.Exp(float64(x)))
}

func sincosf32(a float32) (float32, float32) {
	sin, cos := math.Sincos(math.Pi * float64(a) / 180)
	return float32(sin), float32(cos)
}

func floorf32(x float32) float32 {
	return float32(math.Floor(float64(x)))
}

func sqrtf32(x float32) float32 {
	return float32(math.Sqrt(float64(x)))
}

func minint(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func maxint(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func sort(data []float32) {
	n := len(data)

	if n < 2 {
		return
	}

	if n <= 20 {
		for i := 1; i < n; i++ {
			x := data[i]
			j := i - 1
			for ; j >= 0 && data[j] > x; j-- {
				data[j+1] = data[j]
			}
			data[j+1] = x
		}
		return
	}

	i := 0
	j := n - 1
	x := data[n/2]
	for i <= j {
		for data[i] < x {
			i++
		}
		for data[j] > x {
			j--
		}
		if i <= j {
			data[i], data[j] = data[j], data[i]
			i++
			j--
		}
	}
	if j > 0 {
		sort(data[:j+1])
	}
	if i < n-1 {
		sort(data[i:])
	}
}

// createTempImage creates a temporary image.
func createTempImage(r image.Rectangle) draw.Image {
	return image.NewNRGBA64(r)
}

// isOpaque checks if the given image is opaque.
func isOpaque(img image.Image) bool {
	switch img := img.(type) {
	case *image.NRGBA:
		return img.Opaque()
	case *image.NRGBA64:
		return img.Opaque()
	case *image.RGBA:
		return img.Opaque()
	case *image.RGBA64:
		return img.Opaque()
	case *image.Gray:
		return true
	case *image.Gray16:
		return true
	case *image.YCbCr:
		return true
	case *image.Paletted:
		return img.Opaque()
	}
	return false
}

// genDisk generates a disk-shaped kernel.
func genDisk(ksize int) []float32 {
	if ksize%2 == 0 {
		ksize--
	}
	if ksize < 1 {
		return []float32{}
	}
	disk := make([]float32, ksize*ksize)
	kcenter := ksize / 2
	for i := 0; i < ksize; i++ {
		for j := 0; j < ksize; j++ {
			x := kcenter - i
			y := kcenter - j
			r := math.Sqrt(float64(x*x + y*y))
			if r <= float64(ksize/2) {
				disk[j*ksize+i] = 1
			}
		}
	}
	return disk
}

// copyimage copies an image from src to dst.
func copyimage(dst draw.Image, src image.Image, options *Options) {
	if options == nil {
		options = &defaultOptions
	}

	srcb := src.Bounds()
	dstb := dst.Bounds()
	pixGetter := newPixelGetter(src)
	pixSetter := newPixelSetter(dst)

	parallelize(options.Parallelization, srcb.Min.Y, srcb.Max.Y, func(pmin, pmax int) {
		for srcy := pmin; srcy < pmax; srcy++ {
			for srcx := srcb.Min.X; srcx < srcb.Max.X; srcx++ {
				dstx := dstb.Min.X + srcx - srcb.Min.X
				dsty := dstb.Min.Y + srcy - srcb.Min.Y
				pixSetter.setPixel(dstx, dsty, pixGetter.getPixel(srcx, srcy))
			}
		}
	})
}

type copyimageFilter struct{}

func (p *copyimageFilter) Bounds(srcBounds image.Rectangle) (dstBounds image.Rectangle) {
	dstBounds = image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy())
	return
}

func (p *copyimageFilter) Draw(dst draw.Image, src image.Image, options *Options) {
	copyimage(dst, src, options)
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 go_kafka_client

import (
	"time"
	"math"
	"fmt"
	"sync"
)

type WorkerManager struct {
	Config *ConsumerConfig
	Strategy         WorkerStrategy
	FailureHook FailedCallback
	FailedAttemptHook FailedAttemptCallback
	Workers          []*Worker
	AvailableWorkers chan *Worker
	CurrentBatch map[TaskId]*Task
	InputChannel     chan [] *Message
	OutputChannel    chan map[TopicAndPartition]int64
	LargestOffsets map[TopicAndPartition]int64
	FailCounter *FailureCounter
}

func (wm *WorkerManager) String() string {
	return fmt.Sprintf("%s-workerManager", wm.Config.ConsumerId)
}

func (wm *WorkerManager) Start() {
	for {
		batch := <-wm.InputChannel
		for _, message := range batch {
			wm.CurrentBatch[TaskId{ TopicAndPartition{ message.Topic, message.Partition }, message.Offset }] = &Task{
				Msg: message,
			}
		}

		for _, task := range wm.CurrentBatch {
			worker := <-wm.AvailableWorkers
			worker.Start(task, wm.Strategy)
		}

		wm.awaitResult()

		wm.OutputChannel <- wm.LargestOffsets
		wm.LargestOffsets = make(map[TopicAndPartition]int64)
	}
}

func (wm *WorkerManager) Stop() chan bool {
	finished := make(chan bool)
	go func() {
		for _, worker := range wm.Workers {
			worker.Close()
		}
		finished <- true
	}()

	return finished
}

func (wm *WorkerManager) IsBatchProcessed() bool {
	return len(wm.CurrentBatch) == 0
}

func (wm *WorkerManager) awaitResult() {
	outputChannels := make([]chan WorkerResult, wm.Config.NumWorkers)
	for i, worker := range wm.Workers {
		outputChannels[i] = worker.OutputChannel
	}

	resultsChannel := make(chan WorkerResult)
	stopRedirecting, timeoutChannel := RedirectChannelsToWithTimeout(outputChannels, resultsChannel, wm.Config.WorkerBatchTimeout)
	for {
		select {
		case result := <- resultsChannel: {
			task := wm.CurrentBatch[result.Id()]
			if result.Success() {
				wm.taskIsDone(result)
			} else {
				Warnf(wm, "Worker task %s has failed", result.Id())
				task.Retries++
				if task.Retries >= wm.Config.MaxWorkerRetries {
					Errorf(wm, "Worker task %s has failed after %d retries", result.Id(), wm.Config.MaxWorkerRetries)

					wm.taskIsDone(result)
					if wm.FailCounter.Failed() {
						wm.FailureHook(wm)
					} else {
						wm.FailedAttemptHook(task, result)
					}
				} else {
					Warnf(wm, "Retrying worker task %s %dth time", result.Id(), task.Retries)
					time.Sleep(wm.Config.WorkerBackoff)
					go task.Callee.Start(task, wm.Strategy)
				}
			}

			if wm.IsBatchProcessed() {
				stopRedirecting <- true
				break
			}
		}
		case <-timeoutChannel: {
			Errorf(wm, "Worker batch has timed out")
			stopRedirecting <- true
			outputChannels = make([] chan WorkerResult, 0)
			for _, task := range wm.CurrentBatch {
				channel := make(chan WorkerResult)
				outputChannels = append(outputChannels, channel)
				task.Callee.OutputChannel = channel
				wm.AvailableWorkers <- task.Callee
			}

			wm.CurrentBatch = make(map[TaskId]*Task)

			stopRedirecting, timeoutChannel = RedirectChannelsToWithTimeout(outputChannels, resultsChannel, wm.Config.WorkerBatchTimeout)

			break
		}
		}
	}
}

func (wm *WorkerManager) taskIsDone(result WorkerResult) {
	key := result.Id().TopicPartition
	wm.LargestOffsets[key] = int64(math.Max(float64(wm.LargestOffsets[key]), float64(result.Id().Offset)))
	wm.AvailableWorkers <- wm.CurrentBatch[result.Id()].Callee
	delete(wm.CurrentBatch, result.Id())
}

func NewWorkerManager(config *ConsumerConfig, batchOutputChannel chan map[TopicAndPartition]int64) *WorkerManager {
	workers := make([]*Worker, config.NumWorkers)
	availableWorkers := make(chan *Worker, config.NumWorkers)
	for i := 0; i < config.NumWorkers; i++ {
		workers[i] = &Worker{
			OutputChannel: make(chan WorkerResult),
			CloseTimeout: config.WorkerCloseTimeout,
			TaskTimeout: config.WorkerTaskTimeout,
		}
		availableWorkers <- workers[i]
	}

	return &WorkerManager {
		Config: config,
		Strategy: config.Strategy,
		FailureHook: config.WorkerFailureCallback,
		FailedAttemptHook: config.WorkerFailedAttemptCallback,
		AvailableWorkers: availableWorkers,
		Workers: workers,
		InputChannel: make(chan [] *Message),
		OutputChannel: batchOutputChannel,
		CurrentBatch: make(map[TaskId]*Task),
		LargestOffsets: make(map[TopicAndPartition]int64),
		FailCounter: NewFailureCounter(config.WorkerRetryThreshold, config.WorkerConsideredFailedTimeWindow),
	}
}

type Worker struct {
	OutputChannel chan WorkerResult
	CloseTimeout time.Duration
	TaskTimeout time.Duration
	Closed bool
}

func (w *Worker) Start(task *Task, strategy WorkerStrategy) {
	task.Callee = w
	go func() {
		resultChannel := make(chan WorkerResult)
		go func() {resultChannel <- strategy(w, task.Msg)}()
		select {
		case result := <-resultChannel: {
			w.OutputChannel <- result
		}
		case <-time.After(w.TaskTimeout): {
			w.OutputChannel <- &TimedOutResult{task.Id()}
		}
		}
	}()
}

func (w *Worker) Close() WorkerResult {
	if !w.Closed {
		w.Closed = true
		select {
		case result := <- w.OutputChannel: {
			return result
		}
		case <- time.After(w.CloseTimeout): {
			Warnf(w, "Worker failed to close within %f seconds", w.CloseTimeout.Seconds())
			return nil
		}
		}
	}

	return nil
}

type WorkerStrategy func(*Worker, *Message) WorkerResult

type FailedCallback func(*WorkerManager)

type FailedAttemptCallback func(*Task, WorkerResult)

type FailureCounter struct {
	count int32
	failed bool
	countLock sync.Mutex
	failedThreshold int32
}

func NewFailureCounter(FailedThreshold int32, WorkerConsideredFailedTimeWindow time.Duration) *FailureCounter {
	counter := &FailureCounter {
		failedThreshold : FailedThreshold,
	}
	go func() {
		for {
			select {
			case <- time.After(WorkerConsideredFailedTimeWindow): {
				if counter.count >= FailedThreshold {
					counter.failed = true
					return
				} else {
					InLock(&counter.countLock, func() {
						counter.count = 0
					})
				}
			}
			}
		}
	}()
	return counter
}

func (f *FailureCounter) Failed() bool {
	InLock(&f.countLock, func() { f.count++ })
	return f.count >= f.failedThreshold || f.failed
}

type Task struct {
	Msg *Message
	Retries int
	Callee *Worker
}

func (t *Task) Id() TaskId {
	return TaskId{TopicAndPartition{t.Msg.Topic, t.Msg.Partition}, t.Msg.Offset}
}

type WorkerResult interface {
	Id() TaskId
	Success() bool
}

type SuccessfulResult struct {
	id TaskId
}

func (wr *SuccessfulResult) Id() TaskId {
	return wr.id
}

func (wr *SuccessfulResult) Success() bool {
	return true
}

type ProcessingFailedResult struct {
	id TaskId
}

func (wr *ProcessingFailedResult) Id() TaskId {
	return wr.id
}

func (wr *ProcessingFailedResult) Success() bool {
	return false
}

type TimedOutResult struct {
	id TaskId
}

func (wr *TimedOutResult) Id() TaskId {
	return wr.id
}

func (wr *TimedOutResult) Success() bool {
	return false
}

type TaskId struct {
	TopicPartition TopicAndPartition
	Offset         int64
}

func (tid *TaskId) String() string {
	return fmt.Sprintf("%s, Offset: %d", tid.TopicPartition, tid.Offset)
}
<commit_msg>fixed issue when batch is larger than workers available<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 go_kafka_client

import (
	"time"
	"math"
	"fmt"
	"sync"
)

type WorkerManager struct {
	Config *ConsumerConfig
	Strategy         WorkerStrategy
	FailureHook FailedCallback
	FailedAttemptHook FailedAttemptCallback
	Workers          []*Worker
	AvailableWorkers chan *Worker
	CurrentBatch map[TaskId]*Task
	InputChannel     chan [] *Message
	OutputChannel    chan map[TopicAndPartition]int64
	LargestOffsets map[TopicAndPartition]int64
	FailCounter *FailureCounter
}

func (wm *WorkerManager) String() string {
	return fmt.Sprintf("%s-workerManager", wm.Config.ConsumerId)
}

func (wm *WorkerManager) Start() {
	batchProcessed := make(chan bool)
	go wm.processBatch(batchProcessed)
	for {
		batch := <-wm.InputChannel
		for _, message := range batch {
			wm.CurrentBatch[TaskId{ TopicAndPartition{ message.Topic, message.Partition }, message.Offset }] = &Task{
				Msg: message,
			}
		}

		for _, task := range wm.CurrentBatch {
			worker := <-wm.AvailableWorkers
			worker.Start(task, wm.Strategy)
		}

		<-batchProcessed

		wm.OutputChannel <- wm.LargestOffsets
		wm.LargestOffsets = make(map[TopicAndPartition]int64)
	}
}

func (wm *WorkerManager) Stop() chan bool {
	finished := make(chan bool)
	go func() {
		for _, worker := range wm.Workers {
			worker.Close()
		}
		finished <- true
	}()

	return finished
}

func (wm *WorkerManager) IsBatchProcessed() bool {
	return len(wm.CurrentBatch) == 0
}

func (wm *WorkerManager) processBatch(batchProcessed chan bool) {
	outputChannels := make([]chan WorkerResult, wm.Config.NumWorkers)
	for i, worker := range wm.Workers {
		outputChannels[i] = worker.OutputChannel
	}

	resultsChannel := make(chan WorkerResult)
	stopRedirecting, timeoutChannel := RedirectChannelsToWithTimeout(outputChannels, resultsChannel, wm.Config.WorkerBatchTimeout)
	for {
		select {
		case result := <- resultsChannel: {
			task := wm.CurrentBatch[result.Id()]
			if result.Success() {
				wm.taskIsDone(result)
			} else {
				Warnf(wm, "Worker task %s has failed", result.Id())
				task.Retries++
				if task.Retries >= wm.Config.MaxWorkerRetries {
					Errorf(wm, "Worker task %s has failed after %d retries", result.Id(), wm.Config.MaxWorkerRetries)

					wm.taskIsDone(result)
					if wm.FailCounter.Failed() {
						wm.FailureHook(wm)
					} else {
						wm.FailedAttemptHook(task, result)
					}
				} else {
					Warnf(wm, "Retrying worker task %s %dth time", result.Id(), task.Retries)
					time.Sleep(wm.Config.WorkerBackoff)
					go task.Callee.Start(task, wm.Strategy)
				}
			}

			if wm.IsBatchProcessed() {
				stopRedirecting <- true
				batchProcessed <- true
			}
		}
		case <-timeoutChannel: {
			Errorf(wm, "Worker batch has timed out")
			stopRedirecting <- true
			outputChannels = make([] chan WorkerResult, 0)
			for _, task := range wm.CurrentBatch {
				channel := make(chan WorkerResult)
				outputChannels = append(outputChannels, channel)
				task.Callee.OutputChannel = channel
				wm.AvailableWorkers <- task.Callee
			}

			wm.CurrentBatch = make(map[TaskId]*Task)

			stopRedirecting, timeoutChannel = RedirectChannelsToWithTimeout(outputChannels, resultsChannel, wm.Config.WorkerBatchTimeout)

			batchProcessed <- true
		}
		}
	}
}

func (wm *WorkerManager) taskIsDone(result WorkerResult) {
	key := result.Id().TopicPartition
	wm.LargestOffsets[key] = int64(math.Max(float64(wm.LargestOffsets[key]), float64(result.Id().Offset)))
	wm.AvailableWorkers <- wm.CurrentBatch[result.Id()].Callee
	delete(wm.CurrentBatch, result.Id())
}

func NewWorkerManager(config *ConsumerConfig, batchOutputChannel chan map[TopicAndPartition]int64) *WorkerManager {
	workers := make([]*Worker, config.NumWorkers)
	availableWorkers := make(chan *Worker, config.NumWorkers)
	for i := 0; i < config.NumWorkers; i++ {
		workers[i] = &Worker{
			OutputChannel: make(chan WorkerResult),
			CloseTimeout: config.WorkerCloseTimeout,
			TaskTimeout: config.WorkerTaskTimeout,
		}
		availableWorkers <- workers[i]
	}

	return &WorkerManager {
		Config: config,
		Strategy: config.Strategy,
		FailureHook: config.WorkerFailureCallback,
		FailedAttemptHook: config.WorkerFailedAttemptCallback,
		AvailableWorkers: availableWorkers,
		Workers: workers,
		InputChannel: make(chan [] *Message),
		OutputChannel: batchOutputChannel,
		CurrentBatch: make(map[TaskId]*Task),
		LargestOffsets: make(map[TopicAndPartition]int64),
		FailCounter: NewFailureCounter(config.WorkerRetryThreshold, config.WorkerConsideredFailedTimeWindow),
	}
}

type Worker struct {
	OutputChannel chan WorkerResult
	CloseTimeout time.Duration
	TaskTimeout time.Duration
	Closed bool
}

func (w *Worker) Start(task *Task, strategy WorkerStrategy) {
	task.Callee = w
	go func() {
		resultChannel := make(chan WorkerResult)
		go func() {resultChannel <- strategy(w, task.Msg)}()
		select {
		case result := <-resultChannel: {
			w.OutputChannel <- result
		}
		case <-time.After(w.TaskTimeout): {
			w.OutputChannel <- &TimedOutResult{task.Id()}
		}
		}
	}()
}

func (w *Worker) Close() WorkerResult {
	if !w.Closed {
		w.Closed = true
		select {
		case result := <- w.OutputChannel: {
			return result
		}
		case <- time.After(w.CloseTimeout): {
			Warnf(w, "Worker failed to close within %f seconds", w.CloseTimeout.Seconds())
			return nil
		}
		}
	}

	return nil
}

type WorkerStrategy func(*Worker, *Message) WorkerResult

type FailedCallback func(*WorkerManager)

type FailedAttemptCallback func(*Task, WorkerResult)

type FailureCounter struct {
	count int32
	failed bool
	countLock sync.Mutex
	failedThreshold int32
}

func NewFailureCounter(FailedThreshold int32, WorkerConsideredFailedTimeWindow time.Duration) *FailureCounter {
	counter := &FailureCounter {
		failedThreshold : FailedThreshold,
	}
	go func() {
		for {
			select {
			case <- time.After(WorkerConsideredFailedTimeWindow): {
				if counter.count >= FailedThreshold {
					counter.failed = true
					return
				} else {
					InLock(&counter.countLock, func() {
						counter.count = 0
					})
				}
			}
			}
		}
	}()
	return counter
}

func (f *FailureCounter) Failed() bool {
	InLock(&f.countLock, func() { f.count++ })
	return f.count >= f.failedThreshold || f.failed
}

type Task struct {
	Msg *Message
	Retries int
	Callee *Worker
}

func (t *Task) Id() TaskId {
	return TaskId{TopicAndPartition{t.Msg.Topic, t.Msg.Partition}, t.Msg.Offset}
}

type WorkerResult interface {
	Id() TaskId
	Success() bool
}

type SuccessfulResult struct {
	id TaskId
}

func (wr *SuccessfulResult) Id() TaskId {
	return wr.id
}

func (wr *SuccessfulResult) Success() bool {
	return true
}

type ProcessingFailedResult struct {
	id TaskId
}

func (wr *ProcessingFailedResult) Id() TaskId {
	return wr.id
}

func (wr *ProcessingFailedResult) Success() bool {
	return false
}

type TimedOutResult struct {
	id TaskId
}

func (wr *TimedOutResult) Id() TaskId {
	return wr.id
}

func (wr *TimedOutResult) Success() bool {
	return false
}

type TaskId struct {
	TopicPartition TopicAndPartition
	Offset         int64
}

func (tid *TaskId) String() string {
	return fmt.Sprintf("%s, Offset: %d", tid.TopicPartition, tid.Offset)
}
<|endoftext|>


<commit_before>package meritop

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"

	"github.com/coreos/go-etcd/etcd"
)

type taskRole int

const (
	noneRole taskRole = iota
	parentRole
	childRole
)

const (
	DataRequestPrefix string = "/datareq"
	DataRequestTaskID string = "taskID"
	DataRequestReq    string = "req"
)

// This interface is used by application during taskgraph configuration phase.
type Bootstrap interface {
	// These allow application developer to set the task configuration so framework
	// implementation knows which task to invoke at each node.
	SetTaskBuilder(taskBuilder TaskBuilder)

	// This allow the application to specify how tasks are connection at each epoch
	SetTopology(topology Topology)

	// After all the configure is done, driver need to call start so that all
	// nodes will get into the event loop to run the application.
	Start()
}

// Note that framework can decide how update can be done, and how to serve the updatelog.
type BackedUpFramework interface {
	// Ask framework to do update on this update on this task, which consists
	// of one primary and some backup copies.
	Update(taskID uint64, log UpdateLog)
}

type Framework interface {
	// These two are useful for task to inform the framework their status change.
	// metaData has to be really small, since it might be stored in etcd.
	// Flags that parent/child's metadata of the current task is ready.
	FlagParentMetaReady(meta string)
	FlagChildMetaReady(meta string)

	// This allow the task implementation query its neighbors.
	GetTopology() Topology

	// Some task can inform all participating tasks to exit.
	Exit()

	// Some task can inform all participating tasks to new epoch
	SetEpoch(epoch uint64)

	GetLogger() log.Logger

	// Request data from parent or children.
	DataRequest(toID uint64, meta string)

	// This is used to figure out taskid for current node
	GetTaskID() uint64
}

type framework struct {
	// These should be passed by outside world
	name     string
	etcdURLs []string

	// user defined interfaces
	task     Task
	topology Topology

	taskID        uint64
	epoch         uint64
	etcdClient    *etcd.Client
	stops         []chan bool
	ln            net.Listener
	addressMap    map[uint64]string // taskId -> node address. Maybe in etcd later.
	dataRespChan  chan *dataResponse
	dataCloseChan chan struct{}
}

type dataResponse struct {
	taskID uint64
	req    string
	data   []byte
}

func (f *framework) parentOrChild(taskID uint64) taskRole {
	for _, id := range f.topology.GetParents(f.epoch) {
		if taskID == id {
			return parentRole
		}
	}

	for _, id := range f.topology.GetChildren(f.epoch) {
		if taskID == id {
			return childRole
		}
	}
	return noneRole
}

func (f *framework) start() {
	f.etcdClient = etcd.NewClient(f.etcdURLs)
	f.topology.SetTaskID(f.taskID)
	f.epoch = 0
	f.stops = make([]chan bool, 0)
	f.dataRespChan = make(chan *dataResponse, 100)
	f.dataCloseChan = make(chan struct{})

	// setup etcd watches
	// - create self's parent and child meta flag
	// - watch parents' child meta flag
	// - watch children's parent meta flag
	f.etcdClient.Create(MakeParentMetaPath(f.name, f.GetTaskID()), "", 0)
	f.etcdClient.Create(MakeChildMetaPath(f.name, f.GetTaskID()), "", 0)
	parentStops := f.watchAll(parentRole, f.topology.GetParents(f.epoch))
	childStops := f.watchAll(childRole, f.topology.GetChildren(f.epoch))
	f.stops = append(f.stops, parentStops...)
	f.stops = append(f.stops, childStops...)

	go f.startHttpServerForDataRequest()
	go f.dataResponseReceiver()

	// After framework init finished, it should init task.
	f.task.SetEpoch(f.epoch)
	f.task.Init(f.taskID, f, nil)
}

func newDataReqHandler(f *framework) http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc(DataRequestPrefix, func(w http.ResponseWriter, r *http.Request) {
		q := r.URL.Query()
		fromIDStr := q.Get(DataRequestTaskID)
		fromID, err := strconv.ParseUint(fromIDStr, 0, 64)
		if err != nil {
			log.Fatalf("taskID in query couldn't be parsed: %s", fromIDStr)
		}
		req := q.Get(DataRequestReq)
		var serveData func(uint64, string) []byte
		switch f.parentOrChild(fromID) {
		case parentRole:
			serveData = f.task.ServeAsChild
		case childRole:
			serveData = f.task.ServeAsParent
		default:
			panic("unimplemented")
		}
		d := serveData(fromID, req)

		if _, err := w.Write(d); err != nil {
			log.Printf("response write errored: %v", err)
		}
	})
	return mux
}

// Framework http server for data request.
// Each request will be in the format: "/datareq/{taskID}/{req}".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHttpServerForDataRequest() {
	log.Printf("framework: serving http data request on %s", f.ln.Addr())
	if err := http.Serve(f.ln, newDataReqHandler(f)); err != nil {
		log.Fatalf("http.Serve() returns error: %v\n", err)
	}
}

// Framework event loop handles data response for requests sent in DataRequest().
func (f *framework) dataResponseReceiver() {
	for {
		select {
		case dataResp := <-f.dataRespChan:
			var dataReady func(uint64, string, []byte)
			switch f.parentOrChild(dataResp.taskID) {
			case parentRole:
				dataReady = f.task.ParentDataReady
			case childRole:
				dataReady = f.task.ChildDataReady
			default:
				panic("unimplemented")
			}

			go dataReady(dataResp.taskID, dataResp.req, dataResp.data)
		case <-f.dataCloseChan:
			return
		}
	}
}

func (f *framework) stop() {
	close(f.dataCloseChan)
	for _, c := range f.stops {
		close(c)
	}
}

func (f *framework) FlagParentMetaReady(meta string) {
	f.etcdClient.Set(
		MakeParentMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) FlagChildMetaReady(meta string) {
	f.etcdClient.Set(
		MakeChildMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) SetEpoch(epoch uint64) {
	f.epoch = epoch
}

func (f *framework) watchAll(who taskRole, taskIDs []uint64) []chan bool {
	stops := make([]chan bool, len(taskIDs))

	for i, taskID := range taskIDs {
		receiver := make(chan *etcd.Response, 10)
		stop := make(chan bool, 1)
		stops[i] = stop

		var watchPath string
		var taskCallback func(uint64, string)
		switch who {
		case parentRole:
			// Watch parent's child.
			watchPath = MakeChildMetaPath(f.name, taskID)
			taskCallback = f.task.ParentMetaReady
		case childRole:
			// Watch child's parent.
			watchPath = MakeParentMetaPath(f.name, taskID)
			taskCallback = f.task.ChildMetaReady
		default:
			panic("unimplemented")
		}

		go f.etcdClient.Watch(watchPath, 0, false, receiver, stop)
		go func(receiver <-chan *etcd.Response, taskID uint64) {
			for {
				resp, ok := <-receiver
				if !ok {
					return
				}
				if resp.Action != "set" {
					continue
				}
				taskCallback(taskID, resp.Node.Value)
			}
		}(receiver, taskID)
	}
	return stops
}

func (f *framework) DataRequest(toID uint64, req string) {
	// getAddressFromTaskID
	addr, ok := f.addressMap[toID]
	if !ok {
		log.Fatalf("ID = %d not found", toID)
		return
	}
	u := url.URL{
		Scheme: "http",
		Host:   addr,
		Path:   DataRequestPrefix,
	}
	q := u.Query()
	q.Add(DataRequestTaskID, strconv.FormatUint(f.taskID, 10))
	q.Add(DataRequestReq, req)
	u.RawQuery = q.Encode()
	urlStr := u.String()
	// send request
	// pass the response to the awaiting event loop for data response
	go func(urlStr string) {
		resp, err := http.Get(urlStr)
		if err != nil {
			log.Fatalf("http.Get(%s) returns error: %v", urlStr, err)
		}
		if resp.StatusCode != 200 {
			log.Fatalf("response code = %d, assume = %d", resp.StatusCode, 200)
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("ioutil.ReadAll(%v) returns error: %v", resp.Body, err)
		}
		dataResp := &dataResponse{
			taskID: toID,
			req:    req,
			data:   data,
		}
		f.dataRespChan <- dataResp
	}(urlStr)
}

func (f *framework) GetTopology() Topology {
	panic("unimplemented")
}

func (f *framework) Exit() {
}

func (f *framework) GetLogger() log.Logger {
	panic("unimplemented")
}

func (f *framework) GetTaskID() uint64 {
	return f.taskID
}
<commit_msg>minor fix based on feedback<commit_after>package meritop

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"

	"github.com/coreos/go-etcd/etcd"
)

type taskRole int

const (
	roleNone taskRole = iota
	roleParent
	roleChild
)

const (
	DataRequestPrefix string = "/datareq"
	DataRequestTaskID string = "taskID"
	DataRequestReq    string = "req"
)

// This interface is used by application during taskgraph configuration phase.
type Bootstrap interface {
	// These allow application developer to set the task configuration so framework
	// implementation knows which task to invoke at each node.
	SetTaskBuilder(taskBuilder TaskBuilder)

	// This allow the application to specify how tasks are connection at each epoch
	SetTopology(topology Topology)

	// After all the configure is done, driver need to call start so that all
	// nodes will get into the event loop to run the application.
	Start()
}

// Note that framework can decide how update can be done, and how to serve the updatelog.
type BackedUpFramework interface {
	// Ask framework to do update on this update on this task, which consists
	// of one primary and some backup copies.
	Update(taskID uint64, log UpdateLog)
}

type Framework interface {
	// These two are useful for task to inform the framework their status change.
	// metaData has to be really small, since it might be stored in etcd.
	// Flags that parent/child's metadata of the current task is ready.
	FlagParentMetaReady(meta string)
	FlagChildMetaReady(meta string)

	// This allow the task implementation query its neighbors.
	GetTopology() Topology

	// Some task can inform all participating tasks to exit.
	Exit()

	// Some task can inform all participating tasks to new epoch
	SetEpoch(epoch uint64)

	GetLogger() log.Logger

	// Request data from parent or children.
	DataRequest(toID uint64, meta string)

	// This is used to figure out taskid for current node
	GetTaskID() uint64
}

type framework struct {
	// These should be passed by outside world
	name     string
	etcdURLs []string

	// user defined interfaces
	task     Task
	topology Topology

	taskID        uint64
	epoch         uint64
	etcdClient    *etcd.Client
	stops         []chan bool
	ln            net.Listener
	addressMap    map[uint64]string // taskId -> node address. Maybe in etcd later.
	dataRespChan  chan *dataResponse
	dataCloseChan chan struct{}
}

type dataResponse struct {
	taskID uint64
	req    string
	data   []byte
}

func (f *framework) parentOrChild(taskID uint64) taskRole {
	for _, id := range f.topology.GetParents(f.epoch) {
		if taskID == id {
			return roleParent
		}
	}

	for _, id := range f.topology.GetChildren(f.epoch) {
		if taskID == id {
			return roleChild
		}
	}
	return roleNone
}

func (f *framework) start() {
	f.etcdClient = etcd.NewClient(f.etcdURLs)
	f.topology.SetTaskID(f.taskID)
	f.epoch = 0
	f.stops = make([]chan bool, 0)
	f.dataRespChan = make(chan *dataResponse, 100)
	f.dataCloseChan = make(chan struct{})

	// setup etcd watches
	// - create self's parent and child meta flag
	// - watch parents' child meta flag
	// - watch children's parent meta flag
	f.etcdClient.Create(MakeParentMetaPath(f.name, f.GetTaskID()), "", 0)
	f.etcdClient.Create(MakeChildMetaPath(f.name, f.GetTaskID()), "", 0)
	parentStops := f.watchAll(roleParent, f.topology.GetParents(f.epoch))
	childStops := f.watchAll(roleChild, f.topology.GetChildren(f.epoch))
	f.stops = append(f.stops, parentStops...)
	f.stops = append(f.stops, childStops...)

	go f.startHttp()
	go f.dataResponseReceiver()

	// After framework init finished, it should init task.
	f.task.SetEpoch(f.epoch)
	f.task.Init(f.taskID, f, nil)
}

func newDataReqHandler(f *framework) http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc(DataRequestPrefix, func(w http.ResponseWriter, r *http.Request) {
		q := r.URL.Query()
		fromIDStr := q.Get(DataRequestTaskID)
		fromID, err := strconv.ParseUint(fromIDStr, 0, 64)
		if err != nil {
			log.Fatalf("taskID in query couldn't be parsed: %s", fromIDStr)
		}
		req := q.Get(DataRequestReq)
		var serveData func(uint64, string) []byte
		switch f.parentOrChild(fromID) {
		case roleParent:
			serveData = f.task.ServeAsChild
		case roleChild:
			serveData = f.task.ServeAsParent
		default:
			panic("unimplemented")
		}
		d := serveData(fromID, req)

		if _, err := w.Write(d); err != nil {
			log.Printf("response write errored: %v", err)
		}
	})
	return mux
}

// Framework http server for data request.
// Each request will be in the format: "/datareq?taskID=XXX&req=XXX".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHttp() {
	log.Printf("framework: serving http on %s", f.ln.Addr())
	if err := http.Serve(f.ln, newDataReqHandler(f)); err != nil {
		log.Fatalf("http.Serve() returns error: %v\n", err)
	}
}

// Framework event loop handles data response for requests sent in DataRequest().
func (f *framework) dataResponseReceiver() {
	for {
		select {
		case dataResp := <-f.dataRespChan:
			switch f.parentOrChild(dataResp.taskID) {
			case roleParent:
				go f.task.ParentDataReady(dataResp.taskID, dataResp.req, dataResp.data)
			case roleChild:
				go f.task.ChildDataReady(dataResp.taskID, dataResp.req, dataResp.data)
			default:
				panic("unimplemented")
			}
		case <-f.dataCloseChan:
			return
		}
	}
}

func (f *framework) stop() {
	close(f.dataCloseChan)
	for _, c := range f.stops {
		close(c)
	}
}

func (f *framework) FlagParentMetaReady(meta string) {
	f.etcdClient.Set(
		MakeParentMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) FlagChildMetaReady(meta string) {
	f.etcdClient.Set(
		MakeChildMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) SetEpoch(epoch uint64) {
	f.epoch = epoch
}

func (f *framework) watchAll(who taskRole, taskIDs []uint64) []chan bool {
	stops := make([]chan bool, len(taskIDs))

	for i, taskID := range taskIDs {
		receiver := make(chan *etcd.Response, 10)
		stop := make(chan bool, 1)
		stops[i] = stop

		var watchPath string
		var taskCallback func(uint64, string)
		switch who {
		case roleParent:
			// Watch parent's child.
			watchPath = MakeChildMetaPath(f.name, taskID)
			taskCallback = f.task.ParentMetaReady
		case roleChild:
			// Watch child's parent.
			watchPath = MakeParentMetaPath(f.name, taskID)
			taskCallback = f.task.ChildMetaReady
		default:
			panic("unimplemented")
		}

		go f.etcdClient.Watch(watchPath, 0, false, receiver, stop)
		go func(receiver <-chan *etcd.Response, taskID uint64) {
			for {
				resp, ok := <-receiver
				if !ok {
					return
				}
				if resp.Action != "set" {
					continue
				}
				taskCallback(taskID, resp.Node.Value)
			}
		}(receiver, taskID)
	}
	return stops
}

func (f *framework) DataRequest(toID uint64, req string) {
	// getAddressFromTaskID
	addr, ok := f.addressMap[toID]
	if !ok {
		log.Fatalf("ID = %d not found", toID)
		return
	}
	u := url.URL{
		Scheme: "http",
		Host:   addr,
		Path:   DataRequestPrefix,
	}
	q := u.Query()
	q.Add(DataRequestTaskID, strconv.FormatUint(f.taskID, 10))
	q.Add(DataRequestReq, req)
	u.RawQuery = q.Encode()
	urlStr := u.String()
	// send request
	// pass the response to the awaiting event loop for data response
	go func(urlStr string) {
		resp, err := http.Get(urlStr)
		if err != nil {
			log.Fatalf("http.Get(%s) returns error: %v", urlStr, err)
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			log.Fatalf("response code = %d, assume = %d", resp.StatusCode, 200)
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("ioutil.ReadAll(%v) returns error: %v", resp.Body, err)
		}
		dataResp := &dataResponse{
			taskID: toID,
			req:    req,
			data:   data,
		}
		f.dataRespChan <- dataResp
	}(urlStr)
}

func (f *framework) GetTopology() Topology {
	panic("unimplemented")
}

func (f *framework) Exit() {
}

func (f *framework) GetLogger() log.Logger {
	panic("unimplemented")
}

func (f *framework) GetTaskID() uint64 {
	return f.taskID
}
<|endoftext|>


<commit_before>package dyntab

import (
	//"fmt"
	"reflect"
	"testing"
	"time"
)

type (
	nested struct {
		name2 string
	}

	footers []footer

	footer struct {
		number int
	}

	MyInt struct{ int }

	toString struct {
		ID MyInt
	}
)

func (f footers) Footer() ([]string, error) {
	return []string{"", "hey"}, nil
}

func (f MyInt) MarshalText() ([]byte, error) {
	return []byte("new"), nil
}

var tests = []struct {
	in           interface{}
	expectedHead []string
	expectedBody [][]string
	expectedFoot []string
}{
	{
		in: struct {
			id   int
			Name string `tab:"-"`
		}{
			1, "name",
		},
		expectedHead: []string{"id"},
		expectedBody: [][]string{[]string{"1"}},
		expectedFoot: nil,
	},
	{
		in: struct {
			id int
			Ti time.Time `tab:"tim"`
		}{
			1, time.Date(2009,
				time.November, 10,
				23, 0, 0, 0, time.UTC),
		},
		expectedHead: []string{"id", "tim"},
		expectedBody: [][]string{[]string{"1",
			"2009-11-10T23:00:00Z"}},
		expectedFoot: nil,
	},
	{
		in: []struct {
			id   int    `tab:"id2"`
			Name string `tab:"nam"`
		}{
			{1, "name1"},
			{2, "name2"},
		},
		expectedHead: []string{"id2", "nam"},
		expectedBody: [][]string{
			[]string{"1", "name1"},
			[]string{"2", "name2"},
		},
		expectedFoot: nil,
	},
	{
		in: []struct {
			id int `tab:"id2"`
			nested
		}{
			{1, nested{"naming1"}},
			{2, nested{"naming2"}},
		},
		expectedHead: []string{"id2", "name2"},
		expectedBody: [][]string{
			[]string{"1", "naming1"},
			[]string{"2", "naming2"},
		},
		expectedFoot: nil,
	},
	{
		in: footers{
			{1}, {2},
		},
		expectedHead: []string{"number"},
		expectedBody: [][]string{
			[]string{"1"},
			[]string{"2"},
		},
		expectedFoot: []string{"", "hey"},
	},
	{
		in: toString{
			MyInt{1},
		},
		expectedHead: []string{"ID"},
		expectedBody: [][]string{
			[]string{"new"},
		},
		expectedFoot: nil,
	},
}

func TestGetHeader(t *testing.T) {
	typesToRecurse = []reflect.Type{reflect.TypeOf(nested{})}
	for _, test := range tests {
		ret, err := getHeader(test.in)
		if err != nil {
			t.Error("Got an error", err, "when input", test)
			continue
		}
		if len(ret) != len(test.expectedHead) {
			t.Error("Expected", test.expectedHead, "got", ret)
			continue
		}
		for i, e := range test.expectedHead {
			if e != ret[i] {
				t.Error("Expected", test.expectedHead, "got", ret)
				continue
			}
		}
	}
}

func TestGetBody(t *testing.T) {
	typesToRecurse = []reflect.Type{reflect.TypeOf(nested{})}
	for _, test := range tests {
		ret, err := getBody(test.in)
		if err != nil {
			t.Error("Got an error", err, "when input", test)
			continue
		}
		if len(ret) != len(test.expectedBody) {
			t.Error("Expected", test.expectedBody, "got", ret)
			continue
		}
		for i, er := range test.expectedBody {
			if len(er) != len(ret[i]) {
				t.Error("Expected", test.expectedBody, "got", ret)
				continue
			}
			for j, e := range er {
				if e != ret[i][j] {
					t.Error("Expected", test.expectedBody, "got", ret)
					continue
				}
			}
		}
	}
}

func TestGetFooter(t *testing.T) {
	typesToRecurse = []reflect.Type{reflect.TypeOf(nested{})}
	for _, test := range tests {
		ret, err := getFooter(test.in)
		if err != nil {
			t.Error("Got an error", err, "when input", test)
			continue
		}
		if len(ret) != len(test.expectedFoot) {
			t.Error("Expected", test.expectedFoot, "got", ret)
			continue
		}
		for i, er := range test.expectedFoot {
			if er != ret[i] {
				t.Error("Expected", test.expectedFoot, "got", ret)
				continue
			}
		}
	}
}
<commit_msg>added testcase for Issue #1<commit_after>package dyntab

import (
	//"fmt"
	"reflect"
	"testing"
	"time"
)

type (
	nested struct {
		name2 string
	}

	footers []footer

	footer struct {
		number int
	}

	MyInt struct{ int }

	toString struct {
		ID MyInt
	}

	specialized struct {
		Loc time.Location
	}
)

func (f footers) Footer() ([]string, error) {
	return []string{"", "hey"}, nil
}

func (f MyInt) MarshalText() ([]byte, error) {
	return []byte("new"), nil
}

var tests = []struct {
	in           interface{}
	expectedHead []string
	expectedBody [][]string
	expectedFoot []string
}{
	{
		in: struct {
			id   int
			Name string `tab:"-"`
		}{
			1, "name",
		},
		expectedHead: []string{"id"},
		expectedBody: [][]string{[]string{"1"}},
		expectedFoot: nil,
	},
	{
		in: struct {
			id int
			Ti time.Time `tab:"tim"`
		}{
			1, time.Date(2009,
				time.November, 10,
				23, 0, 0, 0, time.UTC),
		},
		expectedHead: []string{"id", "tim"},
		expectedBody: [][]string{[]string{"1",
			"2009-11-10T23:00:00Z"}},
		expectedFoot: nil,
	},
	{
		in: []struct {
			id   int    `tab:"id2"`
			Name string `tab:"nam"`
		}{
			{1, "name1"},
			{2, "name2"},
		},
		expectedHead: []string{"id2", "nam"},
		expectedBody: [][]string{
			[]string{"1", "name1"},
			[]string{"2", "name2"},
		},
		expectedFoot: nil,
	},
	{
		in: []struct {
			id int `tab:"id2"`
			nested
		}{
			{1, nested{"naming1"}},
			{2, nested{"naming2"}},
		},
		expectedHead: []string{"id2", "name2"},
		expectedBody: [][]string{
			[]string{"1", "naming1"},
			[]string{"2", "naming2"},
		},
		expectedFoot: nil,
	},
	{
		in: footers{
			{1}, {2},
		},
		expectedHead: []string{"number"},
		expectedBody: [][]string{
			[]string{"1"},
			[]string{"2"},
		},
		expectedFoot: []string{"", "hey"},
	},
	{
		in: toString{
			MyInt{1},
		},
		expectedHead: []string{"ID"},
		expectedBody: [][]string{
			[]string{"new"},
		},
		expectedFoot: nil,
	},
	{
		in: specialized{
			*time.UTC,
		},
		expectedHead: []string{"Loc"},
		expectedBody: [][]string{
			[]string{"spec"},
		},
		expectedFoot: nil,
	},
}

func TestGetHeader(t *testing.T) {
	typesToRecurse = []reflect.Type{reflect.TypeOf(nested{})}
	for _, test := range tests {
		ret, err := getHeader(test.in)
		if err != nil {
			t.Error("Got an error", err, "when input", test)
			continue
		}
		if len(ret) != len(test.expectedHead) {
			t.Error("Expected", test.expectedHead, "got", ret)
			continue
		}
		for i, e := range test.expectedHead {
			if e != ret[i] {
				t.Error("Expected", test.expectedHead, "got", ret)
				continue
			}
		}
	}
}

func TestGetBody(t *testing.T) {
	typesToRecurse = []reflect.Type{reflect.TypeOf(nested{})}
	for _, test := range tests {
		ret, err := getBody(test.in)
		if err != nil {
			t.Error("Got an error", err, "when input", test)
			continue
		}
		if len(ret) != len(test.expectedBody) {
			t.Error("Expected", test.expectedBody, "got", ret)
			continue
		}
		for i, er := range test.expectedBody {
			if len(er) != len(ret[i]) {
				t.Error("Expected", test.expectedBody, "got", ret)
				continue
			}
			for j, e := range er {
				if e != ret[i][j] {
					t.Error("Expected", test.expectedBody, "got", ret)
					continue
				}
			}
		}
	}
}

func TestGetFooter(t *testing.T) {
	typesToRecurse = []reflect.Type{reflect.TypeOf(nested{})}
	for _, test := range tests {
		ret, err := getFooter(test.in)
		if err != nil {
			t.Error("Got an error", err, "when input", test)
			continue
		}
		if len(ret) != len(test.expectedFoot) {
			t.Error("Expected", test.expectedFoot, "got", ret)
			continue
		}
		for i, er := range test.expectedFoot {
			if er != ret[i] {
				t.Error("Expected", test.expectedFoot, "got", ret)
				continue
			}
		}
	}
}
<|endoftext|>


<commit_before>package routing

import "github.com/go-errors/errors"

// errorCode is used to represent the various errors that can occur within this
// package.
type errorCode uint8

const (
	// ErrNoPathFound is returned when a path to the target destination
	// does not exist in the graph.
	ErrNoPathFound errorCode = iota

	// ErrNoRouteFound is returned when the router is unable to find a
	// valid route to the target destination after fees and time-lock
	// limitations are factored in.
	ErrNoRouteFound

	// ErrInsufficientCapacity is returned when a path if found, yet the
	// capacity of one of the channels in the path is insufficient to carry
	// the payment.
	ErrInsufficientCapacity

	// ErrMaxHopsExceeded is returned when a candidate path is found, but
	// the length of that path exceeds HopLimit.
	ErrMaxHopsExceeded

	// ErrTargetNotInNetwork is returned when the target of a path-finding
	// or payment attempt isn't known to be within the current version of
	// the channel graph.
	ErrTargetNotInNetwork

	// ErrOutdated is returned when the routing update already have
	// been applied, or a newer update is already known.
	ErrOutdated

	// ErrIgnored is returned when the update have been ignored because
	// this update can't bring us something new, or because a node
	// announcement was given for node not found in any channel.
	ErrIgnored

	// ErrRejected is returned if the update is for a channel ID that was
	// previously added to the reject cache because of an invalid update
	// was attempted to be processed.
	ErrRejected

	// ErrPaymentAttemptTimeout is an error that indicates that a payment
	// attempt timed out before we were able to successfully route an HTLC.
	ErrPaymentAttemptTimeout

	// ErrFeeLimitExceeded is returned when the total fees of a route exceed
	// the user-specified fee limit.
	ErrFeeLimitExceeded
)

// routerError is a structure that represent the error inside the routing package,
// this structure carries additional information about error code in order to
// be able distinguish errors outside of the current package.
type routerError struct {
	err  *errors.Error
	code errorCode
}

// Error represents errors as the string
// NOTE: Part of the error interface.
func (e *routerError) Error() string {
	return e.err.Error()
}

// A compile time check to ensure routerError implements the error interface.
var _ error = (*routerError)(nil)

// newErr creates a routerError by the given error description and its
// corresponding error code.
func newErr(code errorCode, a interface{}) *routerError {
	return &routerError{
		code: code,
		err:  errors.New(a),
	}
}

// newErrf creates a routerError by the given error formatted description and
// its corresponding error code.
func newErrf(code errorCode, format string, a ...interface{}) *routerError {
	return &routerError{
		code: code,
		err:  errors.Errorf(format, a...),
	}
}

// IsError is a helper function which is needed to have ability to check that
// returned error has specific error code.
func IsError(e interface{}, codes ...errorCode) bool {
	err, ok := e.(*routerError)
	if !ok {
		return false
	}

	for _, code := range codes {
		if err.code == code {
			return true
		}
	}

	return false
}
<commit_msg>routing: remove unused error codes<commit_after>package routing

import "github.com/go-errors/errors"

// errorCode is used to represent the various errors that can occur within this
// package.
type errorCode uint8

const (
	// ErrNoPathFound is returned when a path to the target destination
	// does not exist in the graph.
	ErrNoPathFound errorCode = iota

	// ErrMaxHopsExceeded is returned when a candidate path is found, but
	// the length of that path exceeds HopLimit.
	ErrMaxHopsExceeded

	// ErrTargetNotInNetwork is returned when the target of a path-finding
	// or payment attempt isn't known to be within the current version of
	// the channel graph.
	ErrTargetNotInNetwork

	// ErrOutdated is returned when the routing update already have
	// been applied, or a newer update is already known.
	ErrOutdated

	// ErrIgnored is returned when the update have been ignored because
	// this update can't bring us something new, or because a node
	// announcement was given for node not found in any channel.
	ErrIgnored

	// ErrPaymentAttemptTimeout is an error that indicates that a payment
	// attempt timed out before we were able to successfully route an HTLC.
	ErrPaymentAttemptTimeout
)

// routerError is a structure that represent the error inside the routing package,
// this structure carries additional information about error code in order to
// be able distinguish errors outside of the current package.
type routerError struct {
	err  *errors.Error
	code errorCode
}

// Error represents errors as the string
// NOTE: Part of the error interface.
func (e *routerError) Error() string {
	return e.err.Error()
}

// A compile time check to ensure routerError implements the error interface.
var _ error = (*routerError)(nil)

// newErr creates a routerError by the given error description and its
// corresponding error code.
func newErr(code errorCode, a interface{}) *routerError {
	return &routerError{
		code: code,
		err:  errors.New(a),
	}
}

// newErrf creates a routerError by the given error formatted description and
// its corresponding error code.
func newErrf(code errorCode, format string, a ...interface{}) *routerError {
	return &routerError{
		code: code,
		err:  errors.Errorf(format, a...),
	}
}

// IsError is a helper function which is needed to have ability to check that
// returned error has specific error code.
func IsError(e interface{}, codes ...errorCode) bool {
	err, ok := e.(*routerError)
	if !ok {
		return false
	}

	for _, code := range codes {
		if err.code == code {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package rpc

var (
	// Holds geth specific RPC extends which can be used to extend web3
	WEB3Extensions = map[string]string{
		"personal": Personal_JS,
		"txpool":   TxPool_JS,
		"admin":    Admin_JS,
		"eth":      Eth_JS,
		"miner":    Miner_JS,
		"debug":    Debug_JS,
		"net":      Net_JS,
	}
)

const Personal_JS = `
web3._extend({
	property: 'personal',
	methods:
	[
		new web3._extend.Method({
			name: 'newAccount',
			call: 'personal_newAccount',
			params: 1,
			outputFormatter: web3._extend.utils.toAddress
		}),
		new web3._extend.Method({
			name: 'unlockAccount',
			call: 'personal_unlockAccount',
			params: 3,
		}),
		new web3._extend.Method({
			name: 'lockAccount',
			call: 'personal_lockAccount',
			params: 1
		})
	],
	properties:
	[
		new web3._extend.Property({
			name: 'listAccounts',
			getter: 'personal_listAccounts'
		})
	]
});
`

const TxPool_JS = `
web3._extend({
	property: 'txpool',
	methods:
	[
	],
	properties:
	[
		new web3._extend.Property({
			name: 'content',
			getter: 'txpool_content'
		}),
		new web3._extend.Property({
			name: 'inspect',
			getter: 'txpool_inspect'
		}),
		new web3._extend.Property({
			name: 'status',
			getter: 'txpool_status',
			outputFormatter: function(status) {
				status.pending = web3._extend.utils.toDecimal(status.pending);
				status.queued = web3._extend.utils.toDecimal(status.queued);
				return status;
			}
		})
	]
});
`

const Admin_JS = `
web3._extend({
	property: 'admin',
	methods:
	[
		new web3._extend.Method({
			name: 'addPeer',
			call: 'admin_addPeer',
			params: 1
		}),
		new web3._extend.Method({
			name: 'exportChain',
			call: 'admin_exportChain',
			params: 1,
			inputFormatter: [null]
		}),
		new web3._extend.Method({
			name: 'importChain',
			call: 'admin_importChain',
			params: 1
		}),
		new web3._extend.Method({
			name: 'sleepBlocks',
			call: 'admin_sleepBlocks',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setSolc',
			call: 'admin_setSolc',
			params: 1
		}),
		new web3._extend.Method({
			name: 'startRPC',
			call: 'admin_startRPC',
			params: 4
		}),
		new web3._extend.Method({
			name: 'stopRPC',
			call: 'admin_stopRPC',
			params: 0
		}),
		new web3._extend.Method({
			name: 'startWS',
			call: 'admin_startWS',
			params: 4
		}),
		new web3._extend.Method({
			name: 'stopWS',
			call: 'admin_stopWS',
			params: 0
		}),
		new web3._extend.Method({
			name: 'setGlobalRegistrar',
			call: 'admin_setGlobalRegistrar',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setHashReg',
			call: 'admin_setHashReg',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setUrlHint',
			call: 'admin_setUrlHint',
			params: 2
		}),
		new web3._extend.Method({
			name: 'saveInfo',
			call: 'admin_saveInfo',
			params: 2
		}),
		new web3._extend.Method({
			name: 'register',
			call: 'admin_register',
			params: 3
		}),
		new web3._extend.Method({
			name: 'registerUrl',
			call: 'admin_registerUrl',
			params: 3
		}),
		new web3._extend.Method({
			name: 'startNatSpec',
			call: 'admin_startNatSpec',
			params: 0
		}),
		new web3._extend.Method({
			name: 'stopNatSpec',
			call: 'admin_stopNatSpec',
			params: 0
		}),
		new web3._extend.Method({
			name: 'getContractInfo',
			call: 'admin_getContractInfo',
			params: 1
		}),
		new web3._extend.Method({
			name: 'httpGet',
			call: 'admin_httpGet',
			params: 2
		})
	],
	properties:
	[
		new web3._extend.Property({
			name: 'nodeInfo',
			getter: 'admin_nodeInfo'
		}),
		new web3._extend.Property({
			name: 'peers',
			getter: 'admin_peers'
		}),
		new web3._extend.Property({
			name: 'datadir',
			getter: 'admin_datadir'
		})
	]
});
`

const Eth_JS = `
web3._extend({
	property: 'eth',
	methods:
	[
		new web3._extend.Method({
			name: 'sign',
			call: 'eth_sign',
			params: 2,
			inputFormatter: [web3._extend.utils.toAddress, null]
		}),
		new web3._extend.Method({
			name: 'resend',
			call: 'eth_resend',
			params: 3,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal]
		}),
		new web3._extend.Method({
			name: 'getNatSpec',
			call: 'eth_getNatSpec',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
		}),
		new web3._extend.Method({
			name: 'signTransaction',
			call: 'eth_signTransaction',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
		}),
		new web3._extend.Method({
			name: 'submitTransaction',
			call: 'eth_submitTransaction',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
		})
	],
	properties:
	[
		new web3._extend.Property({
			name: 'pendingTransactions',
			getter: 'eth_pendingTransactions'
		})
	]
});
`

const Net_JS = `
web3._extend({
	property: 'net',
	methods: [],
	properties:
	[
		new web3._extend.Property({
			name: 'version',
			getter: 'net_version'
		})
	]
});
`

const Debug_JS = `
web3._extend({
	property: 'debug',
	methods:
	[
		new web3._extend.Method({
			name: 'printBlock',
			call: 'debug_printBlock',
			params: 1
		}),
		new web3._extend.Method({
			name: 'getBlockRlp',
			call: 'debug_getBlockRlp',
			params: 1
		}),
		new web3._extend.Method({
			name: 'setHead',
			call: 'debug_setHead',
			params: 1
		}),
		new web3._extend.Method({
			name: 'traceBlock',
			call: 'debug_traceBlock',
			params: 2
		}),
		new web3._extend.Method({
			name: 'traceBlockByFile',
			call: 'debug_traceBlockByFile',
			params: 2
		}),
		new web3._extend.Method({
			name: 'traceBlockByNumber',
			call: 'debug_traceBlockByNumber',
			params: 2
		}),
		new web3._extend.Method({
			name: 'traceBlockByHash',
			call: 'debug_traceBlockByHash',
			params: 2
		}),
		new web3._extend.Method({
			name: 'seedHash',
			call: 'debug_seedHash',
			params: 1
		}),
		new web3._extend.Method({
			name: 'dumpBlock',
			call: 'debug_dumpBlock',
			params: 1
		}),
		new web3._extend.Method({
			name: 'metrics',
			call: 'debug_metrics',
			params: 1
		}),
		new web3._extend.Method({
			name: 'verbosity',
			call: 'debug_verbosity',
			params: 1
		}),
		new web3._extend.Method({
			name: 'vmodule',
			call: 'debug_vmodule',
			params: 1
		}),
		new web3._extend.Method({
			name: 'backtraceAt',
			call: 'debug_backtraceAt',
			params: 1,
		}),
		new web3._extend.Method({
			name: 'stacks',
			call: 'debug_stacks',
			params: 0,
			outputFormatter: console.log
		}),
		new web3._extend.Method({
			name: 'cpuProfile',
			call: 'debug_cpuProfile',
			params: 2
		}),
		new web3._extend.Method({
			name: 'startCPUProfile',
			call: 'debug_startCPUProfile',
			params: 1
		}),
		new web3._extend.Method({
			name: 'stopCPUProfile',
			call: 'debug_stopCPUProfile',
			params: 0
		}),
		new web3._extend.Method({
			name: 'trace',
			call: 'debug_trace',
			params: 2
		}),
		new web3._extend.Method({
			name: 'startTrace',
			call: 'debug_startTrace',
			params: 1
		}),
		new web3._extend.Method({
			name: 'stopTrace',
			call: 'debug_stopTrace',
			params: 0
		}),
		new web3._extend.Method({
			name: 'blockProfile',
			call: 'debug_blockProfile',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setBlockProfileRate',
			call: 'debug_setBlockProfileRate',
			params: 1
		}),
		new web3._extend.Method({
			name: 'writeBlockProfile',
			call: 'debug_writeBlockProfile',
			params: 1
		}),
		new web3._extend.Method({
			name: 'writeMemProfile',
			call: 'debug_writeMemProfile',
			params: 1
		}),
		new web3._extend.Method({
			name: 'traceTransaction',
			call: 'debug_traceTransaction',
			params: 2
		})
	],
	properties: []
});
`

const Miner_JS = `
web3._extend({
	property: 'miner',
	methods:
	[
		new web3._extend.Method({
			name: 'start',
			call: 'miner_start',
			params: 1
		}),
		new web3._extend.Method({
			name: 'stop',
			call: 'miner_stop',
			params: 1
		}),
		new web3._extend.Method({
			name: 'setEtherbase',
			call: 'miner_setEtherbase',
			params: 1,
			inputFormatter: [web3._extend.formatters.formatInputInt],
			outputFormatter: web3._extend.formatters.formatOutputBool
		}),
		new web3._extend.Method({
			name: 'setExtra',
			call: 'miner_setExtra',
			params: 1
		}),
		new web3._extend.Method({
			name: 'setGasPrice',
			call: 'miner_setGasPrice',
			params: 1,
			inputFormatter: [web3._extend.utils.fromDecial]
		}),
		new web3._extend.Method({
			name: 'startAutoDAG',
			call: 'miner_startAutoDAG',
			params: 0
		}),
		new web3._extend.Method({
			name: 'stopAutoDAG',
			call: 'miner_stopAutoDAG',
			params: 0
		}),
		new web3._extend.Method({
			name: 'makeDAG',
			call: 'miner_makeDAG',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter]
		})
	],
	properties: []
});
`

const Shh_JS = `
web3._extend({
	property: 'shh',
	methods: [],
	properties:
	[
		new web3._extend.Property({
			name: 'version',
			getter: 'shh_version'
		})
	]
});
`
<commit_msg>console: use transaction output formatter for eth.pendingTransactions output<commit_after>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package rpc

var (
	// Holds geth specific RPC extends which can be used to extend web3
	WEB3Extensions = map[string]string{
		"personal": Personal_JS,
		"txpool":   TxPool_JS,
		"admin":    Admin_JS,
		"eth":      Eth_JS,
		"miner":    Miner_JS,
		"debug":    Debug_JS,
		"net":      Net_JS,
	}
)

const Personal_JS = `
web3._extend({
	property: 'personal',
	methods:
	[
		new web3._extend.Method({
			name: 'newAccount',
			call: 'personal_newAccount',
			params: 1,
			outputFormatter: web3._extend.utils.toAddress
		}),
		new web3._extend.Method({
			name: 'unlockAccount',
			call: 'personal_unlockAccount',
			params: 3,
		}),
		new web3._extend.Method({
			name: 'lockAccount',
			call: 'personal_lockAccount',
			params: 1
		})
	],
	properties:
	[
		new web3._extend.Property({
			name: 'listAccounts',
			getter: 'personal_listAccounts'
		})
	]
});
`

const TxPool_JS = `
web3._extend({
	property: 'txpool',
	methods:
	[
	],
	properties:
	[
		new web3._extend.Property({
			name: 'content',
			getter: 'txpool_content'
		}),
		new web3._extend.Property({
			name: 'inspect',
			getter: 'txpool_inspect'
		}),
		new web3._extend.Property({
			name: 'status',
			getter: 'txpool_status',
			outputFormatter: function(status) {
				status.pending = web3._extend.utils.toDecimal(status.pending);
				status.queued = web3._extend.utils.toDecimal(status.queued);
				return status;
			}
		})
	]
});
`

const Admin_JS = `
web3._extend({
	property: 'admin',
	methods:
	[
		new web3._extend.Method({
			name: 'addPeer',
			call: 'admin_addPeer',
			params: 1
		}),
		new web3._extend.Method({
			name: 'exportChain',
			call: 'admin_exportChain',
			params: 1,
			inputFormatter: [null]
		}),
		new web3._extend.Method({
			name: 'importChain',
			call: 'admin_importChain',
			params: 1
		}),
		new web3._extend.Method({
			name: 'sleepBlocks',
			call: 'admin_sleepBlocks',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setSolc',
			call: 'admin_setSolc',
			params: 1
		}),
		new web3._extend.Method({
			name: 'startRPC',
			call: 'admin_startRPC',
			params: 4
		}),
		new web3._extend.Method({
			name: 'stopRPC',
			call: 'admin_stopRPC',
			params: 0
		}),
		new web3._extend.Method({
			name: 'startWS',
			call: 'admin_startWS',
			params: 4
		}),
		new web3._extend.Method({
			name: 'stopWS',
			call: 'admin_stopWS',
			params: 0
		}),
		new web3._extend.Method({
			name: 'setGlobalRegistrar',
			call: 'admin_setGlobalRegistrar',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setHashReg',
			call: 'admin_setHashReg',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setUrlHint',
			call: 'admin_setUrlHint',
			params: 2
		}),
		new web3._extend.Method({
			name: 'saveInfo',
			call: 'admin_saveInfo',
			params: 2
		}),
		new web3._extend.Method({
			name: 'register',
			call: 'admin_register',
			params: 3
		}),
		new web3._extend.Method({
			name: 'registerUrl',
			call: 'admin_registerUrl',
			params: 3
		}),
		new web3._extend.Method({
			name: 'startNatSpec',
			call: 'admin_startNatSpec',
			params: 0
		}),
		new web3._extend.Method({
			name: 'stopNatSpec',
			call: 'admin_stopNatSpec',
			params: 0
		}),
		new web3._extend.Method({
			name: 'getContractInfo',
			call: 'admin_getContractInfo',
			params: 1
		}),
		new web3._extend.Method({
			name: 'httpGet',
			call: 'admin_httpGet',
			params: 2
		})
	],
	properties:
	[
		new web3._extend.Property({
			name: 'nodeInfo',
			getter: 'admin_nodeInfo'
		}),
		new web3._extend.Property({
			name: 'peers',
			getter: 'admin_peers'
		}),
		new web3._extend.Property({
			name: 'datadir',
			getter: 'admin_datadir'
		})
	]
});
`

const Eth_JS = `
web3._extend({
	property: 'eth',
	methods:
	[
		new web3._extend.Method({
			name: 'sign',
			call: 'eth_sign',
			params: 2,
			inputFormatter: [web3._extend.utils.toAddress, null]
		}),
		new web3._extend.Method({
			name: 'resend',
			call: 'eth_resend',
			params: 3,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal]
		}),
		new web3._extend.Method({
			name: 'getNatSpec',
			call: 'eth_getNatSpec',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
		}),
		new web3._extend.Method({
			name: 'signTransaction',
			call: 'eth_signTransaction',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
		}),
		new web3._extend.Method({
			name: 'submitTransaction',
			call: 'eth_submitTransaction',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputTransactionFormatter]
		})
	],
	properties:
	[
		new web3._extend.Property({
			name: 'pendingTransactions',
			getter: 'eth_pendingTransactions',
			outputFormatter: function(txs) {
				var formatted = [];
				for (var i = 0; i < txs.length; i++) {
					formatted.push(web3._extend.formatters.outputTransactionFormatter(txs[i]));
					formatted[i].blockHash = null;
				}
				return formatted;
			}
		})
	]
});
`

const Net_JS = `
web3._extend({
	property: 'net',
	methods: [],
	properties:
	[
		new web3._extend.Property({
			name: 'version',
			getter: 'net_version'
		})
	]
});
`

const Debug_JS = `
web3._extend({
	property: 'debug',
	methods:
	[
		new web3._extend.Method({
			name: 'printBlock',
			call: 'debug_printBlock',
			params: 1
		}),
		new web3._extend.Method({
			name: 'getBlockRlp',
			call: 'debug_getBlockRlp',
			params: 1
		}),
		new web3._extend.Method({
			name: 'setHead',
			call: 'debug_setHead',
			params: 1
		}),
		new web3._extend.Method({
			name: 'traceBlock',
			call: 'debug_traceBlock',
			params: 2
		}),
		new web3._extend.Method({
			name: 'traceBlockByFile',
			call: 'debug_traceBlockByFile',
			params: 2
		}),
		new web3._extend.Method({
			name: 'traceBlockByNumber',
			call: 'debug_traceBlockByNumber',
			params: 2
		}),
		new web3._extend.Method({
			name: 'traceBlockByHash',
			call: 'debug_traceBlockByHash',
			params: 2
		}),
		new web3._extend.Method({
			name: 'seedHash',
			call: 'debug_seedHash',
			params: 1
		}),
		new web3._extend.Method({
			name: 'dumpBlock',
			call: 'debug_dumpBlock',
			params: 1
		}),
		new web3._extend.Method({
			name: 'metrics',
			call: 'debug_metrics',
			params: 1
		}),
		new web3._extend.Method({
			name: 'verbosity',
			call: 'debug_verbosity',
			params: 1
		}),
		new web3._extend.Method({
			name: 'vmodule',
			call: 'debug_vmodule',
			params: 1
		}),
		new web3._extend.Method({
			name: 'backtraceAt',
			call: 'debug_backtraceAt',
			params: 1,
		}),
		new web3._extend.Method({
			name: 'stacks',
			call: 'debug_stacks',
			params: 0,
			outputFormatter: console.log
		}),
		new web3._extend.Method({
			name: 'cpuProfile',
			call: 'debug_cpuProfile',
			params: 2
		}),
		new web3._extend.Method({
			name: 'startCPUProfile',
			call: 'debug_startCPUProfile',
			params: 1
		}),
		new web3._extend.Method({
			name: 'stopCPUProfile',
			call: 'debug_stopCPUProfile',
			params: 0
		}),
		new web3._extend.Method({
			name: 'trace',
			call: 'debug_trace',
			params: 2
		}),
		new web3._extend.Method({
			name: 'startTrace',
			call: 'debug_startTrace',
			params: 1
		}),
		new web3._extend.Method({
			name: 'stopTrace',
			call: 'debug_stopTrace',
			params: 0
		}),
		new web3._extend.Method({
			name: 'blockProfile',
			call: 'debug_blockProfile',
			params: 2
		}),
		new web3._extend.Method({
			name: 'setBlockProfileRate',
			call: 'debug_setBlockProfileRate',
			params: 1
		}),
		new web3._extend.Method({
			name: 'writeBlockProfile',
			call: 'debug_writeBlockProfile',
			params: 1
		}),
		new web3._extend.Method({
			name: 'writeMemProfile',
			call: 'debug_writeMemProfile',
			params: 1
		}),
		new web3._extend.Method({
			name: 'traceTransaction',
			call: 'debug_traceTransaction',
			params: 2
		})
	],
	properties: []
});
`

const Miner_JS = `
web3._extend({
	property: 'miner',
	methods:
	[
		new web3._extend.Method({
			name: 'start',
			call: 'miner_start',
			params: 1
		}),
		new web3._extend.Method({
			name: 'stop',
			call: 'miner_stop',
			params: 1
		}),
		new web3._extend.Method({
			name: 'setEtherbase',
			call: 'miner_setEtherbase',
			params: 1,
			inputFormatter: [web3._extend.formatters.formatInputInt],
			outputFormatter: web3._extend.formatters.formatOutputBool
		}),
		new web3._extend.Method({
			name: 'setExtra',
			call: 'miner_setExtra',
			params: 1
		}),
		new web3._extend.Method({
			name: 'setGasPrice',
			call: 'miner_setGasPrice',
			params: 1,
			inputFormatter: [web3._extend.utils.fromDecial]
		}),
		new web3._extend.Method({
			name: 'startAutoDAG',
			call: 'miner_startAutoDAG',
			params: 0
		}),
		new web3._extend.Method({
			name: 'stopAutoDAG',
			call: 'miner_stopAutoDAG',
			params: 0
		}),
		new web3._extend.Method({
			name: 'makeDAG',
			call: 'miner_makeDAG',
			params: 1,
			inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter]
		})
	],
	properties: []
});
`

const Shh_JS = `
web3._extend({
	property: 'shh',
	methods: [],
	properties:
	[
		new web3._extend.Property({
			name: 'version',
			getter: 'shh_version'
		})
	]
});
`
<|endoftext|>


<commit_before>package game

import (
	"fmt"

	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/observers"
	"github.com/ivan1993spb/snake-server/world"
)

type Game struct {
	world  *world.World
	logger logrus.FieldLogger
}

type ErrCreateGame struct {
	Err error
}

func (e *ErrCreateGame) Error() string {
	return "cannot create game: " + e.Err.Error()
}

func NewGame(logger logrus.FieldLogger, width, height uint8) (*Game, error) {
	w, err := world.NewWorld(width, height)
	if err != nil {
		return nil, fmt.Errorf("cannot create game: %s", err)
	}

	return &Game{
		world:  w,
		logger: logger,
	}, nil
}

func (g *Game) Start(stop <-chan struct{}) {
	g.world.Start(stop)

	observers.LoggerObserver{}.Observe(stop, g.world, g.logger)
	observers.WallObserver{}.Observe(stop, g.world, g.logger)
	observers.AppleObserver{}.Observe(stop, g.world, g.logger)
	observers.SnakeObserver{}.Observe(stop, g.world, g.logger)
}

func (g *Game) World() *world.World {
	return g.world
}

func (g *Game) ListenEvents(stop <-chan struct{}, buffer uint) <-chan Event {
	chout := make(chan Event, buffer)
	go func() {
		defer close(chout)
		for worldEvent := range g.world.Events(stop, buffer) {
			chout <- Event{
				Type:    worldEventTypeToGameEventType(worldEvent.Type),
				Payload: worldEvent.Payload,
			}
		}
	}()
	return chout
}
<commit_msg>Create starting watermelon observer<commit_after>package game

import (
	"fmt"

	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/observers"
	"github.com/ivan1993spb/snake-server/world"
)

type Game struct {
	world  *world.World
	logger logrus.FieldLogger
}

type ErrCreateGame struct {
	Err error
}

func (e *ErrCreateGame) Error() string {
	return "cannot create game: " + e.Err.Error()
}

func NewGame(logger logrus.FieldLogger, width, height uint8) (*Game, error) {
	w, err := world.NewWorld(width, height)
	if err != nil {
		return nil, fmt.Errorf("cannot create game: %s", err)
	}

	return &Game{
		world:  w,
		logger: logger,
	}, nil
}

func (g *Game) Start(stop <-chan struct{}) {
	g.world.Start(stop)

	observers.LoggerObserver{}.Observe(stop, g.world, g.logger)
	observers.WallObserver{}.Observe(stop, g.world, g.logger)
	observers.AppleObserver{}.Observe(stop, g.world, g.logger)
	observers.SnakeObserver{}.Observe(stop, g.world, g.logger)
	observers.WatermelonObserver{}.Observe(stop, g.world, g.logger)
}

func (g *Game) World() *world.World {
	return g.world
}

func (g *Game) ListenEvents(stop <-chan struct{}, buffer uint) <-chan Event {
	chout := make(chan Event, buffer)
	go func() {
		defer close(chout)
		for worldEvent := range g.world.Events(stop, buffer) {
			chout <- Event{
				Type:    worldEventTypeToGameEventType(worldEvent.Type),
				Payload: worldEvent.Payload,
			}
		}
	}()
	return chout
}
<|endoftext|>


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

package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/howeyc/fsnotify"
)

var (
	cmd          *exec.Cmd
	state        sync.Mutex
	eventTime    = make(map[string]int64)
	scheduleTime time.Time
)

func NewWatcher(paths []string, files []string, isgenerate bool) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		ColorLog("[ERRO] Fail to create new Watcher[ %s ]\n", err)
		os.Exit(2)
	}

	go func() {
		for {
			select {
			case e := <-watcher.Event:
				isbuild := true

				// Skip TMP files for Sublime Text.
				if checkTMPFile(e.Name) {
					continue
				}
				if !checkIfWatchExt(e.Name) {
					continue
				}

				mt := getFileModTime(e.Name)
				if t := eventTime[e.Name]; mt == t {
					ColorLog("[SKIP] # %s #\n", e.String())
					isbuild = false
				}

				eventTime[e.Name] = mt

				if isbuild {
					ColorLog("[EVEN] %s\n", e)
					go func() {
						// Wait 1s before autobuild util there is no file change.
						scheduleTime = time.Now().Add(1 * time.Second)
						for {
							time.Sleep(scheduleTime.Sub(time.Now()))
							if time.Now().After(scheduleTime) {
								break
							}
							return
						}

						Autobuild(files, isgenerate)
					}()
				}
			case err := <-watcher.Error:
				ColorLog("[WARN] %s\n", err.Error()) // No need to exit here
			}
		}
	}()

	ColorLog("[INFO] Initializing watcher...\n")
	for _, path := range paths {
		ColorLog("[TRAC] Directory( %s )\n", path)
		err = watcher.Watch(path)
		if err != nil {
			ColorLog("[ERRO] Fail to watch directory[ %s ]\n", err)
			os.Exit(2)
		}
	}

}

// getFileModTime retuens unix timestamp of `os.File.ModTime` by given path.
func getFileModTime(path string) int64 {
	path = strings.Replace(path, "\\", "/", -1)
	f, err := os.Open(path)
	if err != nil {
		ColorLog("[ERRO] Fail to open file[ %s ]\n", err)
		return time.Now().Unix()
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		ColorLog("[ERRO] Fail to get file information[ %s ]\n", err)
		return time.Now().Unix()
	}

	return fi.ModTime().Unix()
}

func Autobuild(files []string, isgenerate bool) {
	state.Lock()
	defer state.Unlock()

	ColorLog("[INFO] Start building...\n")
	path, _ := os.Getwd()
	os.Chdir(path)

	cmdName := "go"
	if conf.Gopm.Enable {
		cmdName = "gopm"
	}

	var err error
	// For applications use full import path like "github.com/.../.."
	// are able to use "go install" to reduce build time.
	if conf.GoInstall || conf.Gopm.Install {
		icmd := exec.Command("go", "list", "./...")
		buf := bytes.NewBuffer([]byte(""))
		icmd.Stdout = buf
		err = icmd.Run()
		if err == nil {
			list := strings.Split(buf.String(), "\n")[1:]
			for _, pkg := range list {
				if len(pkg) == 0 {
					continue
				}
				icmd = exec.Command(cmdName, "install", pkg)
				icmd.Stdout = os.Stdout
				icmd.Stderr = os.Stderr
				err = icmd.Run()
				if err != nil {
					break
				}
			}
		}
	}

	if isgenerate {
		icmd := exec.Command("bee", "generate", "docs")
		icmd.Stdout = os.Stdout
		icmd.Stderr = os.Stderr
		icmd.Run()
		ColorLog("============== generate docs ===================\n")
	}

	if err == nil {
		appName := appname
		if runtime.GOOS == "windows" {
			appName += ".exe"
		}

		args := []string{"build"}
		args = append(args, "-o", appName)
		if buildTags != "" {
			args = append(args, "-tags", buildTags)
		}
		args = append(args, files...)

		bcmd := exec.Command(cmdName, args...)
		bcmd.Stdout = os.Stdout
		bcmd.Stderr = os.Stderr
		err = bcmd.Run()
	}

	if err != nil {
		ColorLog("[ERRO] ============== Build failed ===================\n")
		return
	}
	ColorLog("[SUCC] Build was successful\n")
	Restart(appname)
}

func Kill() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Println("Kill.recover -> ", e)
		}
	}()
	if cmd != nil && cmd.Process != nil {
		err := cmd.Process.Kill()
		if err != nil {
			fmt.Println("Kill -> ", err)
		}
	}
}

func Restart(appname string) {
	Debugf("kill running process")
	Kill()
	go Start(appname)
}

func Start(appname string) {
	ColorLog("[INFO] Restarting %s ...\n", appname)
	if strings.Index(appname, "./") == -1 {
		appname = "./" + appname
	}

	cmd = exec.Command(appname)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Args = append([]string{appname}, conf.CmdArgs...)
	cmd.Env = append(os.Environ(), conf.Envs...)

	go cmd.Run()
	ColorLog("[INFO] %s is running...\n", appname)
	started <- true
}

// checkTMPFile returns true if the event was for TMP files.
func checkTMPFile(name string) bool {
	if strings.HasSuffix(strings.ToLower(name), ".tmp") {
		return true
	}
	return false
}

var watchExts = []string{".go"}

// checkIfWatchExt returns true if the name HasSuffix <watch_ext>.
func checkIfWatchExt(name string) bool {
	for _, s := range watchExts {
		if strings.HasSuffix(name, s) {
			return true
		}
	}
	return false
}
<commit_msg>optimisation disable GC for go build , go list, go install +20% speed on large projects<commit_after>// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/howeyc/fsnotify"
)

var (
	cmd          *exec.Cmd
	state        sync.Mutex
	eventTime    = make(map[string]int64)
	scheduleTime time.Time
)

func NewWatcher(paths []string, files []string, isgenerate bool) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		ColorLog("[ERRO] Fail to create new Watcher[ %s ]\n", err)
		os.Exit(2)
	}

	go func() {
		for {
			select {
			case e := <-watcher.Event:
				isbuild := true

				// Skip TMP files for Sublime Text.
				if checkTMPFile(e.Name) {
					continue
				}
				if !checkIfWatchExt(e.Name) {
					continue
				}

				mt := getFileModTime(e.Name)
				if t := eventTime[e.Name]; mt == t {
					ColorLog("[SKIP] # %s #\n", e.String())
					isbuild = false
				}

				eventTime[e.Name] = mt

				if isbuild {
					ColorLog("[EVEN] %s\n", e)
					go func() {
						// Wait 1s before autobuild util there is no file change.
						scheduleTime = time.Now().Add(1 * time.Second)
						for {
							time.Sleep(scheduleTime.Sub(time.Now()))
							if time.Now().After(scheduleTime) {
								break
							}
							return
						}

						Autobuild(files, isgenerate)
					}()
				}
			case err := <-watcher.Error:
				ColorLog("[WARN] %s\n", err.Error()) // No need to exit here
			}
		}
	}()

	ColorLog("[INFO] Initializing watcher...\n")
	for _, path := range paths {
		ColorLog("[TRAC] Directory( %s )\n", path)
		err = watcher.Watch(path)
		if err != nil {
			ColorLog("[ERRO] Fail to watch directory[ %s ]\n", err)
			os.Exit(2)
		}
	}

}

// getFileModTime retuens unix timestamp of `os.File.ModTime` by given path.
func getFileModTime(path string) int64 {
	path = strings.Replace(path, "\\", "/", -1)
	f, err := os.Open(path)
	if err != nil {
		ColorLog("[ERRO] Fail to open file[ %s ]\n", err)
		return time.Now().Unix()
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		ColorLog("[ERRO] Fail to get file information[ %s ]\n", err)
		return time.Now().Unix()
	}

	return fi.ModTime().Unix()
}

func Autobuild(files []string, isgenerate bool) {
	state.Lock()
	defer state.Unlock()

	ColorLog("[INFO] Start building...\n")
	path, _ := os.Getwd()
	os.Chdir(path)

	cmdName := "go"
	if conf.Gopm.Enable {
		cmdName = "gopm"
	}

	var err error
	// For applications use full import path like "github.com/.../.."
	// are able to use "go install" to reduce build time.
	if conf.GoInstall || conf.Gopm.Install {
		icmd := exec.Command("go", "list", "./...")
		buf := bytes.NewBuffer([]byte(""))
		icmd.Stdout = buf
		icmd.Env = append(os.Environ(), "GOGC=off")
		err = icmd.Run()
		if err == nil {
			list := strings.Split(buf.String(), "\n")[1:]
			for _, pkg := range list {
				if len(pkg) == 0 {
					continue
				}
				icmd = exec.Command(cmdName, "install", pkg)
				icmd.Stdout = os.Stdout
				icmd.Stderr = os.Stderr
				icmd.Env = append(os.Environ(), "GOGC=off")
				err = icmd.Run()
				if err != nil {
					break
				}
			}
		}
	}

	if isgenerate {
		icmd := exec.Command("bee", "generate", "docs")
		icmd.Env = append(os.Environ(), "GOGC=off")
		icmd.Stdout = os.Stdout
		icmd.Stderr = os.Stderr
		icmd.Run()
		ColorLog("============== generate docs ===================\n")
	}

	if err == nil {
		appName := appname
		if runtime.GOOS == "windows" {
			appName += ".exe"
		}

		args := []string{"build"}
		args = append(args, "-o", appName)
		if buildTags != "" {
			args = append(args, "-tags", buildTags)
		}
		args = append(args, files...)

		bcmd := exec.Command(cmdName, args...)
		bcmd.Env = append(os.Environ(), "GOGC=off")
		bcmd.Stdout = os.Stdout
		bcmd.Stderr = os.Stderr
		err = bcmd.Run()
	}

	if err != nil {
		ColorLog("[ERRO] ============== Build failed ===================\n")
		return
	}
	ColorLog("[SUCC] Build was successful\n")
	Restart(appname)
}

func Kill() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Println("Kill.recover -> ", e)
		}
	}()
	if cmd != nil && cmd.Process != nil {
		err := cmd.Process.Kill()
		if err != nil {
			fmt.Println("Kill -> ", err)
		}
	}
}

func Restart(appname string) {
	Debugf("kill running process")
	Kill()
	go Start(appname)
}

func Start(appname string) {
	ColorLog("[INFO] Restarting %s ...\n", appname)
	if strings.Index(appname, "./") == -1 {
		appname = "./" + appname
	}

	cmd = exec.Command(appname)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Args = append([]string{appname}, conf.CmdArgs...)
	cmd.Env = append(os.Environ(), conf.Envs...)

	go cmd.Run()
	ColorLog("[INFO] %s is running...\n", appname)
	started <- true
}

// checkTMPFile returns true if the event was for TMP files.
func checkTMPFile(name string) bool {
	if strings.HasSuffix(strings.ToLower(name), ".tmp") {
		return true
	}
	return false
}

var watchExts = []string{".go"}

// checkIfWatchExt returns true if the name HasSuffix <watch_ext>.
func checkIfWatchExt(name string) bool {
	for _, s := range watchExts {
		if strings.HasSuffix(name, s) {
			return true
		}
	}
	return false
}
<|endoftext|>