<commit_before>/*
Package jsonware has a middleware setup for doing RESTful reqeuests with net/http.
It makes it easy to unobtrusively serialize and deserialize json in a type safe
manner, and handle errors from the internal handlers including logging.
*/
package jsonware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strings"
)

var globalLogger io.Writer

// Log sets the global logger for cloaked errors. Not safe for use by multiple
// goroutines, do this before your http server has been started.
func Log(logger io.Writer) {
	globalLogger = logger
}

/*
JSONHandler handles json api endpoint restful requests. It can be constructed
by passing a suitable function into the JSON function.

Error handling is handled differently depending on whether or not Err was
used to report the error. See Err documentation to understand how to control
error handling.

Cloaked errors are handled by reporting a generic error to the client and
logging the error locally. The log can be set globally via jsonware.Log() or
on each individual handler as an override by the .Log() function there.

	// Register a JSONHandler.
	http.Handle("/", Handler(myHandler).Log(myLogger))
*/
type JSONHandler struct {
	logger io.Writer
	fn     reflect.Value
	in     reflect.Type
}

// Log sets the JSONHandler's logging io.Writer for writing out cloaked errors.
func (j *JSONHandler) Log(logger io.Writer) *JSONHandler {
	j.logger = logger
	return j
}

/*
Err can be used in a JSONHandler to override the error mechanism in
JSONHandler's ServeHTTP method. If a status is set it will obey it,
otherwise it will assume 200 OK. The error message will be relayed to the
client. If you wish to use a general server error, simply return error from
the handler.

	func handler(w http.ResponseWriter, r *http.Request) {
		return nil, nil // No response from ServeHTTP, use w to create one.
	}

	func handler(w http.ResponseWriter, r *http.Request) {
		return nil, errors.New("hi") // 500 Response with cloaked+logged error.
	}

	func handler(w http.ResponseWriter, r *http.Request) {
		return nil, Err{Err: errors.New("hi")} // 200 Response with error output to client
	}

	func handler(w http.ResponseWriter, r *http.Request) {
		return nil, Err{Status: 400, Err: errors.New("hi")} // 400 Response with error output to client
	}

	func handler(w http.ResponseWriter, r *http.Request) {
		return nil, Err{
			Status: 400,
			Err: errors.New("hi")
			Reason: []string{"anything", "serializable", "to", "json"},
		} // 400 Response with error output to client
	}
*/
type Err struct {
	Status int
	Err    error
	Reason interface{}
}

// Error returns Error() from the internal error.
func (e Err) Error() string {
	return e.Err.Error()
}

// ServeHTTP serves an http response, see JSONHandler documentation for details.
func (j JSONHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Ensure request accepts json
	ah := r.Header.Get("Accept")
	if !strings.Contains(ah, "*/*") && !strings.Contains(ah, "application/json") {
		w.Header().Set("Content-Type", "text/plain")
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, "this endpoint only responds to json-accepting clients")
		return
	}

	w.Header().Set("Content-Type", "application/json")

	// Ensure request follows REST principles.
	deserialize := j.fn.Type().NumIn() == 3
	switch {
	case deserialize && !isDataMethod(r.Method):
		fallthrough
	case !deserialize && isDataMethod(r.Method):
		writeError(w, j.logger, Err{
			Status: http.StatusBadRequest,
			Err:    fmt.Errorf("invalid http method to this endpoint: %s", r.Method),
		})
		return
	}

	// Set up arguments for handler call.
	in := []reflect.Value{
		reflect.ValueOf(w), reflect.ValueOf(r),
	}
	var deserializeTo reflect.Value
	if deserialize {
		switch j.in.Kind() {
		case reflect.Slice, reflect.Map:
			deserializeTo = reflect.New(j.in)
			in = append(in, deserializeTo.Elem())
		case reflect.Ptr:
			deserializeTo = reflect.New(j.in.Elem())
			in = append(in, deserializeTo)
		}
	}

	// Do json deserialization of body.
	if deserialize {
		dec := json.NewDecoder(r.Body)

		if err := dec.Decode(deserializeTo.Interface()); err != nil {
			writeError(w, j.logger, Err{
				Status: http.StatusBadRequest,
				Err:    fmt.Errorf("could not deserialize json request body"),
			})
			return
		}
		r.Body.Close()
	}

	out := j.fn.Call(in)

	// Handle error return value
	if !out[1].IsNil() {
		writeError(w, j.logger, out[1].Interface().(error))
		return
	}

	// Serialize the interface{} return value
	if !out[0].IsNil() {
		enc := json.NewEncoder(w)
		if err := enc.Encode(out[0].Interface()); err != nil {
			writeError(w, j.logger, Err{
				Status: http.StatusInternalServerError,
				Err:    fmt.Errorf("problem preparing response"),
			})
			return
		}
	}
}

func isDataMethod(method string) bool {
	return method != "GET" && method != "DELETE"
}

// writeError writes an error out to the response.
func writeError(w http.ResponseWriter, logger io.Writer, err error) {
	logit := func(format string, args ...interface{}) {
		if logger != nil {
			fmt.Fprintf(logger, format, args...)
		} else if globalLogger != nil {
			fmt.Fprintf(globalLogger, format, args...)
		}
	}

	switch e := err.(type) {
	case Err:
		toJSON := map[string]interface{}{
			"error": e.Err.Error(),
		}
		if e.Reason != nil {
			toJSON["reason"] = e.Reason
		}

		buf := &bytes.Buffer{}
		enc := json.NewEncoder(buf)
		if err = enc.Encode(toJSON); err != nil {
			logit("failed to serialize err: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			io.WriteString(w, `{"error":"an internal server error occurred"}`)
			return
		}

		if e.Status != 0 {
			w.WriteHeader(e.Status)
		}
		if _, err = io.Copy(w, buf); err != nil {
			logit("failed to send response: %v", err)
		}
	default:
		logit("internal error: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, `{"error":"an internal server error occurred"}`)
	}
}

/*
Handler changes a function into a JSONHandler.
Acceptable forms of the input function:

	GET/DELETE (Note: all variant return types also work with POST/PUT/PATCH)
	func Fn(w http.ResponseWriter, r *http.Request) (interface{}, error)
	func Fn(w http.ResponseWriter, r *http.Request) (*MyStruct, error)
	func Fn(w http.ResponseWriter, r *http.Request) ([]*MyStruct, error)
	func Fn(w http.ResponseWriter, r *http.Request) (map[string]*MyStruct, error)

	POST/PUT/PATCH
	func Fn(w http.ResponseWriter, r *http.Request, m *MyStruct) (interface{}, error)
	func Fn(w http.ResponseWriter, r *http.Request, m []*MyStruct) (interface{}, error)
	func Fn(w http.ResponseWriter, r *http.Request, m map[string]*MyStruct) (interface{}, error)
*/
func Handler(fn interface{}) *JSONHandler {
	typ := reflect.TypeOf(fn)
	if typ.Kind() != reflect.Func {
		panic("Can only register functions.")
	}

	var p1, p2, p3 reflect.Type

	switch typ.NumIn() {
	case 3:
		p3 = typ.In(2)
		if p3.Kind() != reflect.Ptr && p3.Kind() != reflect.Map && p3.Kind() != reflect.Slice {
			panic("Third argument must be an *object, map, or slice")
		}

		fallthrough
	case 2:
		p1, p2 = typ.In(0), typ.In(1)
		if "http.ResponseWriter" != p1.String() {
			panic("First argument must be an http.ResponseWriter")
		}

		if "*http.Request" != p2.String() {
			panic("Second argument must be a *http.Request")
		}
	default:
		panic("Handler must have 2-3 arguments: ResponseWriter, Request, [Object]")
	}

	if typ.NumOut() != 2 {
		panic("Handler must have two returns: *object or interface{}, and error")
	}

	o1, o2 := typ.Out(0), typ.Out(1)

	if "interface {}" != o1.String() && o1.Kind() != reflect.Ptr && o1.Kind() != reflect.Slice && o1.Kind() != reflect.Map {
		panic("First return must be an empty *object, map, slice or interface{}")
	}

	if "error" != o2.String() {
		panic("Second return must be an error")
	}

	return &JSONHandler{fn: reflect.ValueOf(fn), in: p3}
}
<commit_msg>Update documentation.<commit_after>/*
Package jsonware has a middleware setup for doing RESTful reqeuests with net/http.
It makes it easy to unobtrusively serialize and deserialize json in a type safe
manner, and handle errors from the internal handlers including logging.
*/
package jsonware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strings"
)

var globalLogger io.Writer

// Log sets the global logger for cloaked errors. Not safe for use by multiple
// goroutines, do this before your http server has been started.
func Log(logger io.Writer) {
	globalLogger = logger
}

/*
JSONHandler handles json api endpoint restful requests. It can be constructed
by passing a suitable function into the JSON function.

Error handling is handled differently depending on whether or not Err was
used to report the error. See Err documentation to understand how to control
error handling.

Cloaked errors are handled by reporting a generic error to the client and
logging the error locally. The log can be set globally via jsonware.Log() or
on each individual handler as an override by the .Log() function there.

	// Register a JSONHandler.
	http.Handle("/", Handler(myHandler).Log(myLogger))
*/
type JSONHandler struct {
	logger io.Writer
	fn     reflect.Value
	in     reflect.Type
}

// Log sets the JSONHandler's logging io.Writer for writing out cloaked errors.
func (j *JSONHandler) Log(logger io.Writer) *JSONHandler {
	j.logger = logger
	return j
}

/*
Err can be used in a JSONHandler to override the error mechanism in
JSONHandler's ServeHTTP method. If a status is set it will obey it,
otherwise it will assume 200 OK. The error message will be relayed to the
client. If you wish to use a general server error, simply return error from
the handler.

	func handler(w http.ResponseWriter, r *http.Request) (interface{}, error) {
		return nil, nil // No response from ServeHTTP, use w to create one.
	}

	func handler(w http.ResponseWriter, r *http.Request) (interface{}, error) {
		return nil, errors.New("hi") // 500 Response with cloaked+logged error.
	}

	func handler(w http.ResponseWriter, r *http.Request) (interface{}, error) {
		return nil, Err{Err: errors.New("hi")} // 200 Response with error output to client
	}

	func handler(w http.ResponseWriter, r *http.Request) (interface{}, error) {
		return nil, Err{Status: 400, Err: errors.New("hi")} // 400 Response with error output to client
	}

	func handler(w http.ResponseWriter, r *http.Request) (interface{}, error) {
		return nil, Err{
			Status: 400,
			Err: errors.New("hi")
			Reason: []string{"anything", "serializable", "to", "json"},
		} // 400 Response with error output to client
	}
*/
type Err struct {
	Status int
	Err    error
	Reason interface{}
}

// Error returns Error() from the internal error.
func (e Err) Error() string {
	return e.Err.Error()
}

// ServeHTTP serves an http response, see JSONHandler documentation for details.
func (j JSONHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Ensure request accepts json
	ah := r.Header.Get("Accept")
	if !strings.Contains(ah, "*/*") && !strings.Contains(ah, "application/json") {
		w.Header().Set("Content-Type", "text/plain")
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, "this endpoint only responds to json-accepting clients")
		return
	}

	w.Header().Set("Content-Type", "application/json")

	// Ensure request follows REST principles.
	deserialize := j.fn.Type().NumIn() == 3
	switch {
	case deserialize && !isDataMethod(r.Method):
		fallthrough
	case !deserialize && isDataMethod(r.Method):
		writeError(w, j.logger, Err{
			Status: http.StatusBadRequest,
			Err:    fmt.Errorf("invalid http method to this endpoint: %s", r.Method),
		})
		return
	}

	// Set up arguments for handler call.
	in := []reflect.Value{
		reflect.ValueOf(w), reflect.ValueOf(r),
	}
	var deserializeTo reflect.Value
	if deserialize {
		switch j.in.Kind() {
		case reflect.Slice, reflect.Map:
			deserializeTo = reflect.New(j.in)
			in = append(in, deserializeTo.Elem())
		case reflect.Ptr:
			deserializeTo = reflect.New(j.in.Elem())
			in = append(in, deserializeTo)
		}
	}

	// Do json deserialization of body.
	if deserialize {
		dec := json.NewDecoder(r.Body)

		if err := dec.Decode(deserializeTo.Interface()); err != nil {
			writeError(w, j.logger, Err{
				Status: http.StatusBadRequest,
				Err:    fmt.Errorf("could not deserialize json request body"),
			})
			return
		}
		r.Body.Close()
	}

	out := j.fn.Call(in)

	// Handle error return value
	if !out[1].IsNil() {
		writeError(w, j.logger, out[1].Interface().(error))
		return
	}

	// Serialize the interface{} return value
	if !out[0].IsNil() {
		enc := json.NewEncoder(w)
		if err := enc.Encode(out[0].Interface()); err != nil {
			writeError(w, j.logger, Err{
				Status: http.StatusInternalServerError,
				Err:    fmt.Errorf("problem preparing response"),
			})
			return
		}
	}
}

