<commit_before>package main

import (
	. "./quadedge"
	"fmt"
	"github.com/ajstarks/svgo/float"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"os"
	//	"text/template"
	"bytes"
)

var fileno int = 0

func nextfile() string {
	fileno++
	return fmt.Sprintf("hello%02d.svg", fileno)
}

var debug bool = false

func debugDraw(e0 *Edge, e1 *Edge) {
	if !debug {
		return
	}
	file, err := os.Create(nextfile())
	if err != nil {
		panic("can't create file")
	}
	s := svg.New(file)
	s.Start(1000, 1000)
	ox, oy := 100.0, 100.0 // put origin at (100,100)
	//	small, _ := BoundingBox(e0)
	//	dx, dy := ox-small.X, oy-small.Y
	dx, dy := ox, oy
	s.Circle(ox, oy, 5, "fill:black;stroke:black")
	for i, e := range e0.Edges() {
		if i == 0 {
			s.Circle(e.Org().X+dx, e.Org().Y+dy, 3, "fill:green;stroke:none")
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#f00;stroke-width:1")
		} else {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#00f;stroke-width:1")
		}
	}
	if e1 != nil {
		for i, e := range e1.Edges() {
			if i == 0 {
				s.Circle(e.Org().X+dx, e.Org().Y+dy, 3, "fill:blue;stroke:none")
				s.Line(e.Org().X+dx, e.Org().Y+dy,
					e.Dest().X+dx, e.Dest().Y+dy,
					"stroke:#f00;stroke-width:1")
			} else {
				s.Line(e.Org().X+dx, e.Org().Y+dy,
					e.Dest().X+dx, e.Dest().Y+dy,
					"stroke:#00f;stroke-width:1")
			}
		}
	}
	s.End()
}

func edgeLength(e *Edge) float64 {
	if e == nil {
		return 0.0
	}
	dx := e.Dest().X - e.Org().X
	dy := e.Dest().Y - e.Org().Y
	return math.Sqrt(dx*dx + dy*dy)
}

func edgeRadians(e *Edge) float64 {
	dx := e.Dest().X - e.Org().X
	dy := e.Dest().Y - e.Org().Y
	return math.Atan2(dy, dx)
}

func scale(e0 *Edge, sf float64) {
	for _, e := range e0.Edges() {
		e.SetOrg(&Point2D{sf * e.Org().X, sf * e.Org().Y})
		e = e.Sym()
		e.SetOrg(&Point2D{sf * e.Org().X, sf * e.Org().Y})
	}
}

func rotate(e0 *Edge, rad float64) {
	rotatePoint := func(p *Point2D) *Point2D {
		angle := math.Atan2(p.Y, p.X)
		distance := math.Sqrt(p.X*p.X + p.Y*p.Y)
		angle2 := angle + rad
		y, x := math.Sincos(angle2)
		x, y = distance*x, distance*y
		return &Point2D{x, y}
	}
	for _, e := range e0.Edges() {
		e.SetOrg(rotatePoint(e.Org()))
		e = e.Sym()
		e.SetOrg(rotatePoint(e.Org()))
	}
}

func translate(e0 *Edge, dx, dy float64) {
	for _, e := range e0.Edges() {
		e.SetOrg(&Point2D{dx + e.Org().X, dy + e.Org().Y})
		e = e.Sym()
		e.SetOrg(&Point2D{dx + e.Org().X, dy + e.Org().Y})
	}
}

func attach(e1, e2 *Edge) {
	debugDraw(e1, e2)
	l1 := edgeLength(e1)
	l2 := edgeLength(e2)
	if l1 == 0.0 || l2 == 0.0 {
		return
	}
	sf := l1 / l2
	translate(e2, -e2.Org().X, -e2.Org().Y) // bring origin of e2 to absolute origin (0,0)
	debugDraw(e1, e2)
	scale(e2, sf)
	debugDraw(e1, e2)
	rotate(e2, edgeRadians(e1)-edgeRadians(e2)+math.Pi)
	debugDraw(e1, e2)
	translate(e2, e1.Dest().X, e1.Dest().Y)
	debugDraw(e1, e2)
	Splice(e1.Oprev(), e2.Sym())
	Splice(e1.Sym(), e2.Oprev())
	DeleteEdge(e2)
	debugDraw(e1, nil)
}

func main() {
	http.HandleFunc("/", FrontPage)
	http.HandleFunc("/compile", Compile)
	log.Printf("Listening on localhost:1999")
	log.Fatal(http.ListenAndServe("127.0.0.1:1999", nil))
}

func FrontPage(w http.ResponseWriter, req *http.Request) {
	w.Write(frontPageText)
	//	frontPage.Execute(w)
}

//var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
var frontPageText = []byte(`<!doctype html>

<title>Man, I Fold</title>

3-9: polygon, f: forward, b: back, r: reverse

<input autofocus="true" id="edit" onkeydown="keyHandler(event);"></input>

`)

var e0 *Edge
var outright = true
var internal = make(map[*QuadEdge]bool)

func attachAndMove(e1 *Edge) {
	if e0 == nil {
		e0 = e1
	} else {
		internal[e0.Q] = true
		if outright {
			attach(e0, e1)
			e0 = e0.Oprev()
		} else {
			attach(e0.Sym(), e1)
			e0 = e0.Onext()
		}
	}
}

func Compile(w http.ResponseWriter, req *http.Request) {
	cmd, err := ioutil.ReadAll(req.Body)
	if err != nil {
		w.WriteHeader(404)
		return
	}
	switch string(cmd) {
	case "3":
		attachAndMove(Ngon(3, 40))
	case "4":
		attachAndMove(Ngon(4, 40))
	case "5":
		attachAndMove(Ngon(5, 40))
	case "6":
		attachAndMove(Ngon(6, 40))
	case "7":
		attachAndMove(Ngon(7, 40))
	case "8":
		attachAndMove(Ngon(8, 40))
	case "9":
		attachAndMove(Ngon(9, 40))
	case "f":
		if outright {
			e0 = e0.Sym().Onext()
		} else {
			e0 = e0.Sym().Oprev()
		}
	case "b":
		if outright {
			e0 = e0.Oprev().Sym()
		} else {
			e0 = e0.Onext().Sym()
		}
	case "r":
		e0 = e0.Sym()
		outright = !outright
	default:
	}
	out := draw()
	w.Write(out) // ignore err
}

func draw() []byte {
	buf := new(bytes.Buffer)
	s := svg.New(buf)
	s.Start(1000, 1000)
	// arrowhead
	s.Marker("Triangle", 0, 5, 20, 10,"viewBox='0 0 10 10' markerUnits='strokeWidth' orient='auto'")
	s.Path("M 0 0 L 10 5 L 0 10 z")
	s.MarkerEnd()
	ox, oy := 100.0, 100.0 // put origin at (100,100)
	//	small, _ := BoundingBox(e0)
	//	dx, dy := ox-small.X, oy-small.Y
	dx, dy := ox, oy
	s.Circle(ox, oy, 5, "fill:black;stroke:black")
	for i, e := range e0.Edges() {
		if i == 0 {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"marker-end='url(#Triangle)' style='stroke:#f00;stroke-width:1'")
		} else if internal[e.Q] {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#00f;stroke-width:1;stroke-dasharray:4")
		} else {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#00f;stroke-width:1")
		}
	}
	s.End()
	return buf.Bytes()
}
<commit_msg>Add tabs<commit_after>package main

import (
	. "./quadedge"
	"fmt"
	"github.com/ajstarks/svgo/float"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"os"
	//	"text/template"
	"bytes"
)

var fileno int = 0

func nextfile() string {
	fileno++
	return fmt.Sprintf("hello%02d.svg", fileno)
}

var debug bool = false

func debugDraw(e0 *Edge, e1 *Edge) {
	if !debug {
		return
	}
	file, err := os.Create(nextfile())
	if err != nil {
		panic("can't create file")
	}
	s := svg.New(file)
	s.Start(1000, 1000)
	ox, oy := 100.0, 100.0 // put origin at (100,100)
	//	small, _ := BoundingBox(e0)
	//	dx, dy := ox-small.X, oy-small.Y
	dx, dy := ox, oy
	s.Circle(ox, oy, 5, "fill:black;stroke:black")
	for i, e := range e0.Edges() {
		if i == 0 {
			s.Circle(e.Org().X+dx, e.Org().Y+dy, 3, "fill:green;stroke:none")
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#f00;stroke-width:1")
		} else {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#00f;stroke-width:1")
		}
	}
	if e1 != nil {
		for i, e := range e1.Edges() {
			if i == 0 {
				s.Circle(e.Org().X+dx, e.Org().Y+dy, 3, "fill:blue;stroke:none")
				s.Line(e.Org().X+dx, e.Org().Y+dy,
					e.Dest().X+dx, e.Dest().Y+dy,
					"stroke:#f00;stroke-width:1")
			} else {
				s.Line(e.Org().X+dx, e.Org().Y+dy,
					e.Dest().X+dx, e.Dest().Y+dy,
					"stroke:#00f;stroke-width:1")
			}
		}
	}
	s.End()
}

func edgeLength(e *Edge) float64 {
	if e == nil {
		return 0.0
	}
	dx := e.Dest().X - e.Org().X
	dy := e.Dest().Y - e.Org().Y
	return math.Sqrt(dx*dx + dy*dy)
}

func edgeRadians(e *Edge) float64 {
	dx := e.Dest().X - e.Org().X
	dy := e.Dest().Y - e.Org().Y
	return math.Atan2(dy, dx)
}

func scale(e0 *Edge, sf float64) {
	for _, e := range e0.Edges() {
		e.SetOrg(&Point2D{sf * e.Org().X, sf * e.Org().Y})
		e = e.Sym()
		e.SetOrg(&Point2D{sf * e.Org().X, sf * e.Org().Y})
	}
}

func rotate(e0 *Edge, rad float64) {
	rotatePoint := func(p *Point2D) *Point2D {
		angle := math.Atan2(p.Y, p.X)
		distance := math.Sqrt(p.X*p.X + p.Y*p.Y)
		angle2 := angle + rad
		y, x := math.Sincos(angle2)
		x, y = distance*x, distance*y
		return &Point2D{x, y}
	}
	for _, e := range e0.Edges() {
		e.SetOrg(rotatePoint(e.Org()))
		e = e.Sym()
		e.SetOrg(rotatePoint(e.Org()))
	}
}

func translate(e0 *Edge, dx, dy float64) {
	for _, e := range e0.Edges() {
		e.SetOrg(&Point2D{dx + e.Org().X, dy + e.Org().Y})
		e = e.Sym()
		e.SetOrg(&Point2D{dx + e.Org().X, dy + e.Org().Y})
	}
}

