<commit_before>package main

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

var port = flag.Int("port", 8080, "which port to listen on")
var authApiKey string
var dbUrl string

var rootMetrics = map[string]string{
	"agentVersion": "host.agent_version",
	"os":           "host.os",
	"python":       "host.python_version",
	"uuid":         "host.uuid",

	"system.load.1":       "system.load.1",
	"system.load.5":       "system.load.5",
	"system.load.15":      "system.load.15",
	"system.load.norm.1":  "system.load.norm.1",
	"system.load.norm.5":  "system.load.norm.5",
	"system.load.norm.15": "system.load.norm.15",

	"cpuIdle":   "system.cpu.idle",
	"cpuUser":   "system.cpu.user",
	"cpuWait":   "system.cpu.iowait",
	"cpuSystem": "system.cpu.system",
	"cpuStolen": "system.cpu.stolen",

	"memBuffers":       "system.mem.buffered",
	"memPhysPctUsable": "system.mem.pct_usable",
	"memShared":        "system.mem.shared",
	"memPhysTotal":     "system.mem.total",
	"memPhysUsable":    "system.mem.usable",
	"memCached":        "system.mem.cached",
	"memPhysUsed":      "system.mem.used",
	"memPhysFree":      "system.mem.free",

	"memSwapFree":    "system.swap.free",
	"memSwapTotal":   "system.swap.total",
	"memSwapUsed":    "system.swap.used",
	"memSwapPctFree": "system.swap.pct_free",
}

var diskMetrics = []string{
	"device",
	"total",
	"used",
	"free",
	"in_use",
	"mount",
}

type Metric struct {
	Name    string          `json:"name"`
	Columns []string        `json:"columns"`
	Points  [][]interface{} `json:"points"`
}

func NewMetric(host, name string, timestamp uint64, value interface{}, tags map[string]string) *Metric {
	columns := []string{"time", "value", "hostname"}
	points := [][]interface{}{{timestamp, value, host}}
	if tags != nil {
		for k, v := range tags {
			if k == "hostname" {
				points[0][2] = v
			} else {
				columns = append(columns, k)
				points[0] = append(points[0], v)
			}
		}
	}
	return &Metric{name, columns, points}
}

func NewMetricGroup(host, name string, timestamp uint64, values map[string]interface{}, tags map[string]string) *Metric {
	columns := []string{"time", "hostname"}
	points := [][]interface{}{{timestamp, host}}
	for k, v := range values {
		columns = append(columns, k)
		points[0] = append(points[0], v)
	}
	if tags != nil {
		for k, v := range tags {
			if k == "hostname" {
				points[0][1] = v
			} else {
				columns = append(columns, k)
				points[0] = append(points[0], v)
			}
		}
	}
	return &Metric{name, columns, points}
}

func PushMetrics(metrics []*Metric) {
	if len(metrics) == 0 {
		return
	}
	log.Printf("Pushing %d metrics to InfluxDB\n", len(metrics))

	body, err := json.Marshal(metrics)
	if err != nil {
		log.Println(err)
		return
	}

	resp, err := http.Post(dbUrl, "application/json", bytes.NewBuffer(body))
	if err != nil {
		log.Println(err)
	} else if resp.StatusCode != 200 {
		log.Println("Got Response: ", resp.Status)
	}
}

func mapMetrics(data map[string]interface{}) []*Metric {
	metrics := []*Metric{}
	host := data["internalHostname"].(string)
	timestamp := uint64(data["collection_timestamp"].(float64) * 1000)

	delete(data, "apiKey")
	delete(data, "internalHostname")
	delete(data, "collection_timestamp")

	values := make(map[string]map[string]interface{})

	log.Printf("Parsing metrics for: %s\n", host)
	for key, value := range data {
		name, ok := rootMetrics[key]
		if ok {
			index := strings.LastIndexAny(name, ".")
			group_name := name[:index]
			group := values[group_name]
			if group == nil {
				group = make(map[string]interface{})
				values[group_name] = group
			}
			group[name[index+1:]] = value
			delete(data, key)
		}
	}
	for name, group := range values {
		metrics = append(metrics, NewMetricGroup(host, name, timestamp, group, nil))
	}

	metrics = append(metrics, mapDiskMetrics("system.disk", timestamp, host, data["diskUsage"].([]interface{})))
	delete(data, "diskUsage")
	metrics = append(metrics, mapDiskMetrics("system.fs.inodes", timestamp, host, data["inodes"].([]interface{})))
	delete(data, "inodes")

	debug, err := json.MarshalIndent(data, "", "  ")
	if err == nil {
		fmt.Println(string(debug))
	}
	return metrics
}

func mapDiskMetrics(name string, timestamp uint64, host string, data []interface{}) *Metric {
	columns := append([]string{"time", "hostname"}, diskMetrics...)
	points := make([][]interface{}, len(data))
	metric := &Metric{name, columns, points}
	for i, disk := range data {
		fields := disk.([]interface{})
		percent := fields[4].(string)
		parse, _ := strconv.ParseFloat(percent[:len(percent)-1], 64)
		fields[4] = parse / 100.0
		points[i] = append([]interface{}{timestamp, host}, fields...)
	}
	return metric
}

