<commit_before>// Package millipede provides a framework for creating millipedes.
// millipede is designed to be easy to understand and write, the most simple
// application can be written as follow:
//   func main() {
//     fmt.Println(millipede.New(20))
//   }
package millipede

import (
	"bytes"
	"fmt"
	"math"
	"strings"
	"unicode/utf8"

	"github.com/getmillipede/millipede-go/vendor/github.com/Sirupsen/logrus"
	"github.com/getmillipede/millipede-go/vendor/github.com/kortschak/zalgo"
	"github.com/getmillipede/millipede-go/vendor/github.com/mgutz/ansi"
	"github.com/getmillipede/millipede-go/vendor/golang.org/x/crypto/ssh/terminal"
)

// Millipede defines a millipede configuration
type Millipede struct {
	// Size is the amount of feet pairs
	Size uint64
	// Reverse is the flag that indicates the direction (up/down)
	Reverse bool
	// Skin is the current millipede skin (template)
	Skin string
	// Opposite is the flag that indicates the direction (left/right)
	Opposite bool
	// Width is the width of the millipede (depending on its age and the food it consumes)
	Width uint64
	// Curve is the size of the curve
	Curve uint64
	// Chameleon is the flag that indicates the millipede share its environment color
	Chameleon bool
	// Rainbow is the flag that indicates the millipede live with care bears
	Rainbow bool
	// Zalgo is the flag that invoke the hive-mind representing chaos
	Zalgo bool
	// Step is the amount of steps done by the millipede (useful for animations)
	Steps uint64
	// Center is the flag that centers the millipede in the middle of the screen
	Center bool

	// PadRight is the flag that indicates the need to add spacing on the right of the output
	PadRight bool
}

// Skin defines the different parts of a millipede body
type Skin struct {
	// Head is used by the millipede to think about its life
	Head string
	// Pede are what make this arthropod so special
	Pede string
	// Reverse is the reverse skin of the millipede
	Reverse *Skin
}

// String returns a string representing a millipede
func (m *Millipede) String() string {
	paddingOffsets := []string{""}
	if m.Curve > 0 {
		for n := uint64(1); n < m.Curve*2; n++ {
			size := int(math.Min(float64(n%(m.Curve*2)), float64(m.Curve*2-n%(m.Curve*2))))
			paddingOffsets = append(paddingOffsets, strings.Repeat(" ", size))
		}
		// --opposite support
		if m.Opposite {
			paddingOffsets = append(paddingOffsets[m.Curve:], paddingOffsets[:m.Curve]...)
		}
	}

	skins := map[string]Skin{
		"default": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(███)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(███)═╗",
			},
		},
		"frozen": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(❄❄❄)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(❄❄❄)═╗",
			},
		},
		"corporate": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(©©©)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(©©©)═╗",
			},
		},
		"love": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♥♥♥)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♥♥♥)═╗",
			},
		},
		"musician": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♫♩♬)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♫♩♬)═╗",
			},
		},
		"bocal": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(🐟🐟🐟)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(🐟🐟🐟)═╗",
			},
		},
		"ascii": {
			Head: "  \\o o/  ",
			Pede: "|=(###)=|",
			Reverse: &Skin{
				Head: "  /o o\\  ",
				Pede: "|=(###)=|",
			},
		},
		"inception": {
			Head: "    👀    ",
			Pede: "╚═(🐛🐛🐛)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(🐛🐛🐛)═╗",
			},
		},
		"humancentipede": {
			Head: "    👀    ",
			Pede: "╚═(😷😷😷)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(😷😷😷)═╗",
			},
		},
		"finger": {
			Head: "    👀    ",
			Pede: "👈~~~  ~~~👉",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "👈~~~~~~~~👉",
			},
		},
		"handy": {
			Head: "    👀    ",
			Pede: "╚═(👌👌👌)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(👌👌👌)═╗",
			},
		},
	}

	// --skin support
	skin := skins[m.Skin]
	if skin.Head == "" {
		logrus.Fatalf("no such skin: '%s'", m.Skin)
	}

	// --reverse support
	if m.Reverse && skin.Reverse != nil && skin.Reverse.Head != "" {
		skin = *skin.Reverse
	}

	// --width support
	if m.Width < 3 {
		logrus.Fatalf("millipede cannot have a width < 3")
	}
	if m.Width > 3 {
		w := utf8.RuneCountInString(skin.Head)
		head := StringToRuneSlice(skin.Head)
		skin.Head = string(head[:w/2]) + strings.Repeat(string(head[w/2:w/2+1]), int(m.Width-2)) + string(head[w/2+1:])
		pede := StringToRuneSlice(skin.Pede)
		skin.Pede = string(pede[:w/2]) + strings.Repeat(string(pede[w/2:w/2+1]), int(m.Width-2)) + string(pede[w/2+1:])
	}

	// build the millipede body
	var body []string
	if m.Curve > 0 {
		body = []string{paddingOffsets[m.Steps%(m.Curve*2)] + strings.TrimRight(skin.Head, " ")}
	} else {
		body = []string{strings.TrimRight(skin.Head, " ")}
	}
	var x uint64
	for x = 0; x < m.Size; x++ {
		var line string
		if m.Curve > 0 {
			line = paddingOffsets[(m.Steps+x)%(m.Curve*2)] + skin.Pede
		} else {
			line = "" + skin.Pede
		}
		body = append(body, line)
	}

	// --reverse support
	if m.Reverse {
		for i, j := 0, len(body)-1; i < j; i, j = i+1, j-1 {
			body[i], body[j] = body[j], body[i]
		}
	}

	// --center support
	if m.Center {
		w, _, err := terminal.GetSize(0)
		if err == nil {
			var maxWidth int
			for _, line := range body {
				if len(line) > maxWidth {
					maxWidth = utf8.RuneCount([]byte(line))
				}
			}
			if maxWidth < w {
				leftMarginSize := (w / 2) - (maxWidth / 2)
				margin := strings.Repeat(" ", leftMarginSize)
				for idx, line := range body {
					body[idx] = margin + line
				}
			}
		}
	}

	// --chameleon and --rainbow support
	for idx, line := range body {
		colors := []string{"red", "green", "yellow", "blue", "magenta", "cyan", "white"}

		fgColor := ""
		bgColor := ""

		// --chameleon support
		if m.Chameleon {
			fgColor = "black"
		}

		// --rainbow
		if m.Rainbow {
			bgColor = colors[idx%len(colors)]
			if m.Chameleon {
				fgColor = bgColor
				fgColor = "black"
			}
		}

		if fgColor != "" || bgColor != "" {
			paddingSize := len(line) - len(strings.TrimSpace(line))
			line = strings.Repeat(" ", paddingSize) + ansi.Color(line[paddingSize:], fgColor+":"+bgColor)
		}

		if m.PadRight {
			line = line + strings.Repeat(" ", int(m.Curve))
		}

		body[idx] = line
	}

	output := strings.Join(body, "\n")

	// --zalgo support
	if m.Zalgo {
		buf := new(bytes.Buffer)

		z := zalgo.NewCorrupter(buf)
		z.Zalgo = func(n int, r rune, z *zalgo.Corrupter) bool {
			if string(r) == " " || r == 10 {
				z.Up = 0
				z.Middle = 0
				z.Down = 0
			} else {
				if z.Up == 0 {
					z.Up = complex(0, 0.2)
					z.Middle = complex(0, 0.2)
					z.Down = complex(0.001, 0.3)
				}
				z.Up += 0.1
				z.Middle += complex(0.1, 0.2)
				z.Down += 0.1
			}
			return false
		}
		fmt.Fprintln(z, output)
		output = buf.String()
	}

	return output
}

// New returns a millipede
func New(size uint64) *Millipede {
	return &Millipede{
		Size:      size,
		Reverse:   false,
		Skin:      "default",
		Opposite:  false,
		Width:     3,
		Curve:     4,
		Chameleon: false,
		Rainbow:   false,
		Zalgo:     false,
		Steps:     0,
		Center:    false,
	}
}

// StringToRuneSlice converts a string to a slice of runes
func StringToRuneSlice(input string) []rune {
	output := make([]rune, utf8.RuneCountInString(input))
	n := 0
	for _, r := range input {
		output[n] = r
		n++
	}
	return output
}
<commit_msg>Added --skin=human<commit_after>// Package millipede provides a framework for creating millipedes.
// millipede is designed to be easy to understand and write, the most simple
// application can be written as follow:
//   func main() {
//     fmt.Println(millipede.New(20))
//   }
package millipede

import (
	"bytes"
	"fmt"
	"math"
	"strings"
	"unicode/utf8"

	"github.com/getmillipede/millipede-go/vendor/github.com/Sirupsen/logrus"
	"github.com/getmillipede/millipede-go/vendor/github.com/kortschak/zalgo"
	"github.com/getmillipede/millipede-go/vendor/github.com/mgutz/ansi"
	"github.com/getmillipede/millipede-go/vendor/golang.org/x/crypto/ssh/terminal"
)

// Millipede defines a millipede configuration
type Millipede struct {
	// Size is the amount of feet pairs
	Size uint64
	// Reverse is the flag that indicates the direction (up/down)
	Reverse bool
	// Skin is the current millipede skin (template)
	Skin string
	// Opposite is the flag that indicates the direction (left/right)
	Opposite bool
	// Width is the width of the millipede (depending on its age and the food it consumes)
	Width uint64
	// Curve is the size of the curve
	Curve uint64
	// Chameleon is the flag that indicates the millipede share its environment color
	Chameleon bool
	// Rainbow is the flag that indicates the millipede live with care bears
	Rainbow bool
	// Zalgo is the flag that invoke the hive-mind representing chaos
	Zalgo bool
	// Step is the amount of steps done by the millipede (useful for animations)
	Steps uint64
	// Center is the flag that centers the millipede in the middle of the screen
	Center bool

	// PadRight is the flag that indicates the need to add spacing on the right of the output
	PadRight bool
}

// Skin defines the different parts of a millipede body
type Skin struct {
	// Head is used by the millipede to think about its life
	Head string
	// Pede are what make this arthropod so special
	Pede string
	// Reverse is the reverse skin of the millipede
	Reverse *Skin
}