func tab() *Edge {
	pts := []*Point2D{{0.0,0.0},{40.0,0.0},{30.0,10.0},{10.0,10.0}}
	return Polygon(pts)
}

func attach(e1, e2 *Edge) {
	debugDraw(e1, e2)
	l1 := edgeLength(e1)
	l2 := edgeLength(e2)
	if l1 == 0.0 || l2 == 0.0 {
		return
	}
	sf := l1 / l2
	translate(e2, -e2.Org().X, -e2.Org().Y) // bring origin of e2 to absolute origin (0,0)
	debugDraw(e1, e2)
	scale(e2, sf)
	debugDraw(e1, e2)
	rotate(e2, edgeRadians(e1)-edgeRadians(e2)+math.Pi)
	debugDraw(e1, e2)
	translate(e2, e1.Dest().X, e1.Dest().Y)
	debugDraw(e1, e2)
	Splice(e1.Oprev(), e2.Sym())
	Splice(e1.Sym(), e2.Oprev())
	DeleteEdge(e2)
	debugDraw(e1, nil)
}

func main() {
	http.HandleFunc("/", FrontPage)
	http.HandleFunc("/compile", Compile)
	log.Printf("Listening on localhost:1999")
	log.Fatal(http.ListenAndServe("127.0.0.1:1999", nil))
}

func FrontPage(w http.ResponseWriter, req *http.Request) {
	w.Write(frontPageText)
	//	frontPage.Execute(w)
}

//var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
var frontPageText = []byte(`<!doctype html>

<title>Man, I Fold</title>

3-9: polygon, f: forward, b: back, r: reverse

<input autofocus="true" id="edit" onkeydown="keyHandler(event);"></input>

`)

var e0 *Edge
var outright = true
var internal = make(map[*QuadEdge]bool)

func attachAndMove(e1 *Edge) {
	if e0 == nil {
		e0 = e1
	} else {
		internal[e0.Q] = true
		if outright {
			attach(e0, e1)
			e0 = e0.Oprev()
		} else {
			attach(e0.Sym(), e1)
			e0 = e0.Onext()
		}
	}
}

func Compile(w http.ResponseWriter, req *http.Request) {
	cmd, err := ioutil.ReadAll(req.Body)
	if err != nil {
		w.WriteHeader(404)
		return
	}
	switch string(cmd) {
	case "3":
		attachAndMove(Ngon(3, 40))
	case "4":
		attachAndMove(Ngon(4, 40))
	case "5":
		attachAndMove(Ngon(5, 40))
	case "6":
		attachAndMove(Ngon(6, 40))
	case "7":
		attachAndMove(Ngon(7, 40))
	case "8":
		attachAndMove(Ngon(8, 40))
	case "9":
		attachAndMove(Ngon(9, 40))
	case "f":
		if outright {
			e0 = e0.Sym().Onext()
		} else {
			e0 = e0.Sym().Oprev()
		}
	case "b":
		if outright {
			e0 = e0.Oprev().Sym()
		} else {
			e0 = e0.Onext().Sym()
		}
	case "r":
		e0 = e0.Sym()
		outright = !outright
	case "t":
		attachAndMove(tab())
	default:
	}
	out := draw()
	w.Write(out) // ignore err
}

func draw() []byte {
	buf := new(bytes.Buffer)
	s := svg.New(buf)
	s.Start(1000, 1000)
	// arrowhead
	s.Marker("Triangle", 0, 5, 20, 10,"viewBox='0 0 10 10' markerUnits='strokeWidth' orient='auto'")
	s.Path("M 0 0 L 10 5 L 0 10 z")
	s.MarkerEnd()
	ox, oy := 100.0, 100.0 // put origin at (100,100)
	//	small, _ := BoundingBox(e0)
	//	dx, dy := ox-small.X, oy-small.Y
	dx, dy := ox, oy
	s.Circle(ox, oy, 5, "fill:black;stroke:black")
	for i, e := range e0.Edges() {
		if i == 0 {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"marker-end='url(#Triangle)' style='stroke:#f00;stroke-width:1'")
		} else if internal[e.Q] {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#00f;stroke-width:1;stroke-dasharray:4")
		} else {
			s.Line(e.Org().X+dx, e.Org().Y+dy,
				e.Dest().X+dx, e.Dest().Y+dy,
				"stroke:#00f;stroke-width:1")
		}
	}
	s.End()
	return buf.Bytes()
}
<|endoftext|>


<commit_before>package inlet_http

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
)

type GraphResponse struct {
	GraphName   string
	RespPayload spirit.Payload
	Error       error
}

const (
	REQUEST_TIMEOUT = 30 * time.Second
)

const (
	CTX_HTTP_COOKIES = "CTX_HTTP_COOKIES"
	CTX_HTTP_HEADERS = "CTX_HTTP_HEADERS"

	CMD_HTTP_HEADERS_SET = "CMD_HTTP_HEADERS_SET"
	CMD_HTTP_COOKIES_SET = "CMD_HTTP_COOKIES_SET"
)

type GraphStat struct {
	GraphName     string        `json:"-"`
	RequestCount  int64         `json:"request_count"`
	TimeoutCount  int64         `json:"timeout_count"`
	ErrorCount    int64         `json:"error_count"`
	TotalTimeCost time.Duration `json:"total_time_cost"`

	ErrorRate          float64 `json:"error_rate"`
	TimeoutRate        float64 `json:"timeout_rate"`
	TimeCostPerRequest float64 `json:"time_cost_per_request"`
}

type NameValue struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type InletHTTPRequestPayloadHook func(r *http.Request, graphName string, body []byte, payload *spirit.Payload) (err error)
type InletHTTPResponseHandler func(graphsResponse map[string]GraphResponse, w http.ResponseWriter, r *http.Request)
type InletHTTPErrorResponseHandler func(err error, w http.ResponseWriter, r *http.Request)
type InletHTTPRequestDecoder func(body []byte) (map[string]interface{}, error)

type option func(*InletHTTP)

var (
	grapsStat  map[string]*GraphStat = make(map[string]*GraphStat)
	statLocker sync.Mutex
)

type InletHTTP struct {
	config         Config
	requester      Requester
	graphProvider  GraphProvider
	respHandler    InletHTTPResponseHandler
	errRespHandler InletHTTPErrorResponseHandler
	requestDecoder InletHTTPRequestDecoder
	payloadHook    InletHTTPRequestPayloadHook
	timeout        time.Duration
	timeoutHeader  string

	statChan chan GraphStat
}

func (p *InletHTTP) Option(opts ...option) {
	for _, opt := range opts {
		opt(p)
	}
}

func SetRequestPayloadHook(hook InletHTTPRequestPayloadHook) option {
	return func(f *InletHTTP) {
		f.payloadHook = hook
	}
}

func SetRequestDecoder(decoder InletHTTPRequestDecoder) option {
	return func(f *InletHTTP) {
		f.requestDecoder = decoder
	}
}

func SetRequester(requester Requester) option {
	return func(f *InletHTTP) {
		f.requester = requester
	}
}

func SetHTTPConfig(httpConfig Config) option {
	return func(f *InletHTTP) {
		f.config = httpConfig
	}
}

func SetGraphProvider(graphProvider GraphProvider) option {
	return func(f *InletHTTP) {
		f.graphProvider = graphProvider
	}
}

func SetResponseHandler(handler InletHTTPResponseHandler) option {
	return func(f *InletHTTP) {
		f.respHandler = handler
	}
}

func SetErrorResponseHandler(handler InletHTTPErrorResponseHandler) option {
	return func(f *InletHTTP) {
		f.errRespHandler = handler
	}
}

func SetTimeout(millisecond int64) option {
	return func(f *InletHTTP) {
		f.timeout = time.Duration(millisecond)
	}
}

func SetTimeoutHeader(header string) option {
	return func(f *InletHTTP) {
		f.timeoutHeader = strings.TrimSpace(header)
	}
}

func NewInletHTTP(opts ...option) *InletHTTP {
	inletHTTP := new(InletHTTP)
	inletHTTP.Option(opts...)

	if inletHTTP.requester == nil {
		inletHTTP.requester = NewClassicRequester()
	}

	return inletHTTP
}

func (p *InletHTTP) Requester() Requester {
	return p.requester
}

func statCollector(graphStatChan chan GraphStat) {
	for {
		select {
		case graphStat := <-graphStatChan:
			{
				go func(graphStat GraphStat) {
					statLocker.Lock()
					defer statLocker.Unlock()
					if oldStat, exist := grapsStat[graphStat.GraphName]; !exist {
						graphStat.ErrorRate = float64(graphStat.ErrorCount / graphStat.RequestCount)
						graphStat.TimeCostPerRequest = float64(int64(graphStat.TotalTimeCost) / graphStat.RequestCount)
						graphStat.TimeoutRate = float64(graphStat.TimeoutCount / graphStat.RequestCount)
						grapsStat[graphStat.GraphName] = &graphStat
					} else {
						oldStat.GraphName += graphStat.GraphName
						oldStat.ErrorCount += graphStat.ErrorCount
						oldStat.RequestCount += graphStat.RequestCount
						oldStat.TotalTimeCost += graphStat.TotalTimeCost
						oldStat.TimeoutCount += graphStat.TimeoutCount
						oldStat.ErrorRate = float64(graphStat.ErrorCount / graphStat.RequestCount)
						oldStat.TimeCostPerRequest = float64(int64(graphStat.TotalTimeCost) / graphStat.RequestCount)
						oldStat.TimeoutRate = float64(graphStat.TimeoutCount / graphStat.RequestCount)
					}
				}(graphStat)

			}
		case <-time.After(time.Second):
		}
	}
}