func handleIntake(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	data := make(map[string]interface{})
	err = json.Unmarshal(buf.Bytes(), &data)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	metrics := mapMetrics(data)
	go PushMetrics(metrics)

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApi(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	} else {
		log.Println(buf.String())
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApiKey(w http.ResponseWriter, req *http.Request) bool {
	if req.UserAgent() == "Datadog-Status-Check" {
		io.WriteString(w, "STILL-ALIVE\n")
		return true
	}
	err := req.ParseForm()
	if err != nil {
		log.Println("Error parsing form:", err)
		http.Error(w, err.Error(), 500)
		return true
	}
	values := req.Form
	api_key := values.Get("api_key")
	delete(values, "api_key")
	if len(authApiKey) > 0 && api_key != authApiKey {
		log.Println("Got bad API key:", api_key)
		http.Error(w, "Bad API Key", 403)
		return true
	}
	return false
}

func main() {
	flag.Parse()
	authApiKey = os.Getenv("API_KEY")
	if len(authApiKey) == 0 {
		log.Println("Warning: API_KEY is blank")
	}
	dbUrl = os.Getenv("DB_URL")
	if len(dbUrl) == 0 {
		dbUrl = "http://localhost:8086/db/datadog/series?u=root&p=root"
	}

	log.Println("dd-house listening on", *port)

	http.HandleFunc("/intake", handleIntake)
	http.HandleFunc("/api/v1/series/", handleApi)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
<commit_msg>Push statsd metrics to influxdb<commit_after>package main

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

var port = flag.Int("port", 8080, "which port to listen on")
var authApiKey string
var dbUrl string

var rootMetrics = map[string]string{
	"agentVersion": "host.agent_version",
	"os":           "host.os",
	"python":       "host.python_version",
	"uuid":         "host.uuid",

	"system.load.1":       "system.load.1",
	"system.load.5":       "system.load.5",
	"system.load.15":      "system.load.15",
	"system.load.norm.1":  "system.load.norm.1",
	"system.load.norm.5":  "system.load.norm.5",
	"system.load.norm.15": "system.load.norm.15",

	"cpuIdle":   "system.cpu.idle",
	"cpuUser":   "system.cpu.user",
	"cpuWait":   "system.cpu.iowait",
	"cpuSystem": "system.cpu.system",
	"cpuStolen": "system.cpu.stolen",

	"memBuffers":       "system.mem.buffered",
	"memPhysPctUsable": "system.mem.pct_usable",
	"memShared":        "system.mem.shared",
	"memPhysTotal":     "system.mem.total",
	"memPhysUsable":    "system.mem.usable",
	"memCached":        "system.mem.cached",
	"memPhysUsed":      "system.mem.used",
	"memPhysFree":      "system.mem.free",

	"memSwapFree":    "system.swap.free",
	"memSwapTotal":   "system.swap.total",
	"memSwapUsed":    "system.swap.used",
	"memSwapPctFree": "system.swap.pct_free",
}

var diskMetrics = []string{
	"device",
	"total",
	"used",
	"free",
	"in_use",
	"mount",
}

type Metric struct {
	Name    string          `json:"name"`
	Columns []string        `json:"columns"`
	Points  [][]interface{} `json:"points"`
}

type StatsdSeries struct {
	Series []*StatsdMetric `json:"series"`
}

type StatsdMetric struct {
	Tags     []string        `json:"tags"`
	Metric   string          `json:"metric"`
	Interval float64         `json:"interval"`
	Host     string          `json:"host"`
	Points   [][]interface{} `json:"points"`
	Type     string          `json:"type"`
}

func NewMetric(host, name string, timestamp uint64, value interface{}, tags map[string]string) *Metric {
	columns := []string{"time", "value", "hostname"}
	points := [][]interface{}{{timestamp, value, host}}
	if tags != nil {
		for k, v := range tags {
			if k == "hostname" {
				points[0][2] = v
			} else {
				columns = append(columns, k)
				points[0] = append(points[0], v)
			}
		}
	}
	return &Metric{name, columns, points}
}

func NewMetricGroup(host, name string, timestamp uint64, values map[string]interface{}, tags map[string]string) *Metric {
	columns := []string{"time", "hostname"}
	points := [][]interface{}{{timestamp, host}}
	for k, v := range values {
		columns = append(columns, k)
		points[0] = append(points[0], v)
	}
	if tags != nil {
		for k, v := range tags {
			if k == "hostname" {
				points[0][1] = v
			} else {
				columns = append(columns, k)
				points[0] = append(points[0], v)
			}
		}
	}
	return &Metric{name, columns, points}
}

func PushMetrics(metrics []*Metric) {
	if len(metrics) == 0 {
		return
	}
	log.Printf("Pushing %d metrics to InfluxDB\n", len(metrics))

	body, err := json.Marshal(metrics)
	if err != nil {
		log.Println(err)
		return
	}

	resp, err := http.Post(dbUrl, "application/json", bytes.NewBuffer(body))
	if err != nil {
		log.Println(err)
	} else if resp.StatusCode != 200 {
		log.Println("Got Response: ", resp.Status)
	}
}

func mapStatsd(series []*StatsdMetric) []*Metric {
	metrics := make([]*Metric, len(series))
	host := ""
	for i, metric := range series {
		if len(metric.Host) > 0 {
			host = metric.Host
		}
		columns := []string{"time", "value", "hostname"}
		points := metric.Points
		for i, _ := range points {
			points[i] = append(points[i], host)
		}
		if metric.Tags != nil {
			for _, tag := range metric.Tags {
				split := strings.SplitN(tag, ":", 2)
				if split[0] == "hostname" {
					for i, _ := range points {
						points[i][2] = split[1]
					}
				} else {
					columns = append(columns, split[0])
					for i, _ := range points {
						points[i] = append(points[i], split[1])
					}
				}
			}
		}
		metrics[i] = &Metric{metric.Metric, columns, points}
	}
	for _, metric := range metrics {
		for _, points := range metric.Points {
			if len(points[2].(string)) == 0 {
				points[2] = host
			}
		}
	}
	return metrics
}

func mapMetrics(data map[string]interface{}) []*Metric {
	metrics := []*Metric{}
	host := data["internalHostname"].(string)
	timestamp := uint64(data["collection_timestamp"].(float64) * 1000)

	delete(data, "apiKey")
	delete(data, "internalHostname")
	delete(data, "collection_timestamp")

	values := make(map[string]map[string]interface{})

	log.Printf("Parsing metrics for: %s\n", host)
	for key, value := range data {
		name, ok := rootMetrics[key]
		if ok {
			index := strings.LastIndexAny(name, ".")
			group_name := name[:index]
			group := values[group_name]
			if group == nil {
				group = make(map[string]interface{})
				values[group_name] = group
			}
			group[name[index+1:]] = value
			delete(data, key)
		}
	}
	for name, group := range values {
		metrics = append(metrics, NewMetricGroup(host, name, timestamp, group, nil))
	}

	metrics = append(metrics, mapDiskMetrics("system.disk", timestamp, host, data["diskUsage"].([]interface{})))
	delete(data, "diskUsage")
	metrics = append(metrics, mapDiskMetrics("system.fs.inodes", timestamp, host, data["inodes"].([]interface{})))
	delete(data, "inodes")

	debug, err := json.MarshalIndent(data, "", "  ")
	if err == nil {
		fmt.Println(string(debug))
	}
	return metrics
}

func mapDiskMetrics(name string, timestamp uint64, host string, data []interface{}) *Metric {
	columns := append([]string{"time", "hostname"}, diskMetrics...)
	points := make([][]interface{}, len(data))
	metric := &Metric{name, columns, points}
	for i, disk := range data {
		fields := disk.([]interface{})
		percent := fields[4].(string)
		parse, _ := strconv.ParseFloat(percent[:len(percent)-1], 64)
		fields[4] = parse / 100.0
		points[i] = append([]interface{}{timestamp, host}, fields...)
	}
	return metric
}

func handleIntake(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	data := make(map[string]interface{})
	err = json.Unmarshal(buf.Bytes(), &data)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	metrics := mapMetrics(data)
	go PushMetrics(metrics)

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApi(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	series := StatsdSeries{}
	err = json.Unmarshal(buf.Bytes(), &series)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	metrics := mapStatsd(series.Series)
	go PushMetrics(metrics)

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApiKey(w http.ResponseWriter, req *http.Request) bool {
	if req.UserAgent() == "Datadog-Status-Check" {
		io.WriteString(w, "STILL-ALIVE\n")
		return true
	}
	err := req.ParseForm()
	if err != nil {
		log.Println("Error parsing form:", err)
		http.Error(w, err.Error(), 500)
		return true
	}
	values := req.Form
	api_key := values.Get("api_key")
	delete(values, "api_key")
	if len(authApiKey) > 0 && api_key != authApiKey {
		log.Println("Got bad API key:", api_key)
		http.Error(w, "Bad API Key", 403)
		return true
	}
	return false
}

func main() {
	flag.Parse()
	authApiKey = os.Getenv("API_KEY")
	if len(authApiKey) == 0 {
		log.Println("Warning: API_KEY is blank")
	}
	dbUrl = os.Getenv("DB_URL")
	if len(dbUrl) == 0 {
		dbUrl = "http://localhost:8086/db/datadog/series?u=root&p=root"
	}

	log.Println("dd-house listening on", *port)

	http.HandleFunc("/intake", handleIntake)
	http.HandleFunc("/api/v1/series/", handleApi)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
<|endoftext|>


<commit_before>package jwd

import (
	"math"
	"strings"
)

// According to this tool: http://www.csun.edu/english/edit_distance.php
// parameter order should have no difference in the result. Therefore,
// to avoid panicing later on, we will order the strings according to
// their length.
func order(s1, s2 string) (string, string) {
	if strings.Count(s1, "")-1 <= strings.Count(s2, "")-1 {
		return s1, s2
	} else {
		return s2, s1
	}
}

// Calculates Jaro-Winkler distance of two strings. The function lowercases and sorts the parameters
// so that that the longest string is evaluated against the shorter one.
func Calculate(s1, s2 string) float64 {

	s1, s2 = order(strings.ToLower(s1), strings.ToLower(s2))

	// m as `matching characters`
	// t as `transposition`
	// l as `the length of common prefix at the start of the string up to a maximum of 4 characters`. Not relevant in Jaro distance.
	// See more: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance
	m := 0
	t := 0
	l := 0

	window := math.Floor(float64(math.Max(float64(len(s1)), float64(len(s2)))/2) - 1)

	//debug:
	//fmt.Println("s1 param:", s1, "s2 param:", s2)
	//fmt.Println("Match window:", window, "s1:", len(s1), "s2:", len(s2))

	for i := 0; i < len(s1); i++ {
		// exact match
		if s1[i] == s2[i] {
			m++
			// Jaro-Winkler l as: `the length of common prefix at the start of the string up to a maximum of 4 characters`
			// Not relevant in Jaro distance.
			if i == l && i < 4 {
				l++
			}
		} else {
			if strings.Contains(s2, string(s1[i])) {
				// The character is considered matching if the amount of characters between the occurances in s1 and s2
				// (here `gap`) is less than match window `window`
				gap := strings.Index(s2, string(s1[i])) - strings.Index(s1, string(s1[i]))
				if gap < int(window) {
					m++
					// Somewhere in here is an error, which causes slight (max 0.04 from what I've come across, compared
					// with http://www.csun.edu/english/edit_distance.php) variations in some answers (such as slight
					// variation of Wikipedia example dicksonx and dixonsdsgese).
					// As far as I understood, transposition is only count when character exists in the string and in
					// reach of window. This loop checks whether the end of the `s2` string contains characters which
					// exist in `s1` string.
					// Editing the for loop to the following:
					//
					// 		for k := i; k < len(s1)-i; k++ {
					// 			if strings.Index(s2, string(s1[k])) < i {
					// 				fmt.Println(string(s1[k]), string(s1[i]))
					// 				t++
					// 			}
					// 		}
					//
					// Will yield same results as the libary I took example of:
					// 	https://github.com/NaturalNode/natural/blob/master/lib/natural/distance/jaro-winkler_distance.js
					// However, then the answer will be different from the ones in Wikipedia at:
					// 	https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance
					// It's a mystery to me which one is right and which one is wrong, but I'll bet on the accuracy of
					// http://www.csun.edu/english/edit_distance.php and therefore will remain the loop as following to
					// provide as accurate answer as I can.
					for k := i; k < len(s1); k++ {
						if strings.Index(s2, string(s1[k])) < i {
							t++
						}
					}
				}
			}
		}
	}

	distance := (float64(m)/float64(len(s1)) + float64(m)/float64(len(s2)) + (float64(m)-math.Floor(float64(t)/float64(2)))/float64(m)) / float64(3)
	jwd := distance + (float64(l) * float64(0.1) * (float64(1) - distance))

	//debug:
	//fmt.Println("transpositions:",tf, "m:",m)
	//fmt.Println("distance:",distance, "l:", l)
	//fmt.Println("JWD:", jwd)

	return jwd

}
<commit_msg>doc: add example to source<commit_after>package jwd

import (
	"math"
	"strings"
)

// According to this tool: http://www.csun.edu/english/edit_distance.php
// parameter order should have no difference in the result. Therefore,
// to avoid panicing later on, we will order the strings according to
// their length.
func order(s1, s2 string) (string, string) {
	if strings.Count(s1, "")-1 <= strings.Count(s2, "")-1 {
		return s1, s2
	} else {
		return s2, s1
	}
}

// Calculates Jaro-Winkler distance of two strings. The function lowercases and sorts the parameters
// so that that the longest string is evaluated against the shorter one.
// Example:
//
// 		package main
//
// 		import (
// 			"fmt"
// 			"github.com/9uuso/go-jaro-winkler-distance"
// 		)
//
// 		func main() {
// 			res := jwd.Calculate("DIXON", "DICKSONX")
// 			fmt.Println(res)
// 		}
//

func Calculate(s1, s2 string) float64 {

	s1, s2 = order(strings.ToLower(s1), strings.ToLower(s2))

	// m as `matching characters`
	// t as `transposition`
	// l as `the length of common prefix at the start of the string up to a maximum of 4 characters`. Not relevant in Jaro distance.
	// See more: https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance
	m := 0
	t := 0
	l := 0

	window := math.Floor(float64(math.Max(float64(len(s1)), float64(len(s2)))/2) - 1)

	//debug:
	//fmt.Println("s1 param:", s1, "s2 param:", s2)
	//fmt.Println("Match window:", window, "s1:", len(s1), "s2:", len(s2))

	for i := 0; i < len(s1); i++ {
		// exact match
		if s1[i] == s2[i] {
			m++
			// Jaro-Winkler l as: `the length of common prefix at the start of the string up to a maximum of 4 characters`
			// Not relevant in Jaro distance.
			if i == l && i < 4 {
				l++
			}
		} else {
			if strings.Contains(s2, string(s1[i])) {
				// The character is considered matching if the amount of characters between the occurances in s1 and s2
				// (here `gap`) is less than match window `window`
				gap := strings.Index(s2, string(s1[i])) - strings.Index(s1, string(s1[i]))
				if gap < int(window) {
					m++
					// Somewhere in here is an error, which causes slight (max 0.04 from what I've come across, compared
					// with http://www.csun.edu/english/edit_distance.php) variations in some answers (such as slight
					// variation of Wikipedia example dicksonx and dixonsdsgese).
					// As far as I understood, transposition is only count when character exists in the string and in
					// reach of window. This loop checks whether the end of the `s2` string contains characters which
					// exist in `s1` string.
					// Editing the for loop to the following:
					//
					// 		for k := i; k < len(s1)-i; k++ {
					// 			if strings.Index(s2, string(s1[k])) < i {
					// 				fmt.Println(string(s1[k]), string(s1[i]))
					// 				t++
					// 			}
					// 		}
					//
					// Will yield same results as the libary I took example of:
					// 	https://github.com/NaturalNode/natural/blob/master/lib/natural/distance/jaro-winkler_distance.js
					// However, then the answer will be different from the ones in Wikipedia at:
					// 	https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance
					// It's a mystery to me which one is right and which one is wrong, but I'll bet on the accuracy of
					// http://www.csun.edu/english/edit_distance.php and therefore will remain the loop as following to
					// provide as accurate answer as I can.
					for k := i; k < len(s1); k++ {
						if strings.Index(s2, string(s1[k])) < i {
							t++
						}
					}
				}
			}
		}
	}

	distance := (float64(m)/float64(len(s1)) + float64(m)/float64(len(s2)) + (float64(m)-math.Floor(float64(t)/float64(2)))/float64(m)) / float64(3)
	jwd := distance + (float64(l) * float64(0.1) * (float64(1) - distance))

	//debug:
	//fmt.Println("transpositions:",tf, "m:",m)
	//fmt.Println("distance:",distance, "l:", l)
	//fmt.Println("JWD:", jwd)

	return jwd

}
<|endoftext|>


<commit_before>package falcore

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

type Server struct {
	Addr                string
	Pipeline            *Pipeline
	CompletionCallback  RequestCompletionCallback
	listener            net.Listener
	listenerFile        *os.File
	stopAccepting       chan struct{}
	handlerWaitGroup    *sync.WaitGroup
	logPrefix           string
	AcceptReady         <-chan struct{}
	closableAcceptReady chan struct{}
	bufferPool          *BufferPool
	writeBufferPool     *WriteBufferPool
	PanicHandler        func(conn net.Conn, err interface{})
}

type RequestCompletionCallback func(req *Request, res *http.Response)

func NewServer(port int, pipeline *Pipeline) *Server {
	s := new(Server)
	s.Addr = fmt.Sprintf(":%v", port)
	s.Pipeline = pipeline
	s.stopAccepting = make(chan struct{})
	s.closableAcceptReady = make(chan struct{})
	s.AcceptReady = s.closableAcceptReady
	s.handlerWaitGroup = new(sync.WaitGroup)
	s.logPrefix = fmt.Sprintf("%d", syscall.Getpid())

	// buffer pool for reusing connection bufio.Readers
	s.bufferPool = NewBufferPool(100, 8192)
	s.writeBufferPool = NewWriteBufferPool(100, 4096)

	return s
}

func (srv *Server) FdListen(fd int) error {
	var err error
	srv.listenerFile = os.NewFile(uintptr(fd), "")
	if srv.listener, err = net.FileListener(srv.listenerFile); err != nil {
		return err
	}
	if _, ok := srv.listener.(*net.TCPListener); !ok {
		return errors.New("Broken listener isn't TCP")
	}
	return nil
}

func (srv *Server) socketListen() error {
	var la *net.TCPAddr
	var err error
	if la, err = net.ResolveTCPAddr("tcp", srv.Addr); err != nil {
		return err
	}

	var l *net.TCPListener
	if l, err = net.ListenTCP("tcp", la); err != nil {
		return err
	}
	srv.listener = l
	// setup listener to be non-blocking if we're not on windows.
	// this is required for hot restart to work.
	return srv.setupNonBlockingListener(err, l)
}

func (srv *Server) ListenAndServe() error {
	if srv.Addr == "" {
		srv.Addr = ":http"
	}
	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}
	return srv.serve()
}

func (srv *Server) SocketFd() int {
	return int(srv.listenerFile.Fd())
}

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
	if srv.Addr == "" {
		srv.Addr = ":https"
	}
	config := &tls.Config{
		Rand:       rand.Reader,
		Time:       time.Now,
		NextProtos: []string{"http/1.1"},
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}

	srv.listener = tls.NewListener(srv.listener, config)

	return srv.serve()
}

func (srv *Server) StopAccepting() {
	close(srv.stopAccepting)
}

func (srv *Server) Port() int {
	if l := srv.listener; l != nil {
		a := l.Addr()
		if _, p, e := net.SplitHostPort(a.String()); e == nil && p != "" {
			server_port, _ := strconv.Atoi(p)
			return server_port
		}
	}
	return 0
}

func (srv *Server) serve() error {
	close(srv.closableAcceptReady)

	defer func() {
		Trace("Stopped accepting, waiting for handlers")
		// wait for handlers
		srv.handlerWaitGroup.Wait()
	}()

	for {
		var c net.Conn
		var err error
		if l, ok := srv.listener.(*net.TCPListener); ok {
			l.SetDeadline(time.Now().Add(3 * time.Second))
		}
		c, err = srv.listener.Accept()
		if err != nil {
			if ope, ok := err.(*net.OpError); ok {
				if !(ope.Timeout() && ope.Temporary()) {
					Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), ope)
				}
			} else {
				Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), err)
			}
		} else {
			//Trace("Handling!")
			srv.handlerWaitGroup.Add(1)
			go srv.handler(c)
		}
		select {
		case <-srv.stopAccepting:
			return nil
		default:
		}
	}
	return nil
}