// String returns a string representing a millipede
func (m *Millipede) String() string {
	paddingOffsets := []string{""}
	if m.Curve > 0 {
		for n := uint64(1); n < m.Curve*2; n++ {
			size := int(math.Min(float64(n%(m.Curve*2)), float64(m.Curve*2-n%(m.Curve*2))))
			paddingOffsets = append(paddingOffsets, strings.Repeat(" ", size))
		}
		// --opposite support
		if m.Opposite {
			paddingOffsets = append(paddingOffsets[m.Curve:], paddingOffsets[:m.Curve]...)
		}
	}

	skins := map[string]Skin{
		"default": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(███)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(███)═╗",
			},
		},
		"frozen": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(❄❄❄)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(❄❄❄)═╗",
			},
		},
		"corporate": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(©©©)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(©©©)═╗",
			},
		},
		"love": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♥♥♥)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♥♥♥)═╗",
			},
		},
		"musician": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♫♩♬)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♫♩♬)═╗",
			},
		},
		"bocal": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(🐟🐟🐟)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(🐟🐟🐟)═╗",
			},
		},
		"ascii": {
			Head: "  \\o o/  ",
			Pede: "|=(###)=|",
			Reverse: &Skin{
				Head: "  /o o\\  ",
				Pede: "|=(###)=|",
			},
		},
		"inception": {
			Head: "    👀    ",
			Pede: "╚═(🐛🐛🐛)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(🐛🐛🐛)═╗",
			},
		},
		"humancentipede": {
			Head: "    👀    ",
			Pede: "╚═(😷😷😷)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(😷😷😷)═╗",
			},
		},
		"finger": {
			Head: "    👀    ",
			Pede: "👈~~~  ~~~👉",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "👈~~~~~~~~👉",
			},
		},
		"handy": {
			Head: "    👀    ",
			Pede: "╚═(👌👌👌)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(👌👌👌)═╗",
			},
		},
		"human": {
			Head: " ( ͡° ͜ʖ ͡°)",
			Pede: "👆 ......👆",
			Reverse: &Skin{
				Head: " ( ͡° ͜ʖ ͡°)",
				Pede: "👇 ......👇",
			},
		},
	}

	// --skin support
	skin := skins[m.Skin]
	if skin.Head == "" {
		logrus.Fatalf("no such skin: '%s'", m.Skin)
	}

	// --reverse support
	if m.Reverse && skin.Reverse != nil && skin.Reverse.Head != "" {
		skin = *skin.Reverse
	}

	// --width support
	if m.Width < 3 {
		logrus.Fatalf("millipede cannot have a width < 3")
	}
	if m.Width > 3 {
		w := utf8.RuneCountInString(skin.Head)
		head := StringToRuneSlice(skin.Head)
		skin.Head = string(head[:w/2]) + strings.Repeat(string(head[w/2:w/2+1]), int(m.Width-2)) + string(head[w/2+1:])
		pede := StringToRuneSlice(skin.Pede)
		skin.Pede = string(pede[:w/2]) + strings.Repeat(string(pede[w/2:w/2+1]), int(m.Width-2)) + string(pede[w/2+1:])
	}

	// build the millipede body
	var body []string
	if m.Curve > 0 {
		body = []string{paddingOffsets[m.Steps%(m.Curve*2)] + strings.TrimRight(skin.Head, " ")}
	} else {
		body = []string{strings.TrimRight(skin.Head, " ")}
	}
	var x uint64
	for x = 0; x < m.Size; x++ {
		var line string
		if m.Curve > 0 {
			line = paddingOffsets[(m.Steps+x)%(m.Curve*2)] + skin.Pede
		} else {
			line = "" + skin.Pede
		}
		body = append(body, line)
	}

	// --reverse support
	if m.Reverse {
		for i, j := 0, len(body)-1; i < j; i, j = i+1, j-1 {
			body[i], body[j] = body[j], body[i]
		}
	}

	// --center support
	if m.Center {
		w, _, err := terminal.GetSize(0)
		if err == nil {
			var maxWidth int
			for _, line := range body {
				if len(line) > maxWidth {
					maxWidth = utf8.RuneCount([]byte(line))
				}
			}
			if maxWidth < w {
				leftMarginSize := (w / 2) - (maxWidth / 2)
				margin := strings.Repeat(" ", leftMarginSize)
				for idx, line := range body {
					body[idx] = margin + line
				}
			}
		}
	}

	// --chameleon and --rainbow support
	for idx, line := range body {
		colors := []string{"red", "green", "yellow", "blue", "magenta", "cyan", "white"}

		fgColor := ""
		bgColor := ""

		// --chameleon support
		if m.Chameleon {
			fgColor = "black"
		}

		// --rainbow
		if m.Rainbow {
			bgColor = colors[idx%len(colors)]
			if m.Chameleon {
				fgColor = bgColor
				fgColor = "black"
			}
		}

		if fgColor != "" || bgColor != "" {
			paddingSize := len(line) - len(strings.TrimSpace(line))
			line = strings.Repeat(" ", paddingSize) + ansi.Color(line[paddingSize:], fgColor+":"+bgColor)
		}

		if m.PadRight {
			line = line + strings.Repeat(" ", int(m.Curve))
		}

		body[idx] = line
	}

	output := strings.Join(body, "\n")

	// --zalgo support
	if m.Zalgo {
		buf := new(bytes.Buffer)

		z := zalgo.NewCorrupter(buf)
		z.Zalgo = func(n int, r rune, z *zalgo.Corrupter) bool {
			if string(r) == " " || r == 10 {
				z.Up = 0
				z.Middle = 0
				z.Down = 0
			} else {
				if z.Up == 0 {
					z.Up = complex(0, 0.2)
					z.Middle = complex(0, 0.2)
					z.Down = complex(0.001, 0.3)
				}
				z.Up += 0.1
				z.Middle += complex(0.1, 0.2)
				z.Down += 0.1
			}
			return false
		}
		fmt.Fprintln(z, output)
		output = buf.String()
	}

	return output
}

// New returns a millipede
func New(size uint64) *Millipede {
	return &Millipede{
		Size:      size,
		Reverse:   false,
		Skin:      "default",
		Opposite:  false,
		Width:     3,
		Curve:     4,
		Chameleon: false,
		Rainbow:   false,
		Zalgo:     false,
		Steps:     0,
		Center:    false,
	}
}

// StringToRuneSlice converts a string to a slice of runes
func StringToRuneSlice(input string) []rune {
	output := make([]rune, utf8.RuneCountInString(input))
	n := 0
	for _, r := range input {
		output[n] = r
		n++
	}
	return output
}
<|endoftext|>


<commit_before>package goproxy

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/abourget/goproxy/har"
)

func (proxy *ProxyHttpServer) harLogAggregator() {
	proxy.Logf("Launching harLogAggregator()")
	for {
		select {
		case reqAndResp := <-proxy.harLogEntryCh:

			harEntry := new(har.HarEntry)
			harEntry.Request = har.ParseRequest(reqAndResp.req, reqAndResp.captureContent)
			harEntry.StartedDateTime = reqAndResp.start
			harEntry.Response = har.ParseResponse(reqAndResp.resp, reqAndResp.captureContent)
			harEntry.Time = reqAndResp.end.Sub(reqAndResp.start).Nanoseconds() / 1e6
			harEntry.FillIPAddress(reqAndResp.req)
			proxy.harLog.HarLog.AddEntry(*harEntry)

		case filename := <-proxy.harFlushRequest:
			proxy.Logf("Received HAR flush request to %q", filename)
			if len(proxy.harLog.HarLog.Entries) == 0 {
				proxy.Logf("No HAR entries to flush")
				continue
			}
			err := flushHarToDisk(&proxy.harLog, filename)
			if err != nil {
				proxy.Logf("Error flushing HAR file to disk: %s", err)
			} else {
				proxy.Logf("Wrote HAR file to disk: %s", filename)
			}

			proxy.harLog.HarLog = *(har.NewHarLog()) // reset
		}

	}
}

func flushHarToDisk(har *har.Har, filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	jsonHar, err := json.MarshalIndent(har, "", "  ")
	if err != nil {
		return err
	}

	_, err = file.Write(jsonHar)
	if err != nil {
		return err
	}

	return nil
}

type harReqAndResp struct {
	req            *http.Request
	start          time.Time
	resp           *http.Response
	end            time.Time
	captureContent bool
}

func copyReq(req *http.Request) (*http.Request, *http.Request) {
	reqCopy := new(http.Request)
	*reqCopy = *req
	req.Body, reqCopy.Body = copyReadCloser(req.Body, req.ContentLength)
	return req, reqCopy
}

func copyResp(resp *http.Response) (*http.Response, *http.Response) {
	respCopy := new(http.Response)
	*respCopy = *resp
	resp.Body, respCopy.Body = copyReadCloser(resp.Body, resp.ContentLength)
	return resp, respCopy
}

func copyReadCloser(readCloser io.ReadCloser, len int64) (io.ReadCloser, io.ReadCloser) {
	temp := bytes.NewBuffer(make([]byte, 0, len))
	teeReader := io.TeeReader(readCloser, temp)
	copy := bytes.NewBuffer(make([]byte, 0, len))
	copy.ReadFrom(teeReader)
	return ioutil.NopCloser(temp), ioutil.NopCloser(copy)
}

func (ctx *ProxyCtx) LogToHARFile(captureContent bool) Next {
	ctx.proxy.harFlusherRun.Do(func() {
		go ctx.proxy.harLogAggregator()
	})

	//tr := transport.Transport{Proxy: transport.ProxyFromEnvironment}
	reqAndResp := new(harReqAndResp)
	reqAndResp.start = time.Now()
	reqAndResp.captureContent = captureContent

	req := ctx.Req
	if captureContent && req.ContentLength > 0 {
		req, reqAndResp.req = copyReq(req)
	} else {
		reqAndResp.req = req
	}

	previousRoundTripper := wrapRoundTrip(req, ctx)

	ctx.RoundTripper = RoundTripperFunc(func(req *http.Request, ctx *ProxyCtx) (resp *http.Response, err error) {
		reqAndResp.end = time.Now()
		resp, err = previousRoundTripper.RoundTrip(req, ctx)
		//ctx.UserData["roundtripDetails"] = rtDetails
		if captureContent && resp != nil && resp.ContentLength > 0 {
			resp, reqAndResp.resp = copyResp(resp)
		} else {
			reqAndResp.resp = resp
		}
		ctx.proxy.harLogEntryCh <- *reqAndResp
		return resp, err
	})

	return NEXT
}

func (ctx *ProxyCtx) FlushHARToDisk(filename string) {
	ctx.proxy.FlushHARToDisk(filename)
}

func (proxy *ProxyHttpServer) FlushHARToDisk(filename string) {
	proxy.Logf("Calling a flush of HAR to disk")
	proxy.harFlushRequest <- filename
}
<commit_msg>Added docs.<commit_after>package goproxy

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/abourget/goproxy/har"
)

func (proxy *ProxyHttpServer) harLogAggregator() {
	proxy.Logf("Launching harLogAggregator()")
	for {
		select {
		case reqAndResp := <-proxy.harLogEntryCh:

			harEntry := new(har.HarEntry)
			harEntry.Request = har.ParseRequest(reqAndResp.req, reqAndResp.captureContent)
			harEntry.StartedDateTime = reqAndResp.start
			harEntry.Response = har.ParseResponse(reqAndResp.resp, reqAndResp.captureContent)
			harEntry.Time = reqAndResp.end.Sub(reqAndResp.start).Nanoseconds() / 1e6
			harEntry.FillIPAddress(reqAndResp.req)
			proxy.harLog.HarLog.AddEntry(*harEntry)

		case filename := <-proxy.harFlushRequest:
			proxy.Logf("Received HAR flush request to %q", filename)
			if len(proxy.harLog.HarLog.Entries) == 0 {
				proxy.Logf("No HAR entries to flush")
				continue
			}
			err := flushHarToDisk(&proxy.harLog, filename)
			if err != nil {
				proxy.Logf("Error flushing HAR file to disk: %s", err)
			} else {
				proxy.Logf("Wrote HAR file to disk: %s", filename)
			}

			proxy.harLog.HarLog = *(har.NewHarLog()) // reset
		}

	}
}

func flushHarToDisk(har *har.Har, filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	jsonHar, err := json.MarshalIndent(har, "", "  ")
	if err != nil {
		return err
	}

	_, err = file.Write(jsonHar)
	if err != nil {
		return err
	}

	return nil
}

type harReqAndResp struct {
	req            *http.Request
	start          time.Time
	resp           *http.Response
	end            time.Time
	captureContent bool
}

func copyReq(req *http.Request) (*http.Request, *http.Request) {
	reqCopy := new(http.Request)
	*reqCopy = *req
	req.Body, reqCopy.Body = copyReadCloser(req.Body, req.ContentLength)
	return req, reqCopy
}

func copyResp(resp *http.Response) (*http.Response, *http.Response) {
	respCopy := new(http.Response)
	*respCopy = *resp
	resp.Body, respCopy.Body = copyReadCloser(resp.Body, resp.ContentLength)
	return resp, respCopy
}

func copyReadCloser(readCloser io.ReadCloser, len int64) (io.ReadCloser, io.ReadCloser) {
	temp := bytes.NewBuffer(make([]byte, 0, len))
	teeReader := io.TeeReader(readCloser, temp)
	copy := bytes.NewBuffer(make([]byte, 0, len))
	copy.ReadFrom(teeReader)
	return ioutil.NopCloser(temp), ioutil.NopCloser(copy)
}