func statHandler(w http.ResponseWriter, r *http.Request) {
	if data, e := json.MarshalIndent(grapsStat, " ", "  "); e != nil {
		err := ERR_MARSHAL_STAT_DATA_FAILED.New(errors.Params{"err": e})
		logs.Error(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(data)
	}
	return
}

func (p *InletHTTP) Run(path string, router func(martini.Router), middlerWares ...martini.Handler) {
	if p.graphProvider == nil {
		panic("graph provider is nil")
	}

	if p.requester == nil {
		panic("requester is nil")
	}

	if p.respHandler == nil {
		panic("response handler is nil")
	}

	if p.errRespHandler == nil {
		panic("error response handler is nil")
	}

	if p.requestDecoder == nil {
		panic("request encoder is nil")
	}

	if p.config.Timeout > 0 {
		p.timeout = time.Millisecond * time.Duration(p.config.Timeout)
		p.requester.SetTimeout(p.timeout)
	} else {
		p.timeout = REQUEST_TIMEOUT
	}

	m := martini.Classic()

	m.Group(path, router, middlerWares...)

	if p.config.EnableStat {
		p.statChan = make(chan GraphStat, 1000)
		go statCollector(p.statChan)
		m.Get("/stat", statHandler)
	}

	if p.config.Address != "" {
		m.RunOnAddr(p.config.Address)
	} else {
		m.Run()
	}
}

func (p *InletHTTP) Handler(w http.ResponseWriter, r *http.Request) {
	var err error
	var binBody []byte
	if binBody, err = ioutil.ReadAll(r.Body); err != nil {
		err = ERR_READ_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var mapContent map[string]interface{}

	if mapContent, err = p.requestDecoder(binBody); err != nil {
		err = ERR_UNMARSHAL_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var graphs map[string]spirit.MessageGraph
	if graphs, err = p.graphProvider.GetGraph(r, binBody); err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	cookies := map[string]string{}
	reqCookies := r.Cookies()
	if reqCookies != nil && len(reqCookies) > 0 {
		for _, cookie := range reqCookies {
			cookies[cookie.Name] = cookie.Value
		}
	}

	payloads := map[string]*spirit.Payload{}

	for graphName, _ := range graphs {

		payload := new(spirit.Payload)
		payload.SetContent(mapContent)
		payload.SetContext(CTX_HTTP_COOKIES, cookies)

		if p.payloadHook != nil {
			if e := p.payloadHook(r, graphName, binBody, payload); e != nil {
				p.errRespHandler(e, w, r)
				return
			}
		}

		payloads[graphName] = payload
	}

	responseChan := make(chan GraphResponse)

	defer close(responseChan)

	timeout := p.timeout

	if p.timeoutHeader != "" {
		if strTimeout := r.Header.Get(p.timeoutHeader); strTimeout != "" {
			if intTimeout, e := strconv.Atoi(strTimeout); e != nil {
				e = ERR_REQUEST_TIMEOUT_VALUE_FORMAT_WRONG.New(errors.Params{"value": strTimeout})
				logs.Warn(e)
			} else {
				timeout = time.Duration(intTimeout) * time.Millisecond
			}
		}
	}

	sendPayloadFunc := func(requester Requester,
		graphName string,
		graph spirit.MessageGraph,
		payload spirit.Payload,
		responseChan chan GraphResponse,
		statChan chan GraphStat,
		timeout time.Duration) {
		defer func() {
			if err := recover(); err != nil {
				return
			}
		}()

		start := time.Now()

		var grapStat GraphStat

		var errCount, timeoutCout int64 = 0, 0

		respChan := make(chan spirit.Payload)
		errChan := make(chan error)
		defer close(respChan)
		defer close(errChan)

		resp := GraphResponse{GraphName: graphName}

		msgId, err := requester.Request(graph, payload, respChan, errChan)
		if err != nil {
			resp.Error = err
			return
		}

		defer requester.OnMessageProcessed(msgId)

		select {
		case resp.RespPayload = <-respChan:
		case resp.Error = <-errChan:
			{
				errCount = 1
			}
		case <-time.After(time.Duration(timeout)):
			{
				timeoutCout = 1
				resp.Error = ERR_REQUEST_TIMEOUT.New(errors.Params{"graphName": graphName, "msgId": msgId})
			}
		}
		end := time.Now()
		timeCost := end.Sub(start)

		responseChan <- resp

		if statChan != nil {
			grapStat.GraphName = graphName
			grapStat.RequestCount = 1
			grapStat.ErrorCount = errCount
			grapStat.TimeoutCount = timeoutCout
			grapStat.TotalTimeCost = timeCost / time.Millisecond

			select {
			case statChan <- grapStat:
			case <-time.After(time.Second):
			}
		}
	}

	for graphName, payload := range payloads {
		graph, _ := graphs[graphName]

		go sendPayloadFunc(p.requester, graphName, graph, *payload, responseChan, p.statChan, timeout)
	}

	graphsResponse := map[string]GraphResponse{}

	lenGraph := len(graphs)
	for i := 0; i < lenGraph; i++ {
		select {
		case resp := <-responseChan:
			{
				graphsResponse[resp.GraphName] = resp
			}
		case <-time.After(time.Duration(timeout) + time.Second):
			{
				continue
			}
		}
	}

	for graphName, _ := range graphs {
		if _, exist := graphsResponse[graphName]; !exist {
			err := ERR_REQUEST_TIMEOUT.New(errors.Params{"graphName": graphName})
			resp := GraphResponse{
				GraphName: graphName,
				Error:     err,
			}
			graphsResponse[graphName] = resp
		}
	}

	for _, graphResponse := range graphsResponse {
		p.writeCookiesAndHeaders(graphResponse.RespPayload, w, r)
	}

	p.respHandler(graphsResponse, w, r)

	return
}

func (p *InletHTTP) writeCookiesAndHeaders(payload spirit.Payload, w http.ResponseWriter, r *http.Request) {
	var err error
	// Cookies
	cmdCookiesSize := payload.GetCommandValueSize(CMD_HTTP_COOKIES_SET)
	cmdCookies := make([]interface{}, cmdCookiesSize)
	for i := 0; i < cmdCookiesSize; i++ {
		cookie := new(http.Cookie)
		cmdCookies[i] = cookie
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_COOKIES_SET, cmdCookies); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": err})
		p.errRespHandler(err, w, r)
		return
	}

	for _, cookie := range cmdCookies {
		if c, ok := cookie.(*http.Cookie); ok {
			c.Domain = p.config.Domain
			c.Path = "/"
			http.SetCookie(w, c)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": "object could not parser to cookies"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}

	cmdHeadersSize := payload.GetCommandValueSize(CMD_HTTP_HEADERS_SET)
	cmdHeaders := make([]interface{}, cmdHeadersSize)
	for i := 0; i < cmdHeadersSize; i++ {
		header := new(NameValue)
		cmdHeaders[i] = header
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_HEADERS_SET, cmdHeaders); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	for _, header := range cmdHeaders {
		if nv, ok := header.(*NameValue); ok {
			w.Header().Add(nv.Name, nv.Value)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": "object could not parser to headers"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}
}

func (p *InletHTTP) CallBack(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) Error(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) OnMessageResponse(payload *spirit.Payload) {
	p.requester.OnMessageReceived(*payload)
}
<commit_msg>fix stat float item display issue<commit_after>package inlet_http

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
)

type GraphResponse struct {
	GraphName   string
	RespPayload spirit.Payload
	Error       error
}

const (
	REQUEST_TIMEOUT = 30 * time.Second
)

const (
	CTX_HTTP_COOKIES = "CTX_HTTP_COOKIES"
	CTX_HTTP_HEADERS = "CTX_HTTP_HEADERS"

	CMD_HTTP_HEADERS_SET = "CMD_HTTP_HEADERS_SET"
	CMD_HTTP_COOKIES_SET = "CMD_HTTP_COOKIES_SET"
)

type GraphStat struct {
	GraphName    string `json:"-"`
	RequestCount int64  `json:"request_count"`
	TimeoutCount int64  `json:"timeout_count"`
	ErrorCount   int64  `json:"error_count"`

	TotalTimeCost    time.Duration `json:"-"`
	StrTotalTimeCost string        `json:"total_time_cost"`

	ErrorRate          string `json:"error_rate"`
	TimeoutRate        string `json:"timeout_rate"`
	TimeCostPerRequest string `json:"time_cost_per_request"`
}

func (p *GraphStat) ReCalc() {
	p.ErrorRate = fmt.Sprintf("%.2f", float64(p.ErrorCount/p.RequestCount))
	p.TimeoutRate = fmt.Sprintf("%.2f", float64(p.TimeoutCount/p.RequestCount))
	p.TimeCostPerRequest = fmt.Sprintf("%.2f", float64(float64(p.TotalTimeCost/time.Millisecond)/float64(p.RequestCount)))
	p.StrTotalTimeCost = fmt.Sprintf("%.2f", float64(p.TotalTimeCost/time.Millisecond))
}

type NameValue struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type InletHTTPRequestPayloadHook func(r *http.Request, graphName string, body []byte, payload *spirit.Payload) (err error)
type InletHTTPResponseHandler func(graphsResponse map[string]GraphResponse, w http.ResponseWriter, r *http.Request)
type InletHTTPErrorResponseHandler func(err error, w http.ResponseWriter, r *http.Request)
type InletHTTPRequestDecoder func(body []byte) (map[string]interface{}, error)

type option func(*InletHTTP)

var (
	grapsStat  map[string]*GraphStat = make(map[string]*GraphStat)
	statLocker sync.Mutex
)

type InletHTTP struct {
	config         Config
	requester      Requester
	graphProvider  GraphProvider
	respHandler    InletHTTPResponseHandler
	errRespHandler InletHTTPErrorResponseHandler
	requestDecoder InletHTTPRequestDecoder
	payloadHook    InletHTTPRequestPayloadHook
	timeout        time.Duration
	timeoutHeader  string

	statChan chan GraphStat
}

func (p *InletHTTP) Option(opts ...option) {
	for _, opt := range opts {
		opt(p)
	}
}

func SetRequestPayloadHook(hook InletHTTPRequestPayloadHook) option {
	return func(f *InletHTTP) {
		f.payloadHook = hook
	}
}

func SetRequestDecoder(decoder InletHTTPRequestDecoder) option {
	return func(f *InletHTTP) {
		f.requestDecoder = decoder
	}
}

func SetRequester(requester Requester) option {
	return func(f *InletHTTP) {
		f.requester = requester
	}
}

func SetHTTPConfig(httpConfig Config) option {
	return func(f *InletHTTP) {
		f.config = httpConfig
	}
}

func SetGraphProvider(graphProvider GraphProvider) option {
	return func(f *InletHTTP) {
		f.graphProvider = graphProvider
	}
}

func SetResponseHandler(handler InletHTTPResponseHandler) option {
	return func(f *InletHTTP) {
		f.respHandler = handler
	}
}

func SetErrorResponseHandler(handler InletHTTPErrorResponseHandler) option {
	return func(f *InletHTTP) {
		f.errRespHandler = handler
	}
}

func SetTimeout(millisecond int64) option {
	return func(f *InletHTTP) {
		f.timeout = time.Duration(millisecond)
	}
}

func SetTimeoutHeader(header string) option {
	return func(f *InletHTTP) {
		f.timeoutHeader = strings.TrimSpace(header)
	}
}

func NewInletHTTP(opts ...option) *InletHTTP {
	inletHTTP := new(InletHTTP)
	inletHTTP.Option(opts...)

	if inletHTTP.requester == nil {
		inletHTTP.requester = NewClassicRequester()
	}

	return inletHTTP
}

func (p *InletHTTP) Requester() Requester {
	return p.requester
}

func statCollector(graphStatChan chan GraphStat) {
	for {
		select {
		case graphStat := <-graphStatChan:
			{
				go func(graphStat GraphStat) {
					statLocker.Lock()
					defer statLocker.Unlock()
					if oldStat, exist := grapsStat[graphStat.GraphName]; !exist {
						graphStat.ReCalc()
						grapsStat[graphStat.GraphName] = &graphStat
					} else {
						oldStat.GraphName += graphStat.GraphName
						oldStat.ErrorCount += graphStat.ErrorCount
						oldStat.RequestCount += graphStat.RequestCount
						oldStat.TotalTimeCost += graphStat.TotalTimeCost
						oldStat.TimeoutCount += graphStat.TimeoutCount
						oldStat.ReCalc()
					}
				}(graphStat)

			}
		case <-time.After(time.Second):
		}
	}
}

func statHandler(w http.ResponseWriter, r *http.Request) {
	if data, e := json.MarshalIndent(grapsStat, " ", "  "); e != nil {
		err := ERR_MARSHAL_STAT_DATA_FAILED.New(errors.Params{"err": e})
		logs.Error(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(data)
	}
	return
}

func (p *InletHTTP) Run(path string, router func(martini.Router), middlerWares ...martini.Handler) {
	if p.graphProvider == nil {
		panic("graph provider is nil")
	}

	if p.requester == nil {
		panic("requester is nil")
	}

	if p.respHandler == nil {
		panic("response handler is nil")
	}

	if p.errRespHandler == nil {
		panic("error response handler is nil")
	}

	if p.requestDecoder == nil {
		panic("request encoder is nil")
	}

	if p.config.Timeout > 0 {
		p.timeout = time.Millisecond * time.Duration(p.config.Timeout)
		p.requester.SetTimeout(p.timeout)
	} else {
		p.timeout = REQUEST_TIMEOUT
	}

	m := martini.Classic()

	m.Group(path, router, middlerWares...)

	if p.config.EnableStat {
		p.statChan = make(chan GraphStat, 1000)
		go statCollector(p.statChan)
		m.Get("/stat", statHandler)
	}

	if p.config.Address != "" {
		m.RunOnAddr(p.config.Address)
	} else {
		m.Run()
	}
}

func (p *InletHTTP) Handler(w http.ResponseWriter, r *http.Request) {
	var err error
	var binBody []byte
	if binBody, err = ioutil.ReadAll(r.Body); err != nil {
		err = ERR_READ_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var mapContent map[string]interface{}

	if mapContent, err = p.requestDecoder(binBody); err != nil {
		err = ERR_UNMARSHAL_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var graphs map[string]spirit.MessageGraph
	if graphs, err = p.graphProvider.GetGraph(r, binBody); err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	cookies := map[string]string{}
	reqCookies := r.Cookies()
	if reqCookies != nil && len(reqCookies) > 0 {
		for _, cookie := range reqCookies {
			cookies[cookie.Name] = cookie.Value
		}
	}

	payloads := map[string]*spirit.Payload{}

	for graphName, _ := range graphs {

		payload := new(spirit.Payload)
		payload.SetContent(mapContent)
		payload.SetContext(CTX_HTTP_COOKIES, cookies)

		if p.payloadHook != nil {
			if e := p.payloadHook(r, graphName, binBody, payload); e != nil {
				p.errRespHandler(e, w, r)
				return
			}
		}

		payloads[graphName] = payload
	}

	responseChan := make(chan GraphResponse)

	defer close(responseChan)

	timeout := p.timeout

	if p.timeoutHeader != "" {
		if strTimeout := r.Header.Get(p.timeoutHeader); strTimeout != "" {
			if intTimeout, e := strconv.Atoi(strTimeout); e != nil {
				e = ERR_REQUEST_TIMEOUT_VALUE_FORMAT_WRONG.New(errors.Params{"value": strTimeout})
				logs.Warn(e)
			} else {
				timeout = time.Duration(intTimeout) * time.Millisecond
			}
		}
	}

	sendPayloadFunc := func(requester Requester,
		graphName string,
		graph spirit.MessageGraph,
		payload spirit.Payload,
		responseChan chan GraphResponse,
		statChan chan GraphStat,
		timeout time.Duration) {
		defer func() {
			if err := recover(); err != nil {
				return
			}
		}()

		start := time.Now()

		var grapStat GraphStat

		var errCount, timeoutCout int64 = 0, 0

		respChan := make(chan spirit.Payload)
		errChan := make(chan error)
		defer close(respChan)
		defer close(errChan)

		resp := GraphResponse{GraphName: graphName}

		msgId, err := requester.Request(graph, payload, respChan, errChan)
		if err != nil {
			resp.Error = err
			return
		}

		defer requester.OnMessageProcessed(msgId)

		select {
		case resp.RespPayload = <-respChan:
		case resp.Error = <-errChan:
			{
				errCount = 1
			}
		case <-time.After(time.Duration(timeout)):
			{
				timeoutCout = 1
				resp.Error = ERR_REQUEST_TIMEOUT.New(errors.Params{"graphName": graphName, "msgId": msgId})
			}
		}
		end := time.Now()
		timeCost := end.Sub(start)

		responseChan <- resp

		if statChan != nil {
			grapStat.GraphName = graphName
			grapStat.RequestCount = 1
			grapStat.ErrorCount = errCount
			grapStat.TimeoutCount = timeoutCout
			grapStat.TotalTimeCost = timeCost

			select {
			case statChan <- grapStat:
			case <-time.After(time.Second):
			}
		}
	}

	for graphName, payload := range payloads {
		graph, _ := graphs[graphName]

		go sendPayloadFunc(p.requester, graphName, graph, *payload, responseChan, p.statChan, timeout)
	}

	graphsResponse := map[string]GraphResponse{}

	lenGraph := len(graphs)
	for i := 0; i < lenGraph; i++ {
		select {
		case resp := <-responseChan:
			{
				graphsResponse[resp.GraphName] = resp
			}
		case <-time.After(time.Duration(timeout) + time.Second):
			{
				continue
			}
		}
	}

	for graphName, _ := range graphs {
		if _, exist := graphsResponse[graphName]; !exist {
			err := ERR_REQUEST_TIMEOUT.New(errors.Params{"graphName": graphName})
			resp := GraphResponse{
				GraphName: graphName,
				Error:     err,
			}
			graphsResponse[graphName] = resp
		}
	}

	for _, graphResponse := range graphsResponse {
		p.writeCookiesAndHeaders(graphResponse.RespPayload, w, r)
	}

	p.respHandler(graphsResponse, w, r)

	return
}

func (p *InletHTTP) writeCookiesAndHeaders(payload spirit.Payload, w http.ResponseWriter, r *http.Request) {
	var err error
	// Cookies
	cmdCookiesSize := payload.GetCommandValueSize(CMD_HTTP_COOKIES_SET)
	cmdCookies := make([]interface{}, cmdCookiesSize)
	for i := 0; i < cmdCookiesSize; i++ {
		cookie := new(http.Cookie)
		cmdCookies[i] = cookie
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_COOKIES_SET, cmdCookies); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": err})
		p.errRespHandler(err, w, r)
		return
	}

	for _, cookie := range cmdCookies {
		if c, ok := cookie.(*http.Cookie); ok {
			c.Domain = p.config.Domain
			c.Path = "/"
			http.SetCookie(w, c)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": "object could not parser to cookies"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}

	cmdHeadersSize := payload.GetCommandValueSize(CMD_HTTP_HEADERS_SET)
	cmdHeaders := make([]interface{}, cmdHeadersSize)
	for i := 0; i < cmdHeadersSize; i++ {
		header := new(NameValue)
		cmdHeaders[i] = header
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_HEADERS_SET, cmdHeaders); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	for _, header := range cmdHeaders {
		if nv, ok := header.(*NameValue); ok {
			w.Header().Add(nv.Name, nv.Value)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": "object could not parser to headers"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}
}

func (p *InletHTTP) CallBack(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) Error(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) OnMessageResponse(payload *spirit.Payload) {
	p.requester.OnMessageReceived(*payload)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var verbose bool
var force bool
var copy bool

var ext string = ".was"

func init() {
	flag.BoolVar(&copy, "c", false, "copy instead of move")
	flag.StringVar(&ext, "e", ext, "file extension")
	flag.BoolVar(&force, "f", false, "clobber any conflicting files")
	flag.BoolVar(&verbose, "v", false, "verbose output")
}

func main() {
	flag.Usage = usage

	flag.Parse()

	wasFiles := flag.Args()

	if len(wasFiles) < 1 {
		wasFiles = filesFromStdin()
	}

	if len(wasFiles) < 1 {
		flag.Usage()
		os.Exit(2)
	}

	if !strings.HasPrefix(ext, ".") {
		ext = "." + ext
	}

	if verbose {
		fmt.Println("hello world:%v:%s:", verbose, wasFiles)
	}

FileLoop:
	for _, file := range wasFiles {
		if file == "" {
			if verbose {
				fmt.Fprintf(os.Stderr, "ignoring empty file\n")
			}
			continue FileLoop
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "handling file:%s:len(file):%d:\n", file, len(file))
		}

		//chop off slash from directories
		file = filepath.Clean(file)

		if file == ext {
			fmt.Fprintf(os.Stderr, "ignoring %s:%v\n", ext)
			continue FileLoop
		}

		if _, err := os.Stat(file); err != nil {
			fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
			continue FileLoop
		}

		targetFile := file + ext
		if strings.HasSuffix(file, ext) {
			if verbose {
				fmt.Fprintf(os.Stderr, "doing unwas on:%s\n", targetFile)
			}
			targetFile = file[0 : len(file)-len(ext)]
		}

		if _, err := os.Stat(targetFile); err == nil {
			if verbose {
				fmt.Fprintf(os.Stderr, "target is blocked:%s\n", targetFile)
			}
			if !force {
				fmt.Printf("There's a file in the way:%s:\n", targetFile)
				fmt.Printf("Delete %s? Please type yes or no and then press enter:\n", targetFile)
				if askForConfirmation() {
					if err := os.RemoveAll(targetFile); err != nil {
						fmt.Fprintf(os.Stderr, "could not clear the way for new was file:skipping:%v\n", err)
						continue FileLoop
					}
				} else {
					fmt.Fprintf(os.Stderr, "user chose to not delete target:skipping:%s\n", targetFile)
					continue FileLoop
				}
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "target is clear:%s\n", file)
		}

		if copy {
			copyFileHandle, err := os.Open(file)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
			defer copyFileHandle.Close()

			finfo, err := copyFileHandle.Stat()
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}

			if fmode := finfo.Mode(); fmode.IsDir() {
				fmt.Fprintf(os.Stderr, "skipping:copy is not supported for directories\n")
				continue FileLoop
			}

			targetFileHandle, err := os.Create(targetFile)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
			defer targetFileHandle.Close()

			_, err = io.Copy(targetFileHandle, copyFileHandle)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
		} else {
			if err := os.Rename(file, targetFile); err != nil {
				fmt.Fprintf(os.Stderr, "failed to was:%v\n", err)
				continue FileLoop
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "was'd:%s\n", file)
		}
	}
}

//swiped this from a gist:
//https://gist.github.com/albrow/5882501
func askForConfirmation() bool {
	consolereader := bufio.NewReader(os.Stdin)

	response, err := consolereader.ReadString('\n')
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(2)
	}
	okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
	nokayResponses := []string{"n", "N", "no", "No", "NO"}
	if containsString(okayResponses, response[:len(response)-1]) {
		return true
	} else if containsString(nokayResponses, response[:len(response)-1]) {
		return false
	} else {
		fmt.Println("Please type yes or no and then press enter:")
		return askForConfirmation()
	}
}

// posString returns the first index of element in slice.
// If slice does not contain element, returns -1.
func posString(slice []string, element string) int {
	for index, elem := range slice {
		if elem == element {
			return index
		}
	}
	return -1
}

// containsString returns true iff slice contains element
func containsString(slice []string, element string) bool {
	return !(posString(slice, element) == -1)
}

func filesFromStdin() []string {
	bytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(2)
	}

	return strings.Split(string(bytes), "\n")
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, `

        Description:

Stupid simple but useful tool to move a file or directory and move it back later.
Was moves a list of files to files with a .was extension, and/or moves them back if they already have a .was extension.

	Examples:

was thisFile -> thisFile.was
was thisFile.was -> thisFile
was thisFile thatFile.was -> thisFile.was thatFile
was -c someFile -> someFile someFile.was
was -e=saw someFile -> someFile.saw

was filename1 [filename2 filename3 ...]

WIP

Make it return non-zero if there were any errors
Let user choose the extension.
Read file list from STDIN
`)

	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\n")
}
<commit_msg>return non-zero exit status if errors were encountered<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var verbose bool
var force bool
var copy bool

var ext string = ".was"

var errors bool = false

func init() {
	flag.BoolVar(&copy, "c", false, "copy instead of move")
	flag.StringVar(&ext, "e", ext, "file extension")
	flag.BoolVar(&force, "f", false, "clobber any conflicting files")
	flag.BoolVar(&verbose, "v", false, "verbose output")
}

func main() {
	flag.Usage = usage

	flag.Parse()

	wasFiles := flag.Args()

	if len(wasFiles) < 1 {
		wasFiles = filesFromStdin()
	}

	if len(wasFiles) < 1 {
		flag.Usage()
		os.Exit(2)
	}

	if !strings.HasPrefix(ext, ".") {
		ext = "." + ext
	}

	if verbose {
		fmt.Println("hello world:%v:%s:", verbose, wasFiles)
	}

FileLoop:
	for _, file := range wasFiles {
		if file == "" {
			if verbose {
				fmt.Fprintf(os.Stderr, "ignoring empty file\n")
			}
			continue FileLoop
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "handling file:%s:len(file):%d:\n", file, len(file))
		}

		//chop off slash from directories
		file = filepath.Clean(file)

		if file == ext {
			fmt.Fprintf(os.Stderr, "ignoring %s:%v\n", ext)
			continue FileLoop
		}

		if _, err := os.Stat(file); err != nil {
			fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
			continue FileLoop
		}

		targetFile := file + ext
		if strings.HasSuffix(file, ext) {
			if verbose {
				fmt.Fprintf(os.Stderr, "doing unwas on:%s\n", targetFile)
			}
			targetFile = file[0 : len(file)-len(ext)]
		}

		if _, err := os.Stat(targetFile); err == nil {
			if verbose {
				fmt.Fprintf(os.Stderr, "target is blocked:%s\n", targetFile)
			}
			if !force {
				fmt.Printf("There's a file in the way:%s:\n", targetFile)
				fmt.Printf("Delete %s? Please type yes or no and then press enter:\n", targetFile)
				if askForConfirmation() {
					if err := os.RemoveAll(targetFile); err != nil {
						fmt.Fprintf(os.Stderr, "could not clear the way for new was file:skipping:%v\n", err)
						errors = true
						continue FileLoop
					}
				} else {
					fmt.Fprintf(os.Stderr, "user chose to not delete target:skipping:%s\n", targetFile)
					continue FileLoop
				}
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "target is clear:%s\n", file)
		}

		if copy {
			copyFileHandle, err := os.Open(file)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				errors = true
				continue FileLoop
			}
			defer copyFileHandle.Close()

			finfo, err := copyFileHandle.Stat()
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				errors = true
				continue FileLoop
			}

			if fmode := finfo.Mode(); fmode.IsDir() {
				fmt.Fprintf(os.Stderr, "skipping:copy is not supported for directories\n")
				errors = true
				continue FileLoop
			}

			targetFileHandle, err := os.Create(targetFile)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				errors = true
				continue FileLoop
			}
			defer targetFileHandle.Close()

			_, err = io.Copy(targetFileHandle, copyFileHandle)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				errors = true
				continue FileLoop
			}
		} else {
			if err := os.Rename(file, targetFile); err != nil {
				fmt.Fprintf(os.Stderr, "failed to was:%v\n", err)
				errors = true
				continue FileLoop
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "was'd:%s\n", file)
		}
	}
	if errors {
		os.Exit(1)
	}
}

//swiped this from a gist:
//https://gist.github.com/albrow/5882501
func askForConfirmation() bool {
	consolereader := bufio.NewReader(os.Stdin)

	response, err := consolereader.ReadString('\n')
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(2)
	}
	okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
	nokayResponses := []string{"n", "N", "no", "No", "NO"}
	if containsString(okayResponses, response[:len(response)-1]) {
		return true
	} else if containsString(nokayResponses, response[:len(response)-1]) {
		return false
	} else {
		fmt.Println("Please type yes or no and then press enter:")
		return askForConfirmation()
	}
}

// posString returns the first index of element in slice.
// If slice does not contain element, returns -1.
func posString(slice []string, element string) int {
	for index, elem := range slice {
		if elem == element {
			return index
		}
	}
	return -1
}

// containsString returns true iff slice contains element
func containsString(slice []string, element string) bool {
	return !(posString(slice, element) == -1)
}

func filesFromStdin() []string {
	bytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(2)
	}

	return strings.Split(string(bytes), "\n")
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, `

        Description:

Stupid simple but useful tool to move a file or directory and move it back later.
Was moves a list of files to files with a .was extension, and/or moves them back if they already have a .was extension.

	Examples:

was thisFile -> thisFile.was
was thisFile.was -> thisFile
was thisFile thatFile.was -> thisFile.was thatFile
was -c someFile -> someFile someFile.was
was -e=saw someFile -> someFile.saw

was filename1 [filename2 filename3 ...]

WIP

Make it return non-zero if there were any errors
Let user choose the extension.
Read file list from STDIN
`)

	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\n")
}
<|endoftext|>