func (srv *Server) sentinel(c net.Conn, connClosed chan struct{}) {
	select {
	case <-srv.stopAccepting:
		c.SetReadDeadline(time.Now().Add(3 * time.Second))
	case <-connClosed:
	}
}

// For compatibility with net/http.Server or Google App Engine
// If you are using falcore.Server as a net/http.Handler, you should
// not call any of the Listen methods
func (srv *Server) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
	// We can't get the connection in this case.
	// Need to be really careful about how we use this property elsewhere.
	request := newRequest(req, nil, time.Now())
	res := srv.handlerExecutePipeline(request, false)

	// Copy headers
	theHeader := wr.Header()
	for key, header := range res.Header {
		theHeader[key] = header
	}

	// Write headers
	wr.WriteHeader(res.StatusCode)

	// Write Body
	request.startPipelineStage("server.ResponseWrite")
	if res.Body != nil {
		defer res.Body.Close()
		io.Copy(wr, res.Body)
	}
	request.finishPipelineStage()
	request.finishRequest()

	srv.requestFinished(request, res)
}

func (srv *Server) handler(c net.Conn) {
	var startTime time.Time
	bpe := srv.bufferPool.Take(c)
	defer srv.bufferPool.Give(bpe)
	wbpe := srv.writeBufferPool.Take(c)
	defer srv.writeBufferPool.Give(wbpe)
	closeSentinelChan := make(chan struct{})
	go srv.sentinel(c, closeSentinelChan)
	defer srv.connectionFinished(c, closeSentinelChan)
	var err error
	var req *http.Request
	// no keepalive (for now)
	reqCount := 0
	keepAlive := true
	for err == nil && keepAlive {
		if _, err := bpe.Br.Peek(1); err == nil {
			startTime = time.Now()
		}
		if req, err = http.ReadRequest(bpe.Br); err == nil {
			if req.ProtoAtLeast(1, 1) {
				if req.Header.Get("Connection") == "close" {
					keepAlive = false
				}
			} else if strings.ToLower(req.Header.Get("Connection")) != "keep-alive" {
				keepAlive = false
			}
			request := newRequest(req, c, startTime)
			reqCount++

			pssInit := new(PipelineStageStat)
			pssInit.Name = "server.Init"
			pssInit.StartTime = startTime
			pssInit.EndTime = time.Now()
			pssInit.Type = PipelineStageTypeOverhead
			request.appendPipelineStage(pssInit)

			// execute the pipeline
			var res = srv.handlerExecutePipeline(request, keepAlive)

			// shutting down?
			select {
			case <-srv.stopAccepting:
				keepAlive = false
				res.Close = true
			default:
			}

			// write response
			err = srv.handlerWriteResponse(request, res, c, wbpe.Br)
			if err != nil {
				Error("%s ERROR writing response: <%T %v>", srv.serverLogPrefix(), err, err)
			}

			if res.Close {
				keepAlive = false
			}
		} else {
			// EOF is socket closed
			if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) {
				Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err)
			}
		}
	}
	//Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr())
}

func (srv *Server) handlerExecutePipeline(request *Request, keepAlive bool) *http.Response {

	var res *http.Response
	// execute the pipeline
	if res = srv.Pipeline.execute(request); res == nil {
		res = StringResponse(request.HttpRequest, 404, nil, "Not Found")
	}

	// The res.Write omits Content-length on 0 length bodies, and by spec,
	// it SHOULD. While this is not MUST, it's kinda broken.  See sec 4.4
	// of rfc2616 and a 200 with a zero length does not satisfy any of the
	// 5 conditions if Connection: keep-alive is set :(
	// I'm forcing chunked which seems to work because I couldn't get the
	// content length to write if it was 0.
	// Specifically, the android http client waits forever if there's no
	// content-length instead of assuming zero at the end of headers. der.
	if res.Body == nil {
		if request.HttpRequest.Method != "HEAD" {
			res.ContentLength = 0
		}
		res.TransferEncoding = []string{"identity"}
		res.Body = ioutil.NopCloser(bytes.NewBuffer([]byte{}))
	} else if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) {
		// the following is copied from net/http/transfer.go
		// in the std lib, this is only applied to a request.  we need it on a response

		// Test to see if it's actually zero or just unset.
		var buf [1]byte
		n, _ := io.ReadFull(res.Body, buf[:])
		if n == 1 {
			// Oh, guess there is data in this Body Reader after all.
			// The ContentLength field just wasn't set.
			// Stich the Body back together again, re-attaching our
			// consumed byte.
			res.ContentLength = -1
			res.Body = &lengthFixReadCloser{io.MultiReader(bytes.NewBuffer(buf[:]), res.Body), res.Body}
		} else {
			res.TransferEncoding = []string{"identity"}
		}
	}
	if res.ContentLength < 0 && request.HttpRequest.Method != "HEAD" {
		res.TransferEncoding = []string{"chunked"}
	}

	// For HTTP/1.0 and Keep-Alive, sending the Connection: Keep-Alive response header is required
	// because close is default (opposite of 1.1)
	if keepAlive && !request.HttpRequest.ProtoAtLeast(1, 1) {
		res.Header.Set("Connection", "Keep-Alive")
	}

	// cleanup
	request.HttpRequest.Body.Close()
	return res
}

func (srv *Server) handlerWriteResponse(request *Request, res *http.Response, c net.Conn, bw *bufio.Writer) error {
	request.startPipelineStage("server.ResponseWrite")
	request.CurrentStage.Type = PipelineStageTypeOverhead

	var err error = nil
	var nodelay = srv.setNoDelay(c, false)
	if nodelay {
		err = res.Write(bw)
		bw.Flush()
		srv.setNoDelay(c, true)
	} else {
		err = res.Write(bw)
		bw.Flush()
	}
	if res.Body != nil {
		res.Body.Close()
	}
	request.finishPipelineStage()
	request.finishRequest()
	srv.requestFinished(request, res)
	return err
}

func (srv *Server) serverLogPrefix() string {
	return srv.logPrefix
}

func (srv *Server) requestFinished(request *Request, res *http.Response) {
	if srv.CompletionCallback != nil {
		// Don't block the connecion for this
		go srv.CompletionCallback(request, res)
	}
}

func (srv *Server) connectionFinished(c net.Conn, closeChan chan struct{}) {
	if srv.PanicHandler != nil {
		if err := recover(); err != nil {
			srv.PanicHandler(c, err)
		}
	}

	c.Close()
	close(closeChan)
	srv.handlerWaitGroup.Done()
}

type lengthFixReadCloser struct {
	io.Reader
	io.Closer
}
<commit_msg>cleanup handlerWriteResponse.  also capture errors from Flush<commit_after>package falcore

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

type Server struct {
	Addr                string
	Pipeline            *Pipeline
	CompletionCallback  RequestCompletionCallback
	listener            net.Listener
	listenerFile        *os.File
	stopAccepting       chan struct{}
	handlerWaitGroup    *sync.WaitGroup
	logPrefix           string
	AcceptReady         <-chan struct{}
	closableAcceptReady chan struct{}
	bufferPool          *BufferPool
	writeBufferPool     *WriteBufferPool
	PanicHandler        func(conn net.Conn, err interface{})
}

type RequestCompletionCallback func(req *Request, res *http.Response)

func NewServer(port int, pipeline *Pipeline) *Server {
	s := new(Server)
	s.Addr = fmt.Sprintf(":%v", port)
	s.Pipeline = pipeline
	s.stopAccepting = make(chan struct{})
	s.closableAcceptReady = make(chan struct{})
	s.AcceptReady = s.closableAcceptReady
	s.handlerWaitGroup = new(sync.WaitGroup)
	s.logPrefix = fmt.Sprintf("%d", syscall.Getpid())

	// buffer pool for reusing connection bufio.Readers
	s.bufferPool = NewBufferPool(100, 8192)
	s.writeBufferPool = NewWriteBufferPool(100, 4096)

	return s
}

func (srv *Server) FdListen(fd int) error {
	var err error
	srv.listenerFile = os.NewFile(uintptr(fd), "")
	if srv.listener, err = net.FileListener(srv.listenerFile); err != nil {
		return err
	}
	if _, ok := srv.listener.(*net.TCPListener); !ok {
		return errors.New("Broken listener isn't TCP")
	}
	return nil
}

func (srv *Server) socketListen() error {
	var la *net.TCPAddr
	var err error
	if la, err = net.ResolveTCPAddr("tcp", srv.Addr); err != nil {
		return err
	}

	var l *net.TCPListener
	if l, err = net.ListenTCP("tcp", la); err != nil {
		return err
	}
	srv.listener = l
	// setup listener to be non-blocking if we're not on windows.
	// this is required for hot restart to work.
	return srv.setupNonBlockingListener(err, l)
}

func (srv *Server) ListenAndServe() error {
	if srv.Addr == "" {
		srv.Addr = ":http"
	}
	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}
	return srv.serve()
}

func (srv *Server) SocketFd() int {
	return int(srv.listenerFile.Fd())
}

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
	if srv.Addr == "" {
		srv.Addr = ":https"
	}
	config := &tls.Config{
		Rand:       rand.Reader,
		Time:       time.Now,
		NextProtos: []string{"http/1.1"},
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}

	srv.listener = tls.NewListener(srv.listener, config)

	return srv.serve()
}

func (srv *Server) StopAccepting() {
	close(srv.stopAccepting)
}

func (srv *Server) Port() int {
	if l := srv.listener; l != nil {
		a := l.Addr()
		if _, p, e := net.SplitHostPort(a.String()); e == nil && p != "" {
			server_port, _ := strconv.Atoi(p)
			return server_port
		}
	}
	return 0
}

func (srv *Server) serve() error {
	close(srv.closableAcceptReady)

	defer func() {
		Trace("Stopped accepting, waiting for handlers")
		// wait for handlers
		srv.handlerWaitGroup.Wait()
	}()

	for {
		var c net.Conn
		var err error
		if l, ok := srv.listener.(*net.TCPListener); ok {
			l.SetDeadline(time.Now().Add(3 * time.Second))
		}
		c, err = srv.listener.Accept()
		if err != nil {
			if ope, ok := err.(*net.OpError); ok {
				if !(ope.Timeout() && ope.Temporary()) {
					Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), ope)
				}
			} else {
				Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), err)
			}
		} else {
			//Trace("Handling!")
			srv.handlerWaitGroup.Add(1)
			go srv.handler(c)
		}
		select {
		case <-srv.stopAccepting:
			return nil
		default:
		}
	}
	return nil
}

func (srv *Server) sentinel(c net.Conn, connClosed chan struct{}) {
	select {
	case <-srv.stopAccepting:
		c.SetReadDeadline(time.Now().Add(3 * time.Second))
	case <-connClosed:
	}
}

// For compatibility with net/http.Server or Google App Engine
// If you are using falcore.Server as a net/http.Handler, you should
// not call any of the Listen methods
func (srv *Server) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
	// We can't get the connection in this case.
	// Need to be really careful about how we use this property elsewhere.
	request := newRequest(req, nil, time.Now())
	res := srv.handlerExecutePipeline(request, false)

	// Copy headers
	theHeader := wr.Header()
	for key, header := range res.Header {
		theHeader[key] = header
	}

	// Write headers
	wr.WriteHeader(res.StatusCode)

	// Write Body
	request.startPipelineStage("server.ResponseWrite")
	if res.Body != nil {
		defer res.Body.Close()
		io.Copy(wr, res.Body)
	}
	request.finishPipelineStage()
	request.finishRequest()

	srv.requestFinished(request, res)
}

func (srv *Server) handler(c net.Conn) {
	var startTime time.Time
	bpe := srv.bufferPool.Take(c)
	defer srv.bufferPool.Give(bpe)
	wbpe := srv.writeBufferPool.Take(c)
	defer srv.writeBufferPool.Give(wbpe)
	closeSentinelChan := make(chan struct{})
	go srv.sentinel(c, closeSentinelChan)
	defer srv.connectionFinished(c, closeSentinelChan)
	var err error
	var req *http.Request
	// no keepalive (for now)
	reqCount := 0
	keepAlive := true
	for err == nil && keepAlive {
		if _, err := bpe.Br.Peek(1); err == nil {
			startTime = time.Now()
		}
		if req, err = http.ReadRequest(bpe.Br); err == nil {
			if req.ProtoAtLeast(1, 1) {
				if req.Header.Get("Connection") == "close" {
					keepAlive = false
				}
			} else if strings.ToLower(req.Header.Get("Connection")) != "keep-alive" {
				keepAlive = false
			}
			request := newRequest(req, c, startTime)
			reqCount++

			pssInit := new(PipelineStageStat)
			pssInit.Name = "server.Init"
			pssInit.StartTime = startTime
			pssInit.EndTime = time.Now()
			pssInit.Type = PipelineStageTypeOverhead
			request.appendPipelineStage(pssInit)

			// execute the pipeline
			var res = srv.handlerExecutePipeline(request, keepAlive)

			// shutting down?
			select {
			case <-srv.stopAccepting:
				keepAlive = false
				res.Close = true
			default:
			}

			// write response
			err = srv.handlerWriteResponse(request, res, c, wbpe.Br)
			if err != nil {
				Error("%s ERROR writing response: <%T %v>", srv.serverLogPrefix(), err, err)
			}

			if res.Close {
				keepAlive = false
			}
		} else {
			// EOF is socket closed
			if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) {
				Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err)
			}
		}
	}
	//Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr())
}