func isDataMethod(method string) bool {
	return method != "GET" && method != "DELETE"
}

// writeError writes an error out to the response.
func writeError(w http.ResponseWriter, logger io.Writer, err error) {
	logit := func(format string, args ...interface{}) {
		if logger != nil {
			fmt.Fprintf(logger, format, args...)
		} else if globalLogger != nil {
			fmt.Fprintf(globalLogger, format, args...)
		}
	}

	switch e := err.(type) {
	case Err:
		toJSON := map[string]interface{}{
			"error": e.Err.Error(),
		}
		if e.Reason != nil {
			toJSON["reason"] = e.Reason
		}

		buf := &bytes.Buffer{}
		enc := json.NewEncoder(buf)
		if err = enc.Encode(toJSON); err != nil {
			logit("failed to serialize err: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			io.WriteString(w, `{"error":"an internal server error occurred"}`)
			return
		}

		if e.Status != 0 {
			w.WriteHeader(e.Status)
		}
		if _, err = io.Copy(w, buf); err != nil {
			logit("failed to send response: %v", err)
		}
	default:
		logit("internal error: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		io.WriteString(w, `{"error":"an internal server error occurred"}`)
	}
}

/*
Handler changes a function into a JSONHandler.
Acceptable forms of the input function:

	GET/DELETE (Note: all variant return types also work with POST/PUT/PATCH)
	func Fn(w http.ResponseWriter, r *http.Request) (interface{}, error)
	func Fn(w http.ResponseWriter, r *http.Request) (*MyStruct, error)
	func Fn(w http.ResponseWriter, r *http.Request) ([]*MyStruct, error)
	func Fn(w http.ResponseWriter, r *http.Request) (map[string]*MyStruct, error)

	POST/PUT/PATCH
	func Fn(w http.ResponseWriter, r *http.Request, m *MyStruct) (interface{}, error)
	func Fn(w http.ResponseWriter, r *http.Request, m []*MyStruct) (interface{}, error)
	func Fn(w http.ResponseWriter, r *http.Request, m map[string]*MyStruct) (interface{}, error)
*/
func Handler(fn interface{}) *JSONHandler {
	typ := reflect.TypeOf(fn)
	if typ.Kind() != reflect.Func {
		panic("Can only register functions.")
	}

	var p1, p2, p3 reflect.Type

	switch typ.NumIn() {
	case 3:
		p3 = typ.In(2)
		if p3.Kind() != reflect.Ptr && p3.Kind() != reflect.Map && p3.Kind() != reflect.Slice {
			panic("Third argument must be an *object, map, or slice")
		}

		fallthrough
	case 2:
		p1, p2 = typ.In(0), typ.In(1)
		if "http.ResponseWriter" != p1.String() {
			panic("First argument must be an http.ResponseWriter")
		}

		if "*http.Request" != p2.String() {
			panic("Second argument must be a *http.Request")
		}
	default:
		panic("Handler must have 2-3 arguments: ResponseWriter, Request, [Object]")
	}

	if typ.NumOut() != 2 {
		panic("Handler must have two returns: *object or interface{}, and error")
	}

	o1, o2 := typ.Out(0), typ.Out(1)

	if "interface {}" != o1.String() && o1.Kind() != reflect.Ptr && o1.Kind() != reflect.Slice && o1.Kind() != reflect.Map {
		panic("First return must be an empty *object, map, slice or interface{}")
	}

	if "error" != o2.String() {
		panic("Second return must be an error")
	}

	return &JSONHandler{fn: reflect.ValueOf(fn), in: p3}
}
<|endoftext|>


<commit_before>/*
   Copyright 2012 the go.wde authors

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

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

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

package wde

import (
	"sort"
	"strings"
)

const (
	KeyFunction     = "function"
	KeyLeftSuper    = "left_super"
	KeyRightSuper   = "right_super"
	KeyLeftAlt      = "left_alt"
	KeyRightAlt     = "right_alt"
	KeyLeftControl  = "left_control"
	KeyRightControl = "right_control"
	KeyLeftShift    = "left_shift"
	KeyRightShift   = "right_shift"
	KeyUpArrow      = "up_arrow"
	KeyDownArrow    = "down_arrow"
	KeyLeftArrow    = "left_arrow"
	KeyRightArrow   = "right_arrow"
	KeyInsert       = "insert"
	KeyTab          = "tab"
	KeySpace        = "space"
	KeyA            = "a"
	KeyB            = "b"
	KeyC            = "c"
	KeyD            = "d"
	KeyE            = "e"
	KeyF            = "f"
	KeyG            = "g"
	KeyH            = "h"
	KeyI            = "i"
	KeyJ            = "j"
	KeyK            = "k"
	KeyL            = "l"
	KeyM            = "m"
	KeyN            = "n"
	KeyO            = "o"
	KeyP            = "p"
	KeyQ            = "q"
	KeyR            = "r"
	KeyS            = "s"
	KeyT            = "t"
	KeyU            = "u"
	KeyV            = "v"
	KeyW            = "w"
	KeyX            = "x"
	KeyY            = "y"
	KeyZ            = "z"
	Key1            = "1"
	Key2            = "2"
	Key3            = "3"
	Key4            = "4"
	Key5            = "5"
	Key6            = "6"
	Key7            = "7"
	Key8            = "8"
	Key9            = "9"
	Key0            = "0"
	KeyPadEnd       = "kp_end"
	KeyPadDown      = "kp_down"
	KeyPadNext      = "kp_next"
	KeyPadLeft      = "kp_left"
	KeyPadBegin     = "kp_begin"
	KeyPadRight     = "kp_right"
	KeyPadHome      = "kp_home"
	KeyPadUp        = "kp_up"
	KeyPadPrior     = "kp_prior"
	KeyPadInsert    = "kpInsert"
	KeyPadSlash     = "kpSlash"
	KeyPadStar      = "kpStar"
	KeyPadMinus     = "kpMinus"
	KeyPadPlus      = "kpPlus"
	KeyPadDot       = "kpDot"
	KeyPadEqual     = "kpEqual"
	KeyPadEnter     = "kpEnter"
	KeyBackTick     = "`"
	KeyF1           = "f1"
	KeyF2           = "f2"
	KeyF3           = "f3"
	KeyF4           = "f4"
	KeyF5           = "f5"
	KeyF6           = "f6"
	KeyF7           = "f7"
	KeyF8           = "f8"
	KeyF9           = "f9"
	KeyF10          = "f10"
	KeyF11          = "f11"
	KeyF12          = "f12"
	KeyF13          = "f13"
	KeyF14          = "f14"
	KeyF15          = "f15"
	KeyF16          = "f16"
	KeyMinus        = "-"
	KeyEqual        = "="
	KeyLeftBracket  = "["
	KeyRightBracket = "]"
	KeyBackslash    = `\`
	KeySemicolon    = ";"
	KeyQuote        = "'"
	KeyComma        = ","
	KeyPeriod       = "."
	KeySlash        = "/"
	KeyReturn       = "return"
	KeyEscape       = "escape"
	KeyNumlock      = "numlock"
	KeyDelete       = "delete"
	KeyBackspace    = "backspace"
	KeyHome         = "home"
	KeyEnd          = "end"
	KeyPrior        = "prior"
	KeyNext         = "next"
	KeyCapsLock     = "caps"
)

var chordPrecedence = []string{
	"super",
	"shift",
	"alt",
	"control",
	"function",
}

var chordIndices map[string]int

func init() {
	chordIndices = map[string]int{}
	for i, k := range chordPrecedence {
		chordIndices[k] = i + 1
	}
}

type ChordSorter []string

func (c ChordSorter) Len() int {
	return len(c)
}
func (c ChordSorter) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c ChordSorter) Less(i, j int) (less bool) {
	ip := chordIndices[c[i]]
	jp := chordIndices[c[j]]
	return ip > jp
}

func ConstructChord(keys map[string]bool) (chord string) {
	unikeys := map[string]bool{}
	for key := range keys {
		if strings.HasPrefix(key, "left_") {
			key = key[5:]
		}
		if strings.HasPrefix(key, "right_") {
			key = key[6:]
		}
		unikeys[key] = true
	}
	if len(unikeys) <= 1 {
		return
	}
	allkeys := ChordSorter{}
	for key := range unikeys {
		allkeys = append(allkeys, key)
	}
	sort.Sort(allkeys)
	chord = strings.Join(allkeys, "+")
	return
}
<commit_msg>fixed key chord sorting<commit_after>/*
   Copyright 2012 the go.wde authors

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

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

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

package wde

import (
	"sort"
	"strings"
)

const (
	KeyFunction     = "function"
	KeyLeftSuper    = "left_super"
	KeyRightSuper   = "right_super"
	KeyLeftAlt      = "left_alt"
	KeyRightAlt     = "right_alt"
	KeyLeftControl  = "left_control"
	KeyRightControl = "right_control"
	KeyLeftShift    = "left_shift"
	KeyRightShift   = "right_shift"
	KeyUpArrow      = "up_arrow"
	KeyDownArrow    = "down_arrow"
	KeyLeftArrow    = "left_arrow"
	KeyRightArrow   = "right_arrow"
	KeyInsert       = "insert"
	KeyTab          = "tab"
	KeySpace        = "space"
	KeyA            = "a"
	KeyB            = "b"
	KeyC            = "c"
	KeyD            = "d"
	KeyE            = "e"
	KeyF            = "f"
	KeyG            = "g"
	KeyH            = "h"
	KeyI            = "i"
	KeyJ            = "j"
	KeyK            = "k"
	KeyL            = "l"
	KeyM            = "m"
	KeyN            = "n"
	KeyO            = "o"
	KeyP            = "p"
	KeyQ            = "q"
	KeyR            = "r"
	KeyS            = "s"
	KeyT            = "t"
	KeyU            = "u"
	KeyV            = "v"
	KeyW            = "w"
	KeyX            = "x"
	KeyY            = "y"
	KeyZ            = "z"
	Key1            = "1"
	Key2            = "2"
	Key3            = "3"
	Key4            = "4"
	Key5            = "5"
	Key6            = "6"
	Key7            = "7"
	Key8            = "8"
	Key9            = "9"
	Key0            = "0"
	KeyPadEnd       = "kp_end"
	KeyPadDown      = "kp_down"
	KeyPadNext      = "kp_next"
	KeyPadLeft      = "kp_left"
	KeyPadBegin     = "kp_begin"
	KeyPadRight     = "kp_right"
	KeyPadHome      = "kp_home"
	KeyPadUp        = "kp_up"
	KeyPadPrior     = "kp_prior"
	KeyPadInsert    = "kpInsert"
	KeyPadSlash     = "kpSlash"
	KeyPadStar      = "kpStar"
	KeyPadMinus     = "kpMinus"
	KeyPadPlus      = "kpPlus"
	KeyPadDot       = "kpDot"
	KeyPadEqual     = "kpEqual"
	KeyPadEnter     = "kpEnter"
	KeyBackTick     = "`"
	KeyF1           = "f1"
	KeyF2           = "f2"
	KeyF3           = "f3"
	KeyF4           = "f4"
	KeyF5           = "f5"
	KeyF6           = "f6"
	KeyF7           = "f7"
	KeyF8           = "f8"
	KeyF9           = "f9"
	KeyF10          = "f10"
	KeyF11          = "f11"
	KeyF12          = "f12"
	KeyF13          = "f13"
	KeyF14          = "f14"
	KeyF15          = "f15"
	KeyF16          = "f16"
	KeyMinus        = "-"
	KeyEqual        = "="
	KeyLeftBracket  = "["
	KeyRightBracket = "]"
	KeyBackslash    = `\`
	KeySemicolon    = ";"
	KeyQuote        = "'"
	KeyComma        = ","
	KeyPeriod       = "."
	KeySlash        = "/"
	KeyReturn       = "return"
	KeyEscape       = "escape"
	KeyNumlock      = "numlock"
	KeyDelete       = "delete"
	KeyBackspace    = "backspace"
	KeyHome         = "home"
	KeyEnd          = "end"
	KeyPrior        = "prior"
	KeyNext         = "next"
	KeyCapsLock     = "caps"
)

var chordPrecedence = []string{
	"super",
	"shift",
	"alt",
	"control",
	"function",
}

var chordIndices map[string]int

func init() {
	chordIndices = map[string]int{}
	for i, k := range chordPrecedence {
		// we give these negative values so that when a lookup is done on something
		// that is not in this list, it gets 0 (the default), and comes after each
		// of the keys indicated in chordPrecedence.
		chordIndices[k] = i - len(chordPrecedence)
	}
}

type ChordSorter []string

func (c ChordSorter) Len() int {
	return len(c)
}
func (c ChordSorter) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c ChordSorter) Less(i, j int) (less bool) {
	ip := chordIndices[c[i]]
	jp := chordIndices[c[j]]
	if ip == 0 && jp == 0 {
		if len(c[i]) != len(c[j]) {
			return len(c[i]) > len(c[j])
		}
		return c[i] < c[j]
	}
	return ip < jp
}

func ConstructChord(keys map[string]bool) (chord string) {
	unikeys := map[string]bool{}
	for key := range keys {
		if strings.HasPrefix(key, "left_") {
			key = key[5:]
		}
		if strings.HasPrefix(key, "right_") {
			key = key[6:]
		}
		unikeys[key] = true
	}
	if len(unikeys) <= 1 {
		return
	}
	allkeys := ChordSorter{}
	for key := range unikeys {
		allkeys = append(allkeys, key)
	}

	sort.Sort(allkeys)
	chord = strings.Join(allkeys, "+")
	return
}
<|endoftext|>


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

package gabi

import (
	"crypto/rand"
	"encoding/xml"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"

	"github.com/credentials/safeprime"
)

const (
	//XMLHeader can be a used as the XML header when writing keys in XML format.
	XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
	// DefaultEpochLength is the default epoch length for public keys.
	DefaultEpochLength = 432000
)

// PrivateKey represents an issuer's private key.
type PrivateKey struct {
	XMLName xml.Name `xml:"http://www.zurich.ibm.com/security/idemix IssuerPrivateKey"`
	P       *big.Int `xml:"Elements>p"`
	Q       *big.Int `xml:"Elements>q"`
	PPrime  *big.Int `xml:"Elements>pPrime"`
	QPrime  *big.Int `xml:"Elements>qPrime"`
}

// NewPrivateKey creates a new issuer private key using the provided parameters.
func NewPrivateKey(p, q *big.Int) *PrivateKey {
	sk := PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int)}

	sk.PPrime.Sub(p, bigONE)
	sk.PPrime.Rsh(sk.PPrime, 1)

	sk.QPrime.Sub(q, bigONE)
	sk.QPrime.Rsh(sk.QPrime, 1)

	return &sk
}

// NewPrivateKeyFromXML creates a new issuer private key using the xml data
// provided.
func NewPrivateKeyFromXML(xmlInput string) (*PrivateKey, error) {
	privk := &PrivateKey{}
	err := xml.Unmarshal([]byte(xmlInput), privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// NewPrivateKeyFromFile create a new issuer private key from an xml file.
func NewPrivateKeyFromFile(filename string) (*PrivateKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	privk := &PrivateKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// Print prints the key to stdout.
func (privk *PrivateKey) Print() error {
	return privk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (privk *PrivateKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(privk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the private key to an xml file.
func (privk *PrivateKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return privk.WriteTo(f)
}

// xmlBases is an auxiliary struct to encode/decode the odd way bases are
// represented in the xml representation of public keys
type xmlBases struct {
	Num   int `xml:"num,attr"`
	Bases []*xmlBase
}

type xmlBase struct {
	XMLName xml.Name
	Bigint  string `xml:",innerxml"` // Has to be a string for ",innerxml" to work
}

// xmlFeatures is an auxiliary struct to make the XML encoding/decoding a bit
// easier while keeping the struct for PublicKey somewhat simple.
type xmlFeatures struct {
	Epoch struct {
		Length int `xml:"length,attr"`
	}
}

// Bases is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type Bases []*big.Int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (bl *Bases) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlBases

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}

	arr := make([]*big.Int, t.Num)
	for i := range arr {
		arr[i], _ = new(big.Int).SetString(t.Bases[i].Bigint, 10)
	}

	*bl = Bases(arr)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (bl *Bases) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	l := len(*bl)
	bases := make([]*xmlBase, l)

	for i := range bases {
		bases[i] = &xmlBase{
			XMLName: xml.Name{Local: "Base_" + strconv.Itoa(i)},
			Bigint:  (*bl)[i].String(),
		}
	}

	t := xmlBases{
		Num:   l,
		Bases: bases,
	}
	return e.EncodeElement(t, start)
}

// EpochLength is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type EpochLength int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (el *EpochLength) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlFeatures

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}
	*el = EpochLength(t.Epoch.Length)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (el *EpochLength) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	var t xmlFeatures
	t.Epoch.Length = int(*el)
	return e.EncodeElement(t, start)
}

// PublicKey represents an issuer's public key.
type PublicKey struct {
	XMLName     xml.Name          `xml:"http://www.zurich.ibm.com/security/idemix IssuerPublicKey"`
	N           *big.Int          `xml:"Elements>n"` // Modulus n
	Z           *big.Int          `xml:"Elements>Z"` // Generator Z
	S           *big.Int          `xml:"Elements>S"` // Generator S
	R           Bases             `xml:"Elements>Bases"`
	EpochLength EpochLength       `xml:"Features"`
	Params      *SystemParameters `xml:"-"`
}

// NewPublicKey creates and returns a new public key based on the provided parameters.
func NewPublicKey(N, Z, S *big.Int, R []*big.Int) *PublicKey {
	return &PublicKey{
		N:           N,
		Z:           Z,
		S:           S,
		R:           R,
		EpochLength: DefaultEpochLength,
		Params:      &DefaultSystemParameters,
	}
}

// NewPublicKeyFromXML creates a new issuer public key using the xml data
// provided.
func NewPublicKeyFromXML(xmlInput string) (*PublicKey, error) {
	// TODO: this might fail in the future. The DefaultSystemParameters and the
	// public key might not match!
	pubk := &PublicKey{Params: &DefaultSystemParameters}
	err := xml.Unmarshal([]byte(xmlInput), pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// NewPublicKeyFromFile create a new issuer public key from an xml file.
func NewPublicKeyFromFile(filename string) (*PublicKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	pubk := &PublicKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// Print prints the key to stdout.
func (pubk *PublicKey) Print() error {
	return pubk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (pubk *PublicKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(pubk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the public key to an xml file.
func (pubk *PublicKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return pubk.WriteTo(f)
}

// randomSafePrime produces a safe prime of the requested number of bits
func randomSafePrime(bits int) (*big.Int, error) {
	p2 := new(big.Int)
	for {
		p, err := rand.Prime(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		p2.Rsh(p, 1) // p2 = (p - 1)/2
		if p2.ProbablyPrime(20) {
			return p, nil
		}
	}
}

// GenerateKeyPair generates a private/public keypair for an Issuer
func GenerateKeyPair(param *SystemParameters, attrsAmount int) (*PrivateKey, *PublicKey, error) {
	primeSize := param.Ln / 2

	// p and q need to be safe primes
	p, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	q, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	priv := &PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int)}

	// compute p' and q'
	priv.PPrime.Sub(priv.P, bigONE)
	priv.PPrime.Rsh(priv.PPrime, 1)

	priv.QPrime.Sub(priv.Q, bigONE)
	priv.QPrime.Rsh(priv.QPrime, 1)

	// compute n
	pubk := &PublicKey{Params: param, EpochLength: DefaultEpochLength}
	pubk.N = new(big.Int).Mul(priv.P, priv.Q)

	// Find an acceptable value for S; we follow lead of the Silvia code here:
	// Pick a random l_n value and check whether it is a quadratic residue modulo n

	var s *big.Int
	for {
		s, err = randomBigInt(param.Ln)
		if err != nil {
			return nil, nil, err
		}
		// check if S \elem Z_n
		if s.Cmp(pubk.N) > 0 {
			continue
		}
		if legendreSymbol(s, priv.P) == 1 && legendreSymbol(s, priv.Q) == 1 {
			break
		}
	}

	pubk.S = s

	// Derive Z from S
	var x *big.Int
	for {
		x, _ = randomBigInt(primeSize)
		if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
			break
		}
	}

	// Compute Z = S^x mod n
	pubk.Z = new(big.Int).Exp(pubk.S, x, pubk.N)

	// Derive R_i for i = 0...attrsAmount from S
	pubk.R = make([]*big.Int, attrsAmount)
	for i := 0; i < attrsAmount; i++ {
		pubk.R[i] = new(big.Int)

		var x *big.Int
		for {
			x, _ = randomBigInt(primeSize)
			if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
				break
			}
		}
		// Compute R_i = S^x mod n
		pubk.R[i].Exp(pubk.S, x, pubk.N)
	}

	return priv, pubk, nil
}
<commit_msg>Add public/private key counters<commit_after>// Copyright 2016 Maarten Everts. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gabi

import (
	"crypto/rand"
	"encoding/xml"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"

	"github.com/credentials/safeprime"
)

const (
	//XMLHeader can be a used as the XML header when writing keys in XML format.
	XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
	// DefaultEpochLength is the default epoch length for public keys.
	DefaultEpochLength = 432000
)

// PrivateKey represents an issuer's private key.
type PrivateKey struct {
	XMLName xml.Name `xml:"http://www.zurich.ibm.com/security/idemix IssuerPrivateKey"`
	Counter uint     `xml:"Counter"`
	P       *big.Int `xml:"Elements>p"`
	Q       *big.Int `xml:"Elements>q"`
	PPrime  *big.Int `xml:"Elements>pPrime"`
	QPrime  *big.Int `xml:"Elements>qPrime"`
}

// NewPrivateKey creates a new issuer private key using the provided parameters.
func NewPrivateKey(p, q *big.Int, counter uint) *PrivateKey {
	sk := PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter}

	sk.PPrime.Sub(p, bigONE)
	sk.PPrime.Rsh(sk.PPrime, 1)

	sk.QPrime.Sub(q, bigONE)
	sk.QPrime.Rsh(sk.QPrime, 1)

	return &sk
}

// NewPrivateKeyFromXML creates a new issuer private key using the xml data
// provided.
func NewPrivateKeyFromXML(xmlInput string) (*PrivateKey, error) {
	privk := &PrivateKey{}
	err := xml.Unmarshal([]byte(xmlInput), privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// NewPrivateKeyFromFile create a new issuer private key from an xml file.
func NewPrivateKeyFromFile(filename string) (*PrivateKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	privk := &PrivateKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// Print prints the key to stdout.
func (privk *PrivateKey) Print() error {
	return privk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (privk *PrivateKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(privk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the private key to an xml file.
func (privk *PrivateKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return privk.WriteTo(f)
}

// xmlBases is an auxiliary struct to encode/decode the odd way bases are
// represented in the xml representation of public keys
type xmlBases struct {
	Num   int `xml:"num,attr"`
	Bases []*xmlBase
}

type xmlBase struct {
	XMLName xml.Name
	Bigint  string `xml:",innerxml"` // Has to be a string for ",innerxml" to work
}

// xmlFeatures is an auxiliary struct to make the XML encoding/decoding a bit
// easier while keeping the struct for PublicKey somewhat simple.
type xmlFeatures struct {
	Epoch struct {
		Length int `xml:"length,attr"`
	}
}

// Bases is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type Bases []*big.Int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (bl *Bases) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlBases

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}

	arr := make([]*big.Int, t.Num)
	for i := range arr {
		arr[i], _ = new(big.Int).SetString(t.Bases[i].Bigint, 10)
	}

	*bl = Bases(arr)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (bl *Bases) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	l := len(*bl)
	bases := make([]*xmlBase, l)

	for i := range bases {
		bases[i] = &xmlBase{
			XMLName: xml.Name{Local: "Base_" + strconv.Itoa(i)},
			Bigint:  (*bl)[i].String(),
		}
	}

	t := xmlBases{
		Num:   l,
		Bases: bases,
	}
	return e.EncodeElement(t, start)
}

// EpochLength is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type EpochLength int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (el *EpochLength) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlFeatures

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}
	*el = EpochLength(t.Epoch.Length)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (el *EpochLength) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	var t xmlFeatures
	t.Epoch.Length = int(*el)
	return e.EncodeElement(t, start)
}

// PublicKey represents an issuer's public key.
type PublicKey struct {
	XMLName     xml.Name          `xml:"http://www.zurich.ibm.com/security/idemix IssuerPublicKey"`
	Counter     uint              `xml:"Counter"`
	N           *big.Int          `xml:"Elements>n"` // Modulus n
	Z           *big.Int          `xml:"Elements>Z"` // Generator Z
	S           *big.Int          `xml:"Elements>S"` // Generator S
	R           Bases             `xml:"Elements>Bases"`
	EpochLength EpochLength       `xml:"Features"`
	Params      *SystemParameters `xml:"-"`
}

// NewPublicKey creates and returns a new public key based on the provided parameters.
func NewPublicKey(N, Z, S *big.Int, R []*big.Int, counter uint) *PublicKey {
	return &PublicKey{
		Counter:     counter,
		N:           N,
		Z:           Z,
		S:           S,
		R:           R,
		EpochLength: DefaultEpochLength,
		Params:      &DefaultSystemParameters,
	}
}

// NewPublicKeyFromXML creates a new issuer public key using the xml data
// provided.
func NewPublicKeyFromXML(xmlInput string) (*PublicKey, error) {
	// TODO: this might fail in the future. The DefaultSystemParameters and the
	// public key might not match!
	pubk := &PublicKey{Params: &DefaultSystemParameters}
	err := xml.Unmarshal([]byte(xmlInput), pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// NewPublicKeyFromFile create a new issuer public key from an xml file.
func NewPublicKeyFromFile(filename string) (*PublicKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	pubk := &PublicKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// Print prints the key to stdout.
func (pubk *PublicKey) Print() error {
	return pubk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (pubk *PublicKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(pubk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the public key to an xml file.
func (pubk *PublicKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return pubk.WriteTo(f)
}

// randomSafePrime produces a safe prime of the requested number of bits
func randomSafePrime(bits int) (*big.Int, error) {
	p2 := new(big.Int)
	for {
		p, err := rand.Prime(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		p2.Rsh(p, 1) // p2 = (p - 1)/2
		if p2.ProbablyPrime(20) {
			return p, nil
		}
	}
}

// GenerateKeyPair generates a private/public keypair for an Issuer
func GenerateKeyPair(param *SystemParameters, attrsAmount int, counter uint) (*PrivateKey, *PublicKey, error) {
	primeSize := param.Ln / 2

	// p and q need to be safe primes
	p, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	q, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	priv := &PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter}

	// compute p' and q'
	priv.PPrime.Sub(priv.P, bigONE)
	priv.PPrime.Rsh(priv.PPrime, 1)

	priv.QPrime.Sub(priv.Q, bigONE)
	priv.QPrime.Rsh(priv.QPrime, 1)

	// compute n
	pubk := &PublicKey{Params: param, EpochLength: DefaultEpochLength, Counter: counter}
	pubk.N = new(big.Int).Mul(priv.P, priv.Q)

	// Find an acceptable value for S; we follow lead of the Silvia code here:
	// Pick a random l_n value and check whether it is a quadratic residue modulo n

	var s *big.Int
	for {
		s, err = randomBigInt(param.Ln)
		if err != nil {
			return nil, nil, err
		}
		// check if S \elem Z_n
		if s.Cmp(pubk.N) > 0 {
			continue
		}
		if legendreSymbol(s, priv.P) == 1 && legendreSymbol(s, priv.Q) == 1 {
			break
		}
	}

	pubk.S = s

	// Derive Z from S
	var x *big.Int
	for {
		x, _ = randomBigInt(primeSize)
		if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
			break
		}
	}

	// Compute Z = S^x mod n
	pubk.Z = new(big.Int).Exp(pubk.S, x, pubk.N)

	// Derive R_i for i = 0...attrsAmount from S
	pubk.R = make([]*big.Int, attrsAmount)
	for i := 0; i < attrsAmount; i++ {
		pubk.R[i] = new(big.Int)

		var x *big.Int
		for {
			x, _ = randomBigInt(primeSize)
			if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
				break
			}
		}
		// Compute R_i = S^x mod n
		pubk.R[i].Exp(pubk.S, x, pubk.N)
	}

	return priv, pubk, nil
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

var origTermios *Termios

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J");
	io.WriteString(os.Stdout, "\x1b[H");
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting termial attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() byte {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]);
		cc != 1;
		cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	return buffer[0]
}

/*** input ***/

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J");
		io.WriteString(os.Stdout, "\x1b[H");
		disableRawMode()
		os.Exit(0)
	}
}