<commit_before>package buffalo

import (
	"database/sql"
	"net/http"
	"testing"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/httptest"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/require"
)

func Test_RouteInfo_ServeHTTP_SQL_Error(t *testing.T) {
	r := require.New(t)

	app := New(Options{})
	app.GET("/good", func(c Context) error {
		return c.Render(http.StatusOK, render.String("hi"))
	})

	app.GET("/bad", func(c Context) error {
		return sql.ErrNoRows
	})

	app.GET("/gone-unwrap", func(c Context) error {
		return c.Error(http.StatusGone, sql.ErrNoRows)
	})

	app.GET("/gone-wrap", func(c Context) error {
		return c.Error(http.StatusGone, errors.Wrap(sql.ErrNoRows, "some error wrapping here"))
	})

	w := httptest.New(app)

	res := w.HTML("/good").Get()
	r.Equal(http.StatusOK, res.Code)

	res = w.HTML("/bad").Get()
	r.Equal(http.StatusNotFound, res.Code)

	res = w.HTML("/gone-wrap").Get()
	r.Equal(http.StatusGone, res.Code)

	res = w.HTML("/gone-unwrap").Get()
	r.Equal(http.StatusGone, res.Code)
}
<commit_msg>removing using fmt instead of errors pkg<commit_after>package buffalo