func (srv *Server) handlerExecutePipeline(request *Request, keepAlive bool) *http.Response {

	var res *http.Response
	// execute the pipeline
	if res = srv.Pipeline.execute(request); res == nil {
		res = StringResponse(request.HttpRequest, 404, nil, "Not Found")
	}

	// The res.Write omits Content-length on 0 length bodies, and by spec,
	// it SHOULD. While this is not MUST, it's kinda broken.  See sec 4.4
	// of rfc2616 and a 200 with a zero length does not satisfy any of the
	// 5 conditions if Connection: keep-alive is set :(
	// I'm forcing chunked which seems to work because I couldn't get the
	// content length to write if it was 0.
	// Specifically, the android http client waits forever if there's no
	// content-length instead of assuming zero at the end of headers. der.
	if res.Body == nil {
		if request.HttpRequest.Method != "HEAD" {
			res.ContentLength = 0
		}
		res.TransferEncoding = []string{"identity"}
		res.Body = ioutil.NopCloser(bytes.NewBuffer([]byte{}))
	} else if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) {
		// the following is copied from net/http/transfer.go
		// in the std lib, this is only applied to a request.  we need it on a response

		// Test to see if it's actually zero or just unset.
		var buf [1]byte
		n, _ := io.ReadFull(res.Body, buf[:])
		if n == 1 {
			// Oh, guess there is data in this Body Reader after all.
			// The ContentLength field just wasn't set.
			// Stich the Body back together again, re-attaching our
			// consumed byte.
			res.ContentLength = -1
			res.Body = &lengthFixReadCloser{io.MultiReader(bytes.NewBuffer(buf[:]), res.Body), res.Body}
		} else {
			res.TransferEncoding = []string{"identity"}
		}
	}
	if res.ContentLength < 0 && request.HttpRequest.Method != "HEAD" {
		res.TransferEncoding = []string{"chunked"}
	}

	// For HTTP/1.0 and Keep-Alive, sending the Connection: Keep-Alive response header is required
	// because close is default (opposite of 1.1)
	if keepAlive && !request.HttpRequest.ProtoAtLeast(1, 1) {
		res.Header.Set("Connection", "Keep-Alive")
	}

	// cleanup
	request.HttpRequest.Body.Close()
	return res
}

func (srv *Server) handlerWriteResponse(request *Request, res *http.Response, c net.Conn, bw *bufio.Writer) error {
	// Setup write stage
	request.startPipelineStage("server.ResponseWrite")
	request.CurrentStage.Type = PipelineStageTypeOverhead

	// cleanup
	defer func() {
		request.finishPipelineStage()
		request.finishRequest()
		srv.requestFinished(request, res)
		if res.Body != nil {
			res.Body.Close()
		}
	}()

	// Cycle nodelay flag on socket
	// Note: defers for FILO so this will happen before the write
	// 		 phase is complete, which is what we want.
	if nodelay := srv.setNoDelay(c, false); nodelay {
		defer srv.setNoDelay(c, true)
	}

	var err error
	// Write response
	if err = res.Write(bw); err != nil {
		return err
	}

	// Flush any remaining buffer
	err = bw.Flush()

	return err
}

func (srv *Server) serverLogPrefix() string {
	return srv.logPrefix
}

func (srv *Server) requestFinished(request *Request, res *http.Response) {
	if srv.CompletionCallback != nil {
		// Don't block the connecion for this
		go srv.CompletionCallback(request, res)
	}
}

func (srv *Server) connectionFinished(c net.Conn, closeChan chan struct{}) {
	if srv.PanicHandler != nil {
		if err := recover(); err != nil {
			srv.PanicHandler(c, err)
		}
	}

	c.Close()
	close(closeChan)
	srv.handlerWaitGroup.Done()
}

type lengthFixReadCloser struct {
	io.Reader
	io.Closer
}
<|endoftext|>


<commit_before><commit_msg>cmd/geth: bumped version to 0.9.24<commit_after><|endoftext|>


<commit_before>package eventmaster

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

	assetfs "github.com/elazarl/go-bindata-assetfs"
	"github.com/julienschmidt/httprouter"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	log "github.com/sirupsen/logrus"

	"github.com/wish/eventmaster/jh"
	"github.com/wish/eventmaster/metrics"
	tmpl "github.com/wish/eventmaster/templates"
	"github.com/wish/eventmaster/ui"
)

// Server implements http.Handler for the eventmaster http server.
type Server struct {
	store *EventStore

	handler http.Handler

	ui        http.FileSystem
	templates TemplateGetter
}

// ServeHTTP dispatches to the underlying router.
func (srv *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	srv.handler.ServeHTTP(w, req)
}

// NewServer returns a ready-to-use Server that uses store, and the appropriate
// static and templates facilities.
//
// If static or templates are non-empty then files are served from those
// locations (useful for development). Otherwise the server uses embedded
// static assets.
func NewServer(store *EventStore, static, templates string) *Server {
	// Handle static files either embedded (empty static) or off the filesystem (during dev work)
	var fs http.FileSystem
	switch static {
	case "":
		fs = &assetfs.AssetFS{
			Asset:     ui.Asset,
			AssetDir:  ui.AssetDir,
			AssetInfo: ui.AssetInfo,
		}
	default:
		if p, d := filepath.Split(static); d == "ui" {
			static = p
		}
		fs = http.Dir(static)
	}

	var t TemplateGetter
	switch templates {
	case "":
		t = NewAssetTemplate(tmpl.Asset)
	default:
		t = Disk{Root: templates}
	}

	srv := &Server{
		store:     store,
		ui:        fs,
		templates: t,
	}

	srv.handler = registerRoutes(srv)

	return srv
}

func registerRoutes(srv *Server) http.Handler {
	r := httprouter.New()

	// API endpoints
	r.POST("/v1/event", latency("/v1/event", jh.Adapter(srv.addEvent)))
	r.GET("/v1/event", latency("/v1/event", jh.Adapter(srv.getEvent)))
	r.GET("/v1/event/:id", latency("/v1/event", jh.Adapter(srv.getEventByID)))
	r.POST("/v1/topic", latency("/v1/topic", jh.Adapter(srv.addTopic)))
	r.PUT("/v1/topic/:name", latency("/v1/topic", jh.Adapter(srv.updateTopic)))
	r.GET("/v1/topic", latency("/v1/topic", jh.Adapter(srv.getTopic)))
	r.DELETE("/v1/topic/:name", latency("/v1/topic", jh.Adapter(srv.deleteTopic)))
	r.POST("/v1/dc", latency("/v1/dc", jh.Adapter(srv.addDC)))
	r.PUT("/v1/dc/:name", latency("/v1/dc", jh.Adapter(srv.updateDC)))
	r.GET("/v1/dc", latency("/v1/dc", jh.Adapter(srv.getDC)))

	r.GET("/v1/health", latency("/v1/health", jh.Adapter(srv.healthCheck)))

	// GitHub webhook endpoint
	r.POST("/v1/github_event", latency("/v1/github_event", jh.Adapter(srv.gitHubEvent)))

	// UI endpoints
	r.GET("/", latency("/", srv.HandleMainPage))
	r.GET("/add_event", latency("/add_event", srv.HandleCreatePage))
	r.GET("/topic", latency("/topic", srv.HandleTopicPage))
	r.GET("/dc", latency("/dc", srv.HandleDCPage))
	r.GET("/event", latency("/event", srv.HandleGetEventPage))

	// grafana datasource endpoints
	r.GET("/grafana", latency("/grafana", cors(srv.grafanaOK)))
	r.GET("/grafana/", latency("/grafana/", cors(srv.grafanaOK)))
	r.OPTIONS("/grafana/:route", latency("/grafana", cors(srv.grafanaOK)))
	r.POST("/grafana/annotations", latency("/grafana/annotations", cors(srv.grafanaAnnotations)))
	r.POST("/grafana/search", latency("/grafana/search", cors(srv.grafanaSearch)))

	r.Handler("GET", "/metrics", promhttp.Handler())

	r.Handler("GET", "/ui/*filepath", http.FileServer(srv.ui))

	r.GET("/version/", latency("/version/", srv.version))

	r.PanicHandler = func(w http.ResponseWriter, req *http.Request, i interface{}) {
		metrics.HTTPStatus("panic", http.StatusInternalServerError)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusInternalServerError)
		e := struct {
			E string `json:"error"`
		}{"server panicked"}
		if err := json.NewEncoder(w).Encode(&e); err != nil {
			log.Printf("json encode: %v", err)
		}
	}

	r.NotFound = func(w http.ResponseWriter, req *http.Request) {
		log.Printf("not found: %+v", req.URL.Path)
		metrics.HTTPStatus(http.StatusText(http.StatusNotFound), http.StatusNotFound)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusNotFound)
		e := struct {
			E string `json:"error"`
		}{"not found"}
		if err := json.NewEncoder(w).Encode(&e); err != nil {
			log.Printf("json encode: %v", err)
		}
	}

	r.MethodNotAllowed = func(w http.ResponseWriter, req *http.Request) {
		metrics.HTTPStatus(http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusMethodNotAllowed)
		e := struct {
			E string `json:"error"`
		}{"method not allowed"}
		if err := json.NewEncoder(w).Encode(&e); err != nil {
			log.Printf("json encode: %v", err)
		}
	}

	return r
}

func latency(prefix string, h httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
		start := time.Now()
		defer func() {
			metrics.HTTPLatency(prefix, start)
		}()

		lw := NewStatusRecorder(w)
		h(lw, req, ps)

		metrics.HTTPStatus(prefix, lw.Status())
	}
}

func (srv *Server) healthCheck(w http.ResponseWriter, r *http.Request, _ httprouter.Params) (interface{}, error) {
	return nil, nil
}
<commit_msg>Change URL route due to an undocumented Grafana API change (#72)<commit_after>package eventmaster

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

	assetfs "github.com/elazarl/go-bindata-assetfs"
	"github.com/julienschmidt/httprouter"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	log "github.com/sirupsen/logrus"

	"github.com/wish/eventmaster/jh"
	"github.com/wish/eventmaster/metrics"
	tmpl "github.com/wish/eventmaster/templates"
	"github.com/wish/eventmaster/ui"
)

// Server implements http.Handler for the eventmaster http server.
type Server struct {
	store *EventStore

	handler http.Handler

	ui        http.FileSystem
	templates TemplateGetter
}

// ServeHTTP dispatches to the underlying router.
func (srv *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	srv.handler.ServeHTTP(w, req)
}

// NewServer returns a ready-to-use Server that uses store, and the appropriate
// static and templates facilities.
//
// If static or templates are non-empty then files are served from those
// locations (useful for development). Otherwise the server uses embedded
// static assets.
func NewServer(store *EventStore, static, templates string) *Server {
	// Handle static files either embedded (empty static) or off the filesystem (during dev work)
	var fs http.FileSystem
	switch static {
	case "":
		fs = &assetfs.AssetFS{
			Asset:     ui.Asset,
			AssetDir:  ui.AssetDir,
			AssetInfo: ui.AssetInfo,
		}
	default:
		if p, d := filepath.Split(static); d == "ui" {
			static = p
		}
		fs = http.Dir(static)
	}

	var t TemplateGetter
	switch templates {
	case "":
		t = NewAssetTemplate(tmpl.Asset)
	default:
		t = Disk{Root: templates}
	}

	srv := &Server{
		store:     store,
		ui:        fs,
		templates: t,
	}

	srv.handler = registerRoutes(srv)

	return srv
}