/*** output ***/

func editorRefreshScreen() {
	io.WriteString(os.Stdout, "\x1b[2J");
	io.WriteString(os.Stdout, "\x1b[H");
}

/*** init ***/

func main() {
	enableRawMode()
	defer disableRawMode()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<commit_msg>Step 25<commit_after>package main

import (
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

var origTermios *Termios

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J");
	io.WriteString(os.Stdout, "\x1b[H");
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting termial attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() byte {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]);
		cc != 1;
		cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	return buffer[0]
}

/*** input ***/

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J");
		io.WriteString(os.Stdout, "\x1b[H");
		disableRawMode()
		os.Exit(0)
	}
}

/*** output ***/

func editorRefreshScreen() {
	io.WriteString(os.Stdout, "\x1b[2J");
	io.WriteString(os.Stdout, "\x1b[H");
	editorDrawRows()
	io.WriteString(os.Stdout, "\x1b[H");
}

func editorDrawRows() {
	for y := 0; y < 24; y++ {
		io.WriteString(os.Stdout, "~\r\n");
	}
}

/*** init ***/

func main() {
	enableRawMode()
	defer disableRawMode()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<|endoftext|>


<commit_before>package dht

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"expvar"
	"fmt"
	"net"
	"strconv"
	"time"

	bencode "github.com/jackpal/bencode-go"
	log "github.com/golang/glog"
	"github.com/nictuku/nettools"
)

