<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"net/http"
	"strconv"
	"time"
)

type SettingMessage struct {
	Setting string `json:"setting"`
	Value   bool   `json:"state"`
}

type InfoMessage struct {
	*status
	*settings
}

func statusSender(conn *websocket.Conn) {
	timer := time.NewTicker(1 * time.Second)
	for {
		<-timer.C

		update, _ := json.Marshal(InfoMessage{status: &globalStatus, settings: &globalSettings})
        // TODO: once we switch to hte new WebUI, we will not send settings via websocket
		// update, _ := json.Marshal(&globalStatus)
		_, err := conn.Write(update)

		if err != nil {
			//			log.Printf("Web client disconnected.\n")
			break
		}
	}
}

func handleManagementConnection(conn *websocket.Conn) {
	//	log.Printf("Web client connected.\n")
	go statusSender(conn)

    // TODO: once we have the new WebUI established, the websocket will nolonger receive settings changes
	for {
		var msg SettingMessage
		err := websocket.JSON.Receive(conn, &msg)
		if err == io.EOF {
			break
		} else if err != nil {
			log.Printf("handleManagementConnection: %s\n", err.Error())
		} else {
			if msg.Setting == "UAT_Enabled" {
				globalSettings.UAT_Enabled = msg.Value
			}
			if msg.Setting == "ES_Enabled" {
				globalSettings.ES_Enabled = msg.Value
			}
			if msg.Setting == "GPS_Enabled" {
				globalSettings.GPS_Enabled = msg.Value
			}
			if msg.Setting == "AHRS_Enabled" {
				globalSettings.AHRS_Enabled = msg.Value
			}
			if msg.Setting == "DEBUG" {
				globalSettings.DEBUG = msg.Value
			}

			saveSettings()
		}
	}
}

// AJAX call - /getTraffic. Responds with currently tracked traffic targets.
func handleTrafficRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	/* From JSON package docs:
	"JSON objects only support strings as keys; to encode a Go map type it must be of the form map[string]T (where T is any Go type supported by the json package)."
	*/
	t := make(map[string]TrafficInfo)
	trafficMutex.Lock()
	for icao, traf := range traffic {
		icaoStr := strconv.FormatInt(int64(icao), 16) // Convert to hex.
		t[icaoStr] = traf
	}
	trafficJSON, _ := json.Marshal(&t)
	trafficMutex.Unlock()
	fmt.Fprintf(w, "%s\n", trafficJSON)
}

// AJAX call - /getSituation. Responds with current situation (lat/lon/gdspeed/track/pitch/roll/heading/etc.)
func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	situationJSON, _ := json.Marshal(&mySituation)
	fmt.Fprintf(w, "%s\n", situationJSON)
}

// AJAX call - /getTowers. Responds with all ADS-B ground towers that have sent messages that we were able to parse, along with its stats.
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	towersJSON, _ := json.Marshal(&ADSBTowers)
	fmt.Fprintf(w, "%s\n", towersJSON)
}

// AJAX call - /getSettings. Responds with all stratux.conf data.
func handleSettingsGetRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	settingsJSON, _ := json.Marshal(&globalSettings)
	fmt.Fprintf(w, "%s\n", settingsJSON)
}

// AJAX call - /setSettings. receives via POST command, any/all stratux.conf data.
func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
    // define header in support of cross-domain AJAX
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
    w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
    w.Header().Set("Content-Type", "application/json")

    // for an OPTION method request, we return header without processing.
    // this insures we are recognized as supporting cross-domain AJAX REST calls
    if (r.Method == "POST") {
        raw, _ := httputil.DumpRequest(r, true)
        log.Printf("handleSettingsSetRequest:raw: %s\n", raw)

        decoder := json.NewDecoder(r.Body);
        for {
            var msg map[string]interface{} // support arbitrary JSON

            err := decoder.Decode(&msg)
            if err == io.EOF {
                break
            } else if err != nil {
                log.Printf("handleSettingsSetRequest:error: %s\n", err.Error())
            } else {
                for key, val := range msg {
                    // log.Printf("handleSettingsSetRequest:json: testing for key:%s of type %s\n", key, reflect.TypeOf(val))
                    switch key {
                        case "UAT_Enabled":     globalSettings.UAT_Enabled = val.(bool)
                        case "ES_Enabled":      globalSettings.ES_Enabled = val.(bool)
                        case "GPS_Enabled":     globalSettings.GPS_Enabled = val.(bool)
                        case "AHRS_Enabled":    globalSettings.AHRS_Enabled = val.(bool)
                        case "DEBUG":           globalSettings.DEBUG = val.(bool)
                        case "ReplayLog":       globalSettings.ReplayLog = val.(bool)
                        case "PPM":             globalSettings.PPM = int(val.(float64))
                        default:                log.Printf("handleSettingsSetRequest:json: unrecognized key:%s\n", key)
                    }
                }
                saveSettings()
            }
        }

        // while it may be redundent, we return the latest settings
        settingsJSON, _ := json.Marshal(&globalSettings)
        fmt.Fprintf(w, "%s\n", settingsJSON)
    }
}

func managementInterface() {
	http.Handle("/", http.FileServer(http.Dir("/var/www")))
	http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
	http.HandleFunc("/control",
		func(w http.ResponseWriter, req *http.Request) {
			s := websocket.Server{
				Handler: websocket.Handler(handleManagementConnection)}
			s.ServeHTTP(w, req)
		})

	http.HandleFunc("/getTraffic", handleTrafficRequest)
	http.HandleFunc("/getSituation", handleSituationRequest)
	http.HandleFunc("/getTowers", handleTowersRequest)
	http.HandleFunc("/getSettings", handleSettingsGetRequest)
	http.HandleFunc("/setSettings", handleSettingsSetRequest)

	err := http.ListenAndServe(managementAddr, nil)

	if err != nil {
		log.Printf("managementInterface ListenAndServe: %s\n", err.Error())
	}
}
<commit_msg>REST services getter/setter for settings completed without debug output<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"net/http"
	"strconv"
	"time"
)

type SettingMessage struct {
	Setting string `json:"setting"`
	Value   bool   `json:"state"`
}

type InfoMessage struct {
	*status
	*settings
}

func statusSender(conn *websocket.Conn) {
	timer := time.NewTicker(1 * time.Second)
	for {
		<-timer.C

		update, _ := json.Marshal(InfoMessage{status: &globalStatus, settings: &globalSettings})
        // TODO: once we switch to hte new WebUI, we will not send settings via websocket
		// update, _ := json.Marshal(&globalStatus)
		_, err := conn.Write(update)

		if err != nil {
			//			log.Printf("Web client disconnected.\n")
			break
		}
	}
}

func handleManagementConnection(conn *websocket.Conn) {
	//	log.Printf("Web client connected.\n")
	go statusSender(conn)

    // TODO: once we have the new WebUI established, the websocket will nolonger receive settings changes
	for {
		var msg SettingMessage
		err := websocket.JSON.Receive(conn, &msg)
		if err == io.EOF {
			break
		} else if err != nil {
			log.Printf("handleManagementConnection: %s\n", err.Error())
		} else {
			if msg.Setting == "UAT_Enabled" {
				globalSettings.UAT_Enabled = msg.Value
			}
			if msg.Setting == "ES_Enabled" {
				globalSettings.ES_Enabled = msg.Value
			}
			if msg.Setting == "GPS_Enabled" {
				globalSettings.GPS_Enabled = msg.Value
			}
			if msg.Setting == "AHRS_Enabled" {
				globalSettings.AHRS_Enabled = msg.Value
			}
			if msg.Setting == "DEBUG" {
				globalSettings.DEBUG = msg.Value
			}

			saveSettings()
		}
	}
}

// AJAX call - /getTraffic. Responds with currently tracked traffic targets.
func handleTrafficRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	/* From JSON package docs:
	"JSON objects only support strings as keys; to encode a Go map type it must be of the form map[string]T (where T is any Go type supported by the json package)."
	*/
	t := make(map[string]TrafficInfo)
	trafficMutex.Lock()
	for icao, traf := range traffic {
		icaoStr := strconv.FormatInt(int64(icao), 16) // Convert to hex.
		t[icaoStr] = traf
	}
	trafficJSON, _ := json.Marshal(&t)
	trafficMutex.Unlock()
	fmt.Fprintf(w, "%s\n", trafficJSON)
}

// AJAX call - /getSituation. Responds with current situation (lat/lon/gdspeed/track/pitch/roll/heading/etc.)
func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	situationJSON, _ := json.Marshal(&mySituation)
	fmt.Fprintf(w, "%s\n", situationJSON)
}

// AJAX call - /getTowers. Responds with all ADS-B ground towers that have sent messages that we were able to parse, along with its stats.
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	towersJSON, _ := json.Marshal(&ADSBTowers)
	fmt.Fprintf(w, "%s\n", towersJSON)
}

// AJAX call - /getSettings. Responds with all stratux.conf data.
func handleSettingsGetRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	settingsJSON, _ := json.Marshal(&globalSettings)
	fmt.Fprintf(w, "%s\n", settingsJSON)
}

// AJAX call - /setSettings. receives via POST command, any/all stratux.conf data.
func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
    // define header in support of cross-domain AJAX
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
    w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
    w.Header().Set("Content-Type", "application/json")

    // for an OPTION method request, we return header without processing.
    // this insures we are recognized as supporting cross-domain AJAX REST calls
    if (r.Method == "POST") {
        // raw, _ := httputil.DumpRequest(r, true)
        // log.Printf("handleSettingsSetRequest:raw: %s\n", raw)

        decoder := json.NewDecoder(r.Body);
        for {
            var msg map[string]interface{} // support arbitrary JSON

            err := decoder.Decode(&msg)
            if err == io.EOF {
                break
            } else if err != nil {
                log.Printf("handleSettingsSetRequest:error: %s\n", err.Error())
            } else {
                for key, val := range msg {
                    // log.Printf("handleSettingsSetRequest:json: testing for key:%s of type %s\n", key, reflect.TypeOf(val))
                    switch key {
                        case "UAT_Enabled":     globalSettings.UAT_Enabled = val.(bool)
                        case "ES_Enabled":      globalSettings.ES_Enabled = val.(bool)
                        case "GPS_Enabled":     globalSettings.GPS_Enabled = val.(bool)
                        case "AHRS_Enabled":    globalSettings.AHRS_Enabled = val.(bool)
                        case "DEBUG":           globalSettings.DEBUG = val.(bool)
                        case "ReplayLog":       globalSettings.ReplayLog = val.(bool)
                        case "PPM":             globalSettings.PPM = int(val.(float64))
                        default:                log.Printf("handleSettingsSetRequest:json: unrecognized key:%s\n", key)
                    }
                }
                saveSettings()
            }
        }

        // while it may be redundent, we return the latest settings
        settingsJSON, _ := json.Marshal(&globalSettings)
        fmt.Fprintf(w, "%s\n", settingsJSON)
    }
}