import (
	"database/sql"
	"fmt"
	"net/http"
	"testing"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/httptest"
	"github.com/stretchr/testify/require"
)

func Test_RouteInfo_ServeHTTP_SQL_Error(t *testing.T) {
	r := require.New(t)

	app := New(Options{})
	app.GET("/good", func(c Context) error {
		return c.Render(http.StatusOK, render.String("hi"))
	})

	app.GET("/bad", func(c Context) error {
		return sql.ErrNoRows
	})

	app.GET("/bad-2", func(c Context) error {
		return sql.ErrTxDone
	})

	app.GET("/gone-unwrap", func(c Context) error {
		return c.Error(http.StatusGone, sql.ErrTxDone)
	})

	app.GET("/gone-wrap", func(c Context) error {
		return c.Error(http.StatusGone, fmt.Errorf("some error wrapping here: %w", sql.ErrNoRows))
	})

	w := httptest.New(app)

	res := w.HTML("/good").Get()
	r.Equal(http.StatusOK, res.Code)

	res = w.HTML("/bad").Get()
	r.Equal(http.StatusNotFound, res.Code)

	res = w.HTML("/gone-wrap").Get()
	r.Equal(http.StatusGone, res.Code)

	res = w.HTML("/gone-unwrap").Get()
	r.Equal(http.StatusGone, res.Code)
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/prometheus/client_golang/prometheus"
)

const (
	nginxStatus = `Active connections: 91
server accepts handled requests
 145249 145249 151557
Reading: 0 Writing: 24 Waiting: 66
`
	metricCount = 7
)

func TestNginxStatus(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(nginxStatus))
	})
	server := httptest.NewServer(handler)

	e := NewExporter(server.URL)
	ch := make(chan prometheus.Metric)

	go func() {
		defer close(ch)
		e.Collect(ch)
	}()

	for i := 1; i <= metricCount; i++ {
		m := <-ch
		if m == nil {
			t.Error("expected metric but got nil")
		}
	}
	if <-ch != nil {
		t.Error("expected closed channel")
	}
}
<commit_msg>Fix nginx_exporter_test (#38)<commit_after>package main

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/prometheus/client_golang/prometheus"
)

const (
	nginxStatus = `Active connections: 91
server accepts handled requests
 145249 145249 151557
Reading: 0 Writing: 24 Waiting: 66
`
	metricCount = 8
)