// Search a node again after some time.
var searchRetryPeriod = 15 * time.Second

// Owned by the DHT engine.
type remoteNode struct {
	address net.UDPAddr
	// addressDotFormatted contains a binary representation of the node's host:port address.
	addressBinaryFormat string
	id                  string
	// lastQueryID should be incremented after consumed. Based on the
	// protocol, it would be two letters, but I'm using 0-255, although
	// treated as string.
	lastQueryID int
	// TODO: key by infohash instead?
	pendingQueries   map[string]*queryType // key: transaction ID
	pastQueries      map[string]*queryType // key: transaction ID
	reachable        bool
	lastResponseTime time.Time
	lastSearchTime   time.Time
	ActiveDownloads  []string // List of infohashes we know this peer is downloading.
}

func newRemoteNode(addr net.UDPAddr, id string) *remoteNode {
	return &remoteNode{
		address:             addr,
		addressBinaryFormat: nettools.DottedPortToBinary(addr.String()),
		lastQueryID:         newTransactionId(),
		id:                  id,
		reachable:           false,
		pendingQueries:      map[string]*queryType{},
		pastQueries:         map[string]*queryType{},
	}
}

type queryType struct {
	Type    string
	ih      InfoHash
	srcNode string
}

const (
	// Once in a while I get a few bigger ones, but meh.
	maxUDPPacketSize = 4096
	nodeContactLen   = 32
	nodeIdLen        = 20
)

var (
	totalSent         = expvar.NewInt("totalSent")
	totalReadBytes    = expvar.NewInt("totalReadBytes")
	totalWrittenBytes = expvar.NewInt("totalWrittenBytes")
)

// The 'nodes' response is a string with fixed length contacts concatenated arbitrarily.
func parseNodesString(nodes string) (parsed map[string]string) {
	parsed = make(map[string]string)
	if len(nodes)%nodeContactLen > 0 {
		log.V(3).Infof("DHT: Invalid length of nodes.")
		log.V(3).Infof("DHT: Should be a multiple of %d, got %d", nodeContactLen, len(nodes))
		return
	}
	for i := 0; i < len(nodes); i += nodeContactLen {
		id := nodes[i : i+nodeIdLen]
		address := nettools.BinaryToDottedPort(nodes[i+nodeIdLen : i+nodeContactLen])
		parsed[id] = address
	}
	return

}

// newQuery creates a new transaction id and adds an entry to r.pendingQueries.
// It does not set any extra information to the transaction information, so the
// caller must take care of that.
func (r *remoteNode) newQuery(transType string) (transId string) {
	log.V(4).Infof("newQuery for %x, lastID %v", r.id, r.lastQueryID)
	r.lastQueryID = (r.lastQueryID + 1) % 256
	transId = strconv.Itoa(r.lastQueryID)
	log.V(4).Infof("... new id %v", r.lastQueryID)
	r.pendingQueries[transId] = &queryType{Type: transType}
	return
}

// wasContactedRecently returns true if a node was contacted recently _and_
// one of the recent queries (not necessarily the last) was about the ih. If
// the ih is different at each time, it will keep returning false.
func (r *remoteNode) wasContactedRecently(ih InfoHash) bool {
	if len(r.pendingQueries) == 0 && len(r.pastQueries) == 0 {
		return false
	}
	if !r.lastResponseTime.IsZero() && time.Since(r.lastResponseTime) > searchRetryPeriod {
		return false
	}
	for _, q := range r.pendingQueries {
		if q.ih == ih {
			return true
		}
	}
	for _, q := range r.pastQueries {
		if q.ih == ih {
			return true
		}
	}
	return false
}

type getPeersResponse struct {
	// TODO: argh, values can be a string depending on the client (e.g: original bittorrent).
	Values []string "values"
	Id     string   "id"
	Nodes  string   "nodes"
	Token  string   "token"
}

type answerType struct {
	Id       string   "id"
	Target   string   "target"
	InfoHash InfoHash "info_hash" // should probably be a string.
	Port     int      "port"
	Token    string   "token"
}

// Generic stuff we read from the wire, not knowing what it is. This is as generic as can be.
type responseType struct {
	T string           "t"
	Y string           "y"
	Q string           "q"
	R getPeersResponse "r"
	E []string         "e"
	A answerType       "a"
	// Unsupported mainline extension for client identification.
	// V string(?)	"v"
}

// sendMsg bencodes the data in 'query' and sends it to the remote node.
func sendMsg(conn *net.UDPConn, raddr net.UDPAddr, query interface{}) {
	totalSent.Add(1)
	var b bytes.Buffer
	if err := bencode.Marshal(&b, query); err != nil {
		return
	}
	if n, err := conn.WriteToUDP(b.Bytes(), &raddr); err != nil {
		// debug.Println("DHT: node write failed:", err)
	} else {
		totalWrittenBytes.Add(int64(n))
	}
	return
}

// Read responses from bencode-speaking nodes. Return the appropriate data structure.
func readResponse(p packetType) (response responseType, err error) {
	// The calls to bencode.Unmarshal() can be fragile.
	defer func() {
		if x := recover(); x != nil {
			// debug.Printf("DHT: !!! Recovering from panic() after bencode.Unmarshal %q, %v", string(p.b), x)
		}
	}()
	if e2 := bencode.Unmarshal(bytes.NewBuffer(p.b), &response); e2 == nil {
		err = nil
		return
	} else {
		// debug.Printf("DHT: unmarshal error, odd or partial data during UDP read? %v, err=%s", string(p.b), e2)
		return response, e2
	}
	return
}