func registerRoutes(srv *Server) http.Handler {
	r := httprouter.New()

	// API endpoints
	r.POST("/v1/event", latency("/v1/event", jh.Adapter(srv.addEvent)))
	r.GET("/v1/event", latency("/v1/event", jh.Adapter(srv.getEvent)))
	r.GET("/v1/event/:id", latency("/v1/event", jh.Adapter(srv.getEventByID)))
	r.POST("/v1/topic", latency("/v1/topic", jh.Adapter(srv.addTopic)))
	r.PUT("/v1/topic/:name", latency("/v1/topic", jh.Adapter(srv.updateTopic)))
	r.GET("/v1/topic", latency("/v1/topic", jh.Adapter(srv.getTopic)))
	r.DELETE("/v1/topic/:name", latency("/v1/topic", jh.Adapter(srv.deleteTopic)))
	r.POST("/v1/dc", latency("/v1/dc", jh.Adapter(srv.addDC)))
	r.PUT("/v1/dc/:name", latency("/v1/dc", jh.Adapter(srv.updateDC)))
	r.GET("/v1/dc", latency("/v1/dc", jh.Adapter(srv.getDC)))

	r.GET("/v1/health", latency("/v1/health", jh.Adapter(srv.healthCheck)))

	// GitHub webhook endpoint
	r.POST("/v1/github_event", latency("/v1/github_event", jh.Adapter(srv.gitHubEvent)))

	// UI endpoints
	r.GET("/", latency("/", srv.HandleMainPage))
	r.GET("/add_event", latency("/add_event", srv.HandleCreatePage))
	r.GET("/topic", latency("/topic", srv.HandleTopicPage))
	r.GET("/dc", latency("/dc", srv.HandleDCPage))
	r.GET("/event", latency("/event", srv.HandleGetEventPage))

	// grafana datasource endpoints
	r.GET("/grafana", latency("/grafana", cors(srv.grafanaOK)))
	r.GET("/grafana/", latency("/grafana/", cors(srv.grafanaOK)))
	r.OPTIONS("/grafana/*route", latency("/grafana", cors(srv.grafanaOK)))
	r.POST("/grafana/annotations", latency("/grafana/annotations", cors(srv.grafanaAnnotations)))
	r.POST("/grafana/search", latency("/grafana/search", cors(srv.grafanaSearch)))

	r.Handler("GET", "/metrics", promhttp.Handler())

	r.Handler("GET", "/ui/*filepath", http.FileServer(srv.ui))

	r.GET("/version/", latency("/version/", srv.version))

	r.PanicHandler = func(w http.ResponseWriter, req *http.Request, i interface{}) {
		metrics.HTTPStatus("panic", http.StatusInternalServerError)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusInternalServerError)
		e := struct {
			E string `json:"error"`
		}{"server panicked"}
		if err := json.NewEncoder(w).Encode(&e); err != nil {
			log.Printf("json encode: %v", err)
		}
	}

	r.NotFound = func(w http.ResponseWriter, req *http.Request) {
		log.Printf("not found: %+v", req.URL.Path)
		metrics.HTTPStatus(http.StatusText(http.StatusNotFound), http.StatusNotFound)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusNotFound)
		e := struct {
			E string `json:"error"`
		}{"not found"}
		if err := json.NewEncoder(w).Encode(&e); err != nil {
			log.Printf("json encode: %v", err)
		}
	}

	r.MethodNotAllowed = func(w http.ResponseWriter, req *http.Request) {
		metrics.HTTPStatus(http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusMethodNotAllowed)
		e := struct {
			E string `json:"error"`
		}{"method not allowed"}
		if err := json.NewEncoder(w).Encode(&e); err != nil {
			log.Printf("json encode: %v", err)
		}
	}

	return r
}

func latency(prefix string, h httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
		start := time.Now()
		defer func() {
			metrics.HTTPLatency(prefix, start)
		}()

		lw := NewStatusRecorder(w)
		h(lw, req, ps)

		metrics.HTTPStatus(prefix, lw.Status())
	}
}

func (srv *Server) healthCheck(w http.ResponseWriter, r *http.Request, _ httprouter.Params) (interface{}, error) {
	return nil, nil
}
<|endoftext|>


<commit_before><commit_msg>rkvd/main.go: Increase hashicorp leader lease when no check quorum<commit_after><|endoftext|>


<commit_before>// Copyright 2021 Google Inc. 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.

// Provides integration tests for file operations with implicit_dir flag set.
package implicitdir_test

import (
	"os"
	"testing"
)

func TestRenameFile(t *testing.T) {
	fileName := createTempFile()
	err := clearKernelCache()
	if err != nil {
		t.Errorf("Clear Kernel Cache: %v", err)
	}
	content, err := os.ReadFile(fileName)
	if err != nil {
		t.Errorf("Read: %v", err)
	}
	newFileName := fileName + "Rename"
	if _, err := os.Stat(newFileName); err == nil {
		t.Errorf("Renamed file %s already present", newFileName)
	}

	if err := os.Rename(fileName, newFileName); err != nil {
		t.Errorf("Rename unsuccessful: %v", err)
	}

	if _, err := os.Stat(fileName); err == nil {
		t.Errorf("File %s still exists", fileName)
	}
	if _, err := os.Stat(newFileName); err != nil {
		t.Errorf("Renamed file %s not found", newFileName)
	}
	// Check if the data in the file is the same after renaming.
	compareFileContents(t, newFileName, string(content))
}
<commit_msg>Made error msg in original file removal more clear<commit_after>// Copyright 2021 Google Inc. 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.

// Provides integration tests for file operations with implicit_dir flag set.
package implicitdir_test

import (
	"os"
	"testing"
)

func TestRenameFile(t *testing.T) {
	fileName := createTempFile()
	err := clearKernelCache()
	if err != nil {
		t.Errorf("Clear Kernel Cache: %v", err)
	}
	content, err := os.ReadFile(fileName)
	if err != nil {
		t.Errorf("Read: %v", err)
	}
	newFileName := fileName + "Rename"
	if _, err := os.Stat(newFileName); err == nil {
		t.Errorf("Renamed file %s already present", newFileName)
	}

	if err := os.Rename(fileName, newFileName); err != nil {
		t.Errorf("Rename unsuccessful: %v", err)
	}

	if _, err := os.Stat(fileName); err == nil {
		t.Errorf("Original file %s still exists", fileName)
	}
	if _, err := os.Stat(newFileName); err != nil {
		t.Errorf("Renamed file %s not found", newFileName)
	}
	// Check if the data in the file is the same after renaming.
	compareFileContents(t, newFileName, string(content))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"fmt"
	"net"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"
)

type Server struct {
	unixpath string
	paths    Shortcuts
	file     *os.File
}

func NewServer(unixpath string, savefile string) (*Server, error) {
	// Open gob file to load paths
	file, err := os.OpenFile(savefile, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	s := &Server{unixpath, NewShortcuts(), file}

	stat, err := file.Stat()
	if err != nil {
		return nil, err
	}

	if stat.Size() > 0 {
		if err = s.Load(); err != nil {
			return nil, err
		}
	}

	return s, nil
}

func (s Server) Load() error {
	return gob.NewDecoder(s.file).Decode(&s.paths)
}

func (s Server) Save() error {
	s.file.Seek(0, 0)
	s.file.Truncate(0)

	return gob.NewEncoder(s.file).Encode(s.paths)
}

func (s *Server) Close() {
	if err := s.Save(); err != nil {
		fmt.Println(err)
	}
	s.file.Close()
}

func (s *Server) complete(req string) (string, error) {
	matched := []string{}

	for key, _ := range s.paths {
		ok, err := regexp.MatchString(req, key)
		if err != nil {
			return "", err
		}

		if ok {
			matched = append(matched, key)
		}
	}

	return strings.Join(matched, ","), nil
}

func (s *Server) request(req string) (string, error) {
	// First, return shortcut if exists
	shortcut, err := s.paths.Get(req)
	if err != nil {
		return "", err
	} else if shortcut != "" {
		return shortcut, nil
	}

	// Here, shortcut not exists. Add it to shortcuts.
	// Add func returns absolute req path
	return s.paths.Add(req)
}

func (s *Server) handleConn(c *net.UnixConn) error {
	defer c.Close()

	// Get request
	var req Request
	err := gob.NewDecoder(c).Decode(&req)
	if err != nil {
		return err
	}
	if err = c.CloseRead(); err != nil {
		return err
	}

	// Treat
	errPath := ""
	var resp string

	fmt.Println("Request:", req)

	if req.Type == CompletionRequest {
		resp, err = s.complete(string(req.Req))
		if err != nil {
			errPath = err.Error()
		}
	} else {
		resp, err = s.request(string(req.Req))
		if err != nil {
			errPath = err.Error()
		}
	}

	// Send response
	err = gob.NewEncoder(c).Encode(Response{resp, errPath})
	if err != nil {
		return err
	}
	if err = c.CloseWrite(); err != nil {
		return err
	}

	return nil
}

func (s *Server) listen() error {
	run := true

	// Signals
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt)
	signal.Notify(signals, os.Kill)
	signal.Notify(signals, syscall.SIGTERM)

	// Conns
	conns := make(chan *net.UnixConn, 100)

	// Listen
	l, err := net.ListenUnix("unix", &net.UnixAddr{s.unixpath, "unix"})
	if err != nil {
		return err
	}

	defer l.Close()
	defer os.Remove(s.unixpath)

	// Listen connections and send them to conns chan
	go func() {
		for run {
			c, err := l.AcceptUnix()
			if err != nil {
				fmt.Println(err)
				continue
			}

			conns <- c
		}
	}()

	fmt.Println("Starting server")

	ticker := time.NewTicker(time.Hour)

	// Wait conn or signal
	for run {
		select {
		case <-ticker.C:
			fmt.Println("Save data")
			if err := s.Save(); err != nil {
				fmt.Println(err)
			}
		case c := <-conns:
			fmt.Println("Got new conn")
			err := s.handleConn(c)
			if err != nil {
				fmt.Println(err)
			}
		case s := <-signals:
			fmt.Println("Got signal:", s)
			run = false
		}
	}

	fmt.Println("Ending server")

	return nil
}
<commit_msg>Fix autocompletion using keys of paths<commit_after>package main

import (
	"encoding/gob"
	"fmt"
	"net"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"
)

type Server struct {
	unixpath string
	paths    Shortcuts
	file     *os.File
}

func NewServer(unixpath string, savefile string) (*Server, error) {
	// Open gob file to load paths
	file, err := os.OpenFile(savefile, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	s := &Server{unixpath, NewShortcuts(), file}

	stat, err := file.Stat()
	if err != nil {
		return nil, err
	}

	if stat.Size() > 0 {
		if err = s.Load(); err != nil {
			return nil, err
		}
	}

	return s, nil
}

func (s Server) Load() error {
	return gob.NewDecoder(s.file).Decode(&s.paths)
}

func (s Server) Save() error {
	s.file.Seek(0, 0)
	s.file.Truncate(0)

	return gob.NewEncoder(s.file).Encode(s.paths)
}

func (s *Server) Close() {
	if err := s.Save(); err != nil {
		fmt.Println(err)
	}
	s.file.Close()
}

func (s *Server) complete(req string) (string, error) {
	matched := []string{}

	for key, _ := range s.paths {
		ok, err := regexp.MatchString(req, key)
		if err != nil {
			return "", err
		}

		if ok {
			matched = append(matched, key)
		}
	}

	return strings.Join(matched, "\n"), nil
}

func (s *Server) request(req string) (string, error) {
	// First, return shortcut if exists
	shortcut, err := s.paths.Get(req)
	if err != nil {
		return "", err
	} else if shortcut != "" {
		return shortcut, nil
	}

	// Here, shortcut not exists. Add it to shortcuts.
	// Add func returns absolute req path
	return s.paths.Add(req)
}

func (s *Server) handleConn(c *net.UnixConn) error {
	defer c.Close()

	// Get request
	var req Request
	err := gob.NewDecoder(c).Decode(&req)
	if err != nil {
		return err
	}
	if err = c.CloseRead(); err != nil {
		return err
	}

	// Treat
	errPath := ""
	var resp string

	fmt.Println("Request:", req)

	if req.Type == CompletionRequest {
		resp, err = s.complete(string(req.Req))
		if err != nil {
			errPath = err.Error()
		}
	} else {
		resp, err = s.request(string(req.Req))
		if err != nil {
			errPath = err.Error()
		}
	}

	// Send response
	err = gob.NewEncoder(c).Encode(Response{resp, errPath})
	if err != nil {
		return err
	}
	if err = c.CloseWrite(); err != nil {
		return err
	}

	return nil
}

func (s *Server) listen() error {
	run := true

	// Signals
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt)
	signal.Notify(signals, os.Kill)
	signal.Notify(signals, syscall.SIGTERM)

	// Conns
	conns := make(chan *net.UnixConn, 100)

	// Listen
	l, err := net.ListenUnix("unix", &net.UnixAddr{s.unixpath, "unix"})
	if err != nil {
		return err
	}

	defer l.Close()
	defer os.Remove(s.unixpath)

	// Listen connections and send them to conns chan
	go func() {
		for run {
			c, err := l.AcceptUnix()
			if err != nil {
				fmt.Println(err)
				continue
			}

			conns <- c
		}
	}()

	fmt.Println("Starting server")

	ticker := time.NewTicker(time.Hour)

	// Wait conn or signal
	for run {
		select {
		case <-ticker.C:
			fmt.Println("Save data")
			if err := s.Save(); err != nil {
				fmt.Println(err)
			}
		case c := <-conns:
			fmt.Println("Got new conn")
			err := s.handleConn(c)
			if err != nil {
				fmt.Println(err)
			}
		case s := <-signals:
			fmt.Println("Got signal:", s)
			run = false
		}
	}

	fmt.Println("Ending server")

	return nil
}
<|endoftext|>