func managementInterface() {
	http.Handle("/", http.FileServer(http.Dir("/var/www")))
	http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
	http.HandleFunc("/control",
		func(w http.ResponseWriter, req *http.Request) {
			s := websocket.Server{
				Handler: websocket.Handler(handleManagementConnection)}
			s.ServeHTTP(w, req)
		})

	http.HandleFunc("/getTraffic", handleTrafficRequest)
	http.HandleFunc("/getSituation", handleSituationRequest)
	http.HandleFunc("/getTowers", handleTowersRequest)
	http.HandleFunc("/getSettings", handleSettingsGetRequest)
	http.HandleFunc("/setSettings", handleSettingsSetRequest)

	err := http.ListenAndServe(managementAddr, nil)

	if err != nil {
		log.Printf("managementInterface ListenAndServe: %s\n", err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
)

var (
	root            string
	dontRecurseFlag = flag.Bool("n", false, "don't recursively check paths")
)

func main() {
	flag.Parse()
	if len(flag.Args()) != 1 {
		fmt.Println("missing argument: filepath")
		return
	}

	var err error
	root, err = filepath.Abs(flag.Arg(0))
	if err != nil {
		fmt.Printf("Error finding absolute path :%s", err)
		return
	}

	errors := 0
	filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			fmt.Printf("Error during filesystem walk: %v\n", err)
			return nil
		}
		if fi.IsDir() {
			if *dontRecurseFlag && path != root || filepath.Base(path) == "testdata" {
				return filepath.SkipDir
			}
			return nil
		}
		if !strings.HasSuffix(path, ".go") {
			return nil
		}
		errors += checkPath(path)
		return nil
	})
	if errors > 0 {
		os.Exit(1)
	}
}

func checkPath(path string) (errors int) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, nil, 0)
	if err != nil {
		return errors
	}

	chk := checker{}
	// Package-level vars are exempt.
	for _, d := range f.Decls {
		if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.VAR {
			for _, s := range d.Specs {
				for _, id := range s.(*ast.ValueSpec).Names {
					chk.info(id).escapes = true
				}
			}
		}
	}
	ast.Walk(chk, f)
	for _, i := range chk {
		if !i.escapes && i.assign > i.use {
			fmt.Printf("%s: %s assigned and not used\n", fset.Position(i.id.Pos()), i.id.Name)
			errors++
		}
	}
	return errors
}

type checker map[*ast.Object]*info

type info struct {
	id            *ast.Ident
	assign, use   token.Pos
	loop, funclit ast.Node
	escapes       bool
}

func (chk checker) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.GenDecl:
		if n.Tok == token.VAR {
			for _, s := range n.Specs {
				for _, id := range s.(*ast.ValueSpec).Names {
					chk.info(id)
				}
			}
		}
	case *ast.AssignStmt:
		for _, x := range n.Rhs {
			ast.Walk(chk, x)
		}
		for _, x := range n.Lhs {
			if id, ok := unparen(x).(*ast.Ident); ok {
				chk.info(id).assign = n.End()
			} else {
				ast.Walk(chk, x)
			}
		}
		return nil
	case *ast.BranchStmt:
		if n.Tok == token.GOTO {
			for _, i := range chk {
				if i.use > n.Label.Obj.Decl.(*ast.LabeledStmt).Pos() && i.use < n.Pos() {
					i.use = n.Pos()
				}
			}
		}
	case *ast.FuncDecl:
		if n.Recv != nil {
			for _, id := range n.Recv.List[0].Names {
				chk.info(id)
			}
		}
	case *ast.FuncType:
		if n.Params != nil {
			for _, f := range n.Params.List {
				for _, id := range f.Names {
					chk.info(id)
				}
			}
		}
		if n.Results != nil {
			for _, f := range n.Results.List {
				for _, id := range f.Names {
					chk.info(id).escapes = true
				}
			}
		}
		return nil
	case *ast.Ident:
		i := chk.info(n)
		i.use = n.Pos()
		if i.funclit != nil {
			i.escapes = true
		}
		if i.loop != nil {
			i.use = i.loop.End()
		}
	case *ast.UnaryExpr:
		if id, ok := unparen(n.X).(*ast.Ident); ok && n.Op == token.AND {
			chk.info(id).escapes = true
		}
	case *ast.SelectorExpr:
		// A method call (possibly delayed via a method value) might implicitly take
		// the address of its receiver, causing it to escape.
		// We can't do any better here without knowing the variable's type.
		if id, ok := unparen(n.X).(*ast.Ident); ok {
			chk.info(id).escapes = true
		}
	case *ast.ForStmt:
		walk(chk, n.Init)
		chk.loop(n, true)
		walk(chk, n.Cond)
		walk(chk, n.Post)
		walk(chk, n.Body)
		chk.loop(n, false)
		return nil
	case *ast.RangeStmt:
		walk(chk, n.X)
		chk.loop(n, true)
		if n.Key != nil {
			lhs := []ast.Expr{n.Key}
			if n.Value != nil {
				lhs = append(lhs, n.Value)
			}
			walk(chk, &ast.AssignStmt{Lhs: lhs, Tok: n.Tok, TokPos: n.TokPos, Rhs: []ast.Expr{&ast.Ident{NamePos: n.X.End()}}})
		}
		walk(chk, n.Body)
		chk.loop(n, false)
		return nil
	case *ast.FuncLit:
		walk(chk, n.Type)
		chk.funclit(n, true)
		walk(chk, n.Body)
		chk.funclit(n, false)
		return nil
	}
	return chk
}

func (chk checker) info(id *ast.Ident) *info {
	i := chk[id.Obj]
	if i == nil {
		i = &info{}
		if id.Obj != nil && id.Name != "_" {
			chk[id.Obj] = i
		}
	}
	i.id = id
	return i
}

func (chk checker) loop(loop ast.Node, enter bool) {
	for _, i := range chk {
		if enter && i.loop == nil {
			i.loop = loop
		}
		if !enter && i.loop == loop {
			i.loop = nil
		}
	}
}

func (chk checker) funclit(funclit ast.Node, enter bool) {
	for _, i := range chk {
		if enter && i.funclit == nil {
			i.funclit = funclit
		}
		if !enter && i.funclit == funclit {
			i.funclit = nil
		}
	}
}

func walk(v ast.Visitor, n ast.Node) {
	if n != nil {
		ast.Walk(v, n)
	}
}

func unparen(x ast.Expr) ast.Expr {
	if p, ok := x.(*ast.ParenExpr); ok {
		return unparen(p.X)
	}
	return x
}
<commit_msg>ignore vendor directories<commit_after>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
)

var (
	root            string
	dontRecurseFlag = flag.Bool("n", false, "don't recursively check paths")
)

func main() {
	flag.Parse()
	if len(flag.Args()) != 1 {
		fmt.Println("missing argument: filepath")
		return
	}

	var err error
	root, err = filepath.Abs(flag.Arg(0))
	if err != nil {
		fmt.Printf("Error finding absolute path :%s", err)
		return
	}

	errors := 0
	filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			fmt.Printf("Error during filesystem walk: %v\n", err)
			return nil
		}
		if fi.IsDir() {
			if path != root && (
				*dontRecurseFlag ||
					filepath.Base(path) == "testdata" ||
					filepath.Base(path) == "vendor") {
				return filepath.SkipDir
			}
			return nil
		}
		if !strings.HasSuffix(path, ".go") {
			return nil
		}
		errors += checkPath(path)
		return nil
	})
	if errors > 0 {
		os.Exit(1)
	}
}

func checkPath(path string) (errors int) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, nil, 0)
	if err != nil {
		return errors
	}

	chk := checker{}
	// Package-level vars are exempt.
	for _, d := range f.Decls {
		if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.VAR {
			for _, s := range d.Specs {
				for _, id := range s.(*ast.ValueSpec).Names {
					chk.info(id).escapes = true
				}
			}
		}
	}
	ast.Walk(chk, f)
	for _, i := range chk {
		if !i.escapes && i.assign > i.use {
			fmt.Printf("%s: %s assigned and not used\n", fset.Position(i.id.Pos()), i.id.Name)
			errors++
		}
	}
	return errors
}

type checker map[*ast.Object]*info

type info struct {
	id            *ast.Ident
	assign, use   token.Pos
	loop, funclit ast.Node
	escapes       bool
}

func (chk checker) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.GenDecl:
		if n.Tok == token.VAR {
			for _, s := range n.Specs {
				for _, id := range s.(*ast.ValueSpec).Names {
					chk.info(id)
				}
			}
		}
	case *ast.AssignStmt:
		for _, x := range n.Rhs {
			ast.Walk(chk, x)
		}
		for _, x := range n.Lhs {
			if id, ok := unparen(x).(*ast.Ident); ok {
				chk.info(id).assign = n.End()
			} else {
				ast.Walk(chk, x)
			}
		}
		return nil
	case *ast.BranchStmt:
		if n.Tok == token.GOTO {
			for _, i := range chk {
				if i.use > n.Label.Obj.Decl.(*ast.LabeledStmt).Pos() && i.use < n.Pos() {
					i.use = n.Pos()
				}
			}
		}
	case *ast.FuncDecl:
		if n.Recv != nil {
			for _, id := range n.Recv.List[0].Names {
				chk.info(id)
			}
		}
	case *ast.FuncType:
		if n.Params != nil {
			for _, f := range n.Params.List {
				for _, id := range f.Names {
					chk.info(id)
				}
			}
		}
		if n.Results != nil {
			for _, f := range n.Results.List {
				for _, id := range f.Names {
					chk.info(id).escapes = true
				}
			}
		}
		return nil
	case *ast.Ident:
		i := chk.info(n)
		i.use = n.Pos()
		if i.funclit != nil {
			i.escapes = true
		}
		if i.loop != nil {
			i.use = i.loop.End()
		}
	case *ast.UnaryExpr:
		if id, ok := unparen(n.X).(*ast.Ident); ok && n.Op == token.AND {
			chk.info(id).escapes = true
		}
	case *ast.SelectorExpr:
		// A method call (possibly delayed via a method value) might implicitly take
		// the address of its receiver, causing it to escape.
		// We can't do any better here without knowing the variable's type.
		if id, ok := unparen(n.X).(*ast.Ident); ok {
			chk.info(id).escapes = true
		}
	case *ast.ForStmt:
		walk(chk, n.Init)
		chk.loop(n, true)
		walk(chk, n.Cond)
		walk(chk, n.Post)
		walk(chk, n.Body)
		chk.loop(n, false)
		return nil
	case *ast.RangeStmt:
		walk(chk, n.X)
		chk.loop(n, true)
		if n.Key != nil {
			lhs := []ast.Expr{n.Key}
			if n.Value != nil {
				lhs = append(lhs, n.Value)
			}
			walk(chk, &ast.AssignStmt{Lhs: lhs, Tok: n.Tok, TokPos: n.TokPos, Rhs: []ast.Expr{&ast.Ident{NamePos: n.X.End()}}})
		}
		walk(chk, n.Body)
		chk.loop(n, false)
		return nil
	case *ast.FuncLit:
		walk(chk, n.Type)
		chk.funclit(n, true)
		walk(chk, n.Body)
		chk.funclit(n, false)
		return nil
	}
	return chk
}

func (chk checker) info(id *ast.Ident) *info {
	i := chk[id.Obj]
	if i == nil {
		i = &info{}
		if id.Obj != nil && id.Name != "_" {
			chk[id.Obj] = i
		}
	}
	i.id = id
	return i
}