func TestNginxStatus(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(nginxStatus))
	})
	server := httptest.NewServer(handler)

	e := NewExporter(server.URL)
	ch := make(chan prometheus.Metric)

	go func() {
		defer close(ch)
		e.Collect(ch)
	}()

	for i := 1; i <= metricCount; i++ {
		m := <-ch
		if m == nil {
			t.Error("expected metric but got nil")
		}
	}
	if <-ch != nil {
		t.Error("expected closed channel")
	}
}
<|endoftext|>


<commit_before>package print_store

import (
	"encoding/json"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/cloudfoundry-incubator/runtime-schema/models"

	"github.com/cloudfoundry-incubator/veritas/say"
	"github.com/cloudfoundry-incubator/veritas/veritas_models"
)

func PrintDistribution(tasks bool, lrps bool, clear bool, f io.Reader) error {
	decoder := json.NewDecoder(f)
	var dump veritas_models.StoreDump
	err := decoder.Decode(&dump)
	if err != nil {
		return err
	}

	printDistribution(dump, tasks, lrps, clear)

	return nil
}

func printDistribution(dump veritas_models.StoreDump, includeTasks bool, includeLRPS bool, clear bool) {
	executorIDs := []string{}
	for _, executorPresence := range dump.Services.Executors {
		executorIDs = append(executorIDs, executorPresence.ExecutorID)
	}

	sort.Strings(executorIDs)

	nTasks := map[string]int{}
	nLRPsStarting := map[string]int{}
	nLRPsRunning := map[string]int{}

	for _, tasks := range dump.Tasks {
		for _, task := range tasks {
			nTasks[task.ExecutorID]++
		}
	}

	for _, lrp := range dump.LRPS {
		for _, actuals := range lrp.ActualLRPsByIndex {
			for _, actual := range actuals {
				if actual.State == models.ActualLRPStateStarting {
					nLRPsStarting[actual.ExecutorID]++
				} else {
					nLRPsRunning[actual.ExecutorID]++
				}
			}
		}
	}

	if clear {
		say.Clear()
	}

	say.Println(0, "Distribution")
	for _, executorID := range executorIDs {
		numTasks := nTasks[executorID]
		numLRPs := nLRPsStarting[executorID] + nLRPsRunning[executorID]
		var content string
		if numTasks == 0 && numLRPs == 0 {
			content = say.Red("Empty")
		} else {
			content = fmt.Sprintf("%s%s", say.Yellow(strings.Repeat("•", nTasks[executorID])), say.Green(strings.Repeat("•", nLRPsRunning[executorID])), say.Gray(strings.Repeat("•", nLRPsStarting[executorID])))
		}
		say.Println(0, "%12s: %s", executorID, content)
	}
}
<commit_msg>tweak it again<commit_after>package print_store

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"

	"github.com/cloudfoundry-incubator/runtime-schema/models"

	"github.com/cloudfoundry-incubator/veritas/say"
	"github.com/cloudfoundry-incubator/veritas/veritas_models"
)

func PrintDistribution(tasks bool, lrps bool, clear bool, f io.Reader) error {
	decoder := json.NewDecoder(f)
	var dump veritas_models.StoreDump
	err := decoder.Decode(&dump)
	if err != nil {
		return err
	}

	printDistribution(dump, tasks, lrps, clear)

	return nil
}

func printDistribution(dump veritas_models.StoreDump, includeTasks bool, includeLRPS bool, clear bool) {
	executorIDs := []string{}
	for _, executorPresence := range dump.Services.Executors {
		executorIDs = append(executorIDs, executorPresence.ExecutorID)
	}

	sort.Strings(executorIDs)

	nTasks := map[string]int{}
	nLRPsStarting := map[string]int{}
	nLRPsRunning := map[string]int{}

	for _, tasks := range dump.Tasks {
		for _, task := range tasks {
			nTasks[task.ExecutorID]++
		}
	}

	for _, lrp := range dump.LRPS {
		for _, actuals := range lrp.ActualLRPsByIndex {
			for _, actual := range actuals {
				if actual.State == models.ActualLRPStateStarting {
					nLRPsStarting[actual.ExecutorID]++
				} else {
					nLRPsRunning[actual.ExecutorID]++
				}
			}
		}
	}

	buffer := &bytes.Buffer{}
	say.Println(0, "Distribution")
	for _, executorID := range executorIDs {
		numTasks := nTasks[executorID]
		numLRPs := nLRPsStarting[executorID] + nLRPsRunning[executorID]
		var content string
		if numTasks == 0 && numLRPs == 0 {
			content = say.Red("Empty")
		} else {
			content = fmt.Sprintf("%s%s", say.Yellow(strings.Repeat("•", nTasks[executorID])), say.Green(strings.Repeat("•", nLRPsRunning[executorID])), say.Gray(strings.Repeat("•", nLRPsStarting[executorID])))
		}
		say.Fprintln(buffer, 0, "%12s: %s", executorID, content)
	}

	if clear {
		say.Clear()
	}
	buffer.WriteTo(os.Stdout)
}
<|endoftext|>


<commit_before>// +build windows,amd64

package winapi

import (
	"fmt"
	"time"

	"golang.org/x/sys/windows/registry"

	so "github.com/iamacarpet/go-win64api/shared"
)

func InstalledSoftwareList() ([]so.Software, error) {
	sw64, err := getSoftwareList(`SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall`, "X64")
	if err != nil {
		return nil, err
	}
	sw32, err := getSoftwareList(`SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall`, "X32")
	if err != nil {
		return nil, err
	}

	return append(sw64, sw32...), nil
}