<commit_before>package runtimes

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/leancloud/lean-cli/lean/utils"
)

type filesPattern struct {
	Includes []string
	Excludes []string
}

// Runtime stands for a language runtime
type Runtime struct {
	command    *exec.Cmd
	Name       string
	Exec       string
	Args       []string
	WatchFiles []string
	Envs       []string
	Port       string
	// DeployFiles is the patterns for source code to deploy to the remote server
	DeployFiles filesPattern
	// Errors is the channel that receives the command's error result
	Errors chan error
}

// Run the project, and watch file changes
func (runtime *Runtime) Run() {
	go func() {
		for {
			runtime.command = exec.Command(runtime.Exec, runtime.Args...)
			runtime.command.Env = os.Environ()
			runtime.command.Stdout = os.Stdout
			runtime.command.Stderr = os.Stderr
			runtime.command.Env = os.Environ()

			for _, env := range runtime.Envs {
				runtime.command.Env = append(runtime.command.Env, env)
			}

			fmt.Printf("> 项目已启动，请使用浏览器访问：http://localhost:%s\r\n", runtime.Port)
			err := runtime.command.Run()
			// TODO: this maybe not portable
			if err.Error() == "signal: killed" {
				continue
			} else {
				runtime.Errors <- err
				break
			}
		}
	}()
}

// Watch file changes
func (runtime *Runtime) Watch(interval time.Duration) error {

	// watch file changes
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	lastFiredTime := time.Now()

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				fmt.Println("event:", event)
				now := time.Now()
				if now.Sub(lastFiredTime) > interval {
					err := runtime.command.Process.Kill()
					if err != nil {
						runtime.Errors <- err
					}
					lastFiredTime = now
				}
			case err := <-watcher.Errors:
				runtime.Errors <- err
			}
		}
	}()
	for _, file := range runtime.WatchFiles {
		err = watcher.Add(file)
		if err != nil {
			return err
		}
	}

	return nil
}

// DetectRuntime returns the project's runtime
func DetectRuntime(projectPath string) (*Runtime, error) {
	// order is importand
	if utils.IsFileExists(filepath.Join(projectPath, "cloud", "main.js")) {
		fmt.Println("> 检测到 cloudcode 运行时")
		return nil, nil
	}
	if utils.IsFileExists(filepath.Join(projectPath, "server.js")) && utils.IsFileExists(filepath.Join(projectPath, "package.json")) {
		fmt.Println("> 检测到 node.js 运行时")
		return newNodeRuntime(projectPath)
	}
	if utils.IsFileExists(filepath.Join(projectPath, "requirements.txt")) && utils.IsFileExists(filepath.Join(projectPath, "wsgi.py")) {
		fmt.Println("> 检测到 Python 运行时")
		return newPythonRuntime(projectPath)
	}
	if utils.IsFileExists(filepath.Join(projectPath, "composer.json")) && utils.IsFileExists(filepath.Join("public", "index.php")) {
		fmt.Println("> 检测到 PHP 运行时")
		return newPhpRuntime(projectPath)
	}
	if utils.IsFileExists(filepath.Join(projectPath, "pom.xml")) {
		fmt.Println("> 检测到 Java 运行时")
		return newJavaRuntime(projectPath)
	}
	return nil, errors.New("invalid runtime")
}

func newPythonRuntime(projectPath string) (*Runtime, error) {
	execName := "python2.7"

	if content, err := ioutil.ReadFile(filepath.Join(projectPath, "runtime.txt")); err == nil {
		if strings.HasPrefix(string(content), "python-2.7") {
			execName = "python2.7"
		} else if strings.HasPrefix(string(content), "python-3.5") {
			execName = "python3.5"
		} else {
			return nil, errors.New("invalid python runtime.txt format, only `python-2.7` and `python-3.5` were allowed")
		}
	}

	// for windows don't have a pythonx.x symbol link
	if _, err := exec.LookPath(execName); err != nil {
		fmt.Printf("`%s` command not found, fallback to `python`", execName)
	}

	return &Runtime{
		Name:       "python",
		Exec:       execName,
		Args:       []string{"wsgi.py"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"*.pyc",
			},
		},
		Errors: make(chan error),
	}, nil
}

func newNodeRuntime(projectPath string) (*Runtime, error) {
	execName := "node"
	script := "server.js"
	pkgFile := filepath.Join(projectPath, "package.json")
	if content, err := ioutil.ReadFile(pkgFile); err == nil {
		pkg := new(struct {
			Scripts struct {
				Start string `json:"start"`
			} `json:"scripts"`
		})
		err = json.Unmarshal(content, pkg)
		if err != nil {
			return nil, err
		}
		if pkg.Scripts.Start != "" {
			execName = "npm"
			script = "start"
		}
	}

	return &Runtime{
		Name:       "node.js",
		Exec:       execName,
		Args:       []string{script},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"node_modules/**",
			},
		},
		Errors: make(chan error),
	}, nil
}

func newJavaRuntime(projectPath string) (*Runtime, error) {
	return &Runtime{
		Name:       "java",
		Exec:       "mvn",
		Args:       []string{"jetty:run"},
		WatchFiles: []string{"."},
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"target/**",
			},
		},
	}, nil
}

func newPhpRuntime(projectPath string) (*Runtime, error) {
	return &Runtime{
		Name:       "php",
		Exec:       "php",
		Args:       []string{"-S", "127.0.0.1:3000", "-t", "public"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"vendor/**",
			},
		},
		Errors: make(chan error),
	}, nil
}
<commit_msg>fix: python runtime fallback not work on windows<commit_after>package runtimes

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/leancloud/lean-cli/lean/utils"
)

type filesPattern struct {
	Includes []string
	Excludes []string
}

// Runtime stands for a language runtime
type Runtime struct {
	command    *exec.Cmd
	Name       string
	Exec       string
	Args       []string
	WatchFiles []string
	Envs       []string
	Port       string
	// DeployFiles is the patterns for source code to deploy to the remote server
	DeployFiles filesPattern
	// Errors is the channel that receives the command's error result
	Errors chan error
}

// Run the project, and watch file changes
func (runtime *Runtime) Run() {
	go func() {
		for {
			runtime.command = exec.Command(runtime.Exec, runtime.Args...)
			runtime.command.Env = os.Environ()
			runtime.command.Stdout = os.Stdout
			runtime.command.Stderr = os.Stderr
			runtime.command.Env = os.Environ()

			for _, env := range runtime.Envs {
				runtime.command.Env = append(runtime.command.Env, env)
			}

			fmt.Printf("> 项目已启动，请使用浏览器访问：http://localhost:%s\r\n", runtime.Port)
			err := runtime.command.Run()
			// TODO: this maybe not portable
			if err.Error() == "signal: killed" {
				continue
			} else {
				runtime.Errors <- err
				break
			}
		}
	}()
}

// Watch file changes
func (runtime *Runtime) Watch(interval time.Duration) error {

	// watch file changes
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	lastFiredTime := time.Now()

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				fmt.Println("event:", event)
				now := time.Now()
				if now.Sub(lastFiredTime) > interval {
					err := runtime.command.Process.Kill()
					if err != nil {
						runtime.Errors <- err
					}
					lastFiredTime = now
				}
			case err := <-watcher.Errors:
				runtime.Errors <- err
			}
		}
	}()
	for _, file := range runtime.WatchFiles {
		err = watcher.Add(file)
		if err != nil {
			return err
		}
	}

	return nil
}

// DetectRuntime returns the project's runtime
func DetectRuntime(projectPath string) (*Runtime, error) {
	// order is importand
	if utils.IsFileExists(filepath.Join(projectPath, "cloud", "main.js")) {
		fmt.Println("> 检测到 cloudcode 运行时")
		return nil, nil
	}
	if utils.IsFileExists(filepath.Join(projectPath, "server.js")) && utils.IsFileExists(filepath.Join(projectPath, "package.json")) {
		fmt.Println("> 检测到 node.js 运行时")
		return newNodeRuntime(projectPath)
	}
	if utils.IsFileExists(filepath.Join(projectPath, "requirements.txt")) && utils.IsFileExists(filepath.Join(projectPath, "wsgi.py")) {
		fmt.Println("> 检测到 Python 运行时")
		return newPythonRuntime(projectPath)
	}
	if utils.IsFileExists(filepath.Join(projectPath, "composer.json")) && utils.IsFileExists(filepath.Join("public", "index.php")) {
		fmt.Println("> 检测到 PHP 运行时")
		return newPhpRuntime(projectPath)
	}
	if utils.IsFileExists(filepath.Join(projectPath, "pom.xml")) {
		fmt.Println("> 检测到 Java 运行时")
		return newJavaRuntime(projectPath)
	}
	return nil, errors.New("invalid runtime")
}

func newPythonRuntime(projectPath string) (*Runtime, error) {
	execName := "python2.7"

	if content, err := ioutil.ReadFile(filepath.Join(projectPath, "runtime.txt")); err == nil {
		if strings.HasPrefix(string(content), "python-2.7") {
			execName = "python2.7"
		} else if strings.HasPrefix(string(content), "python-3.5") {
			execName = "python3.5"
		} else {
			return nil, errors.New("invalid python runtime.txt format, only `python-2.7` and `python-3.5` were allowed")
		}
	}

	// for windows don't have a pythonx.x symbol link
	if _, err := exec.LookPath(execName); err != nil {
		fmt.Printf("> `%s` command not found, fallback to `python`\r\n", execName)
		execName = "python"
	}

	return &Runtime{
		Name:       "python",
		Exec:       execName,
		Args:       []string{"wsgi.py"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"*.pyc",
			},
		},
		Errors: make(chan error),
	}, nil
}

func newNodeRuntime(projectPath string) (*Runtime, error) {
	execName := "node"
	script := "server.js"
	pkgFile := filepath.Join(projectPath, "package.json")
	if content, err := ioutil.ReadFile(pkgFile); err == nil {
		pkg := new(struct {
			Scripts struct {
				Start string `json:"start"`
			} `json:"scripts"`
		})
		err = json.Unmarshal(content, pkg)
		if err != nil {
			return nil, err
		}
		if pkg.Scripts.Start != "" {
			execName = "npm"
			script = "start"
		}
	}

	return &Runtime{
		Name:       "node.js",
		Exec:       execName,
		Args:       []string{script},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"node_modules/**",
			},
		},
		Errors: make(chan error),
	}, nil
}

func newJavaRuntime(projectPath string) (*Runtime, error) {
	return &Runtime{
		Name:       "java",
		Exec:       "mvn",
		Args:       []string{"jetty:run"},
		WatchFiles: []string{"."},
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"target/**",
			},
		},
	}, nil
}

func newPhpRuntime(projectPath string) (*Runtime, error) {
	return &Runtime{
		Name:       "php",
		Exec:       "php",
		Args:       []string{"-S", "127.0.0.1:3000", "-t", "public"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"vendor/**",
			},
		},
		Errors: make(chan error),
	}, nil
}
<|endoftext|>


<commit_before><commit_msg>Tweak `hub help hub-help` formatting<commit_after><|endoftext|>


<commit_before>// Copyright 2016~2017 ecofast(无尽愿). All rights reserved.
// Use of this source code is governed by a BSD-style license.

// Package sysutils implements some useful system utility functions
// in the way of which Delphi(2007) RTL has done.
package sysutils

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

func CheckError(e error) {
	if e != nil {
		panic(e)
	}
}

func BoolToStr(b bool) string {
	if b {
		return "1"
	}
	return "0"
}

func IntToStr(i int) string {
	return strconv.FormatInt(int64(i), 10)
}

func StrToInt(s string) int {
	if ret, err := strconv.Atoi(s); err == nil {
		return ret
	}
	panic(fmt.Sprintf("Cannot convert %s to int!", s))
}

func StrToIntDef(s string, defaultvalue int) int {
	if ret, err := strconv.Atoi(s); err == nil {
		return ret
	}
	return defaultvalue
}

func StrToBool(s string) bool {
	if ret, err := strconv.ParseBool(s); err == nil {
		return ret
	}
	return false
}

func FloatToStr(f float64) string {
	return fmt.Sprintf("%g", f)
}

func BytesToStr(bs []byte) string {
	for i := 0; i < len(bs); i++ {
		if bs[i] == 0 {
			return string(bs[0:i])
		}
	}
	return string(bs)
}