func (chk checker) loop(loop ast.Node, enter bool) {
	for _, i := range chk {
		if enter && i.loop == nil {
			i.loop = loop
		}
		if !enter && i.loop == loop {
			i.loop = nil
		}
	}
}

func (chk checker) funclit(funclit ast.Node, enter bool) {
	for _, i := range chk {
		if enter && i.funclit == nil {
			i.funclit = funclit
		}
		if !enter && i.funclit == funclit {
			i.funclit = nil
		}
	}
}

func walk(v ast.Visitor, n ast.Node) {
	if n != nil {
		ast.Walk(v, n)
	}
}

func unparen(x ast.Expr) ast.Expr {
	if p, ok := x.(*ast.ParenExpr); ok {
		return unparen(p.X)
	}
	return x
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// The external controller manager is responsible for running controller loops that
// are cloud provider dependent. It uses the API to listen to new events on resources.

package main

import (
	goflag "flag"
	"fmt"
	"math/rand"
	"os"
	"time"

	"k8s.io/component-base/cli/flag"
	"k8s.io/component-base/logs"
	"k8s.io/kubernetes/cmd/cloud-controller-manager/app"
	_ "k8s.io/kubernetes/pkg/util/prometheusclientgo" // for client metric registration
	_ "k8s.io/kubernetes/pkg/version/prometheus"      // for version metric registration

	"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere"
	"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere/loadbalancer"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/klog"
)

// AppName is the full name of this CCM
const AppName string = "vsphere-cloud-controller-manager"

var version string

func main() {
	loadbalancer.Version = version
	loadbalancer.AppName = AppName

	rand.Seed(time.Now().UTC().UnixNano())

	command := app.NewCloudControllerManagerCommand()

	// TODO: once we switch everything over to Cobra commands, we can go back to calling
	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
	// normalize func and add the go flag set by hand.
	pflag.CommandLine.SetNormalizeFunc(flag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	// utilflag.InitFlags()
	logs.InitLogs()
	defer logs.FlushLogs()

	klog.V(1).Infof("vsphere-cloud-controller-manager version: %s", version)

	// Set cloud-provider flag to vsphere
	command.Flags().VisitAll(func(flag *pflag.Flag) {
		if flag.Name == "cloud-provider" {
			flag.Value.Set(vsphere.ProviderName)
			flag.DefValue = vsphere.ProviderName
			return
		}
	})

	var versionFlag *pflag.Value
	var clusterNameFlag *pflag.Value
	pflag.CommandLine.VisitAll(func(flag *pflag.Flag) {
		switch flag.Name {
		case "cluster-name":
			clusterNameFlag = &flag.Value
		case "version":
			versionFlag = &flag.Value
		}
	})

	command.Use = AppName
	innerRun := command.Run
	command.Run = func(cmd *cobra.Command, args []string) {
		if versionFlag != nil && (*versionFlag).String() != "false" {
			fmt.Printf("%s %s\n", AppName, version)
			os.Exit(0)
		}
		if clusterNameFlag != nil {
			loadbalancer.ClusterName = (*clusterNameFlag).String()
		}
		innerRun(cmd, args)
	}

	if err := command.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}
<commit_msg>fix prometheus imports to use k8s.io/component-base<commit_after>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// The external controller manager is responsible for running controller loops that
// are cloud provider dependent. It uses the API to listen to new events on resources.

package main

import (
	goflag "flag"
	"fmt"
	"math/rand"
	"os"
	"time"

	"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere"
	"k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphere/loadbalancer"
	"k8s.io/component-base/cli/flag"
	"k8s.io/component-base/logs"
	_ "k8s.io/component-base/metrics/prometheus/clientgo" // for client metrics registration
	_ "k8s.io/component-base/metrics/prometheus/version"  // for version metric registration
	"k8s.io/kubernetes/cmd/cloud-controller-manager/app"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/klog"
)

// AppName is the full name of this CCM
const AppName string = "vsphere-cloud-controller-manager"

var version string

func main() {
	loadbalancer.Version = version
	loadbalancer.AppName = AppName

	rand.Seed(time.Now().UTC().UnixNano())

	command := app.NewCloudControllerManagerCommand()

	// TODO: once we switch everything over to Cobra commands, we can go back to calling
	// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
	// normalize func and add the go flag set by hand.
	pflag.CommandLine.SetNormalizeFunc(flag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	// utilflag.InitFlags()
	logs.InitLogs()
	defer logs.FlushLogs()

	klog.V(1).Infof("vsphere-cloud-controller-manager version: %s", version)

	// Set cloud-provider flag to vsphere
	command.Flags().VisitAll(func(flag *pflag.Flag) {
		if flag.Name == "cloud-provider" {
			flag.Value.Set(vsphere.ProviderName)
			flag.DefValue = vsphere.ProviderName
			return
		}
	})

	var versionFlag *pflag.Value
	var clusterNameFlag *pflag.Value
	pflag.CommandLine.VisitAll(func(flag *pflag.Flag) {
		switch flag.Name {
		case "cluster-name":
			clusterNameFlag = &flag.Value
		case "version":
			versionFlag = &flag.Value
		}
	})

	command.Use = AppName
	innerRun := command.Run
	command.Run = func(cmd *cobra.Command, args []string) {
		if versionFlag != nil && (*versionFlag).String() != "false" {
			fmt.Printf("%s %s\n", AppName, version)
			os.Exit(0)
		}
		if clusterNameFlag != nil {
			loadbalancer.ClusterName = (*clusterNameFlag).String()
		}
		innerRun(cmd, args)
	}

	if err := command.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"runtime"

	bserrors "github.com/bugsnag/bugsnag-go/errors"
	"github.com/phrase/client-error-proxy/errors"
	"github.com/phrase/phraseapp-go/phraseapp"
)

const DefaultErrorReportingEndpoint = "https://phraseapp-client-errors.herokuapp.com/errors"

func reportError(cliErr *bserrors.Error, cfg *phraseapp.Config) {
	serializableErr := errors.NewFromBugsnagError(cliErr)

	serializableErr.MetaData = errors.MetaData{
		Environment: errors.Environment{
			Arch: runtime.GOARCH,
			OS:   runtime.GOOS,
		},
		Project: errors.Project{
			ID: projectID(cfg),
		},
		User: errors.User{
			AccessToken: abbreviatedToken(cfg),
			Username:    username(cfg),
		},
		Version: errors.Version{
			BuiltAt:                  BUILT_AT,
			Revision:                 REVISION,
			GeneratorRevision:        RevisionGenerator,
			DocRevision:              RevisionDocs,
			LibraryRevision:          LIBRARY_REVISION,
			LibraryGeneratorRevision: phraseapp.RevisionGenerator,
			LibraryDocRevision:       phraseapp.RevisionDocs,
			GoVersion:                runtime.Version(),
		},
	}

	jsonErr, err := json.Marshal(serializableErr)
	if err != nil {
		return
	}

	endpoint := os.Getenv("ERROR_REPORTING_ENDPOINT")
	if endpoint == "" {
		endpoint = DefaultErrorReportingEndpoint
	}

	response, err := http.Post(endpoint, "application/json", bytes.NewBuffer(jsonErr))
	if err != nil {
		return
	}

	response.Body.Close()
}

func projectID(cfg *phraseapp.Config) string {
	if cfg != nil {
		return cfg.DefaultProjectID
	}

	return ""
}

func abbreviatedToken(cfg *phraseapp.Config) string {
	if cfg != nil {
		token := cfg.Credentials.Token
		if len(token) == 64 {
			return token[len(token)-8:]
		}
	}

	return ""
}

func username(cfg *phraseapp.Config) string {
	if cfg != nil {
		return cfg.Credentials.Username
	}

	return ""
}
<commit_msg>update error reporting endpoint (#71)<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"runtime"

	bserrors "github.com/bugsnag/bugsnag-go/errors"
	"github.com/phrase/client-error-proxy/errors"
	"github.com/phrase/phraseapp-go/phraseapp"
)

const DefaultErrorReportingEndpoint = "https://client-errors.phraseapp.io/errors"

func reportError(cliErr *bserrors.Error, cfg *phraseapp.Config) {
	serializableErr := errors.NewFromBugsnagError(cliErr)

	serializableErr.MetaData = errors.MetaData{
		Environment: errors.Environment{
			Arch: runtime.GOARCH,
			OS:   runtime.GOOS,
		},
		Project: errors.Project{
			ID: projectID(cfg),
		},
		User: errors.User{
			AccessToken: abbreviatedToken(cfg),
			Username:    username(cfg),
		},
		Version: errors.Version{
			BuiltAt:                  BUILT_AT,
			Revision:                 REVISION,
			GeneratorRevision:        RevisionGenerator,
			DocRevision:              RevisionDocs,
			LibraryRevision:          LIBRARY_REVISION,
			LibraryGeneratorRevision: phraseapp.RevisionGenerator,
			LibraryDocRevision:       phraseapp.RevisionDocs,
			GoVersion:                runtime.Version(),
		},
	}

	jsonErr, err := json.Marshal(serializableErr)
	if err != nil {
		return
	}

	endpoint := os.Getenv("ERROR_REPORTING_ENDPOINT")
	if endpoint == "" {
		endpoint = DefaultErrorReportingEndpoint
	}

	response, err := http.Post(endpoint, "application/json", bytes.NewBuffer(jsonErr))
	if err != nil {
		return
	}

	response.Body.Close()
}

func projectID(cfg *phraseapp.Config) string {
	if cfg != nil {
		return cfg.DefaultProjectID
	}

	return ""
}

func abbreviatedToken(cfg *phraseapp.Config) string {
	if cfg != nil {
		token := cfg.Credentials.Token
		if len(token) == 64 {
			return token[len(token)-8:]
		}
	}

	return ""
}

func username(cfg *phraseapp.Config) string {
	if cfg != nil {
		return cfg.Credentials.Username
	}

	return ""
}
<|endoftext|>


<commit_before>package engineio

import (
	"bytes"
	"github.com/googollee/go-engine.io/parser"
	"io"
	"sync"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

func TestConnIoutil(t *testing.T) {

	Convey("Reader", t, func() {
		Convey("Normal read", func() {
			r := bytes.NewBufferString("\x34\xe6\xb5\x8b\xe8\xaf\x95")
			decoder, err := parser.NewDecoder(r)
			So(err, ShouldBeNil)

			closeChan := make(chan struct{})
			reader := newConnReader(decoder, closeChan)
			b := make([]byte, 1024)
			n, err := reader.Read(b)
			So(err, ShouldBeNil)
			So(string(b[:n]), ShouldEqual, "测试")
			n, err = reader.Read(b)
			So(err, ShouldEqual, io.EOF)

			Convey("Wait close", func() {
				check := make(chan int)
				go func() {
					err := reader.Close()
					if err != nil {
						t.Fatal(err)
					}
					check <- 1
				}()

				time.Sleep(time.Second / 10) // wait goroutine start
				select {
				case <-check:
					So("should not run here", ShouldEqual, "")
				default:
				}
				<-closeChan
				time.Sleep(time.Second / 10) // wait goroutine end
				select {
				case <-check:
				default:
					So("should not run here", ShouldEqual, "")
				}

				Convey("Close again", func() {
					err := reader.Close()
					So(err, ShouldBeNil)
				})
			})
		})
	})

	Convey("Wrtier", t, func() {

		Convey("Normal write", func() {
			locker := sync.Mutex{}
			w := bytes.NewBuffer(nil)
			locker.Lock()
			writer := newConnWriter(writeCloser{w}, &locker)

			_, err := writer.Write([]byte("abc"))
			So(err, ShouldBeNil)
			So(w.String(), ShouldEqual, "abc")
			writer.Close()
		})

		Convey("Sync", func() {
			locker := sync.Mutex{}
			w1 := bytes.NewBuffer(nil)
			locker.Lock()
			writer1 := newConnWriter(writeCloser{w1}, &locker)
			check := make(chan int)

			go func() {
				w2 := bytes.NewBuffer(nil)
				locker.Lock()
				writer2 := newConnWriter(writeCloser{w2}, &locker)
				defer writer2.Close()
				check <- 1
			}()

			time.Sleep(time.Second / 10)
			select {
			case <-check:
				So("should not run here", ShouldEqual, "")
			default:
			}
			err := writer1.Close()
			So(err, ShouldBeNil)
			time.Sleep(time.Second / 10) // wait goroutine end
			select {
			case <-check:
			default:
				So("should not run here", ShouldEqual, "")
			}

			Convey("Close again", func() {
				err := writer1.Close()
				So(err, ShouldBeNil)
			})
		})

	})

}

type writeCloser struct {
	io.Writer
}

func (w writeCloser) Close() error {
	return nil
}
<commit_msg>remove gl<commit_after>package engineio

import (
	"bytes"
	"github.com/zhouhui8915/engine.io-go/parser"
	"io"
	"sync"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

func TestConnIoutil(t *testing.T) {

	Convey("Reader", t, func() {
		Convey("Normal read", func() {
			r := bytes.NewBufferString("\x34\xe6\xb5\x8b\xe8\xaf\x95")
			decoder, err := parser.NewDecoder(r)
			So(err, ShouldBeNil)

			closeChan := make(chan struct{})
			reader := newConnReader(decoder, closeChan)
			b := make([]byte, 1024)
			n, err := reader.Read(b)
			So(err, ShouldBeNil)
			So(string(b[:n]), ShouldEqual, "测试")
			n, err = reader.Read(b)
			So(err, ShouldEqual, io.EOF)

			Convey("Wait close", func() {
				check := make(chan int)
				go func() {
					err := reader.Close()
					if err != nil {
						t.Fatal(err)
					}
					check <- 1
				}()

				time.Sleep(time.Second / 10) // wait goroutine start
				select {
				case <-check:
					So("should not run here", ShouldEqual, "")
				default:
				}
				<-closeChan
				time.Sleep(time.Second / 10) // wait goroutine end
				select {
				case <-check:
				default:
					So("should not run here", ShouldEqual, "")
				}

				Convey("Close again", func() {
					err := reader.Close()
					So(err, ShouldBeNil)
				})
			})
		})
	})

	Convey("Wrtier", t, func() {

		Convey("Normal write", func() {
			locker := sync.Mutex{}
			w := bytes.NewBuffer(nil)
			locker.Lock()
			writer := newConnWriter(writeCloser{w}, &locker)

			_, err := writer.Write([]byte("abc"))
			So(err, ShouldBeNil)
			So(w.String(), ShouldEqual, "abc")
			writer.Close()
		})

		Convey("Sync", func() {
			locker := sync.Mutex{}
			w1 := bytes.NewBuffer(nil)
			locker.Lock()
			writer1 := newConnWriter(writeCloser{w1}, &locker)
			check := make(chan int)

			go func() {
				w2 := bytes.NewBuffer(nil)
				locker.Lock()
				writer2 := newConnWriter(writeCloser{w2}, &locker)
				defer writer2.Close()
				check <- 1
			}()

			time.Sleep(time.Second / 10)
			select {
			case <-check:
				So("should not run here", ShouldEqual, "")
			default:
			}
			err := writer1.Close()
			So(err, ShouldBeNil)
			time.Sleep(time.Second / 10) // wait goroutine end
			select {
			case <-check:
			default:
				So("should not run here", ShouldEqual, "")
			}

			Convey("Close again", func() {
				err := writer1.Close()
				So(err, ShouldBeNil)
			})
		})

	})

}

type writeCloser struct {
	io.Writer
}

func (w writeCloser) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/mattn/go-uwsgi"
	"path/filepath"
	"net"
	"net/http"
	"os"
	"strings"

)

var server = flag.String("s", "unix:///tmp/uwsgi.sock", "server address")

func main() {
	flag.Parse()

	var l net.Listener
	var e error
	var s string
	if strings.HasPrefix(*server, "unix://") {
		s = (*server)[7:]
		os.Remove(s)
		l, e = net.Listen("unix", s)
		os.Chmod(s, 0666)
	} else if strings.HasPrefix(*server, "tcp://") {
		s = (*server)[6:]
		l, e = net.Listen("tcp", s)
	} else {
		flag.PrintDefaults()
		os.Exit(1)
	}
	if e != nil {
		println(e.Error())
		os.Exit(1)
	}
	root, _ := filepath.Split(os.Args[0])
	root, _ = filepath.Abs(root)
    http.Serve(&uwsgi.Listener{l}, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		script_name := r.Header.Get("SCRIPT_NAME")
		path := r.URL.Path
		if strings.HasPrefix(path, script_name) {
			path = path[len(script_name):]
		}
		file := filepath.Join(root, filepath.FromSlash(path))
		f, e := os.Stat(file)
		if e == nil && f.IsDir() && len(path) > 0 && path[len(path)-1] != '/' {
			w.Header().Set("Location", r.URL.Path + "/")
			w.WriteHeader(http.StatusFound)
			return
		}

		http.ServeFile(w, r, file)
	}))
}
<commit_msg>go fmt.<commit_after>package main

import (
	"flag"
	"github.com/mattn/go-uwsgi"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

var server = flag.String("s", "unix:///tmp/uwsgi.sock", "server address")

func main() {
	flag.Parse()

	var l net.Listener
	var e error
	var s string
	if strings.HasPrefix(*server, "unix://") {
		s = (*server)[7:]
		os.Remove(s)
		l, e = net.Listen("unix", s)
		os.Chmod(s, 0666)
	} else if strings.HasPrefix(*server, "tcp://") {
		s = (*server)[6:]
		l, e = net.Listen("tcp", s)
	} else {
		flag.PrintDefaults()
		os.Exit(1)
	}
	if e != nil {
		println(e.Error())
		os.Exit(1)
	}
	root, _ := filepath.Split(os.Args[0])
	root, _ = filepath.Abs(root)
	http.Serve(&uwsgi.Listener{l}, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		script_name := r.Header.Get("SCRIPT_NAME")
		path := r.URL.Path
		if strings.HasPrefix(path, script_name) {
			path = path[len(script_name):]
		}
		file := filepath.Join(root, filepath.FromSlash(path))
		f, e := os.Stat(file)
		if e == nil && f.IsDir() && len(path) > 0 && path[len(path)-1] != '/' {
			w.Header().Set("Location", r.URL.Path+"/")
			w.WriteHeader(http.StatusFound)
			return
		}

		http.ServeFile(w, r, file)
	}))
}
<|endoftext|>


<commit_before>//go:generate ./xmlrpcgen --file $GOFILE --debug SearchService
package core

import _ "github.com/beevik/etree"

/*
SearchService xml rpc service for searching in database
*/
type SearchService struct {
}

/*
Search service method
 */
func (h *SearchService) Search(query string, page int, isit bool) ([]string, error) {
    return []string{}, nil
}<commit_msg>Renamed package example<commit_after>//go:generate ./xmlrpcgen --file $GOFILE --debug SearchService
package example

import _ "github.com/beevik/etree"

/*
SearchService xml rpc service for searching in database
*/
type SearchService struct {
}

/*
Search service method
 */
func (h *SearchService) Search(query string, page int, isit bool) ([]string, error) {
    return []string{}, nil
}<|endoftext|>


<commit_before>// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.

package gcache

import (
    "gitee.com/johng/gf/g/container/glist"
    "gitee.com/johng/gf/g/container/gset"
    "gitee.com/johng/gf/g/container/gtype"
    "gitee.com/johng/gf/g/os/gtime"
    "gitee.com/johng/gf/g/util/gconv"
    "math"
    "sync"
    "time"
)

// 缓存对象
type memCache struct {
    dataMu       sync.RWMutex
    expireTimeMu sync.RWMutex
    expireSetMu  sync.RWMutex

    cap          int                            // 控制缓存池大小，超过大小则按照LRU算法进行缓存过期处理(默认为0表示不进行限制)
    data         map[interface{}]memCacheItem   // 缓存数据(所有的缓存数据存放哈希表)
    expireTimes  map[interface{}]int64          // 键名对应的分组过期时间(用于相同键名过期时间快速更新)，键值为10秒级时间戳
    expireSets   map[int64]*gset.Set            // 分组过期时间对应的键名列表(用于自动过期快速删除)，键值为10秒级时间戳

    lru          *memCacheLru                   // LRU缓存限制(只有限定cap池大小时才启用)
    lruGetList   *glist.List                    // Get操作的LRU记录
    eventList    *glist.List                    // 异步处理队列
    closed       *gtype.Bool                    // 关闭事件通知
}

// 缓存数据项
type memCacheItem struct {
    v interface{} // 键值
    e int64       // 过期时间
}

// 异步队列数据项
type memCacheEvent struct {
    k interface{} // 键名
    e int64       // 过期时间
}

const (
    // 当数据不过期时，默认设置的过期属性值，相当于：math.MaxInt64/1000000
    gDEFAULT_MAX_EXPIRE = 9223372036854
)

// 创建底层的缓存对象
func newMemCache(lruCap...int) *memCache {
    c := &memCache {
        lruGetList  : glist.New(),
        data        : make(map[interface{}]memCacheItem),
        expireTimes : make(map[interface{}]int64),
        expireSets  : make(map[int64]*gset.Set),
        eventList   : glist.New(),
        closed      : gtype.NewBool(),
    }
    if len(lruCap) > 0 {
        c.cap = lruCap[0]
        c.lru = newMemCacheLru(c)
    }
    return c
}

// 计算过期缓存的键名(将毫秒换算成秒的整数毫秒，按照10秒进行分组)
func (c *memCache) makeExpireKey(expire int64) int64 {
    return int64(math.Ceil(float64(expire/10000) + 1)*10000)
}

// 获取一个过期键名存放Set,如果没有则返回nil
func (c *memCache) getExpireSet(expire int64) (expireSet *gset.Set) {
    c.expireSetMu.RLock()
    expireSet, _ = c.expireSets[expire]
    c.expireSetMu.RUnlock()
    return nil
}

// 获取或者创建一个过期键名存放Set(由于是异步单线程执行，因此不会出现创建set时的覆盖问题)
func (c *memCache) getOrNewExpireSet(expire int64) (expireSet *gset.Set) {
    if expireSet = c.getExpireSet(expire); expireSet == nil {
        expireSet = gset.New()
        c.expireSetMu.Lock()
        // 写锁二次检索确认
        if es, ok := c.expireSets[expire]; ok {
            expireSet = es
        } else {
            c.expireSets[expire] = expireSet
        }
        c.expireSetMu.Unlock()
    }
    return
}

// 设置kv缓存键值对，过期时间单位为毫秒，expire<=0表示不过期
func (c *memCache) Set(key interface{}, value interface{}, expire int) {
    expireTime := c.getInternalExpire(expire)
    c.dataMu.Lock()
    c.data[key] = memCacheItem{v : value, e : expireTime}
    c.dataMu.Unlock()
    c.eventList.PushBack(&memCacheEvent{k : key, e : expireTime})
}

// 设置kv缓存键值对，内部会对键名的存在性使用写锁进行二次检索确认，如果存在则不再写入；返回键名对应的键值。
// 在高并发下有用，防止数据写入的并发逻辑错误。
func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, expire int) interface{} {
    expireTimestamp := c.getInternalExpire(expire)
    c.dataMu.Lock()
    if v, ok := c.data[key]; ok && !v.IsExpired() {
        c.dataMu.Unlock()
        return v.v
    }
    if f, ok := value.(func() interface {}); ok {
        value = f()
    }
    c.data[key] = memCacheItem{v : value, e : expireTimestamp}
    c.dataMu.Unlock()
    c.eventList.PushBack(&memCacheEvent{k : key, e : expireTimestamp})
    return value
}