// LogToHARFile collects all the content from the Request/Response
// roundtrip and stores it in memory until you call
// `FlushHARToDisk(filename)`.. at which point it will all be flushed
// to disk in HAR file format.
func (ctx *ProxyCtx) LogToHARFile(captureContent bool) Next {
	ctx.proxy.harFlusherRun.Do(func() {
		go ctx.proxy.harLogAggregator()
	})

	//tr := transport.Transport{Proxy: transport.ProxyFromEnvironment}
	reqAndResp := new(harReqAndResp)
	reqAndResp.start = time.Now()
	reqAndResp.captureContent = captureContent

	req := ctx.Req
	if captureContent && req.ContentLength > 0 {
		req, reqAndResp.req = copyReq(req)
	} else {
		reqAndResp.req = req
	}

	previousRoundTripper := wrapRoundTrip(req, ctx)

	ctx.RoundTripper = RoundTripperFunc(func(req *http.Request, ctx *ProxyCtx) (resp *http.Response, err error) {
		reqAndResp.end = time.Now()
		resp, err = previousRoundTripper.RoundTrip(req, ctx)
		//ctx.UserData["roundtripDetails"] = rtDetails
		if captureContent && resp != nil && resp.ContentLength > 0 {
			resp, reqAndResp.resp = copyResp(resp)
		} else {
			reqAndResp.resp = resp
		}
		ctx.proxy.harLogEntryCh <- *reqAndResp
		return resp, err
	})

	return NEXT
}

func (ctx *ProxyCtx) FlushHARToDisk(filename string) {
	ctx.proxy.FlushHARToDisk(filename)
}

func (proxy *ProxyHttpServer) FlushHARToDisk(filename string) {
	proxy.Logf("Calling a flush of HAR to disk")
	proxy.harFlushRequest <- filename
}
<|endoftext|>


<commit_before>package chunkymonkey

import (
    .   "chunkymonkey/types"
)

const (
    BlockIDAir                 = BlockID(0)
    BlockIDStone               = BlockID(1)
    BlockIDGrass               = BlockID(2)
    BlockIDDirt                = BlockID(3)
    BlockIDCobblestone         = BlockID(4)
    BlockIDWood                = BlockID(5)
    BlockIDSapling             = BlockID(6)
    BlockIDBedrock             = BlockID(7)
    BlockIDWater               = BlockID(8)
    BlockIDStationaryWater     = BlockID(9)
    BlockIDLava                = BlockID(10)
    BlockIDStationaryLava      = BlockID(11)
    BlockIDSand                = BlockID(12)
    BlockIDGravel              = BlockID(13)
    BlockIDGoldOre             = BlockID(14)
    BlockIDIronOre             = BlockID(15)
    BlockIDCoalOre             = BlockID(16)
    BlockIDLog                 = BlockID(17)
    BlockIDLeaves              = BlockID(18)
    BlockIDSponge              = BlockID(19)
    BlockIDGlass               = BlockID(20)
    BlockIDRedCloth            = BlockID(21)
    BlockIDOrangeCloth         = BlockID(22)
    BlockIDYellowCloth         = BlockID(23)
    BlockIDLimeCloth           = BlockID(24)
    BlockIDGreenCloth          = BlockID(25)
    BlockIDAquagreenCloth      = BlockID(26)
    BlockIDCyanCloth           = BlockID(27)
    BlockIDBlueCloth           = BlockID(28)
    BlockIDPurpleCloth         = BlockID(29)
    BlockIDIndigoCloth         = BlockID(30)
    BlockIDVioletCloth         = BlockID(31)
    BlockIDMagentaCloth        = BlockID(32)
    BlockIDPinkCloth           = BlockID(33)
    BlockIDBlackCloth          = BlockID(34)
    BlockIDGrayCloth           = BlockID(35)
    BlockIDWhiteCloth          = BlockID(36)
    BlockIDYellowflower        = BlockID(37)
    BlockIDRedRose             = BlockID(38)
    BlockIDBrownMushroom       = BlockID(39)
    BlockIDRedMushroom         = BlockID(40)
    BlockIDGoldBlock           = BlockID(41)
    BlockIDIronBlock           = BlockID(42)
    BlockIDDoubleStep          = BlockID(43)
    BlockIDStep                = BlockID(44)
    BlockIDBrick               = BlockID(45)
    BlockIDTNT                 = BlockID(46)
    BlockIDBookshelf           = BlockID(47)
    BlockIDMossyCobblestone    = BlockID(48)
    BlockIDObsidian            = BlockID(49)
    BlockIDTorch               = BlockID(50)
    BlockIDFire                = BlockID(51)
    BlockIDMobSpawner          = BlockID(52)
    BlockIDWoodenStairs        = BlockID(53)
    BlockIDChest               = BlockID(54)
    BlockIDRedstoneWire        = BlockID(55)
    BlockIDDiamondOre          = BlockID(56)
    BlockIDDiamondBlock        = BlockID(57)
    BlockIDWorkbench           = BlockID(58)
    BlockIDCrops               = BlockID(59)
    BlockIDSoil                = BlockID(60)
    BlockIDFurnace             = BlockID(61)
    BlockIDBurningFurnace      = BlockID(62)
    BlockIDSignPost            = BlockID(63)
    BlockIDWoodenoor           = BlockID(64)
    BlockIDLadder              = BlockID(65)
    BlockIDMinecartTracks      = BlockID(66)
    BlockIDCobblestoneStairs   = BlockID(67)
    BlockIDWallSign            = BlockID(68)
    BlockIDLever               = BlockID(69)
    BlockIDStonePressurePlate  = BlockID(70)
    BlockIDIrondoor            = BlockID(71)
    BlockIDWoodenPressurePlate = BlockID(72)
    BlockIDRedstoneOre         = BlockID(73)
    BlockIDGlowingRedstoneOre  = BlockID(74)
    BlockIDRedstoneTorchOff    = BlockID(75)
    BlockIDRedstoneTorchOn     = BlockID(76)
    BlockIDStoneButton         = BlockID(77)
    BlockIDSnow                = BlockID(78)
    BlockIDIce                 = BlockID(79)
    BlockIDSnowBlock           = BlockID(80)
    BlockIDCactus              = BlockID(81)
    BlockIDClay                = BlockID(82)
    BlockIDReed                = BlockID(83)
    BlockIDJukebox             = BlockID(84)
    BlockIDFence               = BlockID(85)
    BlockIDPumpkin             = BlockID(86)
    BlockIDNetherstone         = BlockID(87)
    BlockIDSlowSand            = BlockID(88)
    BlockIDLightstone          = BlockID(89)
    BlockIDPortal              = BlockID(90)
    BlockIDJackOLantern        = BlockID(91)
)

type Block struct {
    id           BlockID
    name         string
    transparency int8
}

func LoadStandardBlocks(b map[BlockID]*Block) {
    newBlock := func(id BlockID, name string) {
        b[id] = &Block{
            id:           id,
            name:         name,
            transparency: -1,
        }
    }

    newBlock(BlockIDAir, "air")
    newBlock(BlockIDStone, "stone")
    newBlock(BlockIDGrass, "grass")
    newBlock(BlockIDDirt, "dirt")
    newBlock(BlockIDCobblestone, "cobblestone")
    newBlock(BlockIDWood, "wood")
    newBlock(BlockIDSapling, "sapling")
    newBlock(BlockIDBedrock, "bedrock")
    newBlock(BlockIDWater, "water")
    newBlock(BlockIDStationaryWater, "stationary water")
    newBlock(BlockIDLava, "lava")
    newBlock(BlockIDStationaryLava, "stationary lava")
    newBlock(BlockIDSand, "sand")
    newBlock(BlockIDGravel, "gravel")
    newBlock(BlockIDGoldOre, "gold ore")
    newBlock(BlockIDIronOre, "iron ore")
    newBlock(BlockIDCoalOre, "coal ore")
    newBlock(BlockIDLog, "log")
    newBlock(BlockIDLeaves, "leaves")
    newBlock(BlockIDSponge, "sponge")
    newBlock(BlockIDGlass, "glass")
    newBlock(BlockIDRedCloth, "red cloth")
    newBlock(BlockIDOrangeCloth, "orange cloth")
    newBlock(BlockIDYellowCloth, "yellow cloth")
    newBlock(BlockIDLimeCloth, "lime cloth")
    newBlock(BlockIDGreenCloth, "green cloth")
    newBlock(BlockIDAquagreenCloth, "aquagreen cloth")
    newBlock(BlockIDCyanCloth, "cyan cloth")
    newBlock(BlockIDBlueCloth, "blue cloth")
    newBlock(BlockIDPurpleCloth, "purple cloth")
    newBlock(BlockIDIndigoCloth, "indigo cloth")
    newBlock(BlockIDVioletCloth, "violet cloth")
    newBlock(BlockIDMagentaCloth, "magenta cloth")
    newBlock(BlockIDPinkCloth, "Pink Cloth")
    newBlock(BlockIDBlackCloth, "Black Cloth")
    newBlock(BlockIDGrayCloth, "Gray Cloth")
    newBlock(BlockIDWhiteCloth, "white cloth")
    newBlock(BlockIDYellowflower, "yellowflower")
    newBlock(BlockIDRedRose, "red rose")
    newBlock(BlockIDBrownMushroom, "brown mushroom")
    newBlock(BlockIDRedMushroom, "red mushroom")
    newBlock(BlockIDGoldBlock, "gold block")
    newBlock(BlockIDIronBlock, "iron block")
    newBlock(BlockIDDoubleStep, "double step")
    newBlock(BlockIDStep, "step")
    newBlock(BlockIDBrick, "brick")
    newBlock(BlockIDTNT, "t n t")
    newBlock(BlockIDBookshelf, "bookshelf")
    newBlock(BlockIDMossyCobblestone, "mossy cobblestone")
    newBlock(BlockIDObsidian, "obsidian")
    newBlock(BlockIDTorch, "torch")
    newBlock(BlockIDFire, "fire")
    newBlock(BlockIDMobSpawner, "mob spawner")
    newBlock(BlockIDWoodenStairs, "wooden stairs")
    newBlock(BlockIDChest, "chest")
    newBlock(BlockIDRedstoneWire, "redstone wire")
    newBlock(BlockIDDiamondOre, "diamond ore")
    newBlock(BlockIDDiamondBlock, "diamond block")
    newBlock(BlockIDWorkbench, "workbench")
    newBlock(BlockIDCrops, "crops")
    newBlock(BlockIDSoil, "soil")
    newBlock(BlockIDFurnace, "furnace")
    newBlock(BlockIDBurningFurnace, "burning furnace")
    newBlock(BlockIDSignPost, "sign post")
    newBlock(BlockIDWoodenoor, "wooden door")
    newBlock(BlockIDLadder, "ladder")
    newBlock(BlockIDMinecartTracks, "minecart tracks")
    newBlock(BlockIDCobblestoneStairs, "cobblestone stairs")
    newBlock(BlockIDWallSign, "wall sign")
    newBlock(BlockIDLever, "lever")
    newBlock(BlockIDStonePressurePlate, "stone pressure plate")
    newBlock(BlockIDIrondoor, "irondoor")
    newBlock(BlockIDWoodenPressurePlate, "wooden pressure plate")
    newBlock(BlockIDRedstoneOre, "redstone ore")
    newBlock(BlockIDGlowingRedstoneOre, "glowing redstone ore")
    newBlock(BlockIDRedstoneTorchOff, "redstone torch off")
    newBlock(BlockIDRedstoneTorchOn, "redstone torch on")
    newBlock(BlockIDStoneButton, "stone button")
    newBlock(BlockIDSnow, "snow")
    newBlock(BlockIDIce, "ice")
    newBlock(BlockIDSnowBlock, "snow block")
    newBlock(BlockIDCactus, "cactus")
    newBlock(BlockIDClay, "clay")
    newBlock(BlockIDReed, "reed")
    newBlock(BlockIDJukebox, "jukebox")
    newBlock(BlockIDFence, "fence")
    newBlock(BlockIDPumpkin, "pumpkin")
    newBlock(BlockIDNetherstone, "netherstone")
    newBlock(BlockIDSlowSand, "slow sand")
    newBlock(BlockIDLightstone, "lightstone")
    newBlock(BlockIDPortal, "portal")
    newBlock(BlockIDJackOLantern, "jack o lantern")

    setTrans := func(transparency int8, blockTypes []BlockID) {
        for _, blockType := range blockTypes {
            b[blockType].transparency = transparency
        }
    }
    // Setup transparent blocks
    setTrans(0, [...]BlockID{BlockIDAir, BlockIDSapling, BlockIDGlass,
        BlockIDYellowflower, BlockIDRedRose, BlockIDBrownMushroom,
        BlockIDRedMushroom, BlockIDFire, BlockIDMobSpawner, BlockIDWoodenStairs,
        BlockIDRedstoneWire, BlockIDCrops, BlockIDSignPost, BlockIDLadder,
        BlockIDMinecartTracks, BlockIDCobblestoneStairs, BlockIDWallSign,
        BlockIDLever, BlockIDIrondoor, BlockIDRedstoneTorchOff,
        BlockIDRedstoneTorchOn, BlockIDStoneButton, BlockIDSnow, BlockIDCactus,
        BlockIDReed, BlockIDFence, BlockIDPortal}[:])

    // Setup semi-transparent blocks
    setTrans(1, [...]BlockID{BlockIDLeaves}[:])
    setTrans(3, [...]BlockID{BlockIDWater, BlockIDStationaryWater, BlockIDIce}[:])
}
<commit_msg>Remove unnecessary array to slice conversation.<commit_after>package chunkymonkey