// Message to be sent out in the wire. Must not have any extra fields.
type queryMessage struct {
	T string                 "t"
	Y string                 "y"
	Q string                 "q"
	A map[string]interface{} "a"
}

type replyMessage struct {
	T string                 "t"
	Y string                 "y"
	R map[string]interface{} "r"
}

type packetType struct {
	b     []byte
	raddr net.UDPAddr
}

func listen(addr string, listenPort int) (socket *net.UDPConn, err error) {
	// debug.Printf("DHT: Listening for peers on port: %d\n", listenPort)
   log.V(3).Infof("DHT: Listening for peers on IP: %s port: %d\n", addr,listenPort)
	listener, err := net.ListenPacket("udp6", addr+":"+strconv.Itoa(listenPort))
	if err != nil {
		// debug.Println("DHT: Listen failed:", err)
	}
	if listener != nil {
		socket = listener.(*net.UDPConn)
	}
	return
}

// Read from UDP socket, writes slice of byte into channel.
func readFromSocket(socket *net.UDPConn, conChan chan packetType, bytesArena arena, stop chan bool) {
	for {
		b := bytesArena.Pop()
		n, addr, err := socket.ReadFromUDP(b)
		b = b[0:n]
		if n == maxUDPPacketSize {
			// debug.Printf("DHT: Warning. Received packet with len >= %d, some data may have been discarded.\n", maxUDPPacketSize)
		}
		totalReadBytes.Add(int64(n))
		if n > 0 && err == nil {
			p := packetType{b, *addr}
			select {
			case conChan <- p:
				continue
			case <-stop:
				return
			}
		}
		// debug.Println("DHT: readResponse error:", err)

		// Do a non-blocking read of the stop channel and stop this goroutine if the channel
		// has been closed.
		select {
		case <-stop:
			return
		default:
		}
	}
}

func bogusId(id string) bool {
	return len(id) != 20
}

func newTransactionId() int {
	n, err := rand.Read(make([]byte, 1))
	if err != nil {
		return time.Now().Second()
	}
	return n
}

type InfoHash string

// DecodeInfoHash transforms a hex-encoded 20-characters string to a binary
// infohash.
func DecodeInfoHash(x string) (b InfoHash, err error) {
	var h []byte
	h, err = hex.DecodeString(x)
	if len(h) != 20 {
		return "", fmt.Errorf("DecodeInfoHash: expected InfoHash len=20, got %d", len(h))
	}
	return InfoHash(h), err
}

// DecodePeerAddress transforms the binary-encoded host:port address into a
// human-readable format. So, "abcdef" becomes 97.98.99.100:25958.
func DecodePeerAddress(x string) string {
	return nettools.BinaryToDottedPort(x)
}
<commit_msg>skip nodelen checking, still complain<commit_after>package dht

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"expvar"
	"fmt"
	"net"
	"strconv"
	"time"

	bencode "github.com/jackpal/bencode-go"
	log "github.com/golang/glog"
	"github.com/nictuku/nettools"
)

// Search a node again after some time.
var searchRetryPeriod = 15 * time.Second

// Owned by the DHT engine.
type remoteNode struct {
	address net.UDPAddr
	// addressDotFormatted contains a binary representation of the node's host:port address.
	addressBinaryFormat string
	id                  string
	// lastQueryID should be incremented after consumed. Based on the
	// protocol, it would be two letters, but I'm using 0-255, although
	// treated as string.
	lastQueryID int
	// TODO: key by infohash instead?
	pendingQueries   map[string]*queryType // key: transaction ID
	pastQueries      map[string]*queryType // key: transaction ID
	reachable        bool
	lastResponseTime time.Time
	lastSearchTime   time.Time
	ActiveDownloads  []string // List of infohashes we know this peer is downloading.
}

func newRemoteNode(addr net.UDPAddr, id string) *remoteNode {
	return &remoteNode{
		address:             addr,
		addressBinaryFormat: nettools.DottedPortToBinary(addr.String()),
		lastQueryID:         newTransactionId(),
		id:                  id,
		reachable:           false,
		pendingQueries:      map[string]*queryType{},
		pastQueries:         map[string]*queryType{},
	}
}

type queryType struct {
	Type    string
	ih      InfoHash
	srcNode string
}

const (
	// Once in a while I get a few bigger ones, but meh.
	maxUDPPacketSize = 4096
	nodeContactLen   = 32
	nodeIdLen        = 20
)

var (
	totalSent         = expvar.NewInt("totalSent")
	totalReadBytes    = expvar.NewInt("totalReadBytes")
	totalWrittenBytes = expvar.NewInt("totalWrittenBytes")
)

// The 'nodes' response is a string with fixed length contacts concatenated arbitrarily.
func parseNodesString(nodes string) (parsed map[string]string) {
	parsed = make(map[string]string)
	if len(nodes)%nodeContactLen > 0 {
		log.V(3).Infof("DHT: Invalid length of nodes.")
		log.V(3).Infof("DHT: Should be a multiple of %d, got %d", nodeContactLen, len(nodes))
	}
	for i := 0; i < len(nodes); i += nodeContactLen {
		id := nodes[i : i+nodeIdLen]
		address := nettools.BinaryToDottedPort(nodes[i+nodeIdLen : i+nodeContactLen])
		parsed[id] = address
	}
	return

}

// newQuery creates a new transaction id and adds an entry to r.pendingQueries.
// It does not set any extra information to the transaction information, so the
// caller must take care of that.
func (r *remoteNode) newQuery(transType string) (transId string) {
	log.V(4).Infof("newQuery for %x, lastID %v", r.id, r.lastQueryID)
	r.lastQueryID = (r.lastQueryID + 1) % 256
	transId = strconv.Itoa(r.lastQueryID)
	log.V(4).Infof("... new id %v", r.lastQueryID)
	r.pendingQueries[transId] = &queryType{Type: transType}
	return
}

// wasContactedRecently returns true if a node was contacted recently _and_
// one of the recent queries (not necessarily the last) was about the ih. If
// the ih is different at each time, it will keep returning false.
func (r *remoteNode) wasContactedRecently(ih InfoHash) bool {
	if len(r.pendingQueries) == 0 && len(r.pastQueries) == 0 {
		return false
	}
	if !r.lastResponseTime.IsZero() && time.Since(r.lastResponseTime) > searchRetryPeriod {
		return false
	}
	for _, q := range r.pendingQueries {
		if q.ih == ih {
			return true
		}
	}
	for _, q := range r.pastQueries {
		if q.ih == ih {
			return true
		}
	}
	return false
}

type getPeersResponse struct {
	// TODO: argh, values can be a string depending on the client (e.g: original bittorrent).
	Values []string "values"
	Id     string   "id"
	Nodes  string   "nodes"
	Token  string   "token"
}

type answerType struct {
	Id       string   "id"
	Target   string   "target"
	InfoHash InfoHash "info_hash" // should probably be a string.
	Port     int      "port"
	Token    string   "token"
}

// Generic stuff we read from the wire, not knowing what it is. This is as generic as can be.
type responseType struct {
	T string           "t"
	Y string           "y"
	Q string           "q"
	R getPeersResponse "r"
	E []string         "e"
	A answerType       "a"
	// Unsupported mainline extension for client identification.
	// V string(?)	"v"
}

// sendMsg bencodes the data in 'query' and sends it to the remote node.
func sendMsg(conn *net.UDPConn, raddr net.UDPAddr, query interface{}) {
	totalSent.Add(1)
	var b bytes.Buffer
	if err := bencode.Marshal(&b, query); err != nil {
		return
	}
	if n, err := conn.WriteToUDP(b.Bytes(), &raddr); err != nil {
		// debug.Println("DHT: node write failed:", err)
	} else {
		totalWrittenBytes.Add(int64(n))
	}
	return
}

// Read responses from bencode-speaking nodes. Return the appropriate data structure.
func readResponse(p packetType) (response responseType, err error) {
	// The calls to bencode.Unmarshal() can be fragile.
	defer func() {
		if x := recover(); x != nil {
			// debug.Printf("DHT: !!! Recovering from panic() after bencode.Unmarshal %q, %v", string(p.b), x)
		}
	}()
	if e2 := bencode.Unmarshal(bytes.NewBuffer(p.b), &response); e2 == nil {
		err = nil
		return
	} else {
		// debug.Printf("DHT: unmarshal error, odd or partial data during UDP read? %v, err=%s", string(p.b), e2)
		return response, e2
	}
	return
}

// Message to be sent out in the wire. Must not have any extra fields.
type queryMessage struct {
	T string                 "t"
	Y string                 "y"
	Q string                 "q"
	A map[string]interface{} "a"
}

type replyMessage struct {
	T string                 "t"
	Y string                 "y"
	R map[string]interface{} "r"
}

type packetType struct {
	b     []byte
	raddr net.UDPAddr
}

func listen(addr string, listenPort int) (socket *net.UDPConn, err error) {
	// debug.Printf("DHT: Listening for peers on port: %d\n", listenPort)
   log.V(3).Infof("DHT: Listening for peers on IP: %s port: %d\n", addr,listenPort)
	listener, err := net.ListenPacket("udp6", addr+":"+strconv.Itoa(listenPort))
	if err != nil {
		// debug.Println("DHT: Listen failed:", err)
	}
	if listener != nil {
		socket = listener.(*net.UDPConn)
	}
	return
}

// Read from UDP socket, writes slice of byte into channel.
func readFromSocket(socket *net.UDPConn, conChan chan packetType, bytesArena arena, stop chan bool) {
	for {
		b := bytesArena.Pop()
		n, addr, err := socket.ReadFromUDP(b)
		b = b[0:n]
		if n == maxUDPPacketSize {
			// debug.Printf("DHT: Warning. Received packet with len >= %d, some data may have been discarded.\n", maxUDPPacketSize)
		}
		totalReadBytes.Add(int64(n))
		if n > 0 && err == nil {
			p := packetType{b, *addr}
			select {
			case conChan <- p:
				continue
			case <-stop:
				return
			}
		}
		// debug.Println("DHT: readResponse error:", err)

		// Do a non-blocking read of the stop channel and stop this goroutine if the channel
		// has been closed.
		select {
		case <-stop:
			return
		default:
		}
	}
}

func bogusId(id string) bool {
	return len(id) != 20
}

func newTransactionId() int {
	n, err := rand.Read(make([]byte, 1))
	if err != nil {
		return time.Now().Second()
	}
	return n
}

type InfoHash string

// DecodeInfoHash transforms a hex-encoded 20-characters string to a binary
// infohash.
func DecodeInfoHash(x string) (b InfoHash, err error) {
	var h []byte
	h, err = hex.DecodeString(x)
	if len(h) != 20 {
		return "", fmt.Errorf("DecodeInfoHash: expected InfoHash len=20, got %d", len(h))
	}
	return InfoHash(h), err
}

// DecodePeerAddress transforms the binary-encoded host:port address into a
// human-readable format. So, "abcdef" becomes 97.98.99.100:25958.
func DecodePeerAddress(x string) string {
	return nettools.BinaryToDottedPort(x)
}
<|endoftext|>


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

package main

import (
	"log"
)

var cmdList = &Command{
	Name: "list",
	Run: runList,
}

func runList(args []string) {
	// Ask the registry for a list.
	registry := getRegistry()
	jobs, err := registry.ListRecentBackups()
	if err != nil {
		log.Fatalln("Listing recent backups:", err)
	}

	// Print each.
	log.Println("")
	log.Println("")
	log.Println("Recent backups:")
	log.Println("")
	log.Printf(
		"  %-16s   %-40s   %-29s   %s\n",
		"ID",
		"JOB NAME",
		"START TIME",
		"SCORE",
	)

	for _, job := range jobs {
		log.Printf(
			"  %16x   %-40s   %-29s   %s\n",
			job.Id,
			job.Name,
			job.StartTime,
			job.Score.Hex(),
		)
	}
}
<commit_msg>Widened time column.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"log"
)

var cmdList = &Command{
	Name: "list",
	Run: runList,
}