// 根据给定expire参数计算内部使用的expire过期时间
func (c *memCache) getInternalExpire(expire int) int64 {
    if expire != 0 {
        return gtime.Millisecond() + int64(expire)
    } else {
        return gDEFAULT_MAX_EXPIRE
    }
}

// 当键名不存在时写入，并返回true；否则返回false。
func (c *memCache) SetIfNotExist(key interface{}, value interface{}, expire int) bool {
    if !c.Contains(key) {
        c.doSetWithLockCheck(key, value, expire)
        return true
    }
    return false
}

// 批量设置
func (c *memCache) BatchSet(data map[interface{}]interface{}, expire int) {
    expireTime := c.getInternalExpire(expire)
    for k, v := range data {
        c.dataMu.Lock()
        c.data[k] = memCacheItem{v: v, e: expireTime}
        c.dataMu.Unlock()
        c.eventList.PushBack(&memCacheEvent{k: k, e: expireTime})
    }
}

// 获取指定键名的值
func (c *memCache) Get(key interface{}) interface{} {
    c.dataMu.RLock()
    item, ok := c.data[key]
    c.dataMu.RUnlock()
    if ok && !item.IsExpired() {
        // 增加LRU(Least Recently Used)操作记录
        if c.cap > 0 {
            c.lruGetList.PushBack(key)
        }
        return item.v
    }
    return nil
}