import (
    .   "chunkymonkey/types"
)

const (
    BlockIDAir                 = BlockID(0)
    BlockIDStone               = BlockID(1)
    BlockIDGrass               = BlockID(2)
    BlockIDDirt                = BlockID(3)
    BlockIDCobblestone         = BlockID(4)
    BlockIDWood                = BlockID(5)
    BlockIDSapling             = BlockID(6)
    BlockIDBedrock             = BlockID(7)
    BlockIDWater               = BlockID(8)
    BlockIDStationaryWater     = BlockID(9)
    BlockIDLava                = BlockID(10)
    BlockIDStationaryLava      = BlockID(11)
    BlockIDSand                = BlockID(12)
    BlockIDGravel              = BlockID(13)
    BlockIDGoldOre             = BlockID(14)
    BlockIDIronOre             = BlockID(15)
    BlockIDCoalOre             = BlockID(16)
    BlockIDLog                 = BlockID(17)
    BlockIDLeaves              = BlockID(18)
    BlockIDSponge              = BlockID(19)
    BlockIDGlass               = BlockID(20)
    BlockIDRedCloth            = BlockID(21)
    BlockIDOrangeCloth         = BlockID(22)
    BlockIDYellowCloth         = BlockID(23)
    BlockIDLimeCloth           = BlockID(24)
    BlockIDGreenCloth          = BlockID(25)
    BlockIDAquagreenCloth      = BlockID(26)
    BlockIDCyanCloth           = BlockID(27)
    BlockIDBlueCloth           = BlockID(28)
    BlockIDPurpleCloth         = BlockID(29)
    BlockIDIndigoCloth         = BlockID(30)
    BlockIDVioletCloth         = BlockID(31)
    BlockIDMagentaCloth        = BlockID(32)
    BlockIDPinkCloth           = BlockID(33)
    BlockIDBlackCloth          = BlockID(34)
    BlockIDGrayCloth           = BlockID(35)
    BlockIDWhiteCloth          = BlockID(36)
    BlockIDYellowflower        = BlockID(37)
    BlockIDRedRose             = BlockID(38)
    BlockIDBrownMushroom       = BlockID(39)
    BlockIDRedMushroom         = BlockID(40)
    BlockIDGoldBlock           = BlockID(41)
    BlockIDIronBlock           = BlockID(42)
    BlockIDDoubleStep          = BlockID(43)
    BlockIDStep                = BlockID(44)
    BlockIDBrick               = BlockID(45)
    BlockIDTNT                 = BlockID(46)
    BlockIDBookshelf           = BlockID(47)
    BlockIDMossyCobblestone    = BlockID(48)
    BlockIDObsidian            = BlockID(49)
    BlockIDTorch               = BlockID(50)
    BlockIDFire                = BlockID(51)
    BlockIDMobSpawner          = BlockID(52)
    BlockIDWoodenStairs        = BlockID(53)
    BlockIDChest               = BlockID(54)
    BlockIDRedstoneWire        = BlockID(55)
    BlockIDDiamondOre          = BlockID(56)
    BlockIDDiamondBlock        = BlockID(57)
    BlockIDWorkbench           = BlockID(58)
    BlockIDCrops               = BlockID(59)
    BlockIDSoil                = BlockID(60)
    BlockIDFurnace             = BlockID(61)
    BlockIDBurningFurnace      = BlockID(62)
    BlockIDSignPost            = BlockID(63)
    BlockIDWoodenoor           = BlockID(64)
    BlockIDLadder              = BlockID(65)
    BlockIDMinecartTracks      = BlockID(66)
    BlockIDCobblestoneStairs   = BlockID(67)
    BlockIDWallSign            = BlockID(68)
    BlockIDLever               = BlockID(69)
    BlockIDStonePressurePlate  = BlockID(70)
    BlockIDIrondoor            = BlockID(71)
    BlockIDWoodenPressurePlate = BlockID(72)
    BlockIDRedstoneOre         = BlockID(73)
    BlockIDGlowingRedstoneOre  = BlockID(74)
    BlockIDRedstoneTorchOff    = BlockID(75)
    BlockIDRedstoneTorchOn     = BlockID(76)
    BlockIDStoneButton         = BlockID(77)
    BlockIDSnow                = BlockID(78)
    BlockIDIce                 = BlockID(79)
    BlockIDSnowBlock           = BlockID(80)
    BlockIDCactus              = BlockID(81)
    BlockIDClay                = BlockID(82)
    BlockIDReed                = BlockID(83)
    BlockIDJukebox             = BlockID(84)
    BlockIDFence               = BlockID(85)
    BlockIDPumpkin             = BlockID(86)
    BlockIDNetherstone         = BlockID(87)
    BlockIDSlowSand            = BlockID(88)
    BlockIDLightstone          = BlockID(89)
    BlockIDPortal              = BlockID(90)
    BlockIDJackOLantern        = BlockID(91)
)

type Block struct {
    id           BlockID
    name         string
    transparency int8
}

func LoadStandardBlocks(b map[BlockID]*Block) {
    newBlock := func(id BlockID, name string) {
        b[id] = &Block{
            id:           id,
            name:         name,
            transparency: -1,
        }
    }

    newBlock(BlockIDAir, "air")
    newBlock(BlockIDStone, "stone")
    newBlock(BlockIDGrass, "grass")
    newBlock(BlockIDDirt, "dirt")
    newBlock(BlockIDCobblestone, "cobblestone")
    newBlock(BlockIDWood, "wood")
    newBlock(BlockIDSapling, "sapling")
    newBlock(BlockIDBedrock, "bedrock")
    newBlock(BlockIDWater, "water")
    newBlock(BlockIDStationaryWater, "stationary water")
    newBlock(BlockIDLava, "lava")
    newBlock(BlockIDStationaryLava, "stationary lava")
    newBlock(BlockIDSand, "sand")
    newBlock(BlockIDGravel, "gravel")
    newBlock(BlockIDGoldOre, "gold ore")
    newBlock(BlockIDIronOre, "iron ore")
    newBlock(BlockIDCoalOre, "coal ore")
    newBlock(BlockIDLog, "log")
    newBlock(BlockIDLeaves, "leaves")
    newBlock(BlockIDSponge, "sponge")
    newBlock(BlockIDGlass, "glass")
    newBlock(BlockIDRedCloth, "red cloth")
    newBlock(BlockIDOrangeCloth, "orange cloth")
    newBlock(BlockIDYellowCloth, "yellow cloth")
    newBlock(BlockIDLimeCloth, "lime cloth")
    newBlock(BlockIDGreenCloth, "green cloth")
    newBlock(BlockIDAquagreenCloth, "aquagreen cloth")
    newBlock(BlockIDCyanCloth, "cyan cloth")
    newBlock(BlockIDBlueCloth, "blue cloth")
    newBlock(BlockIDPurpleCloth, "purple cloth")
    newBlock(BlockIDIndigoCloth, "indigo cloth")
    newBlock(BlockIDVioletCloth, "violet cloth")
    newBlock(BlockIDMagentaCloth, "magenta cloth")
    newBlock(BlockIDPinkCloth, "Pink Cloth")
    newBlock(BlockIDBlackCloth, "Black Cloth")
    newBlock(BlockIDGrayCloth, "Gray Cloth")
    newBlock(BlockIDWhiteCloth, "white cloth")
    newBlock(BlockIDYellowflower, "yellowflower")
    newBlock(BlockIDRedRose, "red rose")
    newBlock(BlockIDBrownMushroom, "brown mushroom")
    newBlock(BlockIDRedMushroom, "red mushroom")
    newBlock(BlockIDGoldBlock, "gold block")
    newBlock(BlockIDIronBlock, "iron block")
    newBlock(BlockIDDoubleStep, "double step")
    newBlock(BlockIDStep, "step")
    newBlock(BlockIDBrick, "brick")
    newBlock(BlockIDTNT, "t n t")
    newBlock(BlockIDBookshelf, "bookshelf")
    newBlock(BlockIDMossyCobblestone, "mossy cobblestone")
    newBlock(BlockIDObsidian, "obsidian")
    newBlock(BlockIDTorch, "torch")
    newBlock(BlockIDFire, "fire")
    newBlock(BlockIDMobSpawner, "mob spawner")
    newBlock(BlockIDWoodenStairs, "wooden stairs")
    newBlock(BlockIDChest, "chest")
    newBlock(BlockIDRedstoneWire, "redstone wire")
    newBlock(BlockIDDiamondOre, "diamond ore")
    newBlock(BlockIDDiamondBlock, "diamond block")
    newBlock(BlockIDWorkbench, "workbench")
    newBlock(BlockIDCrops, "crops")
    newBlock(BlockIDSoil, "soil")
    newBlock(BlockIDFurnace, "furnace")
    newBlock(BlockIDBurningFurnace, "burning furnace")
    newBlock(BlockIDSignPost, "sign post")
    newBlock(BlockIDWoodenoor, "wooden door")
    newBlock(BlockIDLadder, "ladder")
    newBlock(BlockIDMinecartTracks, "minecart tracks")
    newBlock(BlockIDCobblestoneStairs, "cobblestone stairs")
    newBlock(BlockIDWallSign, "wall sign")
    newBlock(BlockIDLever, "lever")
    newBlock(BlockIDStonePressurePlate, "stone pressure plate")
    newBlock(BlockIDIrondoor, "irondoor")
    newBlock(BlockIDWoodenPressurePlate, "wooden pressure plate")
    newBlock(BlockIDRedstoneOre, "redstone ore")
    newBlock(BlockIDGlowingRedstoneOre, "glowing redstone ore")
    newBlock(BlockIDRedstoneTorchOff, "redstone torch off")
    newBlock(BlockIDRedstoneTorchOn, "redstone torch on")
    newBlock(BlockIDStoneButton, "stone button")
    newBlock(BlockIDSnow, "snow")
    newBlock(BlockIDIce, "ice")
    newBlock(BlockIDSnowBlock, "snow block")
    newBlock(BlockIDCactus, "cactus")
    newBlock(BlockIDClay, "clay")
    newBlock(BlockIDReed, "reed")
    newBlock(BlockIDJukebox, "jukebox")
    newBlock(BlockIDFence, "fence")
    newBlock(BlockIDPumpkin, "pumpkin")
    newBlock(BlockIDNetherstone, "netherstone")
    newBlock(BlockIDSlowSand, "slow sand")
    newBlock(BlockIDLightstone, "lightstone")
    newBlock(BlockIDPortal, "portal")
    newBlock(BlockIDJackOLantern, "jack o lantern")

    setTrans := func(transparency int8, blockTypes []BlockID) {
        for _, blockType := range blockTypes {
            b[blockType].transparency = transparency
        }
    }
    // Setup transparent blocks
    setTrans(0, []BlockID{BlockIDAir, BlockIDSapling, BlockIDGlass,
        BlockIDYellowflower, BlockIDRedRose, BlockIDBrownMushroom,
        BlockIDRedMushroom, BlockIDFire, BlockIDMobSpawner, BlockIDWoodenStairs,
        BlockIDRedstoneWire, BlockIDCrops, BlockIDSignPost, BlockIDLadder,
        BlockIDMinecartTracks, BlockIDCobblestoneStairs, BlockIDWallSign,
        BlockIDLever, BlockIDIrondoor, BlockIDRedstoneTorchOff,
        BlockIDRedstoneTorchOn, BlockIDStoneButton, BlockIDSnow, BlockIDCactus,
        BlockIDReed, BlockIDFence, BlockIDPortal})

    // Setup semi-transparent blocks
    setTrans(1, []BlockID{BlockIDLeaves})
    setTrans(3, []BlockID{BlockIDWater, BlockIDStationaryWater, BlockIDIce})
}
<|endoftext|>


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