func getSoftwareList(baseKey string, arch string) ([]so.Software, error) {
	k, err := registry.OpenKey(registry.LOCAL_MACHINE, baseKey, registry.QUERY_VALUE|registry.ENUMERATE_SUB_KEYS)
	if err != nil {
		return nil, fmt.Errorf("Error reading from registry: %s", err.Error())
	}
	defer k.Close()

	swList := make([]so.Software, 0)

	subkeys, err := k.ReadSubKeyNames(-1)
	if err != nil {
		return nil, fmt.Errorf("Error reading subkey list from registry: %s", err.Error())
	}
	for _, sw := range subkeys {
		sk, err := registry.OpenKey(registry.LOCAL_MACHINE, baseKey+`\`+sw, registry.QUERY_VALUE)
		if err != nil {
			return nil, fmt.Errorf("Error reading from registry (subkey %s): %s", sw, err.Error())
		}

		dn, _, err := sk.GetStringValue("DisplayName")
		if err == nil {
			swv := so.Software{DisplayName: dn, Arch: arch}

			dv, _, err := sk.GetStringValue("DisplayVersion")
			if err == nil {
				swv.DisplayVersion = dv
			}

			pub, _, err := sk.GetStringValue("Publisher")
			if err == nil {
				swv.Pub = pub
			}

			id, _, err := sk.GetStringValue("InstallDate")
			if err == nil {
				swv.InstallDate, _ = time.Parse("20160102", id)
			}

			es, _, err := sk.GetIntegerValue("EstimatedSize")
			if err == nil {
				swv.EstimatedSize = es
			}

			cont, _, err := sk.GetStringValue("Contact")
			if err == nil {
				swv.Contact = cont
			}

			hlp, _, err := sk.GetStringValue("HelpLink")
			if err == nil {
				swv.HelpLink = hlp
			}

			isource, _, err := sk.GetStringValue("InstallSource")
			if err == nil {
				swv.InstallSource = isource
			}

			mver, _, err := sk.GetIntegerValue("VersionMajor")
			if err == nil {
				swv.VersionMajor = mver
			}

			mnver, _, err := sk.GetIntegerValue("VersionMinor")
			if err == nil {
				swv.VersionMinor = mnver
			}

			swList = append(swList, swv)
		}
	}

	return swList, nil
}
<commit_msg>time format mistake<commit_after>// +build windows,amd64

package winapi

import (
	"fmt"
	"time"

	"golang.org/x/sys/windows/registry"

	so "github.com/iamacarpet/go-win64api/shared"
)

func InstalledSoftwareList() ([]so.Software, error) {
	sw64, err := getSoftwareList(`SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall`, "X64")
	if err != nil {
		return nil, err
	}
	sw32, err := getSoftwareList(`SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall`, "X32")
	if err != nil {
		return nil, err
	}

	return append(sw64, sw32...), nil
}

func getSoftwareList(baseKey string, arch string) ([]so.Software, error) {
	k, err := registry.OpenKey(registry.LOCAL_MACHINE, baseKey, registry.QUERY_VALUE|registry.ENUMERATE_SUB_KEYS)
	if err != nil {
		return nil, fmt.Errorf("Error reading from registry: %s", err.Error())
	}
	defer k.Close()

	swList := make([]so.Software, 0)

	subkeys, err := k.ReadSubKeyNames(-1)
	if err != nil {
		return nil, fmt.Errorf("Error reading subkey list from registry: %s", err.Error())
	}
	for _, sw := range subkeys {
		sk, err := registry.OpenKey(registry.LOCAL_MACHINE, baseKey+`\`+sw, registry.QUERY_VALUE)
		if err != nil {
			return nil, fmt.Errorf("Error reading from registry (subkey %s): %s", sw, err.Error())
		}

		dn, _, err := sk.GetStringValue("DisplayName")
		if err == nil {
			swv := so.Software{DisplayName: dn, Arch: arch}

			dv, _, err := sk.GetStringValue("DisplayVersion")
			if err == nil {
				swv.DisplayVersion = dv
			}

			pub, _, err := sk.GetStringValue("Publisher")
			if err == nil {
				swv.Pub = pub
			}

			id, _, err := sk.GetStringValue("InstallDate")
			if err == nil {
				swv.InstallDate, _ = time.Parse("20060102", id)
			}

			es, _, err := sk.GetIntegerValue("EstimatedSize")
			if err == nil {
				swv.EstimatedSize = es
			}

			cont, _, err := sk.GetStringValue("Contact")
			if err == nil {
				swv.Contact = cont
			}

			hlp, _, err := sk.GetStringValue("HelpLink")
			if err == nil {
				swv.HelpLink = hlp
			}

			isource, _, err := sk.GetStringValue("InstallSource")
			if err == nil {
				swv.InstallSource = isource
			}

			mver, _, err := sk.GetIntegerValue("VersionMajor")
			if err == nil {
				swv.VersionMajor = mver
			}

			mnver, _, err := sk.GetIntegerValue("VersionMinor")
			if err == nil {
				swv.VersionMinor = mnver
			}

			swList = append(swList, swv)
		}
	}

	return swList, nil
}
<|endoftext|>


<commit_before>package sortutil

import (
	"fmt"
	"math"
	"reflect"
	"sort"
	"strings"
	"time"
)

// Ordering decides the order in which the specified data is sorted.
type Ordering int

func (o Ordering) String() string {
	return orderings[o]
}

// A runtime panic will occur if case-insensitive is used when not sorting by
// a string type.
const (
	Ascending Ordering = iota
	Descending
	CaseInsensitiveAscending
	CaseInsensitiveDescending
)

var orderings = []string{
	"Ascending",
	"Descending",
	"CaseInsensitiveAscending",
	"CaseInsensitiveDescending",
}

// Recognized non-standard types
var (
	t_time = reflect.TypeOf(time.Time{})
)

// A "universal" sort.Interface adapter.
//   T: The slice type
//   V: The slice
//   G: The Getter function
//   vals: a slice of the values to sort by, e.g. []string for a "Name" field
//   valType: type of the value sorted by, e.g. string
type Sorter struct {
	T        reflect.Type
	V        reflect.Value
	G        Getter
	Ordering Ordering
	vals     []reflect.Value
	valKind  reflect.Kind
	valType  reflect.Type
}

// Sort the values in s.V by retrieving comparison items using s.G(s.V). A
// runtime panic will occur if g is not applicable to the given data x, or if
// the values retrieved by g cannot be compared.
func (s *Sorter) Sort() {
	if s.G == nil {
		s.G = SimpleGetter()
	}
	s.vals = s.G(s.V)
	one := s.vals[0]
	s.valType = one.Type()
	s.valKind = one.Kind()
	switch s.valKind {
	// If the value isn't a standard kind, find a known type to sort by
	default:
		switch s.valType {
		default:
			panic(fmt.Sprintf("Cannot sort by type %v", s.valType))
		case t_time:
			switch s.Ordering {
			default:
				panic(fmt.Sprintf("Invalid ordering %v for time.Time", s.Ordering))
			case Ascending:
				sort.Sort(timeAscending{s})
			case Descending:
				sort.Sort(timeDescending{s})
			}
		}
	// Strings
	case reflect.String:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for strings", s.Ordering))
		case Ascending:
			sort.Sort(stringAscending{s})
		case Descending:
			sort.Sort(stringDescending{s})
		case CaseInsensitiveAscending:
			sort.Sort(stringInsensitiveAscending{s})
		case CaseInsensitiveDescending:
			sort.Sort(stringInsensitiveDescending{s})
		}
	// Booleans
	case reflect.Bool:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for booleans", s.Ordering))
		case Ascending:
			sort.Sort(boolAscending{s})
		case Descending:
			sort.Sort(boolDescending{s})
		}
	// Ints
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for ints", s.Ordering))
		case Ascending:
			sort.Sort(intAscending{s})
		case Descending:
			sort.Sort(intDescending{s})
		}
	// Uints
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for uints", s.Ordering))
		case Ascending:
			sort.Sort(uintAscending{s})
		case Descending:
			sort.Sort(uintDescending{s})
		}
	// Floats
	case reflect.Float32, reflect.Float64:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for floats", s.Ordering))
		case Ascending:
			sort.Sort(floatAscending{s})
		case Descending:
			sort.Sort(floatDescending{s})
		}
	}
}

// Returns the length of the slice being sorted
func (s *Sorter) Len() int {
	return len(s.vals)
}

// Swaps two indices in the slice being sorted
func (s *Sorter) Swap(i, j int) {
	// Updating the structs causes s.vals[i], s.vals[j] to (essentially) be swapped, too.
	// TODO: Inefficient; update with (future?) reflect.Swap/reflect.SetIndex
	tmp := reflect.New(s.T).Elem()
	tmp.Set(s.V.Index(i))
	s.V.Index(i).Set(s.V.Index(j))
	s.V.Index(j).Set(tmp)
}

// *cough* typedef *cough*
type stringAscending struct{ *Sorter }
type stringDescending struct{ *Sorter }
type stringInsensitiveAscending struct{ *Sorter }
type stringInsensitiveDescending struct{ *Sorter }
type boolAscending struct{ *Sorter }
type boolDescending struct{ *Sorter }
type intAscending struct{ *Sorter }
type intDescending struct{ *Sorter }
type uintAscending struct{ *Sorter }
type uintDescending struct{ *Sorter }
type floatAscending struct{ *Sorter }
type floatDescending struct{ *Sorter }
type timeAscending struct{ *Sorter }
type timeDescending struct{ *Sorter }

func (s stringAscending) Less(i, j int) bool {
	return s.Sorter.vals[i].String() < s.Sorter.vals[j].String()
}

func (s stringDescending) Less(i, j int) bool {
	return s.Sorter.vals[i].String() > s.Sorter.vals[j].String()
}

func (s stringInsensitiveAscending) Less(i, j int) bool {
	return strings.ToLower(s.Sorter.vals[i].String()) < strings.ToLower(s.Sorter.vals[j].String())
}

func (s stringInsensitiveDescending) Less(i, j int) bool {
	return strings.ToLower(s.Sorter.vals[i].String()) > strings.ToLower(s.Sorter.vals[j].String())
}

func (s boolAscending) Less(i, j int) bool {
	return !s.Sorter.vals[i].Bool() && s.Sorter.vals[j].Bool()
}
func (s boolDescending) Less(i, j int) bool {
	return s.Sorter.vals[i].Bool() && !s.Sorter.vals[j].Bool()
}

func (s intAscending) Less(i, j int) bool   { return s.Sorter.vals[i].Int() < s.Sorter.vals[j].Int() }
func (s intDescending) Less(i, j int) bool  { return s.Sorter.vals[i].Int() > s.Sorter.vals[j].Int() }
func (s uintAscending) Less(i, j int) bool  { return s.Sorter.vals[i].Uint() < s.Sorter.vals[j].Uint() }
func (s uintDescending) Less(i, j int) bool { return s.Sorter.vals[i].Uint() > s.Sorter.vals[j].Uint() }

func (s floatAscending) Less(i, j int) bool {
	a := s.Sorter.vals[i].Float()
	b := s.Sorter.vals[j].Float()
	return a < b || math.IsNaN(a) && !math.IsNaN(b)
}

func (s floatDescending) Less(i, j int) bool {
	a := s.Sorter.vals[i].Float()
	b := s.Sorter.vals[j].Float()
	return a > b || !math.IsNaN(a) && math.IsNaN(b)
}

func (s timeAscending) Less(i, j int) bool {
	return s.Sorter.vals[i].Interface().(time.Time).Before(s.Sorter.vals[j].Interface().(time.Time))
}

func (s timeDescending) Less(i, j int) bool {
	return s.Sorter.vals[i].Interface().(time.Time).After(s.Sorter.vals[j].Interface().(time.Time))
}

// Returns a Sorter for a slice or array which will sort according to the
// items retrieved by getter, in the given ordering.
func New(slice interface{}, getter Getter, ordering Ordering) *Sorter {
	v := reflect.ValueOf(slice)
	return &Sorter{
		T:        v.Index(0).Type(),
		V:        v,
		G:        getter,
		Ordering: ordering,
	}
}

// Sort a slice or array using a Getter in the order specified by Ordering.
// getter may be nil if sorting a slice of a basic type where identifying a
// parent struct field or slice index isn't necessary, e.g. if sorting an
// []int, []string or []time.Time. A runtime panic will occur if getter is
// not applicable to the given data slice, or if the values retrieved by g
// cannot be compared.
func Sort(slice interface{}, getter Getter, ordering Ordering) {
	New(slice, getter, ordering).Sort()
}

// Reverse a type which implements sort.Interface.
func Reverse(s sort.Interface) {
	for i, j := 0, s.Len()-1; i < j; i, j = i+1, j-1 {
		s.Swap(i, j)
	}
}

// Sort a type using its existing sort.Interface, then reverse it. For a
// slice with a a "normal" sort interface (where Less returns true if i
// is less than j), this causes the slice to be sorted in descending order.
func SortReverse(s sort.Interface) {
	sort.Sort(s)
	Reverse(s)
}
<commit_msg>Convenience functions<commit_after>package sortutil

import (
	"fmt"
	"math"
	"reflect"
	"sort"
	"strings"
	"time"
)

// Ordering decides the order in which the specified data is sorted.
type Ordering int

func (o Ordering) String() string {
	return orderings[o]
}

// A runtime panic will occur if case-insensitive is used when not sorting by
// a string type.
const (
	Ascending Ordering = iota
	Descending
	CaseInsensitiveAscending
	CaseInsensitiveDescending
)

var orderings = []string{
	"Ascending",
	"Descending",
	"CaseInsensitiveAscending",
	"CaseInsensitiveDescending",
}

// Recognized non-standard types
var (
	t_time = reflect.TypeOf(time.Time{})
)

// A "universal" sort.Interface adapter.
//   T: The slice type
//   V: The slice
//   G: The Getter function
//   vals: a slice of the values to sort by, e.g. []string for a "Name" field
//   valType: type of the value sorted by, e.g. string
type Sorter struct {
	T        reflect.Type
	V        reflect.Value
	G        Getter
	Ordering Ordering
	vals     []reflect.Value
	valKind  reflect.Kind
	valType  reflect.Type
}

// Sort the values in s.V by retrieving comparison items using s.G(s.V). A
// runtime panic will occur if g is not applicable to the given data x, or if
// the values retrieved by g cannot be compared.
func (s *Sorter) Sort() {
	if s.G == nil {
		s.G = SimpleGetter()
	}
	s.vals = s.G(s.V)
	one := s.vals[0]
	s.valType = one.Type()
	s.valKind = one.Kind()
	switch s.valKind {
	// If the value isn't a standard kind, find a known type to sort by
	default:
		switch s.valType {
		default:
			panic(fmt.Sprintf("Cannot sort by type %v", s.valType))
		case t_time:
			switch s.Ordering {
			default:
				panic(fmt.Sprintf("Invalid ordering %v for time.Time", s.Ordering))
			case Ascending:
				sort.Sort(timeAscending{s})
			case Descending:
				sort.Sort(timeDescending{s})
			}
		}
	// Strings
	case reflect.String:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for strings", s.Ordering))
		case Ascending:
			sort.Sort(stringAscending{s})
		case Descending:
			sort.Sort(stringDescending{s})
		case CaseInsensitiveAscending:
			sort.Sort(stringInsensitiveAscending{s})
		case CaseInsensitiveDescending:
			sort.Sort(stringInsensitiveDescending{s})
		}
	// Booleans
	case reflect.Bool:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for booleans", s.Ordering))
		case Ascending:
			sort.Sort(boolAscending{s})
		case Descending:
			sort.Sort(boolDescending{s})
		}
	// Ints
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for ints", s.Ordering))
		case Ascending:
			sort.Sort(intAscending{s})
		case Descending:
			sort.Sort(intDescending{s})
		}
	// Uints
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for uints", s.Ordering))
		case Ascending:
			sort.Sort(uintAscending{s})
		case Descending:
			sort.Sort(uintDescending{s})
		}
	// Floats
	case reflect.Float32, reflect.Float64:
		switch s.Ordering {
		default:
			panic(fmt.Sprintf("Invalid ordering %v for floats", s.Ordering))
		case Ascending:
			sort.Sort(floatAscending{s})
		case Descending:
			sort.Sort(floatDescending{s})
		}
	}
}

// Returns the length of the slice being sorted
func (s *Sorter) Len() int {
	return len(s.vals)
}

// Swaps two indices in the slice being sorted
func (s *Sorter) Swap(i, j int) {
	// Updating the structs causes s.vals[i], s.vals[j] to (essentially) be swapped, too.
	// TODO: Inefficient; update with (future?) reflect.Swap/reflect.SetIndex
	tmp := reflect.New(s.T).Elem()
	tmp.Set(s.V.Index(i))
	s.V.Index(i).Set(s.V.Index(j))
	s.V.Index(j).Set(tmp)
}

// *cough* typedef *cough*
type stringAscending struct{ *Sorter }
type stringDescending struct{ *Sorter }
type stringInsensitiveAscending struct{ *Sorter }
type stringInsensitiveDescending struct{ *Sorter }
type boolAscending struct{ *Sorter }
type boolDescending struct{ *Sorter }
type intAscending struct{ *Sorter }
type intDescending struct{ *Sorter }
type uintAscending struct{ *Sorter }
type uintDescending struct{ *Sorter }
type floatAscending struct{ *Sorter }
type floatDescending struct{ *Sorter }
type timeAscending struct{ *Sorter }
type timeDescending struct{ *Sorter }

func (s stringAscending) Less(i, j int) bool {
	return s.Sorter.vals[i].String() < s.Sorter.vals[j].String()
}

func (s stringDescending) Less(i, j int) bool {
	return s.Sorter.vals[i].String() > s.Sorter.vals[j].String()
}

func (s stringInsensitiveAscending) Less(i, j int) bool {
	return strings.ToLower(s.Sorter.vals[i].String()) < strings.ToLower(s.Sorter.vals[j].String())
}

func (s stringInsensitiveDescending) Less(i, j int) bool {
	return strings.ToLower(s.Sorter.vals[i].String()) > strings.ToLower(s.Sorter.vals[j].String())
}

func (s boolAscending) Less(i, j int) bool {
	return !s.Sorter.vals[i].Bool() && s.Sorter.vals[j].Bool()
}
func (s boolDescending) Less(i, j int) bool {
	return s.Sorter.vals[i].Bool() && !s.Sorter.vals[j].Bool()
}

func (s intAscending) Less(i, j int) bool   { return s.Sorter.vals[i].Int() < s.Sorter.vals[j].Int() }
func (s intDescending) Less(i, j int) bool  { return s.Sorter.vals[i].Int() > s.Sorter.vals[j].Int() }
func (s uintAscending) Less(i, j int) bool  { return s.Sorter.vals[i].Uint() < s.Sorter.vals[j].Uint() }
func (s uintDescending) Less(i, j int) bool { return s.Sorter.vals[i].Uint() > s.Sorter.vals[j].Uint() }

func (s floatAscending) Less(i, j int) bool {
	a := s.Sorter.vals[i].Float()
	b := s.Sorter.vals[j].Float()
	return a < b || math.IsNaN(a) && !math.IsNaN(b)
}

func (s floatDescending) Less(i, j int) bool {
	a := s.Sorter.vals[i].Float()
	b := s.Sorter.vals[j].Float()
	return a > b || !math.IsNaN(a) && math.IsNaN(b)
}

func (s timeAscending) Less(i, j int) bool {
	return s.Sorter.vals[i].Interface().(time.Time).Before(s.Sorter.vals[j].Interface().(time.Time))
}

func (s timeDescending) Less(i, j int) bool {
	return s.Sorter.vals[i].Interface().(time.Time).After(s.Sorter.vals[j].Interface().(time.Time))
}

// Returns a Sorter for a slice or array which will sort according to the
// items retrieved by getter, in the given ordering.
func New(slice interface{}, getter Getter, ordering Ordering) *Sorter {
	v := reflect.ValueOf(slice)
	return &Sorter{
		T:        v.Index(0).Type(),
		V:        v,
		G:        getter,
		Ordering: ordering,
	}
}

// Sort a slice or array using a Getter in the order specified by Ordering.
// getter may be nil if sorting a slice of a basic type where identifying a
// parent struct field or slice index isn't necessary, e.g. if sorting an
// []int, []string or []time.Time. A runtime panic will occur if getter is
// not applicable to the given data slice, or if the values retrieved by g
// cannot be compared.
func Sort(slice interface{}, getter Getter, ordering Ordering) {
	New(slice, getter, ordering).Sort()
}

// Sort a slice in ascending order.
func Asc(slice interface{}) {
	New(slice, nil, Ascending).Sort()
}

// Sort a slice in descending order.
func Desc(slice interface{}) {
	New(slice, nil, Descending).Sort()
}

// Sort a slice in case-insensitive ascending order.
func CiAsc(slice interface{}) {
	New(slice, nil, CaseInsensitiveAscending).Sort()
}

// Sort a slice in case-insensitive descending order.
func CiDesc(slice interface{}) {
	New(slice, nil, CaseInsensitiveDescending).Sort()
}

// Sort a slice in ascending order by a field name.
func AscByField(slice interface{}, name string) {
	New(slice, FieldGetter(name), Ascending).Sort()
}

// Sort a slice in descending order by a field name.
func DescByField(slice interface{}, name string) {
	New(slice, FieldGetter(name), Descending).Sort()
}

// Sort a slice in case-insensitive ascending order by a field name.
// (Valid for string types.)
func CiAscByField(slice interface{}, name string) {
	New(slice, FieldGetter(name), CaseInsensitiveAscending).Sort()
}

// Sort a slice in case-insensitive descending order by a field name.
// (Valid for string types.)
func CiDescByField(slice interface{}, name string) {
	New(slice, FieldGetter(name), CaseInsensitiveDescending).Sort()
}

// Sort a slice in ascending order by a list of nested field indices, e.g. 1, 2,
// 3 to sort by the third field from the struct in the second field of the struct
// in the first field of each struct in the slice.
func AscByFieldIndex(slice interface{}, index []int) {
	New(slice, FieldByIndexGetter(index), Ascending).Sort()
}

// Sort a slice in descending order by a list of nested field indices, e.g. 1, 2,
// 3 to sort by the third field from the struct in the second field of the struct
// in the first field of each struct in the slice.
func DescByFieldIndex(slice interface{}, index []int) {
	New(slice, FieldByIndexGetter(index), Descending).Sort()
}

// Sort a slice in case-insensitive ascending order by a list of nested field
// indices, e.g. 1, 2, 3 to sort by the third field from the struct in the
// second field of the struct in the first field of each struct in the slice.
// (Valid for string types.)
func CiAscByFieldIndex(slice interface{}, index []int) {
	New(slice, FieldByIndexGetter(index), CaseInsensitiveAscending).Sort()
}

// Sort a slice in case-insensitive descending order by a list of nested field
// indices, e.g. 1, 2, 3 to sort by the third field from the struct in the
// second field of the struct in the first field of each struct in the slice.
// (Valid for string types.)
func CiDescByFieldIndex(slice interface{}, index []int) {
	New(slice, FieldByIndexGetter(index), CaseInsensitiveDescending).Sort()
}

// Sort a slice in ascending order by an index in a child slice.
func AscByIndex(slice interface{}, index int) {
	New(slice, IndexGetter(index), Ascending).Sort()
}

// Sort a slice in descending order by an index in a child slice.
func DescByIndex(slice interface{}, index int) {
	New(slice, IndexGetter(index), Descending).Sort()
}

// Sort a slice in case-insensitive ascending order by an index in a child
// slice. (Valid for string types.)
func CiAscByIndex(slice interface{}, index int) {
	New(slice, IndexGetter(index), CaseInsensitiveAscending).Sort()
}

// Sort a slice in case-insensitive descending order by an index in a child
// slice. (Valid for string types.)
func CiDescByIndex(slice interface{}, index int) {
	New(slice, IndexGetter(index), CaseInsensitiveDescending).Sort()
}

// Reverse a type which implements sort.Interface.
func Reverse(s sort.Interface) {
	for i, j := 0, s.Len()-1; i < j; i, j = i+1, j-1 {
		s.Swap(i, j)
	}
}

// Sort a type using its existing sort.Interface, then reverse it. For a
// slice with a a "normal" sort interface (where Less returns true if i
// is less than j), this causes the slice to be sorted in descending order.
func SortReverse(s sort.Interface) {
	sort.Sort(s)
	Reverse(s)
}
<|endoftext|>


<commit_before>package main

// Import formatting and IO libraries
import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
)

// Define a structure to hold our page
type Page struct {
	Title string
	Body  []byte // IO libs expect a byte slice rather than a string
}

// Add a save method to our Page struct so we can persist our data
// This method's signature reads: "This is a method named save that takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type error."
func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

// Load pages too
func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/view/"):]
	p, _ := loadPage(title)
	t, _ := template.ParseFiles("view.html")
	t.Execute(w, p)
}

func editHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/edit/"):]
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
	t, _ := template.ParseFiles("edit.html")
	t.Execute(w, p)
}

func main() {
	// p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
	// p1.save()
	// p2, _ := loadPage("TestPage")
	// fmt.Println(string(p2.Body))
	http.HandleFunc("/view/", viewHandler)
	http.HandleFunc("/edit/", editHandler)
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Refactor template rendering.<commit_after>package main

// Import formatting and IO libraries
import (
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
)

// Define a structure to hold our page
type Page struct {
	Title string
	Body  []byte // IO libs expect a byte slice rather than a string
}

// Add a save method to our Page struct so we can persist our data
// This method's signature reads: "This is a method named save that takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type error."
func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

// Load pages too
func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
    t, _ := template.ParseFiles(tmpl + ".html")
        t.Execute(w, p)
        }

func viewHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/view/"):]
	p, _ := loadPage(title)
        renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/edit/"):]
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
        renderTemplate(w, "edit", p)
}

func main() {
	// p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
	// p1.save()
	// p2, _ := loadPage("TestPage")
	// fmt.Println(string(p2.Body))
	http.HandleFunc("/view/", viewHandler)
	http.HandleFunc("/edit/", editHandler)
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>