func GetApplicationPath() string {
	path := filepath.Dir(os.Args[0])
	return path + string(os.PathSeparator)
}

func DirectoryExists(path string) bool {
	fileInfo, err := os.Stat(path)
	if err == nil && fileInfo.IsDir() {
		return true
	}
	return false
}

func FileExists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

func CreateFile(filename string) bool {
	// os.MkdirAll(path.Dir(filename))
	_, err := os.Create(filename)
	if err == nil {
		return true
	}
	return false
}

func IncludeTrailingBackslash(path string) string {
	if !strings.HasSuffix(path, string(os.PathSeparator)) {
		return path + string(os.PathSeparator)
	}
	return path
}

func ChangeFileExt(filename, extension string) string {
	i := strings.LastIndex(filename, ".")
	if i >= 0 {
		ret := filename[:i]
		return ret + extension
	}
	return filename + extension
}
<commit_msg>add datetime  print routines<commit_after>// Copyright 2016~2017 ecofast(无尽愿). All rights reserved.
// Use of this source code is governed by a BSD-style license.

// Package sysutils implements some useful system utility functions
// in the way of which Delphi(2007) RTL has done.
package sysutils

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

func CheckError(e error) {
	if e != nil {
		panic(e)
	}
}

func BoolToStr(b bool) string {
	if b {
		return "1"
	}
	return "0"
}

func IntToStr(i int) string {
	return strconv.FormatInt(int64(i), 10)
}

func StrToInt(s string) int {
	if ret, err := strconv.Atoi(s); err == nil {
		return ret
	}
	panic(fmt.Sprintf("Cannot convert %s to int!", s))
}

func StrToIntDef(s string, defaultvalue int) int {
	if ret, err := strconv.Atoi(s); err == nil {
		return ret
	}
	return defaultvalue
}

func StrToBool(s string) bool {
	if ret, err := strconv.ParseBool(s); err == nil {
		return ret
	}
	return false
}

func FloatToStr(f float64) string {
	return fmt.Sprintf("%g", f)
}

func BytesToStr(bs []byte) string {
	for i := 0; i < len(bs); i++ {
		if bs[i] == 0 {
			return string(bs[0:i])
		}
	}
	return string(bs)
}

func GetApplicationPath() string {
	path := filepath.Dir(os.Args[0])
	return path + string(os.PathSeparator)
}

func DirectoryExists(path string) bool {
	fileInfo, err := os.Stat(path)
	if err == nil && fileInfo.IsDir() {
		return true
	}
	return false
}

func FileExists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

func CreateFile(filename string) bool {
	// os.MkdirAll(path.Dir(filename))
	_, err := os.Create(filename)
	if err == nil {
		return true
	}
	return false
}

func IncludeTrailingBackslash(path string) string {
	if !strings.HasSuffix(path, string(os.PathSeparator)) {
		return path + string(os.PathSeparator)
	}
	return path
}

func ChangeFileExt(filename, extension string) string {
	i := strings.LastIndex(filename, ".")
	if i >= 0 {
		ret := filename[:i]
		return ret + extension
	}
	return filename + extension
}

func DateTimeToStr(dt time.Time) string {
	year, month, day := dt.Date()
	hour, min, sec := dt.Clock()
	return fmt.Sprintf("%d-%d-%d %d:%d:%d", year, int(month), day, hour, min, sec)
}

func DateToStr(dt time.Time) string {
	year, month, day := dt.Date()
	return fmt.Sprintf("%d-%d-%d", year, int(month), day)
}

func TimeToStr(dt time.Time) string {
	hour, min, sec := dt.Clock()
	return fmt.Sprintf("%d:%d:%d", hour, min, sec)
}
<|endoftext|>


<commit_before>// +build ansi

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"time"
	"unicode"
)

type AnsiCell struct {
	fg uicolor
	bg uicolor
	r  rune
}

type termui struct {
	bStdin     *bufio.Reader
	bStdout    *bufio.Writer
	cells      []AnsiCell
	backBuffer []AnsiCell
	cursor     position
	stty       string
}

func (ui *termui) GetIndex(x, y int) int {
	return y*UIWidth + x
}

func (ui *termui) GetPos(i int) (int, int) {
	return i - (i/UIWidth)*UIWidth, i / UIWidth
}

func (ui *termui) ResetCells() {
	for i := 0; i < len(ui.cells); i++ {
		ui.cells[i].r = ' '
		ui.cells[i].bg = ColorBg
	}
}

func (ui *termui) Init() error {
	ui.bStdin = bufio.NewReader(os.Stdin)
	ui.bStdout = bufio.NewWriter(os.Stdout)
	ui.cells = make([]AnsiCell, UIWidth*UIHeight)
	ui.ResetCells()
	ui.backBuffer = make([]AnsiCell, UIWidth*UIHeight)
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	return nil
}

func (ui *termui) Close() {
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	ui.bStdout.Flush()
	cmd := exec.Command("stty", ui.stty)
	cmd.Stdin = os.Stdin
	err := cmd.Run()
	if err != nil {
		cmd = exec.Command("stty", "sane")
		cmd.Stdin = os.Stdin
		cmd.Run()
	}
}

func (ui *termui) PostInit() {
	ui.HideCursor()
	fmt.Fprintf(ui.bStdout, "\x1b[?25l")
	cmd := exec.Command("stty", "-g")
	cmd.Stdin = os.Stdin
	save, err := cmd.Output()
	if err != nil {
		save = []byte("sane")
	}
	ui.stty = string(save)
	cmd = exec.Command("stty", "raw", "-echo")
	cmd.Stdin = os.Stdin
	cmd.Run()
}

func (ui *termui) MoveTo(x, y int) {
	fmt.Fprintf(ui.bStdout, "\x1b[%d;%dH", y+1, x+1)
}

func (ui *termui) Clear() {
	ui.ResetCells()
}

func (ui *termui) Flush() {
	for i := 0; i < len(ui.cells); i++ {
		if ui.cells[i] == ui.backBuffer[i] {
			continue
		}
		cell := ui.cells[i]
		x, y := ui.GetPos(i)
		ui.MoveTo(x, y)
		fmt.Fprintf(ui.bStdout, "\x1b[38;5;%dm", cell.fg)
		fmt.Fprintf(ui.bStdout, "\x1b[48;5;%dm", cell.bg)
		ui.bStdout.WriteRune(cell.r)
		fmt.Fprintf(ui.bStdout, "\x1b[0m")
		ui.backBuffer[i] = cell
	}
	ui.MoveTo(ui.cursor.X, ui.cursor.Y)
	ui.bStdout.Flush()
}

func (ui *termui) Small() bool {
	return false
}

func (ui *termui) HideCursor() {
	ui.cursor = InvalidPos
}

func (ui *termui) SetCursor(pos position) {
	ui.cursor = pos
}

func (ui *termui) SetCell(x, y int, r rune, fg, bg uicolor) {
	i := ui.GetIndex(x, y)
	if i >= len(ui.cells) {
		return
	}
	ui.cells[ui.GetIndex(x, y)] = AnsiCell{fg: fg, bg: bg, r: r}

}

func (ui *termui) ReadChar() rune {
	r, _, _ := ui.bStdin.ReadRune()
	return r
}

func (ui *termui) ExploreStep(g *game) bool {
	time.Sleep(10 * time.Millisecond)
	ui.DrawDungeonView(g, NormalMode)
	return false
}

func (ui *termui) WaitForContinue(g *game, line int) {
loop:
	for {
		r := ui.ReadChar()
		switch r {
		case '\x1b', ' ':
			break loop
		}
	}
}

func (ui *termui) PromptConfirmation(g *game) bool {
	for {
		r := ui.ReadChar()
		switch r {
		case 'Y', 'y':
			return true
		default:
			return false
		}
	}
}

func (ui *termui) PressAnyKey() error {
	for {
		ui.ReadChar()
		return nil
	}
}

func (ui *termui) PlayerTurnEvent(g *game, ev event) (err error, again, quit bool) {
	again = true
	r := ui.ReadChar()
	switch r {
	case 'W':
		ui.EnterWizard(g)
		return nil, true, false
	case 'Q':
		if ui.Quit(g) {
			return nil, false, true
		}
		return nil, true, false
	}
	err, again, quit = ui.HandleKeyAction(g, runeKeyAction{r: r})
	if err != nil {
		again = true
	}
	return err, again, quit
}

func (ui *termui) Scroll(n int) (m int, quit bool) {
	r := ui.ReadChar()
	switch r {
	case '\x1b', ' ':
		quit = true
	case 'u':
		n -= 12
	case 'd':
		n += 12
	case 'j', '2':
		n++
	case 'k', '8':
		n--
	}
	return n, quit
}

func (ui *termui) ReadRuneKey() rune {
	for {
		r := ui.ReadChar()
		if r == ' ' || r == '\x1b' {
			return 0
		}
		if unicode.IsPrint(r) {
			return r
		}
	}
}

func (ui *termui) MenuAction(n int) (m int, action configAction) {
	r := ui.ReadChar()
	switch r {
	case 'a':
		action = ChangeConfig
	case '\x1b', ' ':
		action = QuitConfig
	case 'u':
		n -= DungeonHeight / 2
	case 'd':
		n += DungeonHeight / 2
	case 'j', '2':
		n++
	case 'k', '8':
		n--
	case 'R':
		action = ResetConfig
	}
	return n, action
}

func (ui *termui) TargetModeEvent(g *game, targ Targeter, data *examineData) (err error, again, quit, notarg bool) {
	r := ui.ReadChar()
	return ui.CursorKeyAction(g, targ, runeKeyAction{r: r}, data)
}

func (ui *termui) Select(g *game, ev event, l int) (index int, alternate bool, err error) {
	for {
		r := ui.ReadChar()
		switch {
		case r == '\x1b' || r == ' ':
			return -1, false, errors.New(DoNothing)
		case 97 <= r && int(r) < 97+l:
			return int(r - 97), false, nil
		case r == '?':
			return -1, true, nil
		case r == ' ':
			return -1, false, errors.New(DoNothing)
		}
	}
}
<commit_msg>reduce output size in --tags ansi backend<commit_after>// +build ansi

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"time"
	"unicode"
)

type AnsiCell struct {
	fg uicolor
	bg uicolor
	r  rune
}

type termui struct {
	bStdin     *bufio.Reader
	bStdout    *bufio.Writer
	cells      []AnsiCell
	backBuffer []AnsiCell
	cursor     position
	stty       string
}

func (ui *termui) GetIndex(x, y int) int {
	return y*UIWidth + x
}

func (ui *termui) GetPos(i int) (int, int) {
	return i - (i/UIWidth)*UIWidth, i / UIWidth
}

func (ui *termui) ResetCells() {
	for i := 0; i < len(ui.cells); i++ {
		ui.cells[i].r = ' '
		ui.cells[i].bg = ColorBg
	}
}

func (ui *termui) Init() error {
	ui.bStdin = bufio.NewReader(os.Stdin)
	ui.bStdout = bufio.NewWriter(os.Stdout)
	ui.cells = make([]AnsiCell, UIWidth*UIHeight)
	ui.ResetCells()
	ui.backBuffer = make([]AnsiCell, UIWidth*UIHeight)
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	return nil
}

func (ui *termui) Close() {
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	ui.bStdout.Flush()
	cmd := exec.Command("stty", ui.stty)
	cmd.Stdin = os.Stdin
	err := cmd.Run()
	if err != nil {
		cmd = exec.Command("stty", "sane")
		cmd.Stdin = os.Stdin
		cmd.Run()
	}
}

func (ui *termui) PostInit() {
	ui.HideCursor()
	fmt.Fprintf(ui.bStdout, "\x1b[?25l")
	cmd := exec.Command("stty", "-g")
	cmd.Stdin = os.Stdin
	save, err := cmd.Output()
	if err != nil {
		save = []byte("sane")
	}
	ui.stty = string(save)
	cmd = exec.Command("stty", "raw", "-echo")
	cmd.Stdin = os.Stdin
	cmd.Run()
}

func (ui *termui) MoveTo(x, y int) {
	fmt.Fprintf(ui.bStdout, "\x1b[%d;%dH", y+1, x+1)
}

func (ui *termui) Clear() {
	ui.ResetCells()
}