package main

import (
	"crypto/tls"
	"log"
	"net/http"
	"os"

	"github.com/GeertJohan/go.rice"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/sivel/spinclass/common"
	"github.com/sivel/spinclass/config"
	"github.com/sivel/spinclass/handler"
	"github.com/sivel/spinclass/spin"
)

var (
	Roster common.RosterType
)

func main() {
	conf := config.Config()

	Roster = make(common.RosterType)

	router := mux.NewRouter().StrictSlash(true)

	h := handler.Handler{
		Router: router,
		Config: conf,
		Roster: Roster,
		Class: spin.Class{
			Config: conf,
			Roster: Roster,
		},
	}

	h.Class.Create()

	loggingHandler := handlers.CombinedLoggingHandler(os.Stdout, router)

	box := rice.MustFindBox("static")
	router.PathPrefix("/").Handler(http.FileServer(box.HTTPBox()))
	router.HandleFunc("/spin/up", h.SpinUp).Methods("POST")
	router.HandleFunc("/spin/down", h.SpinDown).Methods("POST")
	router.HandleFunc("/odometer", h.Odometer).Methods("POST")
	router.HandleFunc("/final", h.Final).Methods("POST")

	http.Handle("/", loggingHandler)

	server := &http.Server{
		Addr:    conf.Server.Port,
		Handler: loggingHandler,
	}
	if len(conf.Server.Cert) == 0 || len(conf.Server.Key) == 0 {
		log.Fatal(server.ListenAndServe())
	} else {
		tlsConfig := &tls.Config{MinVersion: tls.VersionTLS10}
		server.TLSConfig = tlsConfig
		log.Fatal(server.ListenAndServeTLS(conf.Server.Cert, conf.Server.Key))
	}
}
<commit_msg>Move the '/' PathPrefix last<commit_after>// Copyright 2015 Matt Martz <matt@sivel.net>
// All Rights Reserved.
//
//    Licensed under the Apache License, Version 2.0 (the "License"); you may
//    not use this file except in compliance with the License. You may obtain
//    a copy of the License at
//
//         http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
//    License for the specific language governing permissions and limitations
//    under the License.

package main

import (
	"crypto/tls"
	"log"
	"net/http"
	"os"

	"github.com/GeertJohan/go.rice"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/sivel/spinclass/common"
	"github.com/sivel/spinclass/config"
	"github.com/sivel/spinclass/handler"
	"github.com/sivel/spinclass/spin"
)

var (
	Roster common.RosterType
)

func main() {
	conf := config.Config()

	Roster = make(common.RosterType)

	router := mux.NewRouter().StrictSlash(true)

	h := handler.Handler{
		Router: router,
		Config: conf,
		Roster: Roster,
		Class: spin.Class{
			Config: conf,
			Roster: Roster,
		},
	}

	h.Class.Create()

	loggingHandler := handlers.CombinedLoggingHandler(os.Stdout, router)

	box := rice.MustFindBox("static")
	router.HandleFunc("/spin/up", h.SpinUp).Methods("POST")
	router.HandleFunc("/spin/down", h.SpinDown).Methods("POST")
	router.HandleFunc("/odometer", h.Odometer).Methods("POST")
	router.HandleFunc("/final", h.Final).Methods("POST")
	router.PathPrefix("/").Handler(http.FileServer(box.HTTPBox()))

	http.Handle("/", loggingHandler)

	server := &http.Server{
		Addr:    conf.Server.Port,
		Handler: loggingHandler,
	}
	if len(conf.Server.Cert) == 0 || len(conf.Server.Key) == 0 {
		log.Fatal(server.ListenAndServe())
	} else {
		tlsConfig := &tls.Config{MinVersion: tls.VersionTLS10}
		server.TLSConfig = tlsConfig
		log.Fatal(server.ListenAndServeTLS(conf.Server.Cert, conf.Server.Key))
	}
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd 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 containers

import (
	"context"
	"errors"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/cio"
	"github.com/containerd/containerd/cmd/ctr/commands"
	"github.com/containerd/containerd/cmd/ctr/commands/run"
	"github.com/containerd/containerd/log"
	"github.com/urfave/cli"
)

// Command is the cli command for managing containers
var Command = cli.Command{
	Name:    "containers",
	Usage:   "manage containers",
	Aliases: []string{"c", "container"},
	Subcommands: []cli.Command{
		createCommand,
		deleteCommand,
		infoCommand,
		listCommand,
		setLabelsCommand,
	},
}

var createCommand = cli.Command{
	Name:      "create",
	Usage:     "create container",
	ArgsUsage: "[flags] Image|RootFS CONTAINER",
	Flags:     append(commands.SnapshotterFlags, commands.ContainerFlags...),
	Action: func(context *cli.Context) error {
		var (
			id     string
			ref    string
			config = context.IsSet("config")
		)

		if config {
			id = context.Args().First()
			if context.NArg() > 1 {
				return errors.New("with spec config file, only container id should be provided")
			}
		} else {
			id = context.Args().Get(1)
			ref = context.Args().First()
			if ref == "" {
				return errors.New("image ref must be provided")
			}
		}
		if id == "" {
			return errors.New("container id must be provided")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		_, err = run.NewContainer(ctx, client, context)
		if err != nil {
			return err
		}
		return nil
	},
}

var listCommand = cli.Command{
	Name:      "list",
	Aliases:   []string{"ls"},
	Usage:     "list containers",
	ArgsUsage: "[flags] [<filter>, ...]",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "print only the container id",
		},
	},
	Action: func(context *cli.Context) error {
		var (
			filters = context.Args()
			quiet   = context.Bool("quiet")
		)
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		containers, err := client.Containers(ctx, filters...)
		if err != nil {
			return err
		}
		if quiet {
			for _, c := range containers {
				fmt.Printf("%s\n", c.ID())
			}
			return nil
		}
		w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
		fmt.Fprintln(w, "CONTAINER\tIMAGE\tRUNTIME\t")
		for _, c := range containers {
			info, err := c.Info(ctx)
			if err != nil {
				return err
			}
			imageName := info.Image
			if imageName == "" {
				imageName = "-"
			}
			if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t\n",
				c.ID(),
				imageName,
				info.Runtime.Name,
			); err != nil {
				return err
			}
		}
		return w.Flush()
	},
}

var deleteCommand = cli.Command{
	Name:      "delete",
	Usage:     "delete one or more existing containers",
	ArgsUsage: "[flags] CONTAINER [CONTAINER, ...]",
	Aliases:   []string{"del", "rm"},
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "keep-snapshot",
			Usage: "do not clean up snapshot with container",
		},
	},
	Action: func(context *cli.Context) error {
		var exitErr error
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		deleteOpts := []containerd.DeleteOpts{}
		if !context.Bool("keep-snapshot") {
			deleteOpts = append(deleteOpts, containerd.WithSnapshotCleanup)
		}

		if context.NArg() == 0 {
			return errors.New("must specify at least one container to delete")
		}
		for _, arg := range context.Args() {
			if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil {
				if exitErr == nil {
					exitErr = err
				}
				log.G(ctx).WithError(err).Errorf("failed to delete container %q", arg)
			}
		}
		return exitErr
	},
}

func deleteContainer(ctx context.Context, client *containerd.Client, id string, opts ...containerd.DeleteOpts) error {
	container, err := client.LoadContainer(ctx, id)
	if err != nil {
		return err
	}
	task, err := container.Task(ctx, cio.Load)
	if err != nil {
		return container.Delete(ctx, opts...)
	}
	status, err := task.Status(ctx)
	if err != nil {
		return err
	}
	if status.Status == containerd.Stopped || status.Status == containerd.Created {
		if _, err := task.Delete(ctx); err != nil {
			return err
		}
		return container.Delete(ctx, opts...)
	}
	return fmt.Errorf("cannot delete a non stopped container: %v", status)

}