// 当键名存在时返回其键值，否则写入指定的键值
func (c *memCache) GetOrSet(key interface{}, value interface{}, expire int) interface{} {
    if v := c.Get(key); v == nil {
        return c.doSetWithLockCheck(key, value, expire)
    } else {
        return v
    }
}

// 当键名存在时返回其键值，否则写入指定的键值，键值由指定的函数生成
func (c *memCache) GetOrSetFunc(key interface{}, f func() interface{}, expire int) interface{} {
    if v := c.Get(key); v == nil {
        // 可能存在多个goroutine被阻塞在这里，f可能是并发运行
        return c.doSetWithLockCheck(key, f(), expire)
    } else {
        return v
    }
}

// 与GetOrSetFunc不同的是，f是在写锁机制内执行
func (c *memCache) GetOrSetFuncLock(key interface{}, f func() interface{}, expire int) interface{} {
    if v := c.Get(key); v == nil {
        return c.doSetWithLockCheck(key, f, expire)
    } else {
        return v
    }
}

// 是否存在指定的键名，true表示存在，false表示不存在。
func (c *memCache) Contains(key interface{}) bool {
    return c.Get(key) != nil
}

// 删除指定键值对，并返回被删除的键值
func (c *memCache) Remove(key interface{}) (value interface{}) {
    c.dataMu.RLock()
    item, ok := c.data[key]
    c.dataMu.RUnlock()
    if ok {
        value = item.v
        c.dataMu.Lock()
        delete(c.data, key)
        c.dataMu.Unlock()
        c.eventList.PushBack(&memCacheEvent{k: key, e: gtime.Millisecond() - 1000})
    }
    return
}

// 批量删除键值对，并返回被删除的键值对数据
func (c *memCache) BatchRemove(keys []interface{}) {
    for _, key := range keys {
        c.Remove(key)
    }
}

// 返回缓存的所有数据键值对(不包含已过期数据)
func (c *memCache) Data() map[interface{}]interface{} {
    m := make(map[interface{}]interface{})
    c.dataMu.RLock()
    for k, v := range c.data {
        if !v.IsExpired() {
            m[k] = v.v
        }
    }
    c.dataMu.RUnlock()
    return m
}

// 获得所有的键名，组成数组返回
func (c *memCache) Keys() []interface{} {
    keys := make([]interface{}, 0)
    c.dataMu.RLock()
    for k, v := range c.data {
        if !v.IsExpired() {
            keys = append(keys, k)
        }
    }
    c.dataMu.RUnlock()
    return keys
}

// 获得所有的键名，组成字符串数组返回
func (c *memCache) KeyStrings() []string {
    return gconv.Strings(c.Keys())
}

// 获得所有的值，组成数组返回
func (c *memCache) Values() []interface{} {
    values := make([]interface{}, 0)
    c.dataMu.RLock()
    for _, v := range c.data {
        if !v.IsExpired() {
            values = append(values, v.v)
        }
    }
    c.dataMu.RUnlock()
    return values
}

// 获得缓存对象的键值对数量
func (c *memCache) Size() (size int) {
    c.dataMu.RLock()
    size = len(c.data)
    c.dataMu.RUnlock()
    return
}

// 删除缓存对象
func (c *memCache) Close()  {
    if c.cap > 0 {
        c.lru.Close()
    }
    c.closed.Set(true)
}

// 数据异步任务循环:
// 1、将事件列表中的数据异步处理，并同步结果到expireTimes和expireSets属性中；
// 2、清理过期键值对数据；
func (c *memCache) autoLoop() {
    event         := (*memCacheEvent)(nil)
    oldExpireTime := int64(0)
    newExpireTime := int64(0)
    for {
        if c.closed.Val() {
            return
        }
        // ========================
        // 数据同步处理
        // ========================
        for {
            v := c.eventList.PopFront()
            if v == nil {
                break
            }
            event = v.(*memCacheEvent)
            // 获得旧的过期时间分组
            c.expireTimeMu.RLock()
            oldExpireTime = c.expireTimes[event.k]
            c.expireTimeMu.RUnlock()
            // 计算新的过期时间分组
            newExpireTime = c.makeExpireKey(event.e)
            if newExpireTime != oldExpireTime {
                c.getOrNewExpireSet(newExpireTime).Add(event.k)
                if oldExpireTime != 0 {
                    c.getOrNewExpireSet(oldExpireTime).Remove(event.k)
                }
                // 重新设置对应键名的过期时间
                c.expireTimeMu.Lock()
                c.expireTimes[event.k] = newExpireTime
                c.expireTimeMu.Unlock()
            }
            // 写入操作也会增加到LRU(Least Recently Used)操作记录
            if c.cap > 0 {
                c.lru.Push(event.k)
            }
        }
        // 异步处理读取操作的LRU列表
        if c.cap > 0 && c.lruGetList.Len() > 0 {
            for {
                if v := c.lruGetList.PopFront(); v != nil {
                    c.lru.Push(v)
                } else {
                    break
                }
            }
        }
        // ========================
        // 缓存过期处理
        // ========================
        ek := c.makeExpireKey(gtime.Millisecond())
        eks := []int64{ek - 10000, ek - 20000, ek - 30000, ek - 40000, ek - 50000}
        for _, expireTime := range eks {
            if expireSet := c.getExpireSet(expireTime); expireSet != nil {
                // 遍历Set，执行数据过期删除
                expireSet.Iterator(func(key interface{}) bool {
                    return c.clearByKey(key)
                })
                // Set数据处理完之后删除该Set
                c.expireSetMu.Lock()
                delete(c.expireSets, expireTime)
                c.expireSetMu.Unlock()
            }
        }

        // 每间隔1秒批量处理一次
        time.Sleep(time.Second)
    }
}

// 删除对应键名的缓存数据
func (c *memCache) clearByKey(key interface{}, force...bool) bool {
    // 删除缓存数据
    c.dataMu.Lock()
    // 删除核对，真正的过期才删除
    if item, ok := c.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) {
        delete(c.data, key)
    }
    c.dataMu.Unlock()

    // 删除异步处理数据项
    c.expireTimeMu.Lock()
    delete(c.expireTimes, key)
    c.expireTimeMu.Unlock()

    // 删除LRU管理对象中指定键名
    c.lru.Remove(key)

    return true
}
<commit_msg>hot fix for gcache<commit_after>// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.

package gcache

import (
    "gitee.com/johng/gf/g/container/glist"
    "gitee.com/johng/gf/g/container/gset"
    "gitee.com/johng/gf/g/container/gtype"
    "gitee.com/johng/gf/g/os/gtime"
    "gitee.com/johng/gf/g/util/gconv"
    "math"
    "sync"
    "time"
)

// 缓存对象
type memCache struct {
    dataMu       sync.RWMutex
    expireTimeMu sync.RWMutex
    expireSetMu  sync.RWMutex

    cap          int                            // 控制缓存池大小，超过大小则按照LRU算法进行缓存过期处理(默认为0表示不进行限制)
    data         map[interface{}]memCacheItem   // 缓存数据(所有的缓存数据存放哈希表)
    expireTimes  map[interface{}]int64          // 键名对应的分组过期时间(用于相同键名过期时间快速更新)，键值为10秒级时间戳
    expireSets   map[int64]*gset.Set            // 分组过期时间对应的键名列表(用于自动过期快速删除)，键值为10秒级时间戳

    lru          *memCacheLru                   // LRU缓存限制(只有限定cap池大小时才启用)
    lruGetList   *glist.List                    // Get操作的LRU记录
    eventList    *glist.List                    // 异步处理队列
    closed       *gtype.Bool                    // 关闭事件通知
}

// 缓存数据项
type memCacheItem struct {
    v interface{} // 键值
    e int64       // 过期时间
}

// 异步队列数据项
type memCacheEvent struct {
    k interface{} // 键名
    e int64       // 过期时间
}

const (
    // 当数据不过期时，默认设置的过期属性值，相当于：math.MaxInt64/1000000
    gDEFAULT_MAX_EXPIRE = 9223372036854
)

// 创建底层的缓存对象
func newMemCache(lruCap...int) *memCache {
    c := &memCache {
        lruGetList  : glist.New(),
        data        : make(map[interface{}]memCacheItem),
        expireTimes : make(map[interface{}]int64),
        expireSets  : make(map[int64]*gset.Set),
        eventList   : glist.New(),
        closed      : gtype.NewBool(),
    }
    if len(lruCap) > 0 {
        c.cap = lruCap[0]
        c.lru = newMemCacheLru(c)
    }
    return c
}

// 计算过期缓存的键名(将毫秒换算成秒的整数毫秒，按照10秒进行分组)
func (c *memCache) makeExpireKey(expire int64) int64 {
    return int64(math.Ceil(float64(expire/10000) + 1)*10000)
}