func runList(args []string) {
	// Ask the registry for a list.
	registry := getRegistry()
	jobs, err := registry.ListRecentBackups()
	if err != nil {
		log.Fatalln("Listing recent backups:", err)
	}

	// Print each.
	log.Println("")
	log.Println("")
	log.Println("Recent backups:")
	log.Println("")
	log.Printf(
		"  %-16s   %-40s   %-33s   %s\n",
		"ID",
		"JOB NAME",
		"START TIME",
		"SCORE",
	)

	for _, job := range jobs {
		log.Printf(
			"  %16x   %-40s   %-33s   %s\n",
			job.Id,
			job.Name,
			job.StartTime,
			job.Score.Hex(),
		)
	}
}
<|endoftext|>


<commit_before>/*
Package lmdb provides bindings to the lmdb C API.  The package bindings are
fairly low level and are designed to provide a minimal interface that prevents
misuse to a reasonable extent.  When in doubt refer to the C documentation as a
reference.

	http://symas.com/mdb/doc/group__mdb.html

Experimental

This package is experimental and the API is in flux while core development is
being done and the spartan but volumnous LMDB docs are being completly
deciphered.

Transactions

Readonly transactions in LMDB operate on a snapshot of the database at the time
the transaction began.  The number of simultaneously active read transaction is
bounded and configured when the environment is initialized.

LMDB allows only one read-write transaction to be active at a time.  Attempts
to create write transactions will block until no other write transactions are
active.

LMDB allows read-write transactions to have subtransactions which may be
aborted and rolled back without aborting their parent.  Transactions cannot be
used while they have an active subtransaction.

The lmdb package supplies managed, and unmanaged transaction types. Managed
transactions which do not require explicit calling of Abort()/Commit() are
provided through Env methods Update(), View(), and RunTxn(). Unmanaged readonly
transactions created with the method BeginView() and unmanaged readwrite
transactions with BeginUpdate().

Errors

The errors returned by the package API will with few exceptions have type Errno
or syscall.Errno.  The only errors of type Errno returned are those defined in
lmdb.h, those which have constants defined in this package.  Other errno values
like EINVAL will by of type syscall.Errno.
*/
package lmdb

/*
#cgo CFLAGS: -pthread -W -Wall -Wno-unused-parameter -Wbad-function-cast -O2 -g
#cgo freebsd CFLAGS: -DMDB_DSYNC=O_SYNC
#cgo openbsd CFLAGS: -DMDB_DSYNC=O_SYNC
#cgo netbsd CFLAGS: -DMDB_DSYNC=O_SYNC

#include "lmdb.h"
*/
import "C"

import (
	"fmt"
	"syscall"
)

// Errno represents the class of error defined by LMDB.  The only values of
// type Errno returned by the API are those declared as constants in this
// package.  Other errors resulting from non-zero errno values will be of type
// syscall.Errno.
type Errno C.int

// minimum and maximum values produced for the Errno type. syscall.Errnos of
// other values may still be produced.
const minErrno, maxErrno C.int = C.MDB_KEYEXIST, C.MDB_LAST_ERRCODE

func (e Errno) Error() string {
	s := C.GoString(C.mdb_strerror(C.int(e)))
	if s == "" {
		return fmt.Sprint("mdb errno:", int(e))
	}
	return s
}

// _errno is for use by tests that can't import C
func _errno(ret int) error {
	return errno(C.int(ret))
}

// errno transforms an integer returned by the LMDB C API into an error value,
// which may be nil.
func errno(ret C.int) error {
	if ret == C.MDB_SUCCESS {
		return nil
	}
	if minErrno <= ret && ret <= maxErrno {
		return Errno(ret)
	}
	return syscall.Errno(ret)
}

// The set of error codes defined by LMDB are typed constants.
const (
	ErrKeyExist        Errno = C.MDB_KEYEXIST
	ErrNotFound        Errno = C.MDB_NOTFOUND
	ErrPageNotFound    Errno = C.MDB_PAGE_NOTFOUND
	ErrCorrupted       Errno = C.MDB_CORRUPTED
	ErrPanic           Errno = C.MDB_PANIC
	ErrVersionMismatch Errno = C.MDB_VERSION_MISMATCH
	ErrInvalid         Errno = C.MDB_INVALID
	ErrMapFull         Errno = C.MDB_MAP_FULL
	ErrDBsFull         Errno = C.MDB_DBS_FULL
	ErrReadersFull     Errno = C.MDB_READERS_FULL
	ErrTLSFull         Errno = C.MDB_TLS_FULL
	ErrTxnFull         Errno = C.MDB_TXN_FULL
	ErrCursorFull      Errno = C.MDB_CURSOR_FULL
	ErrPageFull        Errno = C.MDB_PAGE_FULL
	ErrMapResized      Errno = C.MDB_MAP_RESIZED
	ErrIncompatibile   Errno = C.MDB_INCOMPATIBLE
)

// Version returns a string representation of the LMDB version.
//
// See mdb_version.
func Version() string {
	var major, minor, patch *C.int
	ver_str := C.mdb_version(major, minor, patch)
	return C.GoString(ver_str)
}

func cbool(b bool) C.int {
	if b {
		return 1
	}
	return 0
}
<commit_msg>godoc: env and dbi<commit_after>/*
Package lmdb provides bindings to the lmdb C API.  The package bindings are
fairly low level and are designed to provide a minimal interface that prevents
misuse to a reasonable extent.  When in doubt refer to the C documentation as a
reference.

	http://symas.com/mdb/doc/group__mdb.html

Experimental

This package is experimental and the API is in flux while core development is
being done and the spartan but volumnous LMDB docs are being completly
deciphered.

Environment

An LMDB environment is represented as one file on the filesystem (though often
a secondary corresponding lock file exists).  Most commonly the environment is
opened by supplying a directory path.

	err = env.Open("/path/to/database", 0, 0644)

Data for the above environment will be stored in the file
"/path/to/database/data.mdb" with permissions 0644.

Databases

A database in an LMDB environment is an ordered key-value store for data blobs.
A database is referenced by an opaque handle known as its DBI.  A single LMDB
environment can have multiple named databases.

There is also a (unnamed) root database that can be used to store data.  But
the root database must not be used in conjunction with named databases because
it serves as an index of named databases.  See the Txn.OpenDBI example for more
details.

Transactions

Readonly transactions in LMDB operate on a snapshot of the database at the time
the transaction began.  The number of simultaneously active read transaction is
bounded and configured when the environment is initialized.

LMDB allows only one read-write transaction to be active at a time.  Attempts
to create write transactions will block until no other write transactions are
active.

LMDB allows read-write transactions to have subtransactions which may be
aborted and rolled back without aborting their parent.  Transactions cannot be
used while they have an active subtransaction.

The lmdb package supplies managed, and unmanaged transaction types. Managed
transactions which do not require explicit calling of Abort()/Commit() are
provided through Env methods Update(), View(), and RunTxn(). Unmanaged readonly
transactions created with the method BeginView() and unmanaged readwrite
transactions with BeginUpdate().
*/
package lmdb

/*
#cgo CFLAGS: -pthread -W -Wall -Wno-unused-parameter -Wbad-function-cast -O2 -g
#cgo freebsd CFLAGS: -DMDB_DSYNC=O_SYNC
#cgo openbsd CFLAGS: -DMDB_DSYNC=O_SYNC
#cgo netbsd CFLAGS: -DMDB_DSYNC=O_SYNC

#include "lmdb.h"
*/
import "C"

import (
	"fmt"
	"syscall"
)

// Errno represents the class of error defined by LMDB.  The only values of
// type Errno returned by the API are those declared as constants in this
// package.  Other errors resulting from non-zero errno values will be of type
// syscall.Errno.
type Errno C.int

// minimum and maximum values produced for the Errno type. syscall.Errnos of
// other values may still be produced.
const minErrno, maxErrno C.int = C.MDB_KEYEXIST, C.MDB_LAST_ERRCODE

func (e Errno) Error() string {
	s := C.GoString(C.mdb_strerror(C.int(e)))
	if s == "" {
		return fmt.Sprint("mdb errno:", int(e))
	}
	return s
}

// _errno is for use by tests that can't import C
func _errno(ret int) error {
	return errno(C.int(ret))
}

// errno transforms an integer returned by the LMDB C API into an error value,
// which may be nil.
func errno(ret C.int) error {
	if ret == C.MDB_SUCCESS {
		return nil
	}
	if minErrno <= ret && ret <= maxErrno {
		return Errno(ret)
	}
	return syscall.Errno(ret)
}

// The set of error codes defined by LMDB are typed constants.
// See the list of LMDB return codes for more information
//
//		http://symas.com/mdb/doc/group__errors.html
const (
	ErrKeyExist        Errno = C.MDB_KEYEXIST
	ErrNotFound        Errno = C.MDB_NOTFOUND
	ErrPageNotFound    Errno = C.MDB_PAGE_NOTFOUND
	ErrCorrupted       Errno = C.MDB_CORRUPTED
	ErrPanic           Errno = C.MDB_PANIC
	ErrVersionMismatch Errno = C.MDB_VERSION_MISMATCH
	ErrInvalid         Errno = C.MDB_INVALID
	ErrMapFull         Errno = C.MDB_MAP_FULL
	ErrDBsFull         Errno = C.MDB_DBS_FULL
	ErrReadersFull     Errno = C.MDB_READERS_FULL
	ErrTLSFull         Errno = C.MDB_TLS_FULL
	ErrTxnFull         Errno = C.MDB_TXN_FULL
	ErrCursorFull      Errno = C.MDB_CURSOR_FULL
	ErrPageFull        Errno = C.MDB_PAGE_FULL
	ErrMapResized      Errno = C.MDB_MAP_RESIZED
	ErrIncompatibile   Errno = C.MDB_INCOMPATIBLE
)

// Version returns a string representation of the LMDB version.
//
// See mdb_version.
func Version() string {
	var major, minor, patch *C.int
	ver_str := C.mdb_version(major, minor, patch)
	return C.GoString(ver_str)
}

func cbool(b bool) C.int {
	if b {
		return 1
	}
	return 0
}
<|endoftext|>


<commit_before>// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package logs

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/issue9/logs/internal/config"
	"github.com/issue9/logs/writers"
)

// 定义了一些日志的类型
const (
	LevelInfo = iota
	LevelTrace
	LevelDebug
	LevelWarn
	LevelError
	LevelCritical
	levelSize
)

var levels = map[string]int{
	"info":     LevelInfo,
	"trace":    LevelTrace,
	"debug":    LevelDebug,
	"warn":     LevelWarn,
	"error":    LevelError,
	"critical": LevelCritical,
}

var (
	loggers [levelSize]*logger

	discard = log.New(ioutil.Discard, "", 0)
	ininted bool
)

type logger struct {
	flush writers.Flusher
	log   *log.Logger // 要确保这些值不能为空，因为要保证对应的 ERROR() 等函数的返回值是始终可用的。
}

func (l *logger) set(w io.Writer, prefix string, flag int) {
	if f, ok := w.(writers.Flusher); ok {
		l.flush = f
	}
	l.log = log.New(w, prefix, flag)
}

func init() {
	for index := range loggers {
		loggers[index] = &logger{
			log: discard,
		}
	}
}

// InitFromXMLFile 从一个 XML 文件中初始化日志系统。
// 再次调用该函数，将会根据新的配置文件重新初始化日志系统。
func InitFromXMLFile(path string) error {
	cfg, err := config.ParseXMLFile(path)
	if err != nil {
		return err
	}
	return initFromConfig(cfg)
}

// InitFromXMLString 从一个 XML 字符串初始化日志系统。
// 再次调用该函数，将会根据新的配置文件重新初始化日志系统。
func InitFromXMLString(xml string) error {
	cfg, err := config.ParseXMLString(xml)
	if err != nil {
		return err
	}
	return initFromConfig(cfg)
}

// SetWriter 设置某一个类型的输出通道
//
// 若将 w 设置为 nil 等同于 iotuil.Discard，即关闭此类型的输出。
func SetWriter(level int, w io.Writer, prefix string, flag int) error {
	if level < 0 || level > levelSize {
		return errors.New("无效的 level 值")
	}

	if w == nil {
		loggers[level].flush = nil
		loggers[level].log = discard
		return nil
	}

	loggers[level].set(w, prefix, flag)
	return nil
}