var setLabelsCommand = cli.Command{
	Name:        "label",
	Usage:       "set and clear labels for a container",
	ArgsUsage:   "[flags] CONTAINER [<key>=<value>, ...]",
	Description: "set and clear labels for a container",
	Flags:       []cli.Flag{},
	Action: func(context *cli.Context) error {
		containerID, labels := commands.ObjectWithLabelArgs(context)
		if containerID == "" {
			return errors.New("container id must be provided")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()

		container, err := client.LoadContainer(ctx, containerID)
		if err != nil {
			return err
		}

		setlabels, err := container.SetLabels(ctx, labels)
		if err != nil {
			return err
		}

		var labelStrings []string
		for k, v := range setlabels {
			labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
		}

		fmt.Println(strings.Join(labelStrings, ","))

		return nil
	},
}

var infoCommand = cli.Command{
	Name:      "info",
	Usage:     "get info about a container",
	ArgsUsage: "CONTAINER",
	Action: func(context *cli.Context) error {
		id := context.Args().First()
		if id == "" {
			return errors.New("container id must be provided")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		container, err := client.LoadContainer(ctx, id)
		if err != nil {
			return err
		}
		info, err := container.Info(ctx)
		if err != nil {
			return err
		}
		commands.PrintAsJSON(info)

		return nil
	},
}
<commit_msg>decode Spec value in command 'ctr c info <containerid>'<commit_after>/*
   Copyright The containerd 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 containers

import (
	"context"
	"errors"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/cio"
	"github.com/containerd/containerd/cmd/ctr/commands"
	"github.com/containerd/containerd/cmd/ctr/commands/run"
	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/log"
	"github.com/containerd/typeurl"
	"github.com/urfave/cli"
)

// Command is the cli command for managing containers
var Command = cli.Command{
	Name:    "containers",
	Usage:   "manage containers",
	Aliases: []string{"c", "container"},
	Subcommands: []cli.Command{
		createCommand,
		deleteCommand,
		infoCommand,
		listCommand,
		setLabelsCommand,
	},
}

var createCommand = cli.Command{
	Name:      "create",
	Usage:     "create container",
	ArgsUsage: "[flags] Image|RootFS CONTAINER",
	Flags:     append(commands.SnapshotterFlags, commands.ContainerFlags...),
	Action: func(context *cli.Context) error {
		var (
			id     string
			ref    string
			config = context.IsSet("config")
		)

		if config {
			id = context.Args().First()
			if context.NArg() > 1 {
				return errors.New("with spec config file, only container id should be provided")
			}
		} else {
			id = context.Args().Get(1)
			ref = context.Args().First()
			if ref == "" {
				return errors.New("image ref must be provided")
			}
		}
		if id == "" {
			return errors.New("container id must be provided")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		_, err = run.NewContainer(ctx, client, context)
		if err != nil {
			return err
		}
		return nil
	},
}

var listCommand = cli.Command{
	Name:      "list",
	Aliases:   []string{"ls"},
	Usage:     "list containers",
	ArgsUsage: "[flags] [<filter>, ...]",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "print only the container id",
		},
	},
	Action: func(context *cli.Context) error {
		var (
			filters = context.Args()
			quiet   = context.Bool("quiet")
		)
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		containers, err := client.Containers(ctx, filters...)
		if err != nil {
			return err
		}
		if quiet {
			for _, c := range containers {
				fmt.Printf("%s\n", c.ID())
			}
			return nil
		}
		w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
		fmt.Fprintln(w, "CONTAINER\tIMAGE\tRUNTIME\t")
		for _, c := range containers {
			info, err := c.Info(ctx)
			if err != nil {
				return err
			}
			imageName := info.Image
			if imageName == "" {
				imageName = "-"
			}
			if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t\n",
				c.ID(),
				imageName,
				info.Runtime.Name,
			); err != nil {
				return err
			}
		}
		return w.Flush()
	},
}

var deleteCommand = cli.Command{
	Name:      "delete",
	Usage:     "delete one or more existing containers",
	ArgsUsage: "[flags] CONTAINER [CONTAINER, ...]",
	Aliases:   []string{"del", "rm"},
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "keep-snapshot",
			Usage: "do not clean up snapshot with container",
		},
	},
	Action: func(context *cli.Context) error {
		var exitErr error
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		deleteOpts := []containerd.DeleteOpts{}
		if !context.Bool("keep-snapshot") {
			deleteOpts = append(deleteOpts, containerd.WithSnapshotCleanup)
		}

		if context.NArg() == 0 {
			return errors.New("must specify at least one container to delete")
		}
		for _, arg := range context.Args() {
			if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil {
				if exitErr == nil {
					exitErr = err
				}
				log.G(ctx).WithError(err).Errorf("failed to delete container %q", arg)
			}
		}
		return exitErr
	},
}

func deleteContainer(ctx context.Context, client *containerd.Client, id string, opts ...containerd.DeleteOpts) error {
	container, err := client.LoadContainer(ctx, id)
	if err != nil {
		return err
	}
	task, err := container.Task(ctx, cio.Load)
	if err != nil {
		return container.Delete(ctx, opts...)
	}
	status, err := task.Status(ctx)
	if err != nil {
		return err
	}
	if status.Status == containerd.Stopped || status.Status == containerd.Created {
		if _, err := task.Delete(ctx); err != nil {
			return err
		}
		return container.Delete(ctx, opts...)
	}
	return fmt.Errorf("cannot delete a non stopped container: %v", status)

}

var setLabelsCommand = cli.Command{
	Name:        "label",
	Usage:       "set and clear labels for a container",
	ArgsUsage:   "[flags] CONTAINER [<key>=<value>, ...]",
	Description: "set and clear labels for a container",
	Flags:       []cli.Flag{},
	Action: func(context *cli.Context) error {
		containerID, labels := commands.ObjectWithLabelArgs(context)
		if containerID == "" {
			return errors.New("container id must be provided")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()

		container, err := client.LoadContainer(ctx, containerID)
		if err != nil {
			return err
		}

		setlabels, err := container.SetLabels(ctx, labels)
		if err != nil {
			return err
		}

		var labelStrings []string
		for k, v := range setlabels {
			labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v))
		}

		fmt.Println(strings.Join(labelStrings, ","))

		return nil
	},
}

var infoCommand = cli.Command{
	Name:      "info",
	Usage:     "get info about a container",
	ArgsUsage: "CONTAINER",
	Action: func(context *cli.Context) error {
		id := context.Args().First()
		if id == "" {
			return errors.New("container id must be provided")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		container, err := client.LoadContainer(ctx, id)
		if err != nil {
			return err
		}
		info, err := container.Info(ctx)
		if err != nil {
			return err
		}

		if info.Spec != nil && info.Spec.Value != nil {
			v, err := typeurl.UnmarshalAny(info.Spec)
			if err != nil {
				return err
			}
			commands.PrintAsJSON(struct {
				containers.Container
				Spec interface{} `json:"Spec,omitempty"`
			}{
				Container: info,
				Spec:      v,
			})
			return nil
		}
		commands.PrintAsJSON(info)
		return nil
	},
}
<|endoftext|>


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

// +build darwin freebsd

package net

/*
#include <netdb.h>
*/
import "C"

func cgoAddrInfoFlags() C.int {
	return C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
}
<commit_msg>net: fix cgoAddrInfoFlags() on FreeBSD         CL 6250075 removed AI_MASK mask on all BSD variants,         however FreeBSD's AI_MASK does not include AI_V4MAPPED         and AI_ALL, and its libc is strict about the ai_flags.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd

package net

/*
#include <netdb.h>
*/
import "C"

func cgoAddrInfoFlags() C.int {
	return (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"xgb"
)

func main() {
	c, err := xgb.Dial(os.Getenv("DISPLAY"))
	if err != nil {
		fmt.Printf("cannot connect: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("vendor = '%s'\n", string(c.Setup.Vendor))

	win := c.NewId()
	gc := c.NewId()

	c.CreateWindow(0, win, c.DefaultScreen().Root, 150, 150, 200, 200, 0, 0, 0, 0, nil)
	c.ChangeWindowAttributes(win, xgb.CWEventMask,
		[]uint32{xgb.EventMaskExposure | xgb.EventMaskKeyRelease})
	c.CreateGC(gc, win, 0, nil)
	c.MapWindow(win)

	atom, _ := c.InternAtom(0, "HELLO")
	fmt.Printf("atom = %d\n", atom.Atom)

	points := make([]xgb.Point, 2)
	points[1] = xgb.Point{5, 5}
	points[1] = xgb.Point{100, 120}

	hosts, _ := c.ListHosts()
	fmt.Printf("hosts = %+v\n", hosts)

	ecookie := c.ListExtensionsRequest()
	exts, _ := c.ListExtensionsReply(ecookie)
	for _, name := range exts.Names {
		fmt.Printf("exts = '%s'\n", name.Name)
	}

	for {
		reply, err := c.WaitForEvent()
		if err != nil {
			fmt.Printf("error: %v\n", err)
			os.Exit(1)
		}
		fmt.Printf("event %T\n", reply)
		switch event := reply.(type) {
		case xgb.ExposeEvent:
			c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
		case xgb.KeyReleaseEvent:
			fmt.Printf("key release!\n")
			points[0].X = event.EventX
			points[0].Y = event.EventY
			c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
			c.Bell(75)
		}
	}

	c.Close()
}
<commit_msg>Fix xgb/example.go typo.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"xgb"
)

func main() {
	c, err := xgb.Dial(os.Getenv("DISPLAY"))
	if err != nil {
		fmt.Printf("cannot connect: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("vendor = '%s'\n", string(c.Setup.Vendor))

	win := c.NewId()
	gc := c.NewId()

	c.CreateWindow(0, win, c.DefaultScreen().Root, 150, 150, 200, 200, 0, 0, 0, 0, nil)
	c.ChangeWindowAttributes(win, xgb.CWEventMask,
		[]uint32{xgb.EventMaskExposure | xgb.EventMaskKeyRelease})
	c.CreateGC(gc, win, 0, nil)
	c.MapWindow(win)

	atom, _ := c.InternAtom(0, "HELLO")
	fmt.Printf("atom = %d\n", atom.Atom)

	points := make([]xgb.Point, 2)
	points[0] = xgb.Point{5, 5}
	points[1] = xgb.Point{100, 120}

	hosts, _ := c.ListHosts()
	fmt.Printf("hosts = %+v\n", hosts)

	ecookie := c.ListExtensionsRequest()
	exts, _ := c.ListExtensionsReply(ecookie)
	for _, name := range exts.Names {
		fmt.Printf("exts = '%s'\n", name.Name)
	}

	for {
		reply, err := c.WaitForEvent()
		if err != nil {
			fmt.Printf("error: %v\n", err)
			os.Exit(1)
		}
		fmt.Printf("event %T\n", reply)
		switch event := reply.(type) {
		case xgb.ExposeEvent:
			c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
		case xgb.KeyReleaseEvent:
			fmt.Printf("key release!\n")
			points[0].X = event.EventX
			points[0].Y = event.EventY
			c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
			c.Bell(75)
		}
	}

	c.Close()
}
<|endoftext|>


<commit_before>package models

type Error struct {
  Message string
  Type string
}

var (
  AlreadyExistsError = &Error{
    Message: "Already exists.",
    Type: "exists",
  }
  SaveErr = &Error{
    Message: "Error during save.",
    Type: "save",
  }
  NotFoundErr = &Error{
    Message: "Not found.",
    Type: "not_found",
  }
  DBErr = &Error{
    Message: "Database error.",
    Type: "db",
  }
  TokenErr = &Error{
    Message: "Error generating token",
    Type: "token",
  }
)

func (err *Error) Error() string {
  return err.Message
}
<commit_msg>Remove Type from errors. Easier to just `err == models.<err>`.<commit_after>package models

type Error struct {
  Message string
  Type string
}

var (
  AlreadyExistsError = &Error{
    Message: "Already exists.",
  }
  SaveErr = &Error{
    Message: "Error during save.",
  }
  NotFoundErr = &Error{
    Message: "Not found.",
  }
  DBErr = &Error{
    Message: "Database error.",
  }
  TokenErr = &Error{
    Message: "Error generating token",
  }
  TokenNotFound = &Error{
    Message: "Token could not be found.",
  }
)

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


<commit_before>package models

import "time"

// Silence is vanilla silence + some additional attributes
// Unsee adds JIRA support, it can extract JIRA IDs from comments
// extracted ID is used to generate link to JIRA issue
// this means Unsee needs to store additional fields for each silence
type Silence struct {
	ID       string `json:"id"`
	Matchers []struct {
		Name    string `json:"name"`
		Value   string `json:"value"`
		IsRegex bool   `json:"isRegex"`
	} `json:"matchers"`
	StartsAt  time.Time `json:"startsAt"`
	EndsAt    time.Time `json:"endsAt"`
	CreatedAt time.Time `json:"createdAt"`
	CreatedBy string    `json:"createdBy"`
	Comment   string    `json:"comment"`
	// unsee fields
	JiraID  string `json:"jiraID"`
	JiraURL string `json:"jiraURL"`
}

// Alert is vanilla alert + some additional attributes
// unsee extends an alert object with:
// * Links map, it's generated from annotations if annotation value is an url
//   it's pulled out of annotation map and returned under links field,
//   unsee UI used this to show links differently than other annotations
// * Fingerprint, which is a sha1 of the entire alert
type Alert struct {
	Annotations  map[string]string `json:"annotations"`
	Labels       map[string]string `json:"labels"`
	StartsAt     time.Time         `json:"startsAt"`
	EndsAt       time.Time         `json:"endsAt"`
	GeneratorURL string            `json:"generatorURL"`
	Inhibited    bool              `json:"inhibited"`
	Silenced     string            `json:"silenced"`
	// unsee fields
	Links       map[string]string `json:"links"`
	Fingerprint string            `json:"-"`
}

// AlertList is flat list of UnseeAlert objects
type AlertList []Alert

func (a AlertList) Len() int {
	return len(a)

}
func (a AlertList) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
func (a AlertList) Less(i, j int) bool {
	// compare timestamps, if equal compare fingerprints to stable sort order
	if a[i].StartsAt.After(a[j].StartsAt) {
		return true
	}
	if a[i].StartsAt.Before(a[j].StartsAt) {
		return false
	}
	return a[i].Fingerprint < a[j].Fingerprint
}

// AlertGroup is vanilla Alertmanager group, but alerts are flattened
// There is a hash computed from all alerts, it's used by UI to quickly tell
// if there was any change in a group and it needs to refresh it
type AlertGroup struct {
	Labels      map[string]string `json:"labels"`
	Alerts      AlertList         `json:"alerts"`
	ID          string            `json:"id"`
	Hash        string            `json:"hash"`
	ActiveCount int               `json:"activeCount"`
}

// Filter holds returned data on any filter passed by the user as part of the query
type Filter struct {
	Text    string `json:"text"`
	Hits    int    `json:"hits"`
	IsValid bool   `json:"isValid"`
}

// Color is used by UnseeLabelColor to reprenset colors as RGBA
type Color struct {
	Red   uint8 `json:"red"`
	Green uint8 `json:"green"`
	Blue  uint8 `json:"blue"`
	Alpha uint8 `json:"alpha"`
}

// LabelColors holds color information for labels that should be colored in the UI
// every configured label will have a distinct coloring for each value
type LabelColors struct {
	Font       Color `json:"font"`
	Background Color `json:"background"`
}

// LabelsColorMap is a map of "Label Key" -> "Label Value" -> UnseeLabelColors
type LabelsColorMap map[string]map[string]LabelColors

// LabelsCountMap is a map of "Label Key" -> "Label Value" -> number of occurence
type LabelsCountMap map[string]map[string]int

// AlertsResponse is the structure of JSON response UI will use to get alert data
type AlertsResponse struct {
	Status      string             `json:"status"`
	Error       string             `json:"error,omitempty"`
	Timestamp   string             `json:"timestamp"`
	Version     string             `json:"version"`
	AlertGroups []AlertGroup       `json:"groups"`
	Silences    map[string]Silence `json:"silences"`
	Colors      LabelsColorMap     `json:"colors"`
	Filters     []Filter           `json:"filters"`
	Counters    LabelsCountMap     `json:"counters"`
}

// Autocomplete is the structure of autocomplete object for filter hints
// this is internal represenation, not what's returned to the user
type Autocomplete struct {
	Value  string   `json:"value"`
	Tokens []string `json:"tokens"`
}
<commit_msg>Add new attrs for tracking alert status and linking silences / inhibiting alerts<commit_after>package models

import "time"

// Silence is vanilla silence + some additional attributes
// Unsee adds JIRA support, it can extract JIRA IDs from comments
// extracted ID is used to generate link to JIRA issue
// this means Unsee needs to store additional fields for each silence
type Silence struct {
	ID       string `json:"id"`
	Matchers []struct {
		Name    string `json:"name"`
		Value   string `json:"value"`
		IsRegex bool   `json:"isRegex"`
	} `json:"matchers"`
	StartsAt  time.Time `json:"startsAt"`
	EndsAt    time.Time `json:"endsAt"`
	CreatedAt time.Time `json:"createdAt"`
	CreatedBy string    `json:"createdBy"`
	Comment   string    `json:"comment"`
	// unsee fields
	JiraID  string `json:"jiraID"`
	JiraURL string `json:"jiraURL"`
}

// Alert is vanilla alert + some additional attributes
// unsee extends an alert object with:
// * Links map, it's generated from annotations if annotation value is an url
//   it's pulled out of annotation map and returned under links field,
//   unsee UI used this to show links differently than other annotations
// * Fingerprint, which is a sha1 of the entire alert
type Alert struct {
	Annotations  map[string]string `json:"annotations"`
	Labels       map[string]string `json:"labels"`
	StartsAt     time.Time         `json:"startsAt"`
	EndsAt       time.Time         `json:"endsAt"`
	GeneratorURL string            `json:"generatorURL"`
	Status       string            `json:"Status"`
	SilencedBy   []string          `json:"silencedBy"`
	InhibitedBy  []string          `json:"inhibitedBy"`
	Inhibited    bool              `json:"inhibited"`
	Silenced     string            `json:"silenced"`
	// unsee fields
	Links       map[string]string `json:"links"`
	Fingerprint string            `json:"-"`
}

// AlertList is flat list of UnseeAlert objects
type AlertList []Alert

func (a AlertList) Len() int {
	return len(a)

}
func (a AlertList) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
func (a AlertList) Less(i, j int) bool {
	// compare timestamps, if equal compare fingerprints to stable sort order
	if a[i].StartsAt.After(a[j].StartsAt) {
		return true
	}
	if a[i].StartsAt.Before(a[j].StartsAt) {
		return false
	}
	return a[i].Fingerprint < a[j].Fingerprint
}

// AlertGroup is vanilla Alertmanager group, but alerts are flattened
// There is a hash computed from all alerts, it's used by UI to quickly tell
// if there was any change in a group and it needs to refresh it
type AlertGroup struct {
	Labels      map[string]string `json:"labels"`
	Alerts      AlertList         `json:"alerts"`
	ID          string            `json:"id"`
	Hash        string            `json:"hash"`
	ActiveCount int               `json:"activeCount"`
}

// Filter holds returned data on any filter passed by the user as part of the query
type Filter struct {
	Text    string `json:"text"`
	Hits    int    `json:"hits"`
	IsValid bool   `json:"isValid"`
}

// Color is used by UnseeLabelColor to reprenset colors as RGBA
type Color struct {
	Red   uint8 `json:"red"`
	Green uint8 `json:"green"`
	Blue  uint8 `json:"blue"`
	Alpha uint8 `json:"alpha"`
}

// LabelColors holds color information for labels that should be colored in the UI
// every configured label will have a distinct coloring for each value
type LabelColors struct {
	Font       Color `json:"font"`
	Background Color `json:"background"`
}

// LabelsColorMap is a map of "Label Key" -> "Label Value" -> UnseeLabelColors
type LabelsColorMap map[string]map[string]LabelColors

// LabelsCountMap is a map of "Label Key" -> "Label Value" -> number of occurence
type LabelsCountMap map[string]map[string]int

// AlertsResponse is the structure of JSON response UI will use to get alert data
type AlertsResponse struct {
	Status      string             `json:"status"`
	Error       string             `json:"error,omitempty"`
	Timestamp   string             `json:"timestamp"`
	Version     string             `json:"version"`
	AlertGroups []AlertGroup       `json:"groups"`
	Silences    map[string]Silence `json:"silences"`
	Colors      LabelsColorMap     `json:"colors"`
	Filters     []Filter           `json:"filters"`
	Counters    LabelsCountMap     `json:"counters"`
}

// Autocomplete is the structure of autocomplete object for filter hints
// this is internal represenation, not what's returned to the user
type Autocomplete struct {
	Value  string   `json:"value"`
	Tokens []string `json:"tokens"`
}
<|endoftext|>


<commit_before>package lib

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"strings"

	"github.com/thomersch/gosmparse"
)

// ConfigJSON - struct representing the config file format
type ConfigJSON map[string]Group

// Group - a collection of groups
type Group [][]string

// Pattern - a group if one or more AND conditions
type Pattern []string

// FeatureSet struct
type FeatureSet struct {
	NodeConditions     Group
	WayConditions      Group
	RelationConditions Group
}

// NewFeatureSetFromJSON - load a featureset from JSON
func NewFeatureSetFromJSON(path string) (*FeatureSet, error) {

	file, e := ioutil.ReadFile(path)
	if nil != e {
		return nil, e
	}

	decoder := json.NewDecoder(bytes.NewReader(file))
	var config ConfigJSON
	decoder.Decode(&config)

	var fs = &FeatureSet{}
	fs.NodeConditions = config["node"]
	fs.WayConditions = config["way"]
	fs.RelationConditions = config["relation"]

	return fs, nil
}

// MatchNode - yes/no if any target feature matches this node
func (fs *FeatureSet) MatchNode(n gosmparse.Node) bool {
	return matchAny(n.Tags, fs.NodeConditions)
}

// MatchWay - yes/no if any target feature matches this way
func (fs *FeatureSet) MatchWay(w gosmparse.Way) bool {
	return matchAny(w.Tags, fs.WayConditions)
}

// MatchRelation - yes/no if any target feature matches this relation
func (fs *FeatureSet) MatchRelation(r gosmparse.Relation) bool {
	return matchAny(r.Tags, fs.RelationConditions)
}

// matchAny - match any group (logical OR)
func matchAny(tags map[string]string, groups Group) bool {

	// no tags at all
	if len(tags) == 0 {
		return false
	}

	// trim all keys/value of extra whitespace
	tags = trimTags(tags)

	// OR groups
	for _, group := range groups {
		// AND conditions
		if matchAll(tags, group) {
			return true
		}
	}

	return false
}

// matchAll - match all conditions (logical AND)
func matchAll(tags map[string]string, pattern Pattern) bool {
	if len(pattern) == 0 {
		return false
	}
	for _, condition := range pattern {
		if !matchOne(tags, condition) {
			return false
		}
	}
	return true
}

// matchOne - match a single condition
func matchOne(tags map[string]string, condition string) bool {

	// split to array, first part will be the key and second the value (if required)
	part := strings.Split(condition, "=")
	val, isFound := tags[part[0]]

	// key check
	if isFound {

		// checking key only
		if len(part) == 1 {
			return true
		}

		// value check
		if val == part[1] {
			return true
		}
	}

	return false
}

func trimTags(tags map[string]string) map[string]string {
	trimmed := make(map[string]string)
	for k, v := range tags {
		trimmed[strings.TrimSpace(k)] = strings.TrimSpace(v)
	}
	return trimmed
}
<commit_msg>formatting: clean up variable naming / syntax<commit_after>package lib

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"strings"

	"github.com/thomersch/gosmparse"
)

// ConfigJSON - struct representing the config file format
type ConfigJSON map[string]Group

// Group - a collection of groups
type Group [][]string

// Pattern - a group if one or more AND conditions
type Pattern []string

// FeatureSet struct
type FeatureSet struct {
	NodeConditions     Group
	WayConditions      Group
	RelationConditions Group
}

// NewFeatureSetFromJSON - load a featureset from JSON
func NewFeatureSetFromJSON(path string) (*FeatureSet, error) {

	file, e := ioutil.ReadFile(path)
	if nil != e {
		return nil, e
	}

	decoder := json.NewDecoder(bytes.NewReader(file))
	var config ConfigJSON
	decoder.Decode(&config)

	var fs = &FeatureSet{}
	fs.NodeConditions = config["node"]
	fs.WayConditions = config["way"]
	fs.RelationConditions = config["relation"]

	return fs, nil
}

// MatchNode - yes/no if any target feature matches this node
func (fs *FeatureSet) MatchNode(n gosmparse.Node) bool {
	return matchGroup(n.Tags, fs.NodeConditions)
}

// MatchWay - yes/no if any target feature matches this way
func (fs *FeatureSet) MatchWay(w gosmparse.Way) bool {
	return matchGroup(w.Tags, fs.WayConditions)
}

// MatchRelation - yes/no if any target feature matches this relation
func (fs *FeatureSet) MatchRelation(r gosmparse.Relation) bool {
	return matchGroup(r.Tags, fs.RelationConditions)
}

// matchGroup - match ANY pattern in group (logical OR)
func matchGroup(tags map[string]string, group Group) bool {

	// no tags at all
	if len(tags) == 0 {
		return false
	}

	// trim all keys/value of extra whitespace
	tags = trimTags(tags)

	// OR groups
	for _, pattern := range group {
		// AND conditions
		if matchPattern(tags, pattern) {
			return true
		}
	}

	return false
}

// matchPattern - match ALL conditions in pattern (logical AND)
func matchPattern(tags map[string]string, pattern Pattern) bool {
	if len(pattern) == 0 {
		return false
	}
	for _, condition := range pattern {
		if !matchCondition(tags, condition) {
			return false
		}
	}
	return true
}

// matchCondition - match a single condition
func matchCondition(tags map[string]string, condition string) bool {

	// split to array, first part will be the key and second the value (if required)
	part := strings.Split(condition, "=")
	val, isFound := tags[part[0]]

	// key check
	if isFound {

		// checking key only
		if len(part) == 1 {
			return true
		}

		// value check
		if val == part[1] {
			return true
		}
	}

	return false
}

// trimTags - remove leading/trailing spaces from tag keys/values
func trimTags(tags map[string]string) map[string]string {
	trimmed := make(map[string]string)
	for k, v := range tags {
		trimmed[strings.TrimSpace(k)] = strings.TrimSpace(v)
	}
	return trimmed
}
<|endoftext|>


<commit_before>package compound_test

import (
	"testing"
	"testing/quick"

	"github.com/tv42/compound"
)

type MyType struct {
	A uint64
	B string
	C uint64
}

func cmp(a, b MyType) int {
	switch {
	case a.A < b.A:
		return -1
	case a.A > b.A:
		return 1
	default:
		switch {
		case a.B < b.B:
			return -1
		case a.B > b.B:
			return 1
		default:
			switch {
			case string(a.C) < string(b.C):
				return -1
			case string(a.C) > string(b.C):
				return 1
			default:
				return 0
			}
		}
	}
}

func TestQuickOrder(t *testing.T) {
	unknown := func(a, b MyType) int {
		as := string(compound.Key(a))
		bs := string(compound.Key(b))
		switch {
		case as < bs:
			return -1
		case as == bs:
			return 0
		case as > bs:
			return 1
		}
		panic("this cannot happen")
	}

	if err := quick.CheckEqual(cmp, unknown, nil); err != nil {
		t.Error(err)
	}
}

func TestQuickRoundtrip(t *testing.T) {
	good := func(a MyType) (MyType, error) {
		return a, nil
	}
	unknown := func(a MyType) (MyType, error) {
		key := compound.Key(a)
		var r MyType
		err := compound.Decode(key, &r)
		return r, err
	}
	if err := quick.CheckEqual(good, unknown, nil); err != nil {
		t.Error(err)
	}
}
<commit_msg>Add quick check for short keys<commit_after>package compound_test

import (
	"testing"
	"testing/quick"

	"github.com/tv42/compound"
)

type MyType struct {
	A uint64
	B string
	C uint64
}

func cmp(a, b MyType) int {
	switch {
	case a.A < b.A:
		return -1
	case a.A > b.A:
		return 1
	default:
		switch {
		case a.B < b.B:
			return -1
		case a.B > b.B:
			return 1
		default:
			switch {
			case string(a.C) < string(b.C):
				return -1
			case string(a.C) > string(b.C):
				return 1
			default:
				return 0
			}
		}
	}
}

func TestQuickOrder(t *testing.T) {
	unknown := func(a, b MyType) int {
		as := string(compound.Key(a))
		bs := string(compound.Key(b))
		switch {
		case as < bs:
			return -1
		case as == bs:
			return 0
		case as > bs:
			return 1
		}
		panic("this cannot happen")
	}

	if err := quick.CheckEqual(cmp, unknown, nil); err != nil {
		t.Error(err)
	}
}

func TestQuickRoundtrip(t *testing.T) {
	good := func(a MyType) (MyType, error) {
		return a, nil
	}
	unknown := func(a MyType) (MyType, error) {
		key := compound.Key(a)
		var r MyType
		err := compound.Decode(key, &r)
		return r, err
	}
	if err := quick.CheckEqual(good, unknown, nil); err != nil {
		t.Error(err)
	}
}

func TestQuickErrorShort(t *testing.T) {
	check := func(a MyType) bool {
		key := compound.Key(a)
		for i := 0; i < len(key); i++ {
			var r MyType
			input := key[:i]
			err := compound.Decode(input, &r)
			if err != compound.ErrTooShort {
				t.Errorf("expected too short error for %q, got %v", input, err)
				return false
			}
		}
		return true
	}
	if err := quick.Check(check, nil); err != nil {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package helper

import (
	"time"

	"github.com/skynology/cloud-types"
)

// 创建新Helper
func NewHelper() *Helper {
	return &Helper{
		HideFields:    []string{},
		ProtectFields: []string{},
		Logs:          []types.CloudLog{},
		Data:          make(map[string]interface{}),
	}
}

// Helper
type Helper struct {
	Type          string
	IsFunction    bool
	HideFields    []string
	ProtectFields []string
	Result        interface{}
	Data          map[string]interface{}
	Logs          []types.CloudLog
	Errors        types.CloudError
}

// 完成并退出
// result 参数必须为可转为Json的对象
func (h *Helper) Render(result interface{}) {
	// 不允许在表hook中使用
	if h.Type == "hook" {
		return
	}
	h.Result = result
}

// 更新字段
func (h *Helper) Set(fieldName string, value interface{}) {
	h.Data[fieldName] = value
}

// 取消并返回
// 返回 RESTFul Error格式,
// Code: -1, Error: message
func (h *Helper) Cancel(message string) {
	h.Errors = types.CloudError{Code: -1, Message: message}
}

// 取消并返回
// 返回 RESTFul Error格式,
// Code: code, Error: message
func (h *Helper) CancelWithCode(message string, code int) {
	h.Errors = types.CloudError{Code: code, Message: message}
}

// 隐藏字段。不返回给API调用者
func (h *Helper) Hide(fieldName string) {
	h.HideFields = append(h.HideFields, fieldName)
}

// 保护字段， 设置过的字段将无法更新
func (h *Helper) Protect(fieldName string) {
	h.ProtectFields = append(h.ProtectFields, fieldName)
}

// 打印log, 方便调试
func (h *Helper) Log(message string) {
	h.LogWithFlag(message, "info")
}

func (h *Helper) LogWithFlag(message string, flag string) {
	l := types.CloudLog{}
	l.Content = message
	l.CreatedAt = time.Now().Format(time.RFC3339Nano)
	l.Flag = flag
	h.Logs = append(h.Logs, l)
}
<commit_msg>增加内部函数相关参数<commit_after>package helper

import (
	"time"

	"github.com/skynology/cloud-types"
	"github.com/skynology/go-sdk"
)

// 用于云代码中调用其他函数
type FuncHandler interface {
	Call(h *Helper, req types.CloudRequest, app *skynology.App, name string, data map[string]interface{}) (result map[string]interface{}, err error)
}

// 创建新Helper
func NewHelper(handler FuncHandler) *Helper {
	return &Helper{
		HideFields:    []string{},
		ProtectFields: []string{},
		Logs:          []types.CloudLog{},
		Data:          make(map[string]interface{}),
		funcHandler:   handler,
	}
}

// Helper
type Helper struct {
	Type          string
	IsFunction    bool
	HideFields    []string
	ProtectFields []string
	Result        interface{}
	Data          map[string]interface{}
	Logs          []types.CloudLog
	Errors        types.CloudError
	funcHandler   FuncHandler
}

// 云代码中调用函数
func (h *Helper) Call(req types.CloudRequest, app *skynology.App, name string, data map[string]interface{}) (result map[string]interface{}, err error) {
	result, err = h.funcHandler.Call(h, req, app, name, data)
	return
}

// 完成并退出
// result 参数必须为可转为Json的对象
func (h *Helper) Render(result interface{}) {
	// 不允许在表hook中使用
	if h.Type == "hook" {
		return
	}
	h.Result = result
}

// 更新字段
func (h *Helper) Set(fieldName string, value interface{}) {
	h.Data[fieldName] = value
}

// 取消并返回
// 返回 RESTFul Error格式,
// Code: -1, Error: message
func (h *Helper) Cancel(message string) {
	h.Errors = types.CloudError{Code: -1, Message: message}
}

// 取消并返回
// 返回 RESTFul Error格式,
// Code: code, Error: message
func (h *Helper) CancelWithCode(message string, code int) {
	h.Errors = types.CloudError{Code: code, Message: message}
}

// 隐藏字段。不返回给API调用者
func (h *Helper) Hide(fieldName string) {
	h.HideFields = append(h.HideFields, fieldName)
}

// 保护字段， 设置过的字段将无法更新
func (h *Helper) Protect(fieldName string) {
	h.ProtectFields = append(h.ProtectFields, fieldName)
}

// 打印log, 方便调试
func (h *Helper) Log(message string) {
	h.LogWithFlag(message, "info")
}

func (h *Helper) LogWithFlag(message string, flag string) {
	l := types.CloudLog{}
	l.Content = message
	l.CreatedAt = time.Now().Format(time.RFC3339Nano)
	l.Flag = flag
	h.Logs = append(h.Logs, l)
}
<|endoftext|>


<commit_before>package nakadi

import (
	"encoding/json"
	"net"
	"net/http"
	"time"

	"github.com/pkg/errors"
)

// newHTTPClient crates an http client which is used for non streaming requests.
func newHTTPClient(timeout time.Duration) *http.Client {
	return &http.Client{
		Timeout: timeout,
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			Dial:                (&net.Dialer{Timeout: timeout}).Dial,
			TLSHandshakeTimeout: timeout,
		},
	}
}

// newHTTPStream creates an http client which is used for streaming purposes.
func newHTTPStream(timeout time.Duration) *http.Client {
	return &http.Client{
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			Dial:                (&net.Dialer{Timeout: timeout}).Dial,
			TLSHandshakeTimeout: timeout,
		},
	}
}

// problemJSON is used to decode error responses.
type problemJSON struct {
	Title  string `json:"title"`
	Detail string `json:"detail"`
	Status int    `json:"status"`
	Type   string `json:"type"`
}

type errorJSON struct {
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

// decodeResponseToError will try do decode into problemJSON then errorJSON
// and extract details from this defined formats.
// It will fallback to creating and error with message body
// Second parameter is an error message
func decodeResponseToError(buffer []byte, msg string) error {
	problem := problemJSON{}
	err := json.Unmarshal(buffer, &problem)
	if err == nil {
		return errors.Errorf("%s: %s", msg, problem.Detail)
	}
	errJSON := &errorJSON{}

	err = json.Unmarshal(buffer, &errJSON)
	if err == nil {
		return errors.Errorf("%s: %s", msg, errJSON.ErrorDescription)
	}
	return errors.Errorf("%s: %s", msg, string(buffer))
}
<commit_msg>issue-12: add backoff configuration struct<commit_after>package nakadi

import (
	"encoding/json"
	"net"
	"net/http"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/pkg/errors"
)

// newHTTPClient crates an http client which is used for non streaming requests.
func newHTTPClient(timeout time.Duration) *http.Client {
	return &http.Client{
		Timeout: timeout,
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			Dial:                (&net.Dialer{Timeout: timeout}).Dial,
			TLSHandshakeTimeout: timeout,
		},
	}
}

// newHTTPStream creates an http client which is used for streaming purposes.
func newHTTPStream(timeout time.Duration) *http.Client {
	return &http.Client{
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			Dial:                (&net.Dialer{Timeout: timeout}).Dial,
			TLSHandshakeTimeout: timeout,
		},
	}
}

// problemJSON is used to decode error responses.
type problemJSON struct {
	Title  string `json:"title"`
	Detail string `json:"detail"`
	Status int    `json:"status"`
	Type   string `json:"type"`
}

type errorJSON struct {
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

// decodeResponseToError will try do decode into problemJSON then errorJSON
// and extract details from this defined formats.
// It will fallback to creating and error with message body
// Second parameter is an error message
func decodeResponseToError(buffer []byte, msg string) error {
	problem := problemJSON{}
	err := json.Unmarshal(buffer, &problem)
	if err == nil {
		return errors.Errorf("%s: %s", msg, problem.Detail)
	}
	errJSON := &errorJSON{}

	err = json.Unmarshal(buffer, &errJSON)
	if err == nil {
		return errors.Errorf("%s: %s", msg, errJSON.ErrorDescription)
	}
	return errors.Errorf("%s: %s", msg, string(buffer))
}

// backOffConfiguration holds initial values for the initialization of a backoff that can
// be used in retries.
type backOffConfiguration struct {
	// Whether to retry failed request or not.
	Retry bool
	// The initial (minimal) retry interval used for the exponential backoff.
	InitialRetryInterval time.Duration
	// MaxRetryInterval the maximum retry interval.
	MaxRetryInterval time.Duration
	// MaxElapsedTime is the maximum time spent on retries.
	MaxElapsedTime time.Duration
}

// createBackOff initializes a new backoff from configured parameters.
func (rc *backOffConfiguration) createBackOff() backoff.BackOff {
	if !rc.Retry {
		return &backoff.StopBackOff{}
	}

	back := backoff.NewExponentialBackOff()
	back.InitialInterval = rc.InitialRetryInterval
	back.MaxInterval = rc.MaxRetryInterval
	back.MaxElapsedTime = rc.MaxElapsedTime

	return back
}
<|endoftext|>