// 获取一个过期键名存放Set,如果没有则返回nil
func (c *memCache) getExpireSet(expire int64) (expireSet *gset.Set) {
    c.expireSetMu.RLock()
    expireSet, _ = c.expireSets[expire]
    c.expireSetMu.RUnlock()
    return
}

// 获取或者创建一个过期键名存放Set(由于是异步单线程执行，因此不会出现创建set时的覆盖问题)
func (c *memCache) getOrNewExpireSet(expire int64) (expireSet *gset.Set) {
    if expireSet = c.getExpireSet(expire); expireSet == nil {
        expireSet = gset.New()
        c.expireSetMu.Lock()
        // 写锁二次检索确认
        if es, ok := c.expireSets[expire]; ok {
            expireSet = es
        } else {
            c.expireSets[expire] = expireSet
        }
        c.expireSetMu.Unlock()
    }
    return
}

// 设置kv缓存键值对，过期时间单位为毫秒，expire<=0表示不过期
func (c *memCache) Set(key interface{}, value interface{}, expire int) {
    expireTime := c.getInternalExpire(expire)
    c.dataMu.Lock()
    c.data[key] = memCacheItem{v : value, e : expireTime}
    c.dataMu.Unlock()
    c.eventList.PushBack(&memCacheEvent{k : key, e : expireTime})
}

// 设置kv缓存键值对，内部会对键名的存在性使用写锁进行二次检索确认，如果存在则不再写入；返回键名对应的键值。
// 在高并发下有用，防止数据写入的并发逻辑错误。
func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, expire int) interface{} {
    expireTimestamp := c.getInternalExpire(expire)
    c.dataMu.Lock()
    if v, ok := c.data[key]; ok && !v.IsExpired() {
        c.dataMu.Unlock()
        return v.v
    }
    if f, ok := value.(func() interface {}); ok {
        value = f()
    }
    c.data[key] = memCacheItem{v : value, e : expireTimestamp}
    c.dataMu.Unlock()
    c.eventList.PushBack(&memCacheEvent{k : key, e : expireTimestamp})
    return value
}

// 根据给定expire参数计算内部使用的expire过期时间
func (c *memCache) getInternalExpire(expire int) int64 {
    if expire != 0 {
        return gtime.Millisecond() + int64(expire)
    } else {
        return gDEFAULT_MAX_EXPIRE
    }
}

// 当键名不存在时写入，并返回true；否则返回false。
func (c *memCache) SetIfNotExist(key interface{}, value interface{}, expire int) bool {
    if !c.Contains(key) {
        c.doSetWithLockCheck(key, value, expire)
        return true
    }
    return false
}

// 批量设置
func (c *memCache) BatchSet(data map[interface{}]interface{}, expire int) {
    expireTime := c.getInternalExpire(expire)
    for k, v := range data {
        c.dataMu.Lock()
        c.data[k] = memCacheItem{v: v, e: expireTime}
        c.dataMu.Unlock()
        c.eventList.PushBack(&memCacheEvent{k: k, e: expireTime})
    }
}

// 获取指定键名的值
func (c *memCache) Get(key interface{}) interface{} {
    c.dataMu.RLock()
    item, ok := c.data[key]
    c.dataMu.RUnlock()
    if ok && !item.IsExpired() {
        // 增加LRU(Least Recently Used)操作记录
        if c.cap > 0 {
            c.lruGetList.PushBack(key)
        }
        return item.v
    }
    return nil
}

// 当键名存在时返回其键值，否则写入指定的键值
func (c *memCache) GetOrSet(key interface{}, value interface{}, expire int) interface{} {
    if v := c.Get(key); v == nil {
        return c.doSetWithLockCheck(key, value, expire)
    } else {
        return v
    }
}

// 当键名存在时返回其键值，否则写入指定的键值，键值由指定的函数生成
func (c *memCache) GetOrSetFunc(key interface{}, f func() interface{}, expire int) interface{} {
    if v := c.Get(key); v == nil {
        // 可能存在多个goroutine被阻塞在这里，f可能是并发运行
        return c.doSetWithLockCheck(key, f(), expire)
    } else {
        return v
    }
}

// 与GetOrSetFunc不同的是，f是在写锁机制内执行
func (c *memCache) GetOrSetFuncLock(key interface{}, f func() interface{}, expire int) interface{} {
    if v := c.Get(key); v == nil {
        return c.doSetWithLockCheck(key, f, expire)
    } else {
        return v
    }
}

// 是否存在指定的键名，true表示存在，false表示不存在。
func (c *memCache) Contains(key interface{}) bool {
    return c.Get(key) != nil
}

// 删除指定键值对，并返回被删除的键值
func (c *memCache) Remove(key interface{}) (value interface{}) {
    c.dataMu.RLock()
    item, ok := c.data[key]
    c.dataMu.RUnlock()
    if ok {
        value = item.v
        c.dataMu.Lock()
        delete(c.data, key)
        c.dataMu.Unlock()
        c.eventList.PushBack(&memCacheEvent{k: key, e: gtime.Millisecond() - 1000})
    }
    return
}

// 批量删除键值对，并返回被删除的键值对数据
func (c *memCache) BatchRemove(keys []interface{}) {
    for _, key := range keys {
        c.Remove(key)
    }
}

// 返回缓存的所有数据键值对(不包含已过期数据)
func (c *memCache) Data() map[interface{}]interface{} {
    m := make(map[interface{}]interface{})
    c.dataMu.RLock()
    for k, v := range c.data {
        if !v.IsExpired() {
            m[k] = v.v
        }
    }
    c.dataMu.RUnlock()
    return m
}

// 获得所有的键名，组成数组返回
func (c *memCache) Keys() []interface{} {
    keys := make([]interface{}, 0)
    c.dataMu.RLock()
    for k, v := range c.data {
        if !v.IsExpired() {
            keys = append(keys, k)
        }
    }
    c.dataMu.RUnlock()
    return keys
}

// 获得所有的键名，组成字符串数组返回
func (c *memCache) KeyStrings() []string {
    return gconv.Strings(c.Keys())
}

// 获得所有的值，组成数组返回
func (c *memCache) Values() []interface{} {
    values := make([]interface{}, 0)
    c.dataMu.RLock()
    for _, v := range c.data {
        if !v.IsExpired() {
            values = append(values, v.v)
        }
    }
    c.dataMu.RUnlock()
    return values
}

// 获得缓存对象的键值对数量
func (c *memCache) Size() (size int) {
    c.dataMu.RLock()
    size = len(c.data)
    c.dataMu.RUnlock()
    return
}

// 删除缓存对象
func (c *memCache) Close()  {
    if c.cap > 0 {
        c.lru.Close()
    }
    c.closed.Set(true)
}

// 数据异步任务循环:
// 1、将事件列表中的数据异步处理，并同步结果到expireTimes和expireSets属性中；
// 2、清理过期键值对数据；
func (c *memCache) autoLoop() {
    event         := (*memCacheEvent)(nil)
    oldExpireTime := int64(0)
    newExpireTime := int64(0)
    for {
        if c.closed.Val() {
            return
        }
        // ========================
        // 数据同步处理
        // ========================
        for {
            v := c.eventList.PopFront()
            if v == nil {
                break
            }
            event = v.(*memCacheEvent)
            // 获得旧的过期时间分组
            c.expireTimeMu.RLock()
            oldExpireTime = c.expireTimes[event.k]
            c.expireTimeMu.RUnlock()
            // 计算新的过期时间分组
            newExpireTime = c.makeExpireKey(event.e)
            if newExpireTime != oldExpireTime {
                c.getOrNewExpireSet(newExpireTime).Add(event.k)
                if oldExpireTime != 0 {
                    c.getOrNewExpireSet(oldExpireTime).Remove(event.k)
                }
                // 重新设置对应键名的过期时间
                c.expireTimeMu.Lock()
                c.expireTimes[event.k] = newExpireTime
                c.expireTimeMu.Unlock()
            }
            // 写入操作也会增加到LRU(Least Recently Used)操作记录
            if c.cap > 0 {
                c.lru.Push(event.k)
            }
        }
        // 异步处理读取操作的LRU列表
        if c.cap > 0 && c.lruGetList.Len() > 0 {
            for {
                if v := c.lruGetList.PopFront(); v != nil {
                    c.lru.Push(v)
                } else {
                    break
                }
            }
        }
        // ========================
        // 缓存过期处理
        // ========================
        ek := c.makeExpireKey(gtime.Millisecond())
        eks := []int64{ek - 10000, ek - 20000, ek - 30000, ek - 40000, ek - 50000}
        for _, expireTime := range eks {
            if expireSet := c.getExpireSet(expireTime); expireSet != nil {
                // 遍历Set，执行数据过期删除
                expireSet.Iterator(func(key interface{}) bool {
                    return c.clearByKey(key)
                })
                // Set数据处理完之后删除该Set
                c.expireSetMu.Lock()
                delete(c.expireSets, expireTime)
                c.expireSetMu.Unlock()
            }
        }

        // 每间隔1秒批量处理一次
        time.Sleep(time.Second)
    }
}

// 删除对应键名的缓存数据
func (c *memCache) clearByKey(key interface{}, force...bool) bool {
    // 删除缓存数据
    c.dataMu.Lock()
    // 删除核对，真正的过期才删除
    if item, ok := c.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) {
        delete(c.data, key)
    }
    c.dataMu.Unlock()

    // 删除异步处理数据项
    c.expireTimeMu.Lock()
    delete(c.expireTimes, key)
    c.expireTimeMu.Unlock()

    // 删除LRU管理对象中指定键名
    c.lru.Remove(key)

    return true
}
<|endoftext|>


<commit_before>// written by Daniel Oaks <daniel@danieloaks.net>
// released under the ISC license

package ircmsg

import "bytes"
import "strings"

var (
	// valtoescape replaces real characters with message tag escapes.
	valtoescape = strings.NewReplacer("\\", "\\\\", ";", "\\:", " ", "\\s", "\r", "\\r", "\n", "\\n")

	escapedCharLookupTable [256]byte
)

func init() {
	// most chars escape to themselves
	for i := 0; i < 256; i += 1 {
		escapedCharLookupTable[i] = byte(i)
	}
	// these are the exceptions
	escapedCharLookupTable[':'] = ';'
	escapedCharLookupTable['s'] = ' '
	escapedCharLookupTable['r'] = '\r'
	escapedCharLookupTable['n'] = '\n'
}

// EscapeTagValue takes a value, and returns an escaped message tag value.
//
// This function is automatically used when lines are created from an
// IrcMessage, so you don't need to call it yourself before creating a line.
func EscapeTagValue(inString string) string {
	return valtoescape.Replace(inString)
}