func (ui *termui) Flush() {
	var prevfg, prevbg uicolor
	first := true
	for i := 0; i < len(ui.cells); i++ {
		if ui.cells[i] == ui.backBuffer[i] {
			continue
		}
		cell := ui.cells[i]
		x, y := ui.GetPos(i)
		ui.MoveTo(x, y)
		pfg := true
		pbg := true
		if first {
			prevfg = cell.fg
			prevbg = cell.bg
			first = false
		} else {
			if prevfg == cell.fg {
				pfg = false
			} else {
				prevfg = cell.fg
			}
			if prevbg == cell.bg {
				pbg = false
			} else {
				prevbg = cell.bg
			}
		}
		if pfg {
			fmt.Fprintf(ui.bStdout, "\x1b[38;5;%dm", cell.fg)
		}
		if pbg {
			fmt.Fprintf(ui.bStdout, "\x1b[48;5;%dm", cell.bg)
		}
		ui.bStdout.WriteRune(cell.r)
		ui.backBuffer[i] = cell
	}
	ui.MoveTo(ui.cursor.X, ui.cursor.Y)
	fmt.Fprintf(ui.bStdout, "\x1b[0m")
	ui.bStdout.Flush()
}

func (ui *termui) Small() bool {
	return false
}

func (ui *termui) HideCursor() {
	ui.cursor = InvalidPos
}

func (ui *termui) SetCursor(pos position) {
	ui.cursor = pos
}

func (ui *termui) SetCell(x, y int, r rune, fg, bg uicolor) {
	i := ui.GetIndex(x, y)
	if i >= len(ui.cells) {
		return
	}
	ui.cells[ui.GetIndex(x, y)] = AnsiCell{fg: fg, bg: bg, r: r}

}

func (ui *termui) ReadChar() rune {
	r, _, _ := ui.bStdin.ReadRune()
	return r
}

func (ui *termui) ExploreStep(g *game) bool {
	time.Sleep(10 * time.Millisecond)
	ui.DrawDungeonView(g, NormalMode)
	return false
}

func (ui *termui) WaitForContinue(g *game, line int) {
loop:
	for {
		r := ui.ReadChar()
		switch r {
		case '\x1b', ' ':
			break loop
		}
	}
}

func (ui *termui) PromptConfirmation(g *game) bool {
	for {
		r := ui.ReadChar()
		switch r {
		case 'Y', 'y':
			return true
		default:
			return false
		}
	}
}

func (ui *termui) PressAnyKey() error {
	for {
		ui.ReadChar()
		return nil
	}
}

func (ui *termui) PlayerTurnEvent(g *game, ev event) (err error, again, quit bool) {
	again = true
	r := ui.ReadChar()
	switch r {
	case 'W':
		ui.EnterWizard(g)
		return nil, true, false
	case 'Q':
		if ui.Quit(g) {
			return nil, false, true
		}
		return nil, true, false
	}
	err, again, quit = ui.HandleKeyAction(g, runeKeyAction{r: r})
	if err != nil {
		again = true
	}
	return err, again, quit
}

func (ui *termui) Scroll(n int) (m int, quit bool) {
	r := ui.ReadChar()
	switch r {
	case '\x1b', ' ':
		quit = true
	case 'u':
		n -= 12
	case 'd':
		n += 12
	case 'j', '2':
		n++
	case 'k', '8':
		n--
	}
	return n, quit
}

func (ui *termui) ReadRuneKey() rune {
	for {
		r := ui.ReadChar()
		if r == ' ' || r == '\x1b' {
			return 0
		}
		if unicode.IsPrint(r) {
			return r
		}
	}
}

func (ui *termui) MenuAction(n int) (m int, action configAction) {
	r := ui.ReadChar()
	switch r {
	case 'a':
		action = ChangeConfig
	case '\x1b', ' ':
		action = QuitConfig
	case 'u':
		n -= DungeonHeight / 2
	case 'd':
		n += DungeonHeight / 2
	case 'j', '2':
		n++
	case 'k', '8':
		n--
	case 'R':
		action = ResetConfig
	}
	return n, action
}

func (ui *termui) TargetModeEvent(g *game, targ Targeter, data *examineData) (err error, again, quit, notarg bool) {
	r := ui.ReadChar()
	return ui.CursorKeyAction(g, targ, runeKeyAction{r: r}, data)
}

func (ui *termui) Select(g *game, ev event, l int) (index int, alternate bool, err error) {
	for {
		r := ui.ReadChar()
		switch {
		case r == '\x1b' || r == ' ':
			return -1, false, errors.New(DoNothing)
		case 97 <= r && int(r) < 97+l:
			return int(r - 97), false, nil
		case r == '?':
			return -1, true, nil
		case r == ' ':
			return -1, false, errors.New(DoNothing)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>log file being processed<commit_after><|endoftext|>


<commit_before>// +build ignore

package main

import (
	"os"
	"os/exec"
	"strings"
)

func main() {
	var err error

	var cmd = exec.Command("git", "describe")
	var out []byte
	out, err = cmd.CombinedOutput()
	if err != nil {
		panic(err)
	}
	var build = string(out)
	build = strings.TrimSpace(build)

	var f *os.File
	f, err = os.Create("build.go")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	_, err = f.WriteString(`// build.go is a generated file and should not be modified by hand

package version

const Build = "` + build + `"
`)
	if err != nil {
		panic(err)
	}
}
<commit_msg>version: improve generated code error message<commit_after>// +build ignore

package main

import (
	"os"
	"os/exec"
	"strings"
)

func main() {
	var err error

	var cmd = exec.Command("git", "describe")
	var out []byte
	out, err = cmd.CombinedOutput()
	if err != nil {
		panic("Unable to run `git describe`: " + err.Error())
	}
	var build = string(out)
	build = strings.TrimSpace(build)

	var f *os.File
	f, err = os.Create("build.go")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	_, err = f.WriteString(`// build.go is a generated file and should not be modified by hand

package version

const Build = "` + build + `"
`)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before><commit_msg>enhance print config<commit_after><|endoftext|>


<commit_before><commit_msg>add config module<commit_after><|endoftext|>


<commit_before>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package semtech

import (
	"encoding/json"
	"errors"
	"strings"
	"time"
)

// Unmarshal parses a raw response from a server and turn in into a packet.
// Will return an error if the response fields are incorrect.
func Unmarshal(raw []byte) (*Packet, error) {
	size := len(raw)

	if size < 3 {
		return nil, errors.New("Invalid raw data format")
	}

	packet := &Packet{
		Version:    raw[0],
		Token:      raw[1:3],
		Identifier: raw[3],
		GatewayId:  nil,
		Payload:    nil,
	}

	if packet.Version != VERSION {
		return nil, errors.New("Unreckognized protocol version")
	}

	if packet.Identifier > PULL_ACK {
		return nil, errors.New("Unreckognized protocol identifier")
	}

	cursor := 4
	if packet.Identifier == PULL_DATA || packet.Identifier == PUSH_DATA {
		if size < 12 {
			return nil, errors.New("Invalid gateway identifier")
		}
		packet.GatewayId = raw[cursor:12]
		cursor = 12
	}

	var err error
	if size > cursor && (packet.Identifier == PUSH_DATA || packet.Identifier == PULL_RESP) {
		packet.Payload = new(Payload)
		packet.Payload.Raw = raw[cursor:]
		err = json.Unmarshal(raw[cursor:], packet.Payload)
	}

	return packet, err
}

// UnmarshalJSON implements the Unmarshaler interface from encoding/json
func (t *timeparser) UnmarshalJSON(raw []byte) error {
	str := strings.Trim(string(raw), `"`)
	v, err := time.Parse("2006-01-02 15:04:05 GMT", str)
	if err != nil {
		v, err = time.Parse(time.RFC3339, str)
	}
	if err != nil {
		v, err = time.Parse(time.RFC3339Nano, str)
	}
	if err != nil {
		return errors.New("Unkown date format. Unable to parse time")
	}
	t.value = &v
	return nil
}

// UnmarshalJSON implements the Unmarshaler interface from encoding/json
func (d *datrparser) UnmarshalJSON(raw []byte) error {
	v := strings.Trim(string(raw), `"`)

	if v == "" {
		return errors.New("Invalid datr format")
	}

	d.value = &v
	return nil
}

// UnmarshalJSON implements the Unmarshaler interface from encoding/json
func (p *Payload) UnmarshalJSON(raw []byte) error {
	proxy := payloadProxy{
		ProxStat: &statProxy{
			Stat: new(Stat),
		},
		ProxTXPK: &txpkProxy{
			TXPK: new(TXPK),
		},
	}

	if err := json.Unmarshal(raw, &proxy); err != nil {
		return err
	}

	if proxy.ProxStat.Stat != nil {
		if proxy.ProxStat.Time != nil {
			proxy.ProxStat.Stat.Time = proxy.ProxStat.Time.value
		}
		p.Stat = proxy.ProxStat.Stat
	}

	if proxy.ProxTXPK.TXPK != nil {
		if proxy.ProxTXPK.Time != nil {
			proxy.ProxTXPK.TXPK.Time = proxy.ProxTXPK.Time.value
		}
		if proxy.ProxTXPK.Datr != nil {
			proxy.ProxTXPK.TXPK.Datr = proxy.ProxTXPK.Datr.value
		}
		p.TXPK = proxy.ProxTXPK.TXPK
	}

	for _, rxpk := range proxy.ProxRXPK {
		if rxpk.Time != nil {
			rxpk.RXPK.Time = rxpk.Time.value
		}
		if rxpk.Datr != nil {
			rxpk.RXPK.Datr = rxpk.Datr.value
		}
		p.RXPK = append(p.RXPK, *rxpk.RXPK)
	}

	return nil
}
<commit_msg>[simulators.gateway] Fix error in Unmarshal function<commit_after>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package semtech

import (
	"encoding/json"
	"errors"
	"strings"
	"time"
)

// Unmarshal parses a raw response from a server and turn in into a packet.
// Will return an error if the response fields are incorrect.
func Unmarshal(raw []byte) (*Packet, error) {
	size := len(raw)

	if size < 4 {
		return nil, errors.New("Invalid raw data format")
	}

	packet := &Packet{
		Version:    raw[0],
		Token:      raw[1:3],
		Identifier: raw[3],
		GatewayId:  nil,
		Payload:    nil,
	}

	if packet.Version != VERSION {
		return nil, errors.New("Unreckognized protocol version")
	}

	if packet.Identifier > PULL_ACK {
		return nil, errors.New("Unreckognized protocol identifier")
	}

	cursor := 4
	if packet.Identifier == PULL_DATA || packet.Identifier == PUSH_DATA {
		if size < 12 {
			return nil, errors.New("Invalid gateway identifier")
		}
		packet.GatewayId = raw[cursor:12]
		cursor = 12
	}

	var err error
	if size > cursor && (packet.Identifier == PUSH_DATA || packet.Identifier == PULL_RESP) {
		packet.Payload = new(Payload)
		packet.Payload.Raw = raw[cursor:]
		err = json.Unmarshal(raw[cursor:], packet.Payload)
	}

	return packet, err
}

// UnmarshalJSON implements the Unmarshaler interface from encoding/json
func (t *timeparser) UnmarshalJSON(raw []byte) error {
	str := strings.Trim(string(raw), `"`)
	v, err := time.Parse("2006-01-02 15:04:05 GMT", str)
	if err != nil {
		v, err = time.Parse(time.RFC3339, str)
	}
	if err != nil {
		v, err = time.Parse(time.RFC3339Nano, str)
	}
	if err != nil {
		return errors.New("Unkown date format. Unable to parse time")
	}
	t.value = &v
	return nil
}

// UnmarshalJSON implements the Unmarshaler interface from encoding/json
func (d *datrparser) UnmarshalJSON(raw []byte) error {
	v := strings.Trim(string(raw), `"`)

	if v == "" {
		return errors.New("Invalid datr format")
	}

	d.value = &v
	return nil
}

// UnmarshalJSON implements the Unmarshaler interface from encoding/json
func (p *Payload) UnmarshalJSON(raw []byte) error {
	proxy := payloadProxy{
		ProxStat: &statProxy{
			Stat: new(Stat),
		},
		ProxTXPK: &txpkProxy{
			TXPK: new(TXPK),
		},
	}

	if err := json.Unmarshal(raw, &proxy); err != nil {
		return err
	}

	if proxy.ProxStat.Stat != nil {
		if proxy.ProxStat.Time != nil {
			proxy.ProxStat.Stat.Time = proxy.ProxStat.Time.value
		}
		p.Stat = proxy.ProxStat.Stat
	}

	if proxy.ProxTXPK.TXPK != nil {
		if proxy.ProxTXPK.Time != nil {
			proxy.ProxTXPK.TXPK.Time = proxy.ProxTXPK.Time.value
		}
		if proxy.ProxTXPK.Datr != nil {
			proxy.ProxTXPK.TXPK.Datr = proxy.ProxTXPK.Datr.value
		}
		p.TXPK = proxy.ProxTXPK.TXPK
	}

	for _, rxpk := range proxy.ProxRXPK {
		if rxpk.Time != nil {
			rxpk.RXPK.Time = rxpk.Time.value
		}
		if rxpk.Datr != nil {
			rxpk.RXPK.Datr = rxpk.Datr.value
		}
		p.RXPK = append(p.RXPK, *rxpk.RXPK)
	}

	return nil
}
<|endoftext|>