// 从 config.Config 中初始化整个 logs 系统
func initFromConfig(cfg *config.Config) error {
	for name, c := range cfg.Items {
		flag := 0
		flagStr, found := c.Attrs["flag"]
		if found && (len(flagStr) > 0) {
			var err error
			flag, err = parseFlag(flagStr)
			if err != nil {
				return err
			}
		}

		w, err := toWriter(c)
		if err != nil {
			return err
		}
		index, found := levels[name]
		if !found {
			return fmt.Errorf("未知道的二级元素名称:[%v]", name)
		}

		loggers[index].set(w, c.Attrs["prefix"], flag)
	}

	return nil
}

// Flush 输出所有的缓存内容。
// 若是通过 os.Exit() 退出程序的，在执行之前，
// 一定记得调用 Flush() 输出可能缓存的日志内容。
func Flush() {
	for _, l := range loggers {
		if l.flush != nil {
			l.flush.Flush()
		}
	}
}

// INFO 获取 INFO 级别的 log.Logger 实例，在未指定 info 级别的日志时，该实例返回一个 nil。
func INFO() *log.Logger {
	return loggers[LevelInfo].log
}

// Info 相当于 INFO().Println(v...) 的简写方式
// Info 函数默认是带换行符的，若需要不带换行符的，请使用 DEBUG().Print() 函数代替。
// 其它相似函数也有类型功能。
func Info(v ...interface{}) {
	loggers[LevelInfo].log.Output(2, fmt.Sprintln(v...))
}

// Infof 相当于 INFO().Printf(format, v...) 的简写方式
func Infof(format string, v ...interface{}) {
	loggers[LevelInfo].log.Output(2, fmt.Sprintf(format, v...))
}

// DEBUG 获取 DEBUG 级别的 log.Logger 实例，在未指定 debug 级别的日志时，该实例返回一个 nil。
func DEBUG() *log.Logger {
	return loggers[LevelDebug].log
}

// Debug 相当于 DEBUG().Println(v...) 的简写方式
func Debug(v ...interface{}) {
	loggers[LevelDebug].log.Output(2, fmt.Sprintln(v...))
}

// Debugf 相当于 DEBUG().Printf(format, v...) 的简写方式
func Debugf(format string, v ...interface{}) {
	loggers[LevelDebug].log.Output(2, fmt.Sprintf(format, v...))
}

// TRACE 获取 TRACE 级别的 log.Logger 实例，在未指定 trace 级别的日志时，该实例返回一个 nil。
func TRACE() *log.Logger {
	return loggers[LevelTrace].log
}

// Trace 相当于 TRACE().Println(v...) 的简写方式
func Trace(v ...interface{}) {
	loggers[LevelTrace].log.Output(2, fmt.Sprintln(v...))
}

// Tracef 相当于 TRACE().Printf(format, v...) 的简写方式
func Tracef(format string, v ...interface{}) {
	loggers[LevelTrace].log.Output(2, fmt.Sprintf(format, v...))
}

// WARN 获取 WARN 级别的 log.Logger 实例，在未指定 warn 级别的日志时，该实例返回一个 nil。
func WARN() *log.Logger {
	return loggers[LevelWarn].log
}

// Warn 相当于 WARN().Println(v...) 的简写方式
func Warn(v ...interface{}) {
	loggers[LevelWarn].log.Output(2, fmt.Sprintln(v...))
}

// Warnf 相当于 WARN().Printf(format, v...) 的简写方式
func Warnf(format string, v ...interface{}) {
	loggers[LevelWarn].log.Output(2, fmt.Sprintf(format, v...))
}

// ERROR 获取 ERROR 级别的 log.Logger 实例，在未指定 error 级别的日志时，该实例返回一个 nil。
func ERROR() *log.Logger {
	return loggers[LevelError].log
}

// Error 相当于 ERROR().Println(v...) 的简写方式
func Error(v ...interface{}) {
	loggers[LevelError].log.Output(2, fmt.Sprintln(v...))
}

// Errorf 相当于 ERROR().Printf(format, v...) 的简写方式
func Errorf(format string, v ...interface{}) {
	loggers[LevelError].log.Output(2, fmt.Sprintf(format, v...))
}

// CRITICAL 获取 CRITICAL 级别的 log.Logger 实例，在未指定 critical 级别的日志时，该实例返回一个 nil。
func CRITICAL() *log.Logger {
	return loggers[LevelCritical].log
}

// Critical 相当于 CRITICAL().Println(v...)的简写方式
func Critical(v ...interface{}) {
	loggers[LevelCritical].log.Output(2, fmt.Sprintln(v...))
}

// Criticalf 相当于 CRITICAL().Printf(format, v...) 的简写方式
func Criticalf(format string, v ...interface{}) {
	loggers[LevelCritical].log.Output(2, fmt.Sprintf(format, v...))
}

// All 向所有的日志输出内容。
func All(v ...interface{}) {
	all(v...)
}

// Allf 向所有的日志输出内容。
func Allf(format string, v ...interface{}) {
	allf(format, v...)
}

// Fatal 输出错误信息，然后退出程序。
func Fatal(v ...interface{}) {
	all(v...)
	Flush()
	os.Exit(2)
}

// Fatalf 输出错误信息，然后退出程序。
func Fatalf(format string, v ...interface{}) {
	allf(format, v...)
	Flush()
	os.Exit(2)
}

// Panic 输出错误信息，然后触发 panic。
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	all(s)
	Flush()
	panic(s)
}

// Panicf 输出错误信息，然后触发 panic。
func Panicf(format string, v ...interface{}) {
	allf(format, v...)
	Flush()
	panic(fmt.Sprintf(format, v...))
}

func all(v ...interface{}) {
	for _, l := range loggers {
		l.log.Output(3, fmt.Sprintln(v...))
	}
}

func allf(format string, v ...interface{}) {
	for _, l := range loggers {
		l.log.Output(3, fmt.Sprintf(format, v...))
	}
}
<commit_msg>删除不必要的变量<commit_after>// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package logs

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/issue9/logs/internal/config"
	"github.com/issue9/logs/writers"
)

// 定义了一些日志的类型
const (
	LevelInfo = iota
	LevelTrace
	LevelDebug
	LevelWarn
	LevelError
	LevelCritical
	levelSize
)

var levels = map[string]int{
	"info":     LevelInfo,
	"trace":    LevelTrace,
	"debug":    LevelDebug,
	"warn":     LevelWarn,
	"error":    LevelError,
	"critical": LevelCritical,
}

var (
	loggers [levelSize]*logger

	discard = log.New(ioutil.Discard, "", 0)
)

type logger struct {
	flush writers.Flusher
	log   *log.Logger // 要确保这些值不能为空，因为要保证对应的 ERROR() 等函数的返回值是始终可用的。
}

func (l *logger) set(w io.Writer, prefix string, flag int) {
	if f, ok := w.(writers.Flusher); ok {
		l.flush = f
	}
	l.log = log.New(w, prefix, flag)
}

func init() {
	for index := range loggers {
		loggers[index] = &logger{
			log: discard,
		}
	}
}

// InitFromXMLFile 从一个 XML 文件中初始化日志系统。
// 再次调用该函数，将会根据新的配置文件重新初始化日志系统。
func InitFromXMLFile(path string) error {
	cfg, err := config.ParseXMLFile(path)
	if err != nil {
		return err
	}
	return initFromConfig(cfg)
}

// InitFromXMLString 从一个 XML 字符串初始化日志系统。
// 再次调用该函数，将会根据新的配置文件重新初始化日志系统。
func InitFromXMLString(xml string) error {
	cfg, err := config.ParseXMLString(xml)
	if err != nil {
		return err
	}
	return initFromConfig(cfg)
}

// SetWriter 设置某一个类型的输出通道
//
// 若将 w 设置为 nil 等同于 iotuil.Discard，即关闭此类型的输出。
func SetWriter(level int, w io.Writer, prefix string, flag int) error {
	if level < 0 || level > levelSize {
		return errors.New("无效的 level 值")
	}

	if w == nil {
		loggers[level].flush = nil
		loggers[level].log = discard
		return nil
	}

	loggers[level].set(w, prefix, flag)
	return nil
}

// 从 config.Config 中初始化整个 logs 系统
func initFromConfig(cfg *config.Config) error {
	for name, c := range cfg.Items {
		flag := 0
		flagStr, found := c.Attrs["flag"]
		if found && (len(flagStr) > 0) {
			var err error
			flag, err = parseFlag(flagStr)
			if err != nil {
				return err
			}
		}

		w, err := toWriter(c)
		if err != nil {
			return err
		}
		index, found := levels[name]
		if !found {
			return fmt.Errorf("未知道的二级元素名称:[%v]", name)
		}

		loggers[index].set(w, c.Attrs["prefix"], flag)
	}

	return nil
}

// Flush 输出所有的缓存内容。
// 若是通过 os.Exit() 退出程序的，在执行之前，
// 一定记得调用 Flush() 输出可能缓存的日志内容。
func Flush() {
	for _, l := range loggers {
		if l.flush != nil {
			l.flush.Flush()
		}
	}
}

// INFO 获取 INFO 级别的 log.Logger 实例，在未指定 info 级别的日志时，该实例返回一个 nil。
func INFO() *log.Logger {
	return loggers[LevelInfo].log
}

// Info 相当于 INFO().Println(v...) 的简写方式
// Info 函数默认是带换行符的，若需要不带换行符的，请使用 DEBUG().Print() 函数代替。
// 其它相似函数也有类型功能。
func Info(v ...interface{}) {
	loggers[LevelInfo].log.Output(2, fmt.Sprintln(v...))
}

// Infof 相当于 INFO().Printf(format, v...) 的简写方式
func Infof(format string, v ...interface{}) {
	loggers[LevelInfo].log.Output(2, fmt.Sprintf(format, v...))
}

// DEBUG 获取 DEBUG 级别的 log.Logger 实例，在未指定 debug 级别的日志时，该实例返回一个 nil。
func DEBUG() *log.Logger {
	return loggers[LevelDebug].log
}

// Debug 相当于 DEBUG().Println(v...) 的简写方式
func Debug(v ...interface{}) {
	loggers[LevelDebug].log.Output(2, fmt.Sprintln(v...))
}

// Debugf 相当于 DEBUG().Printf(format, v...) 的简写方式
func Debugf(format string, v ...interface{}) {
	loggers[LevelDebug].log.Output(2, fmt.Sprintf(format, v...))
}

// TRACE 获取 TRACE 级别的 log.Logger 实例，在未指定 trace 级别的日志时，该实例返回一个 nil。
func TRACE() *log.Logger {
	return loggers[LevelTrace].log
}

// Trace 相当于 TRACE().Println(v...) 的简写方式
func Trace(v ...interface{}) {
	loggers[LevelTrace].log.Output(2, fmt.Sprintln(v...))
}

// Tracef 相当于 TRACE().Printf(format, v...) 的简写方式
func Tracef(format string, v ...interface{}) {
	loggers[LevelTrace].log.Output(2, fmt.Sprintf(format, v...))
}

// WARN 获取 WARN 级别的 log.Logger 实例，在未指定 warn 级别的日志时，该实例返回一个 nil。
func WARN() *log.Logger {
	return loggers[LevelWarn].log
}

// Warn 相当于 WARN().Println(v...) 的简写方式
func Warn(v ...interface{}) {
	loggers[LevelWarn].log.Output(2, fmt.Sprintln(v...))
}

// Warnf 相当于 WARN().Printf(format, v...) 的简写方式
func Warnf(format string, v ...interface{}) {
	loggers[LevelWarn].log.Output(2, fmt.Sprintf(format, v...))
}

// ERROR 获取 ERROR 级别的 log.Logger 实例，在未指定 error 级别的日志时，该实例返回一个 nil。
func ERROR() *log.Logger {
	return loggers[LevelError].log
}

// Error 相当于 ERROR().Println(v...) 的简写方式
func Error(v ...interface{}) {
	loggers[LevelError].log.Output(2, fmt.Sprintln(v...))
}

// Errorf 相当于 ERROR().Printf(format, v...) 的简写方式
func Errorf(format string, v ...interface{}) {
	loggers[LevelError].log.Output(2, fmt.Sprintf(format, v...))
}