// UnescapeTagValue takes an escaped message tag value, and returns the raw value.
//
// This function is automatically used when lines are interpreted by ParseLine,
// so you don't need to call it yourself after parsing a line.
func UnescapeTagValue(inString string) string {
	// buf.Len() == 0 is the fastpath where we have not needed to unescape any chars
	var buf bytes.Buffer
	remainder := inString
	for {
		backslashPos := strings.IndexByte(remainder, '\\')

		if backslashPos == -1 {
			if buf.Len() == 0 {
				return inString
			} else {
				buf.WriteString(remainder)
				break
			}
		} else if backslashPos == len(remainder)-1 {
			// trailing backslash, which we strip
			if buf.Len() == 0 {
				return inString[:len(inString)-1]
			} else {
				buf.WriteString(remainder[:len(remainder)-1])
				break
			}
		}

		// non-trailing backslash detected; we're now on the slowpath
		// where we modify the string
		if buf.Len() == 0 {
			buf.Grow(len(inString)) // just an optimization
		}
		buf.WriteString(remainder[:backslashPos])
		buf.WriteByte(escapedCharLookupTable[remainder[backslashPos+1]])
		remainder = remainder[backslashPos+2:]
	}

	return buf.String()
}

func validateTagName(name string) bool {
	if len(name) == 0 {
		return false
	}
	if name[0] == '+' {
		name = name[1:]
	}
	if len(name) == 0 {
		return false
	}
	// let's err on the side of leniency here; allow -./ (45-47) in any position
	for i := 0; i < len(name); i++ {
		c := name[i]
		if !(('-' <= c && c <= '/') || ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) {
			return false
		}
	}
	return true
}
<commit_msg>use strings.Builder for tag unescaping<commit_after>// written by Daniel Oaks <daniel@danieloaks.net>
// released under the ISC license

package ircmsg

import "strings"

var (
	// valtoescape replaces real characters with message tag escapes.
	valtoescape = strings.NewReplacer("\\", "\\\\", ";", "\\:", " ", "\\s", "\r", "\\r", "\n", "\\n")

	escapedCharLookupTable [256]byte
)

func init() {
	// most chars escape to themselves
	for i := 0; i < 256; i += 1 {
		escapedCharLookupTable[i] = byte(i)
	}
	// these are the exceptions
	escapedCharLookupTable[':'] = ';'
	escapedCharLookupTable['s'] = ' '
	escapedCharLookupTable['r'] = '\r'
	escapedCharLookupTable['n'] = '\n'
}

// EscapeTagValue takes a value, and returns an escaped message tag value.
//
// This function is automatically used when lines are created from an
// IrcMessage, so you don't need to call it yourself before creating a line.
func EscapeTagValue(inString string) string {
	return valtoescape.Replace(inString)
}

// UnescapeTagValue takes an escaped message tag value, and returns the raw value.
//
// This function is automatically used when lines are interpreted by ParseLine,
// so you don't need to call it yourself after parsing a line.
func UnescapeTagValue(inString string) string {
	// buf.Len() == 0 is the fastpath where we have not needed to unescape any chars
	var buf strings.Builder
	remainder := inString
	for {
		backslashPos := strings.IndexByte(remainder, '\\')

		if backslashPos == -1 {
			if buf.Len() == 0 {
				return inString
			} else {
				buf.WriteString(remainder)
				break
			}
		} else if backslashPos == len(remainder)-1 {
			// trailing backslash, which we strip
			if buf.Len() == 0 {
				return inString[:len(inString)-1]
			} else {
				buf.WriteString(remainder[:len(remainder)-1])
				break
			}
		}

		// non-trailing backslash detected; we're now on the slowpath
		// where we modify the string
		if buf.Len() == 0 {
			buf.Grow(len(inString)) // just an optimization
		}
		buf.WriteString(remainder[:backslashPos])
		buf.WriteByte(escapedCharLookupTable[remainder[backslashPos+1]])
		remainder = remainder[backslashPos+2:]
	}

	return buf.String()
}

func validateTagName(name string) bool {
	if len(name) == 0 {
		return false
	}
	if name[0] == '+' {
		name = name[1:]
	}
	if len(name) == 0 {
		return false
	}
	// let's err on the side of leniency here; allow -./ (45-47) in any position
	for i := 0; i < len(name); i++ {
		c := name[i]
		if !(('-' <= c && c <= '/') || ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	e "github.com/dzlab/elastic-go"
	t "time"
)

func chap33() {
	c := &e.Elasticsearch{Addr: "localhost:9200"}

	// use cardinality to approximate count of uniquer values
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("distinct_colors").AddMetric(e.Cardiality, e.Field, "color")).Get()
	// a more interesting question: how many colors were sold each month
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("months").AddDict(e.DateHistogram, e.Dict{e.Field: "sold", e.Interval: "month"}).AddBucket(e.NewBucket("distinct_colors").AddMetric(e.Cardiality, e.Field, "color"))).Get()

	// configure the cardinaility HuperLogLog (HLL) algorithm
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("distinct_colors").AddDict(e.Cardiality, e.Dict{e.Field: "color", e.PrecisionThreshold: 100})).Get()

	// calculte hashes for HLL at index time for speedup
	c.Index("cars").Delete()
	c.Index("cars").Mappings("transactions", e.NewMapping().AddField("color", e.Dict{e.Type: "string", "fields": e.Dict{"hash": e.Dict{e.Type: "murmur3"}}})).Put()
	c.Bulk("cars", "transactions").AddOperation(e.NewOperation(1).Add("price", 10000).Add("color", "red").Add("make", "honda").Add("sold", "2014-10-28")).AddOperation(e.NewOperation(2).Add("price", 20000).Add("color", "red").Add("make", "honda").Add("sold", "2014-11-05")).AddOperation(e.NewOperation(3).Add("price", 30000).Add("color", "green").Add("make", "ford").Add("sold", "2014-05-18")).AddOperation(e.NewOperation(4).Add("price", 15000).Add("color", "blue").Add("make", "toyota").Add("sold", "2014-07-02")).AddOperation(e.NewOperation(5).Add("price", 12000).Add("color", "green").Add("make", "toyota").Add("sold", "2014-08-19")).AddOperation(e.NewOperation(6).Add("price", 20000).Add("color", "red").Add("make", "honda").Add("sold", "2014-11-05")).AddOperation(e.NewOperation(7).Add("price", 80000).Add("color", "red").Add("make", "bmw").Add("sold", "2014-01-01")).AddOperation(e.NewOperation(8).Add("price", 25000).Add("color", "blue").Add("make", "ford").Add("sold", "2014-02-12")).Post()
	// cardinality aggregtion on the hashed field
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("distinct_colors").AddMetric(e.Cardiality, e.Field, "color.hash")).Get()

	// percentile metric
	c.Index("website").Delete()
	c.Bulk("website", "logs").AddOperation(e.NewOperation(1).Add("latency", 100).Add("zone", "US").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(2).Add("latency", 80).Add("zone", "US").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(3).Add("latency", 99).Add("zone", "US").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(4).Add("latency", 102).Add("zone", "US").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(5).Add("latency", 75).Add("zone", "US").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(6).Add("latency", 82).Add("zone", "US").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(7).Add("latency", 100).Add("zone", "EU").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(8).Add("latency", 280).Add("zone", "EU").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(9).Add("latency", 155).Add("zone", "EU").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(10).Add("latency", 623).Add("zone", "EU").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(11).Add("latency", 380).Add("zone", "EU").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(12).Add("latency", 319).Add("zone", "EU").Add("timestamp", "2014-10-29")).Post()

	t.Sleep(1 * t.Second)

	// run percentile to get an array of predefined percentiles
	c.Aggs("website", "logs").SetMetric(e.Count).Add(e.NewBucket("load_times").AddMetric(e.Percentiles, e.Field, "latency")).Add(e.NewBucket("avg_load_time").AddMetric(e.Avg, e.Field, "latency")).Get()
	// let see if this is corelated with the geographic locations
	c.Aggs("website", "logs").SetMetric(e.Count).Add(e.NewBucket("zones").AddTerm(e.Field, "zone").AddBucket(e.NewBucket("load_times").AddDict(e.Percentiles, e.Dict{e.Field: "latency", e.Percents: []float32{50, 95.0, 99.0}})).AddBucket(e.NewBucket("load_avg").AddMetric(e.Avg, e.Field, "latency"))).Get()

	// use percentile_metric to find the percentile corresponding to 200 ms
	c.Aggs("website", "logs").SetMetric(e.Count).Add(e.NewBucket("zones").AddTerm(e.Field, "zone").AddBucket(e.NewBucket("load_times").AddDict(e.PercentileRanks, e.Dict{e.Field: "latency", e.Values: []int{210, 800}}))).Get()
}
<commit_msg>added comment to describe example<commit_after>package main

import (
	e "github.com/dzlab/elastic-go"
	t "time"
)

// chap33 examples from chapter 33 of Elasticsearch the Definitive Guide. It's about approximation algorithms: cardinality, percentiles.
func chap33() {
	c := &e.Elasticsearch{Addr: "localhost:9200"}

	// use cardinality to approximate count of uniquer values
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("distinct_colors").AddMetric(e.Cardiality, e.Field, "color")).Get()
	// a more interesting question: how many colors were sold each month
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("months").AddDict(e.DateHistogram, e.Dict{e.Field: "sold", e.Interval: "month"}).AddBucket(e.NewBucket("distinct_colors").AddMetric(e.Cardiality, e.Field, "color"))).Get()

	// configure the cardinaility HuperLogLog (HLL) algorithm
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("distinct_colors").AddDict(e.Cardiality, e.Dict{e.Field: "color", e.PrecisionThreshold: 100})).Get()

	// calculte hashes for HLL at index time for speedup
	c.Index("cars").Delete()
	c.Index("cars").Mappings("transactions", e.NewMapping().AddField("color", e.Dict{e.Type: "string", "fields": e.Dict{"hash": e.Dict{e.Type: "murmur3"}}})).Put()
	c.Bulk("cars", "transactions").AddOperation(e.NewOperation(1).Add("price", 10000).Add("color", "red").Add("make", "honda").Add("sold", "2014-10-28")).AddOperation(e.NewOperation(2).Add("price", 20000).Add("color", "red").Add("make", "honda").Add("sold", "2014-11-05")).AddOperation(e.NewOperation(3).Add("price", 30000).Add("color", "green").Add("make", "ford").Add("sold", "2014-05-18")).AddOperation(e.NewOperation(4).Add("price", 15000).Add("color", "blue").Add("make", "toyota").Add("sold", "2014-07-02")).AddOperation(e.NewOperation(5).Add("price", 12000).Add("color", "green").Add("make", "toyota").Add("sold", "2014-08-19")).AddOperation(e.NewOperation(6).Add("price", 20000).Add("color", "red").Add("make", "honda").Add("sold", "2014-11-05")).AddOperation(e.NewOperation(7).Add("price", 80000).Add("color", "red").Add("make", "bmw").Add("sold", "2014-01-01")).AddOperation(e.NewOperation(8).Add("price", 25000).Add("color", "blue").Add("make", "ford").Add("sold", "2014-02-12")).Post()
	// cardinality aggregtion on the hashed field
	c.Aggs("cars", "transactions").SetMetric(e.Count).Add(e.NewBucket("distinct_colors").AddMetric(e.Cardiality, e.Field, "color.hash")).Get()

	// percentile metric
	c.Index("website").Delete()
	c.Bulk("website", "logs").AddOperation(e.NewOperation(1).Add("latency", 100).Add("zone", "US").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(2).Add("latency", 80).Add("zone", "US").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(3).Add("latency", 99).Add("zone", "US").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(4).Add("latency", 102).Add("zone", "US").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(5).Add("latency", 75).Add("zone", "US").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(6).Add("latency", 82).Add("zone", "US").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(7).Add("latency", 100).Add("zone", "EU").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(8).Add("latency", 280).Add("zone", "EU").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(9).Add("latency", 155).Add("zone", "EU").Add("timestamp", "2014-10-29")).AddOperation(e.NewOperation(10).Add("latency", 623).Add("zone", "EU").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(11).Add("latency", 380).Add("zone", "EU").Add("timestamp", "2014-10-28")).AddOperation(e.NewOperation(12).Add("latency", 319).Add("zone", "EU").Add("timestamp", "2014-10-29")).Post()

	t.Sleep(1 * t.Second)

	// run percentile to get an array of predefined percentiles
	c.Aggs("website", "logs").SetMetric(e.Count).Add(e.NewBucket("load_times").AddMetric(e.Percentiles, e.Field, "latency")).Add(e.NewBucket("avg_load_time").AddMetric(e.Avg, e.Field, "latency")).Get()
	// let see if this is corelated with the geographic locations
	c.Aggs("website", "logs").SetMetric(e.Count).Add(e.NewBucket("zones").AddTerm(e.Field, "zone").AddBucket(e.NewBucket("load_times").AddDict(e.Percentiles, e.Dict{e.Field: "latency", e.Percents: []float32{50, 95.0, 99.0}})).AddBucket(e.NewBucket("load_avg").AddMetric(e.Avg, e.Field, "latency"))).Get()

	// use percentile_metric to find the percentile corresponding to 200 ms
	c.Aggs("website", "logs").SetMetric(e.Count).Add(e.NewBucket("zones").AddTerm(e.Field, "zone").AddBucket(e.NewBucket("load_times").AddDict(e.PercentileRanks, e.Dict{e.Field: "latency", e.Values: []int{210, 800}}))).Get()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/rdwilliamson/snippets"

	cl "github.com/rdwilliamson/cl11"
	"github.com/rdwilliamson/cl11/examples/utils"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

var kernel = `
__kernel void reduce(__global float* data, int size)
{
	if (get_global_id(0) < size) {
		data[get_global_id(0)] += 1;
	}
}
`

func main() {

	platforms, err := cl.GetPlatforms()
	check(err)
	for _, p := range platforms {
		devices, err := p.GetDevices()
		check(err)
		for _, d := range devices {

			c, err := cl.CreateContext([]*cl.Device{d}, cl.ContextProperties{}, nil)
			check(err)

			progam, err := c.CreateProgramWithSource([][]byte{[]byte(kernel)})
			check(err)

			err = progam.Build([]*cl.Device{d}, "")
			check(err)

			kernel, err := progam.CreateKernel("reduce")
			check(err)

			size := 256 * 1024 * 1024 / 4
			if size > int(d.MaxMemAllocSize) {
				size = int(d.MaxMemAllocSize)
			}
			values := utils.RandomFloat32(size)

			data, err := c.CreateDeviceBufferInitializedBy(cl.MemoryReadOnly, values)
			check(err)

			var resultMem [4]byte
			_, err = c.CreateDeviceBufferFromHostMemory(cl.MemoryWriteOnly, resultMem[:])
			check(err)

			err = kernel.SetArgument(0, data)
			check(err)
			err = kernel.SetArgument(1, size)
			check(err)

			cq, err := c.CreateCommandQueue(d, cl.QueueProfilingEnable)
			check(err)

			if size%int(d.MaxWorkGroupSize) > 0 {
				size = (size/int(d.MaxWorkGroupSize) + 1) * int(d.MaxWorkGroupSize)
			}
			globalSize := []int{size}
			localSize := []int{int(d.MaxWorkGroupSize)}

			var event cl.Event
			err = cq.EnqueueNDRangeKernel(kernel, nil, globalSize, localSize, nil, &event)
			check(err)

			check(event.Wait())

			check(event.GetProfilingInfo())

			fmt.Println(d.Name, time.Duration(event.End-event.Start), snippets.PrintBytes(int64(size*4)))
		}
	}
}
<commit_msg>Fixed run errors.<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/rdwilliamson/snippets"

	cl "github.com/rdwilliamson/cl11"
	"github.com/rdwilliamson/cl11/examples/utils"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

var kernel = `
__kernel void reduce(__global float* data, int size)
{
	if (get_global_id(0) < size) {
		data[get_global_id(0)] += 1;
	}
}
`

func main() {

	platforms, err := cl.GetPlatforms()
	check(err)
	for _, p := range platforms {
		devices, err := p.GetDevices()
		check(err)
		for _, d := range devices {

			c, err := cl.CreateContext([]*cl.Device{d}, cl.ContextProperties{}, nil)
			check(err)

			progam, err := c.CreateProgramWithSource([][]byte{[]byte(kernel)})
			check(err)

			err = progam.Build([]*cl.Device{d}, "")
			check(err)

			kernel, err := progam.CreateKernel("reduce")
			check(err)

			size := 256 * 1024 * 1024 / 4
			if size*4 > int(d.MaxMemAllocSize) {
				size = int(d.MaxMemAllocSize) / 4
			}
			values := utils.RandomFloat32(size)

			data, err := c.CreateDeviceBufferInitializedBy(cl.MemoryReadOnly, values)
			check(err)

			var resultMem [4]byte
			_, err = c.CreateDeviceBufferFromHostMemory(cl.MemoryWriteOnly, resultMem[:])
			check(err)

			err = kernel.SetArgument(0, data)
			check(err)
			err = kernel.SetArgument(1, size)
			check(err)

			cq, err := c.CreateCommandQueue(d, cl.QueueProfilingEnable)
			check(err)

			localSize := kernel.WorkGroupInfo[0].PreferredWorkGroupSizeMultiple
			globalSize := size
			if size%localSize > 0 {
				globalSize = (globalSize/localSize + 1) * localSize
			}

			var event cl.Event
			err = cq.EnqueueNDRangeKernel(kernel, nil, []int{globalSize}, []int{localSize}, nil, &event)
			check(err)

			check(event.Wait())

			check(event.GetProfilingInfo())

			fmt.Println(d.Name, time.Duration(event.End-event.Start), snippets.PrintBytes(int64(size*4)))
		}
	}
}
<|endoftext|>


<commit_before>package egoscale

// API represents an API service
type API struct {
	Description string     `json:"description,omitempty" doc:"description of the api"`
	IsAsync     bool       `json:"isasync,omitempty" doc:"true if api is asynchronous"`
	Name        string     `json:"name,omitempty" doc:"the name of the api command"`
	Related     string     `json:"related,omitempty" doc:"comma separated related apis"`
	Since       string     `json:"since,omitempty" doc:"version of CloudStack the api was introduced in"`
	Type        string     `json:"type,omitempty" doc:"response field type"`
	Params      []APIParam `json:"params,omitempty" doc:"the list params the api accepts"`
	Response    []APIField `json:"response,omitempty" doc:"api response fields"`
}

// APIParam represents an API parameter field
type APIParam struct {
	Description string `json:"description"`
	Length      int64  `json:"length"`
	Name        string `json:"name"`
	Required    bool   `json:"required"`
	Since       string `json:"since,omitempty"`
	Type        string `json:"type"`
}

// APIField represents an API response field
type APIField struct {
	Description string     `json:"description"`
	Name        string     `json:"name"`
	Response    []APIField `json:"response,omitempty"`
	Type        string     `json:"type"`
}

// ListAPIs represents a query to list the api
type ListAPIs struct {
	Name string `json:"name,omitempty" doc:"API name"`
	_    bool   `name:"listApis" description:"lists all available apis on the server"`
}

// ListAPIsResponse represents a list of API
type ListAPIsResponse struct {
	Count int   `json:"count"`
	API   []API `json:"api"`
}

// Response returns the struct to unmarshal
func (*ListAPIs) Response() interface{} {
	return new(ListAPIsResponse)
}
<commit_msg>apis: listApis to always show isasync (#374)<commit_after>package egoscale

// API represents an API service
type API struct {
	Description string     `json:"description,omitempty" doc:"description of the api"`
	IsAsync     bool       `json:"isasync" doc:"true if api is asynchronous"`
	Name        string     `json:"name,omitempty" doc:"the name of the api command"`
	Related     string     `json:"related,omitempty" doc:"comma separated related apis"`
	Since       string     `json:"since,omitempty" doc:"version of CloudStack the api was introduced in"`
	Type        string     `json:"type,omitempty" doc:"response field type"`
	Params      []APIParam `json:"params,omitempty" doc:"the list params the api accepts"`
	Response    []APIField `json:"response,omitempty" doc:"api response fields"`
}

// APIParam represents an API parameter field
type APIParam struct {
	Description string `json:"description"`
	Length      int64  `json:"length"`
	Name        string `json:"name"`
	Required    bool   `json:"required"`
	Since       string `json:"since,omitempty"`
	Type        string `json:"type"`
}

// APIField represents an API response field
type APIField struct {
	Description string     `json:"description"`
	Name        string     `json:"name"`
	Response    []APIField `json:"response,omitempty"`
	Type        string     `json:"type"`
}

// ListAPIs represents a query to list the api
type ListAPIs struct {
	Name string `json:"name,omitempty" doc:"API name"`
	_    bool   `name:"listApis" description:"lists all available apis on the server"`
}

// ListAPIsResponse represents a list of API
type ListAPIsResponse struct {
	Count int   `json:"count"`
	API   []API `json:"api"`
}

// Response returns the struct to unmarshal
func (*ListAPIs) Response() interface{} {
	return new(ListAPIsResponse)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"os/exec"
)

func main() {
	if len(os.Args) < 3 {
		fmt.Fprintln(os.Stderr, "Usage: aroc DIRECTORY COMMAND [ARGS…]")
		os.Exit(1)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Watch(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}

	var cmd *exec.Cmd

	go func() {
		for {
			select {
			case _ = <-watcher.Event:
				log.Println("Changes in directory, restarting")
				cmd.Process.Signal(os.Interrupt)
			case err := <-watcher.Error:
				log.Fatal("error:", err)
			}
		}
	}()

	for {
		cmd = exec.Command(os.Args[2])
		cmd.Args = os.Args[2:]
		cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
		err := cmd.Run()
		if err != nil {
			if err, ok := err.(*exec.ExitError); !ok {
				log.Fatal(err)
			}
		}
	}
}
<commit_msg>Switch from fsnotify to fsevents<commit_after>package main

import (
	"fmt"
	"github.com/sdegutis/go.fsevents"
	"log"
	"os"
	"os/exec"
)

func main() {
	if len(os.Args) < 3 {
		fmt.Fprintln(os.Stderr, "Usage: aroc DIRECTORY COMMAND [ARGS…]")
		os.Exit(1)
	}

	ch := fsevents.WatchPaths([]string{os.Args[1]})

	var cmd *exec.Cmd

	go func() {
		for _ = range ch {
			log.Println("Changes in directory, restarting")
			cmd.Process.Signal(os.Interrupt)
		}
	}()

	for {
		cmd = exec.Command(os.Args[2])
		cmd.Args = os.Args[2:]
		cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
		err := cmd.Run()
		if err != nil {
			if err, ok := err.(*exec.ExitError); !ok {
				log.Fatal(err)
			}
		}
	}
}
<|endoftext|>