// CRITICAL 获取 CRITICAL 级别的 log.Logger 实例，在未指定 critical 级别的日志时，该实例返回一个 nil。
func CRITICAL() *log.Logger {
	return loggers[LevelCritical].log
}

// Critical 相当于 CRITICAL().Println(v...)的简写方式
func Critical(v ...interface{}) {
	loggers[LevelCritical].log.Output(2, fmt.Sprintln(v...))
}

// Criticalf 相当于 CRITICAL().Printf(format, v...) 的简写方式
func Criticalf(format string, v ...interface{}) {
	loggers[LevelCritical].log.Output(2, fmt.Sprintf(format, v...))
}

// All 向所有的日志输出内容。
func All(v ...interface{}) {
	all(v...)
}

// Allf 向所有的日志输出内容。
func Allf(format string, v ...interface{}) {
	allf(format, v...)
}

// Fatal 输出错误信息，然后退出程序。
func Fatal(v ...interface{}) {
	all(v...)
	Flush()
	os.Exit(2)
}

// Fatalf 输出错误信息，然后退出程序。
func Fatalf(format string, v ...interface{}) {
	allf(format, v...)
	Flush()
	os.Exit(2)
}

// Panic 输出错误信息，然后触发 panic。
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	all(s)
	Flush()
	panic(s)
}

// Panicf 输出错误信息，然后触发 panic。
func Panicf(format string, v ...interface{}) {
	allf(format, v...)
	Flush()
	panic(fmt.Sprintf(format, v...))
}

func all(v ...interface{}) {
	for _, l := range loggers {
		l.log.Output(3, fmt.Sprintln(v...))
	}
}

func allf(format string, v ...interface{}) {
	for _, l := range loggers {
		l.log.Output(3, fmt.Sprintf(format, v...))
	}
}
<|endoftext|>


<commit_before>package textdistance

import (
	"math"
	"strings"
)

// JaroDistance calculates jaro distance between s1 and s2.
// This implementation is influenced by an implementation of [lucene](http://lucene.apache.org/)
// Note that this calculation's result is normalized ( the result will be bewtwen 0 and 1)
// and if t1 and t2 are exactly the same, the result is 1.0.
// This function returns distance and prefix (for jaro-winkler distance)
func JaroDistance(s1, s2 string) (float64, int) {
	if s1 == s2 {
		return 1.0, 0.0
	}
	var longer string
	var shorter string
	if len(s1) > len(s2) {
		longer = s1
		shorter = s2
	} else {
		longer = s2
		shorter = s1
	}
	scope := int(math.Floor(float64(len(longer)/2))) - 1
	// m is the number of matching characters.
	m := 0
	matchFlags := make([]bool, len(longer))
	matchIndexes := make([]int, len(longer))
	for i := range matchIndexes {
		matchIndexes[i] = -1
	}

	for i := 0; i < len(shorter); i++ {
		k := Min(i+scope+1, len(longer))
		for j := Max(i-scope, 0); j < k; j++ {
			if matchFlags[j] || shorter[i] != longer[j] {
				continue
			}
			matchIndexes[i] = j
			matchFlags[j] = true
			m++
			break
		}
	}
	ms1 := make([]uint8, m)
	ms2 := make([]uint8, m)
	si := 0
	for i := 0; i < len(shorter); i++ {
		if matchIndexes[i] != -1 {
			ms1[si] = shorter[i]
			si++
		}
	}
	si = 0
	for i := 0; i < len(longer); i++ {
		if matchFlags[i] {
			ms2[si] = longer[i]
			si++
		}
	}

	t := 0
	for i, c := range ms1 {
		if c != ms2[i] {
			t++
		}
	}
	prefix := 0
	longerArray := strings.Split(longer, "")
	shorterArray := strings.Split(shorter, "")
	for i := 0; i < len(shorter); i++ {
		if longerArray[i] == shorterArray[i] {
			prefix++
		} else {
			break
		}
	}
	if m == 0 {
		return 0.0, 0.0
	}
	newt := float64(t) / 2.0
	newm := float64(m)
	return 1 / 3.0 * (newm/float64(len(s1)) + newm/float64(len(s2)) + (newm-newt)/newm), prefix
}
<commit_msg>faster to not split string and just iterate string and compare runes<commit_after>package textdistance

import (
	"math"
)

// JaroDistance calculates jaro distance between s1 and s2.
// This implementation is influenced by an implementation of [lucene](http://lucene.apache.org/)
// Note that this calculation's result is normalized ( the result will be bewtwen 0 and 1)
// and if t1 and t2 are exactly the same, the result is 1.0.
// This function returns distance and prefix (for jaro-winkler distance)
func JaroDistance(s1, s2 string) (float64, int) {
	if s1 == s2 {
		return 1.0, 0.0
	}
	var longer string
	var shorter string
	if len(s1) > len(s2) {
		longer = s1
		shorter = s2
	} else {
		longer = s2
		shorter = s1
	}
	scope := int(math.Floor(float64(len(longer)/2))) - 1
	// m is the number of matching characters.
	m := 0
	matchFlags := make([]bool, len(longer))
	matchIndexes := make([]int, len(longer))
	for i := range matchIndexes {
		matchIndexes[i] = -1
	}

	for i := 0; i < len(shorter); i++ {
		k := Min(i+scope+1, len(longer))
		for j := Max(i-scope, 0); j < k; j++ {
			if matchFlags[j] || shorter[i] != longer[j] {
				continue
			}
			matchIndexes[i] = j
			matchFlags[j] = true
			m++
			break
		}
	}
	ms1 := make([]uint8, m)
	ms2 := make([]uint8, m)
	si := 0
	for i := 0; i < len(shorter); i++ {
		if matchIndexes[i] != -1 {
			ms1[si] = shorter[i]
			si++
		}
	}
	si = 0
	for i := 0; i < len(longer); i++ {
		if matchFlags[i] {
			ms2[si] = longer[i]
			si++
		}
	}

	t := 0
	for i, c := range ms1 {
		if c != ms2[i] {
			t++
		}
	}
	prefix := 0
	for i := 0; i < len(shorter); i++ {
		if longer[i] == shorter[i] {
			prefix++
		} else {
			break
		}
	}
	if m == 0 {
		return 0.0, 0.0
	}
	newt := float64(t) / 2.0
	newm := float64(m)
	return 1 / 3.0 * (newm/float64(len(s1)) + newm/float64(len(s2)) + (newm-newt)/newm), prefix
}
<|endoftext|>


<commit_before>package jira

import (
	"github.com/coryb/oreo"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("jira")

const VERSION = "1.0.11"

type Jira struct {
	Endpoint string     `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
	UA       HttpClient `json:"-" yaml:"-"`
}

func NewJira(endpoint string) *Jira {
	return &Jira{
		Endpoint: endpoint,
		UA:       oreo.New(),
	}
}
<commit_msg>version bump<commit_after>package jira

import (
	"github.com/coryb/oreo"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("jira")

const VERSION = "1.0.12"

type Jira struct {
	Endpoint string     `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
	UA       HttpClient `json:"-" yaml:"-"`
}

func NewJira(endpoint string) *Jira {
	return &Jira{
		Endpoint: endpoint,
		UA:       oreo.New(),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"net/http"
	"strings"

	"github.com/codegangsta/martini"
	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-flynn/cluster"
	"github.com/martini-contrib/render"
)

type clusterClient interface {
	ListHosts() (map[string]host.Host, error)
	ConnectHost(string) (cluster.Host, error)
}

func jobList(app *ct.App, cc clusterClient, r render.Render) {
	hosts, err := cc.ListHosts()
	if err != nil {
		// TODO: 500/handle error
	}
	var jobs []ct.Job
	for _, h := range hosts {
		for _, j := range h.Jobs {
			if j.Attributes["flynn-controller.app"] != app.ID {
				continue
			}

			job := ct.Job{
				ID:        h.ID + ":" + j.ID,
				Type:      j.Attributes["flynn-controller.type"],
				ReleaseID: j.Attributes["flynn-controller.release"],
			}
			if job.Type == "" {
				job.Cmd = j.Config.Cmd
			}
			jobs = append(jobs, job)
		}
	}

	r.JSON(200, jobs)
}

func jobLog(app *ct.App, params martini.Params, cluster cluster.Host, w http.ResponseWriter) {
	attachReq := &host.AttachReq{
		JobID: params["job_id"],
		Flags: host.AttachFlagStdout | host.AttachFlagStderr | host.AttachFlagStdin | host.AttachFlagLogs,
	}
	if _, ok := params["tail"]; ok {
		attachReq.Flags |= host.AttachFlagStream
	}
	stream, _, err := cluster.Attach(attachReq, false)
	if err != nil {
		// TODO: 500/log error
		// TODO: handle AttachWouldWait
	}
	defer stream.Close()
	io.Copy(w, stream)
}

func parseJobID(params martini.Params) (string, string) {
	id := strings.SplitN(params["job_id"], ":", 2)
	if len(id) != 2 || id[0] == "" || id[1] == "" {
		return "", ""
	}
	return id[0], id[1]
}

func connectHostMiddleware(c martini.Context, params martini.Params, cl clusterClient) {
	hostID, jobID := parseJobID(params)
	if hostID == "" {
		// TODO: error
	}
	params["job_id"] = jobID

	client, err := cl.ConnectHost(hostID)
	if err != nil {
		// TODO: 500/log error
	}
	c.MapTo(client, (*cluster.Host)(nil))

	c.Next()
	client.Close()
}

func killJob(app *ct.App, params martini.Params, client cluster.Host) {
	if err := client.StopJob(params["job_id"]); err != nil {
		// TODO: 500/log error
	}
}
<commit_msg>controller: Remove extraneous log flag<commit_after>package main

import (
	"io"
	"net/http"
	"strings"

	"github.com/codegangsta/martini"
	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-flynn/cluster"
	"github.com/martini-contrib/render"
)

type clusterClient interface {
	ListHosts() (map[string]host.Host, error)
	ConnectHost(string) (cluster.Host, error)
}

func jobList(app *ct.App, cc clusterClient, r render.Render) {
	hosts, err := cc.ListHosts()
	if err != nil {
		// TODO: 500/handle error
	}
	var jobs []ct.Job
	for _, h := range hosts {
		for _, j := range h.Jobs {
			if j.Attributes["flynn-controller.app"] != app.ID {
				continue
			}

			job := ct.Job{
				ID:        h.ID + ":" + j.ID,
				Type:      j.Attributes["flynn-controller.type"],
				ReleaseID: j.Attributes["flynn-controller.release"],
			}
			if job.Type == "" {
				job.Cmd = j.Config.Cmd
			}
			jobs = append(jobs, job)
		}
	}

	r.JSON(200, jobs)
}

func jobLog(app *ct.App, params martini.Params, cluster cluster.Host, w http.ResponseWriter) {
	attachReq := &host.AttachReq{
		JobID: params["job_id"],
		Flags: host.AttachFlagStdout | host.AttachFlagStderr | host.AttachFlagLogs,
	}
	if _, ok := params["tail"]; ok {
		attachReq.Flags |= host.AttachFlagStream
	}
	stream, _, err := cluster.Attach(attachReq, false)
	if err != nil {
		// TODO: 500/log error
		// TODO: handle AttachWouldWait
	}
	defer stream.Close()
	io.Copy(w, stream)
}

func parseJobID(params martini.Params) (string, string) {
	id := strings.SplitN(params["job_id"], ":", 2)
	if len(id) != 2 || id[0] == "" || id[1] == "" {
		return "", ""
	}
	return id[0], id[1]
}

func connectHostMiddleware(c martini.Context, params martini.Params, cl clusterClient) {
	hostID, jobID := parseJobID(params)
	if hostID == "" {
		// TODO: error
	}
	params["job_id"] = jobID

	client, err := cl.ConnectHost(hostID)
	if err != nil {
		// TODO: 500/log error
	}
	c.MapTo(client, (*cluster.Host)(nil))

	c.Next()
	client.Close()
}

func killJob(app *ct.App, params martini.Params, client cluster.Host) {
	if err := client.StopJob(params["job_id"]); err != nil {
		// TODO: 500/log error
	}
}
<|endoftext|>