<commit_before>package echo

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"reflect"
	"runtime"
	"strings"
	"sync"

	"github.com/labstack/gommon/log"
	"github.com/webx-top/echo/engine"
	"github.com/webx-top/echo/logger"
)

type (
	Echo struct {
		prefix           string
		middleware       []Middleware
		head             Handler
		maxParam         *int
		notFoundHandler  HandlerFunc
		httpErrorHandler HTTPErrorHandler
		binder           Binder
		renderer         Renderer
		pool             sync.Pool
		debug            bool
		router           *Router
		logger           logger.Logger
	}

	Route struct {
		Method  string
		Path    string
		Handler string
		Format  string
		Params  []string
	}

	HTTPError struct {
		Code    int
		Message string
	}

	Middleware interface {
		Handle(Handler) Handler
	}

	MiddlewareFunc func(Handler) Handler

	Handler interface {
		Handle(Context) error
	}

	HandleNamer interface {
		HandleName() string
	}

	HandlerFunc func(Context) error

	// HTTPErrorHandler is a centralized HTTP error handler.
	HTTPErrorHandler func(error, Context)

	// Validator is the interface that wraps the Validate method.
	Validator interface {
		Validate() error
	}

	// Renderer is the interface that wraps the Render method.
	Renderer interface {
		Render(w io.Writer, name string, data interface{}, c Context) error
	}
)

const (
	// CONNECT HTTP method
	CONNECT = "CONNECT"
	// DELETE HTTP method
	DELETE = "DELETE"
	// GET HTTP method
	GET = "GET"
	// HEAD HTTP method
	HEAD = "HEAD"
	// OPTIONS HTTP method
	OPTIONS = "OPTIONS"
	// PATCH HTTP method
	PATCH = "PATCH"
	// POST HTTP method
	POST = "POST"
	// PUT HTTP method
	PUT = "PUT"
	// TRACE HTTP method
	TRACE = "TRACE"

	//-------------
	// Media types
	//-------------

	ApplicationJSON                  = "application/json"
	ApplicationJSONCharsetUTF8       = ApplicationJSON + "; " + CharsetUTF8
	ApplicationJavaScript            = "application/javascript"
	ApplicationJavaScriptCharsetUTF8 = ApplicationJavaScript + "; " + CharsetUTF8
	ApplicationXML                   = "application/xml"
	ApplicationXMLCharsetUTF8        = ApplicationXML + "; " + CharsetUTF8
	ApplicationForm                  = "application/x-www-form-urlencoded"
	ApplicationProtobuf              = "application/protobuf"
	ApplicationMsgpack               = "application/msgpack"
	TextHTML                         = "text/html"
	TextHTMLCharsetUTF8              = TextHTML + "; " + CharsetUTF8
	TextPlain                        = "text/plain"
	TextPlainCharsetUTF8             = TextPlain + "; " + CharsetUTF8
	MultipartForm                    = "multipart/form-data"
	OctetStream                      = "application/octet-stream"

	//---------
	// Charset
	//---------

	CharsetUTF8 = "charset=utf-8"

	//---------
	// Headers
	//---------

	AcceptEncoding     = "Accept-Encoding"
	Authorization      = "Authorization"
	ContentDisposition = "Content-Disposition"
	ContentEncoding    = "Content-Encoding"
	ContentLength      = "Content-Length"
	ContentType        = "Content-Type"
	IfModifiedSince    = "If-Modified-Since"
	LastModified       = "Last-Modified"
	Location           = "Location"
	Upgrade            = "Upgrade"
	Vary               = "Vary"
	WWWAuthenticate    = "WWW-Authenticate"
	XForwardedFor      = "X-Forwarded-For"
	XRealIP            = "X-Real-IP"
)

var (
	methods = []string{
		CONNECT,
		DELETE,
		GET,
		HEAD,
		OPTIONS,
		PATCH,
		POST,
		PUT,
		TRACE,
	}

	//--------
	// Errors
	//--------

	ErrUnsupportedMediaType  = NewHTTPError(http.StatusUnsupportedMediaType)
	ErrNotFound              = NewHTTPError(http.StatusNotFound)
	ErrUnauthorized          = NewHTTPError(http.StatusUnauthorized)
	ErrMethodNotAllowed      = NewHTTPError(http.StatusMethodNotAllowed)
	ErrRendererNotRegistered = errors.New("renderer not registered")
	ErrInvalidRedirectCode   = errors.New("invalid redirect status code")

	//----------------
	// Error handlers
	//----------------

	notFoundHandler = HandlerFunc(func(c Context) error {
		return ErrNotFound
	})

	methodNotAllowedHandler = HandlerFunc(func(c Context) error {
		return ErrMethodNotAllowed
	})
)

// New creates an instance of Echo.
func New() (e *Echo) {
	return NewWithContext(func(e *Echo) Context {
		return NewContext(nil, nil, e)
	})
}

func NewWithContext(fn func(*Echo) Context) (e *Echo) {
	e = &Echo{maxParam: new(int)}
	e.pool.New = func() interface{} {
		return fn(e)
	}
	e.router = NewRouter(e)

	//----------
	// Defaults
	//----------

	e.SetHTTPErrorHandler(e.DefaultHTTPErrorHandler)
	e.SetBinder(&binder{Echo: e})

	// Logger
	e.logger = log.New("echo")

	return
}

func (m MiddlewareFunc) Handle(h Handler) Handler {
	return m(h)
}

func (h HandlerFunc) Handle(c Context) error {
	return h(c)
}

// Router returns router.
func (e *Echo) Router() *Router {
	return e.router
}

// SetLogger sets the logger instance.
func (e *Echo) SetLogger(l logger.Logger) {
	e.logger = l
}

// Logger returns the logger instance.
func (e *Echo) Logger() logger.Logger {
	return e.logger
}

// DefaultHTTPErrorHandler invokes the default HTTP error handler.
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if he, ok := err.(*HTTPError); ok {
		code = he.Code
		msg = he.Message
	}
	if e.debug {
		msg = err.Error()
	}
	if !c.Response().Committed() {
		c.String(code, msg)
	}
	e.logger.Debug(err)
}

// SetHTTPErrorHandler registers a custom Echo.HTTPErrorHandler.
func (e *Echo) SetHTTPErrorHandler(h HTTPErrorHandler) {
	e.httpErrorHandler = h
}

// SetBinder registers a custom binder. It's invoked by Context.Bind().
func (e *Echo) SetBinder(b Binder) {
	e.binder = b
}

// SetRenderer registers an HTML template renderer. It's invoked by Context.Render().
func (e *Echo) SetRenderer(r Renderer) {
	e.renderer = r
}

// SetDebug enable/disable debug mode.
func (e *Echo) SetDebug(on bool) {
	e.debug = on
	if logger, ok := e.logger.(*log.Logger); ok {
		if on {
			logger.SetLevel(log.DEBUG)
		} else {
			logger.SetLevel(log.INFO)
		}
	}
}

// Debug returns debug mode (enabled or disabled).
func (e *Echo) Debug() bool {
	return e.debug
}

// Use adds handler to the middleware chain.
func (e *Echo) Use(middleware ...Middleware) {
	e.middleware = append(e.middleware, middleware...)
}

// PreUse adds handler to the middleware chain.
func (e *Echo) PreUse(middleware ...Middleware) {
	e.middleware = append(middleware, e.middleware...)
}

// Connect adds a CONNECT route > handler to the router.
func (e *Echo) Connect(path string, h Handler, m ...Middleware) {
	e.add(CONNECT, path, h, m...)
}

// Delete adds a DELETE route > handler to the router.
func (e *Echo) Delete(path string, h Handler, m ...Middleware) {
	e.add(DELETE, path, h, m...)
}

// Get adds a GET route > handler to the router.
func (e *Echo) Get(path string, h Handler, m ...Middleware) {
	e.add(GET, path, h, m...)
}

// Head adds a HEAD route > handler to the router.
func (e *Echo) Head(path string, h Handler, m ...Middleware) {
	e.add(HEAD, path, h, m...)
}

// Options adds an OPTIONS route > handler to the router.
func (e *Echo) Options(path string, h Handler, m ...Middleware) {
	e.add(OPTIONS, path, h, m...)
}

// Patch adds a PATCH route > handler to the router.
func (e *Echo) Patch(path string, h Handler, m ...Middleware) {
	e.add(PATCH, path, h, m...)
}

// Post adds a POST route > handler to the router.
func (e *Echo) Post(path string, h Handler, m ...Middleware) {
	e.add(POST, path, h, m...)
}

// Put adds a PUT route > handler to the router.
func (e *Echo) Put(path string, h Handler, m ...Middleware) {
	e.add(PUT, path, h, m...)
}

// Trace adds a TRACE route > handler to the router.
func (e *Echo) Trace(path string, h Handler, m ...Middleware) {
	e.add(TRACE, path, h, m...)
}

// Any adds a route > handler to the router for all HTTP methods.
func (e *Echo) Any(path string, handler Handler, middleware ...Middleware) {
	for _, m := range methods {
		e.add(m, path, handler, middleware...)
	}
}

// Match adds a route > handler to the router for multiple HTTP methods provided.
func (e *Echo) Match(methods []string, path string, handler Handler, middleware ...Middleware) {
	for _, m := range methods {
		e.add(m, path, handler, middleware...)
	}
}

func (e *Echo) add(method, path string, handler Handler, middleware ...Middleware) {
	var name string
	if hn, ok := handler.(HandleNamer); ok {
		name = hn.HandleName()
	} else {
		name = handlerName(handler)
	}
	for _, m := range middleware {
		handler = m.Handle(handler)
	}
	fpath, pnames := e.router.Add(method, path, HandlerFunc(func(c Context) error {
		return handler.Handle(c)
	}), e)
	e.logger.Debugf(`ROUTE|[%v]%v -> %v`+"\n", method, fpath, name)
	r := Route{
		Method:  method,
		Path:    path,
		Handler: name,
		Format:  fpath,
		Params:  pnames,
	}
	if _, ok := e.router.nroute[name]; !ok {
		e.router.nroute[name] = []int{len(e.router.routes)}
	} else {
		e.router.nroute[name] = append(e.router.nroute[name], len(e.router.routes))
	}
	e.router.routes = append(e.router.routes, r)
}

// Group creates a new sub-router with prefix.
func (e *Echo) Group(prefix string, m ...Middleware) (g *Group) {
	g = &Group{prefix: prefix, echo: e}
	g.Use(m...)
	return
}

// URI generates a URI from handler.
func (e *Echo) URI(handler interface{}, params ...interface{}) string {
	uri := ``
	var name string
	if h, ok := handler.(Handler); ok {
		if hn, ok := h.(HandleNamer); ok {
			name = hn.HandleName()
		} else {
			name = handlerName(h)
		}
	} else if h, ok := handler.(string); ok {
		name = h
	} else {
		return uri
	}
	if indexes, ok := e.router.nroute[name]; ok && len(indexes) > 0 {
		r := e.router.routes[indexes[0]]
		length := len(params)
		if length == 1 {
			switch params[0].(type) {
			case url.Values:
				val := params[0].(url.Values)
				uri = r.Path
				for _, name := range r.Params {
					tag := `:` + name
					v := val.Get(name)
					uri = strings.Replace(uri, tag+`/`, v+`/`, -1)
					if strings.HasSuffix(uri, tag) {
						uri = strings.TrimSuffix(uri, tag) + v
					}
					val.Del(name)
				}
				q := val.Encode()
				if q != `` {
					uri += `?` + q
				}
			case map[string]string:
				val := params[0].(map[string]string)
				uri = r.Path
				for _, name := range r.Params {
					tag := `:` + name
					v, _ := val[name]
					uri = strings.Replace(uri, tag+`/`, v+`/`, -1)
					if strings.HasSuffix(uri, tag) {
						uri = strings.TrimSuffix(uri, tag) + v
					}
				}
			case []interface{}:
				val := params[0].([]interface{})
				uri = fmt.Sprintf(r.Format, val...)
			}
		} else {
			uri = fmt.Sprintf(r.Format, params...)
		}
	}
	return uri
}

// URL is an alias for `URI` function.
func (e *Echo) URL(h interface{}, params ...interface{}) string {
	return e.URI(h, params...)
}

// Routes returns the registered routes.
func (e *Echo) Routes() []Route {
	return e.router.routes
}

// Chain middleware
func (e *Echo) chainMiddleware() {
	if e.head != nil {
		return
	}
	e.head = e.router.Handle(nil)
	for i := len(e.middleware) - 1; i >= 0; i-- {
		e.head = e.middleware[i].Handle(e.head)
	}
}

func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) {
	c := e.pool.Get().(Context)
	c.Reset(req, res)

	e.chainMiddleware()

	if err := e.head.Handle(c); err != nil {
		c.Error(err)
	}

	e.pool.Put(c)
}

// Run starts the HTTP engine.
func (e *Echo) Run(eng engine.Engine) {
	eng.SetHandler(e)
	eng.SetLogger(e.logger)
	eng.Start()
}

func NewHTTPError(code int, msg ...string) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	if len(msg) > 0 {
		he.Message = msg[0]
	}
	return he
}

// Error returns message.
func (e *HTTPError) Error() string {
	return e.Message
}

func handlerName(h interface{}) string {
	v := reflect.ValueOf(h)
	t := v.Type()
	if t.Kind() == reflect.Func {
		return runtime.FuncForPC(v.Pointer()).Name()
	}
	return t.String()
}

func Methods() []string {
	return methods
}
<commit_msg>update<commit_after>package echo

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"reflect"
	"runtime"
	"strings"
	"sync"

	"github.com/labstack/gommon/log"
	"github.com/webx-top/echo/engine"
	"github.com/webx-top/echo/logger"
)

type (
	Echo struct {
		prefix           string
		middleware       []Middleware
		head             Handler
		maxParam         *int
		notFoundHandler  HandlerFunc
		httpErrorHandler HTTPErrorHandler
		binder           Binder
		renderer         Renderer
		pool             sync.Pool
		debug            bool
		router           *Router
		logger           logger.Logger
	}

	Route struct {
		Method  string
		Path    string
		Handler string
		Format  string
		Params  []string
	}

	HTTPError struct {
		Code    int
		Message string
	}

	Middleware interface {
		Handle(Handler) Handler
	}

	MiddlewareFunc func(Handler) Handler

	Handler interface {
		Handle(Context) error
	}

	HandleNamer interface {
		HandleName() string
	}

	HandlerFunc func(Context) error

	// HTTPErrorHandler is a centralized HTTP error handler.
	HTTPErrorHandler func(error, Context)

	// Validator is the interface that wraps the Validate method.
	Validator interface {
		Validate() error
	}

	// Renderer is the interface that wraps the Render method.
	Renderer interface {
		Render(w io.Writer, name string, data interface{}, c Context) error
	}
)

const (
	// CONNECT HTTP method
	CONNECT = "CONNECT"
	// DELETE HTTP method
	DELETE = "DELETE"
	// GET HTTP method
	GET = "GET"
	// HEAD HTTP method
	HEAD = "HEAD"
	// OPTIONS HTTP method
	OPTIONS = "OPTIONS"
	// PATCH HTTP method
	PATCH = "PATCH"
	// POST HTTP method
	POST = "POST"
	// PUT HTTP method
	PUT = "PUT"
	// TRACE HTTP method
	TRACE = "TRACE"

	//-------------
	// Media types
	//-------------

	ApplicationJSON                  = "application/json"
	ApplicationJSONCharsetUTF8       = ApplicationJSON + "; " + CharsetUTF8
	ApplicationJavaScript            = "application/javascript"
	ApplicationJavaScriptCharsetUTF8 = ApplicationJavaScript + "; " + CharsetUTF8
	ApplicationXML                   = "application/xml"
	ApplicationXMLCharsetUTF8        = ApplicationXML + "; " + CharsetUTF8
	ApplicationForm                  = "application/x-www-form-urlencoded"
	ApplicationProtobuf              = "application/protobuf"
	ApplicationMsgpack               = "application/msgpack"
	TextHTML                         = "text/html"
	TextHTMLCharsetUTF8              = TextHTML + "; " + CharsetUTF8
	TextPlain                        = "text/plain"
	TextPlainCharsetUTF8             = TextPlain + "; " + CharsetUTF8
	MultipartForm                    = "multipart/form-data"
	OctetStream                      = "application/octet-stream"

	//---------
	// Charset
	//---------

	CharsetUTF8 = "charset=utf-8"

	//---------
	// Headers
	//---------

	AcceptEncoding     = "Accept-Encoding"
	Authorization      = "Authorization"
	ContentDisposition = "Content-Disposition"
	ContentEncoding    = "Content-Encoding"
	ContentLength      = "Content-Length"
	ContentType        = "Content-Type"
	IfModifiedSince    = "If-Modified-Since"
	LastModified       = "Last-Modified"
	Location           = "Location"
	Upgrade            = "Upgrade"
	Vary               = "Vary"
	WWWAuthenticate    = "WWW-Authenticate"
	XForwardedFor      = "X-Forwarded-For"
	XRealIP            = "X-Real-IP"
)

var (
	methods = []string{
		CONNECT,
		DELETE,
		GET,
		HEAD,
		OPTIONS,
		PATCH,
		POST,
		PUT,
		TRACE,
	}

	//--------
	// Errors
	//--------

	ErrUnsupportedMediaType  = NewHTTPError(http.StatusUnsupportedMediaType)
	ErrNotFound              = NewHTTPError(http.StatusNotFound)
	ErrUnauthorized          = NewHTTPError(http.StatusUnauthorized)
	ErrMethodNotAllowed      = NewHTTPError(http.StatusMethodNotAllowed)
	ErrRendererNotRegistered = errors.New("renderer not registered")
	ErrInvalidRedirectCode   = errors.New("invalid redirect status code")

	//----------------
	// Error handlers
	//----------------

	notFoundHandler = HandlerFunc(func(c Context) error {
		return ErrNotFound
	})

	methodNotAllowedHandler = HandlerFunc(func(c Context) error {
		return ErrMethodNotAllowed
	})
)

// New creates an instance of Echo.
func New() (e *Echo) {
	return NewWithContext(func(e *Echo) Context {
		return NewContext(nil, nil, e)
	})
}

func NewWithContext(fn func(*Echo) Context) (e *Echo) {
	e = &Echo{maxParam: new(int)}
	e.pool.New = func() interface{} {
		return fn(e)
	}
	e.router = NewRouter(e)

	//----------
	// Defaults
	//----------

	e.SetHTTPErrorHandler(e.DefaultHTTPErrorHandler)
	e.SetBinder(&binder{Echo: e})

	// Logger
	e.logger = log.New("echo")

	return
}

func (m MiddlewareFunc) Handle(h Handler) Handler {
	return m(h)
}

func (h HandlerFunc) Handle(c Context) error {
	return h(c)
}

// Router returns router.
func (e *Echo) Router() *Router {
	return e.router
}

// SetLogger sets the logger instance.
func (e *Echo) SetLogger(l logger.Logger) {
	e.logger = l
}

// Logger returns the logger instance.
func (e *Echo) Logger() logger.Logger {
	return e.logger
}

// DefaultHTTPErrorHandler invokes the default HTTP error handler.
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if he, ok := err.(*HTTPError); ok {
		code = he.Code
		msg = he.Message
	}
	if e.debug {
		msg = err.Error()
	}
	if !c.Response().Committed() {
		c.String(code, msg)
	}
	e.logger.Debug(err)
}

// SetHTTPErrorHandler registers a custom Echo.HTTPErrorHandler.
func (e *Echo) SetHTTPErrorHandler(h HTTPErrorHandler) {
	e.httpErrorHandler = h
}

// SetBinder registers a custom binder. It's invoked by Context.Bind().
func (e *Echo) SetBinder(b Binder) {
	e.binder = b
}

// SetRenderer registers an HTML template renderer. It's invoked by Context.Render().
func (e *Echo) SetRenderer(r Renderer) {
	e.renderer = r
}

// SetDebug enable/disable debug mode.
func (e *Echo) SetDebug(on bool) {
	e.debug = on
	if logger, ok := e.logger.(*log.Logger); ok {
		if on {
			logger.SetLevel(log.DEBUG)
		} else {
			logger.SetLevel(log.INFO)
		}
	}
}

// Debug returns debug mode (enabled or disabled).
func (e *Echo) Debug() bool {
	return e.debug
}

// Use adds handler to the middleware chain.
func (e *Echo) Use(middleware ...Middleware) {
	e.middleware = append(e.middleware, middleware...)
}

// PreUse adds handler to the middleware chain.
func (e *Echo) PreUse(middleware ...Middleware) {
	e.middleware = append(middleware, e.middleware...)
}

// Connect adds a CONNECT route > handler to the router.
func (e *Echo) Connect(path string, h Handler, m ...Middleware) {
	e.add(CONNECT, path, h, m...)
}

// Delete adds a DELETE route > handler to the router.
func (e *Echo) Delete(path string, h Handler, m ...Middleware) {
	e.add(DELETE, path, h, m...)
}

// Get adds a GET route > handler to the router.
func (e *Echo) Get(path string, h Handler, m ...Middleware) {
	e.add(GET, path, h, m...)
}

// Head adds a HEAD route > handler to the router.
func (e *Echo) Head(path string, h Handler, m ...Middleware) {
	e.add(HEAD, path, h, m...)
}

// Options adds an OPTIONS route > handler to the router.
func (e *Echo) Options(path string, h Handler, m ...Middleware) {
	e.add(OPTIONS, path, h, m...)
}

// Patch adds a PATCH route > handler to the router.
func (e *Echo) Patch(path string, h Handler, m ...Middleware) {
	e.add(PATCH, path, h, m...)
}

// Post adds a POST route > handler to the router.
func (e *Echo) Post(path string, h Handler, m ...Middleware) {
	e.add(POST, path, h, m...)
}

// Put adds a PUT route > handler to the router.
func (e *Echo) Put(path string, h Handler, m ...Middleware) {
	e.add(PUT, path, h, m...)
}

// Trace adds a TRACE route > handler to the router.
func (e *Echo) Trace(path string, h Handler, m ...Middleware) {
	e.add(TRACE, path, h, m...)
}

// Any adds a route > handler to the router for all HTTP methods.
func (e *Echo) Any(path string, handler Handler, middleware ...Middleware) {
	for _, m := range methods {
		e.add(m, path, handler, middleware...)
	}
}

// Match adds a route > handler to the router for multiple HTTP methods provided.
func (e *Echo) Match(methods []string, path string, handler Handler, middleware ...Middleware) {
	for _, m := range methods {
		e.add(m, path, handler, middleware...)
	}
}

func (e *Echo) add(method, path string, handler Handler, middleware ...Middleware) {
	var name string
	if hn, ok := handler.(HandleNamer); ok {
		name = hn.HandleName()
	} else {
		name = handlerName(handler)
	}
	for _, m := range middleware {
		handler = m.Handle(handler)
	}
	fpath, pnames := e.router.Add(method, path, HandlerFunc(func(c Context) error {
		return handler.Handle(c)
	}), e)
	e.logger.Debugf(`ROUTE|[%v]%v -> %v`+"\n", method, fpath, name)
	r := Route{
		Method:  method,
		Path:    path,
		Handler: name,
		Format:  fpath,
		Params:  pnames,
	}
	if _, ok := e.router.nroute[name]; !ok {
		e.router.nroute[name] = []int{len(e.router.routes)}
	} else {
		e.router.nroute[name] = append(e.router.nroute[name], len(e.router.routes))
	}
	e.router.routes = append(e.router.routes, r)
}

// Group creates a new sub-router with prefix.
func (e *Echo) Group(prefix string, m ...Middleware) (g *Group) {
	g = &Group{prefix: prefix, echo: e}
	g.Use(m...)
	return
}

// URI generates a URI from handler.
func (e *Echo) URI(handler interface{}, params ...interface{}) string {
	uri := ``
	var name string
	if h, ok := handler.(Handler); ok {
		if hn, ok := h.(HandleNamer); ok {
			name = hn.HandleName()
		} else {
			name = handlerName(h)
		}
	} else if h, ok := handler.(string); ok {
		name = h
	} else {
		return uri
	}
	if indexes, ok := e.router.nroute[name]; ok && len(indexes) > 0 {
		r := e.router.routes[indexes[0]]
		length := len(params)
		if length == 1 {
			switch params[0].(type) {
			case url.Values:
				val := params[0].(url.Values)
				uri = r.Path
				for _, name := range r.Params {
					tag := `:` + name
					v := val.Get(name)
					uri = strings.Replace(uri, tag+`/`, v+`/`, -1)
					if strings.HasSuffix(uri, tag) {
						uri = strings.TrimSuffix(uri, tag) + v
					}
					val.Del(name)
				}
				q := val.Encode()
				if q != `` {
					uri += `?` + q
				}
			case map[string]string:
				val := params[0].(map[string]string)
				uri = r.Path
				for _, name := range r.Params {
					tag := `:` + name
					v, _ := val[name]
					uri = strings.Replace(uri, tag+`/`, v+`/`, -1)
					if strings.HasSuffix(uri, tag) {
						uri = strings.TrimSuffix(uri, tag) + v
					}
				}
			case []interface{}:
				val := params[0].([]interface{})
				uri = fmt.Sprintf(r.Format, val...)
			}
		} else {
			uri = fmt.Sprintf(r.Format, params...)
		}
	}
	return uri
}

// URL is an alias for `URI` function.
func (e *Echo) URL(h interface{}, params ...interface{}) string {
	return e.URI(h, params...)
}

// Routes returns the registered routes.
func (e *Echo) Routes() []Route {
	return e.router.routes
}

// NamedRoutes returns the registered handler name.
func (e *Echo) NamedRoutes() map[string][]int {
	return e.router.nroute
}

// Chain middleware
func (e *Echo) chainMiddleware() {
	if e.head != nil {
		return
	}
	e.head = e.router.Handle(nil)
	for i := len(e.middleware) - 1; i >= 0; i-- {
		e.head = e.middleware[i].Handle(e.head)
	}
}

func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) {
	c := e.pool.Get().(Context)
	c.Reset(req, res)

	e.chainMiddleware()

	if err := e.head.Handle(c); err != nil {
		c.Error(err)
	}

	e.pool.Put(c)
}

// Run starts the HTTP engine.
func (e *Echo) Run(eng engine.Engine) {
	eng.SetHandler(e)
	eng.SetLogger(e.logger)
	eng.Start()
}

func NewHTTPError(code int, msg ...string) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	if len(msg) > 0 {
		he.Message = msg[0]
	}
	return he
}

// Error returns message.
func (e *HTTPError) Error() string {
	return e.Message
}

func handlerName(h interface{}) string {
	v := reflect.ValueOf(h)
	t := v.Type()
	if t.Kind() == reflect.Func {
		return runtime.FuncForPC(v.Pointer()).Name()
	}
	return t.String()
}

func Methods() []string {
	return methods
}
<|endoftext|>


<commit_before>package bmdb

import (
	"sync"

	"github.com/missionMeteora/bmdb/mdb"
)

// Tx represents a read-only or read/write transaction on the database.
// Read-only transactions can be used for retrieving values for keys and creating cursors.
// Read/write transactions can create and remove buckets and create and remove keys.
type Tx struct {
	db       *DB
	txn      *mdb.Txn
	managed  bool
	writable bool
	done     bool

	// closeCallback is used to notify the parent DB about a closed transaction
	closeCallback func()

	// A protected registry.
	mux            sync.RWMutex
	commitHandlers []func()
	cursors        map[*Cursor]struct{}
}

// CreateBucket creates a new bucket.
// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long.
func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) {
	if tx.done {
		return nil, ErrTxDone
	} else if len(name) == 0 {
		return nil, ErrNoBucketName
	} else if len(name) > MaxNameLength {
		return nil, ErrNameTooLong
	}
	if b := tx.Bucket(name); b != nil {
		return nil, ErrBucketExists
	}
	n := string(name)
	dbi, err := tx.txn.DBIOpen(&n, mdb.CREATE)
	if err != nil {
		return nil, err
	}
	return &Bucket{dbi: dbi, tx: tx}, nil
}

// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
// Returns an error if the bucket name is blank, or if the bucket name is too long.
func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) {
	if tx.done {
		return nil, ErrTxDone
	} else if !tx.Writable() {
		return nil, ErrTxNotWritable
	} else if len(name) == 0 {
		return nil, ErrNoBucketName
	} else if len(name) > MaxNameLength {
		return nil, ErrNameTooLong
	}
	b := tx.Bucket(name)
	if b != nil {
		return b, nil
	}
	return tx.CreateBucket(name)
}

// Bucket retrieves a bucket by name. Returns nil if the bucket does not exist.
func (tx *Tx) Bucket(name []byte) *Bucket {
	if tx.done {
		return nil
	} else if len(name) == 0 {
		return nil
	} else if len(name) > MaxNameLength {
		return nil
	}
	// try to open an existing bucket
	n := string(name)
	dbi, err := tx.txn.DBIOpen(&n, 0)
	if err != nil {
		return nil
	}
	return &Bucket{dbi: dbi, tx: tx}
}

// BucketNames XXX.
func (tx *Tx) BucketNames() *Bucket {
	// try to open an existing bucket
	dbi, err := tx.txn.DBIOpen(nil, 0)
	if err != nil {
		return nil
	}
	return &Bucket{dbi: dbi, tx: tx}
}

// DeleteBucket deletes a bucket.
// Returns an error if the bucket cannot be found or the provided name was incorrect.
func (tx *Tx) DeleteBucket(name []byte) error {
	if tx.done {
		return ErrTxDone
	} else if len(name) == 0 {
		return ErrNoBucketName
	} else if len(name) > MaxNameLength {
		return ErrNameTooLong
	} else if !tx.Writable() {
		return ErrTxNotWritable
	}
	b := tx.Bucket(name)
	if b != nil {
		return tx.txn.Drop(b.dbi, 1)
	}
	return ErrBucketNotFound
}

// OnCommit adds a handler function to be executed after the transaction successfully commits.
func (tx *Tx) OnCommit(fn func()) {
	tx.mux.Lock()
	tx.commitHandlers = append(tx.commitHandlers, fn)
	tx.mux.Unlock()
}

// Rollback closes the transaction and ignores all previous updates.
func (tx *Tx) Rollback() error {
	if tx.managed {
		return ErrTxManaged
	} else if tx.done {
		return ErrTxDone
	}
	tx.done = true
	tx.mux.Lock()
	defer tx.mux.Unlock()
	tx.txn.Abort()
	if !tx.Writable() {
		for c := range tx.cursors {
			c.Close()
		}
	}
	tx.cursors = nil
	tx.commitHandlers = nil
	if tx.closeCallback != nil {
		tx.closeCallback()
	}
	return nil
}

// Commit commits all the operations of a transaction into the database and writes to the disk.
// The transaction handle is freed. It and its cursors must not be used again after this call.
func (tx *Tx) Commit() error {
	if tx.managed {
		return ErrTxManaged
	} else if tx.done {
		return ErrTxDone
	}
	tx.mux.Lock()
	defer tx.mux.Unlock()
	tx.done = true
	err := tx.txn.Commit()
	if err != nil {
		tx.txn.Abort()
	} else {
		for _, hdl := range tx.commitHandlers {
			hdl()
		}
	}
	if !tx.Writable() {
		for c := range tx.cursors {
			c.Close()
		}
	}
	tx.cursors = nil
	tx.commitHandlers = nil
	if tx.closeCallback != nil {
		tx.closeCallback()
	}
	return nil
}

// Writable returns whether the transaction can perform write operations.
func (tx *Tx) Writable() bool {
	return tx.writable
}

func (tx *Tx) close() {
	if tx.done {
		return
	}
	tx.done = true
	tx.mux.Lock()
	defer tx.mux.Unlock()
	tx.txn.Abort()
	if !tx.Writable() {
		for c := range tx.cursors {
			c.Close()
		}
	}
	tx.cursors = nil
	if tx.closeCallback != nil {
		tx.closeCallback()
	}
}

func (tx *Tx) registerCursor(c *Cursor) {
	tx.mux.Lock()
	tx.cursors[c] = struct{}{}
	tx.mux.Unlock()
}

func (tx *Tx) activeCursorsCount() int {
	tx.mux.RLock()
	n := len(tx.cursors)
	tx.mux.RUnlock()
	return n
}
<commit_msg>fix "double free or corruption" error<commit_after>package bmdb

import (
	"fmt"
	"sync"

	"github.com/missionMeteora/bmdb/mdb"
)

// Tx represents a read-only or read/write transaction on the database.
// Read-only transactions can be used for retrieving values for keys and creating cursors.
// Read/write transactions can create and remove buckets and create and remove keys.
type Tx struct {
	db       *DB
	txn      *mdb.Txn
	managed  bool
	writable bool
	done     bool

	// closeCallback is used to notify the parent DB about a closed transaction
	closeCallback func()

	// A protected registry.
	mux            sync.RWMutex
	commitHandlers []func()
	cursors        map[*Cursor]struct{}
}

// CreateBucket creates a new bucket.
// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long.
func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) {
	if tx.done {
		return nil, ErrTxDone
	} else if len(name) == 0 {
		return nil, ErrNoBucketName
	} else if len(name) > MaxNameLength {
		return nil, ErrNameTooLong
	}
	if b := tx.Bucket(name); b != nil {
		return nil, ErrBucketExists
	}
	n := string(name)
	dbi, err := tx.txn.DBIOpen(&n, mdb.CREATE)
	if err != nil {
		return nil, err
	}
	return &Bucket{dbi: dbi, tx: tx}, nil
}

// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
// Returns an error if the bucket name is blank, or if the bucket name is too long.
func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) {
	if tx.done {
		return nil, ErrTxDone
	} else if !tx.Writable() {
		return nil, ErrTxNotWritable
	} else if len(name) == 0 {
		return nil, ErrNoBucketName
	} else if len(name) > MaxNameLength {
		return nil, ErrNameTooLong
	}
	b := tx.Bucket(name)
	if b != nil {
		return b, nil
	}
	return tx.CreateBucket(name)
}

// Bucket retrieves a bucket by name. Returns nil if the bucket does not exist.
func (tx *Tx) Bucket(name []byte) *Bucket {
	if tx.done {
		return nil
	} else if len(name) == 0 {
		return nil
	} else if len(name) > MaxNameLength {
		return nil
	}
	// try to open an existing bucket
	n := string(name)
	dbi, err := tx.txn.DBIOpen(&n, 0)
	if err != nil {
		return nil
	}
	return &Bucket{dbi: dbi, tx: tx}
}

// BucketNames XXX.
func (tx *Tx) BucketNames() *Bucket {
	// try to open an existing bucket
	dbi, err := tx.txn.DBIOpen(nil, 0)
	if err != nil {
		return nil
	}
	return &Bucket{dbi: dbi, tx: tx}
}

// DeleteBucket deletes a bucket.
// Returns an error if the bucket cannot be found or the provided name was incorrect.
func (tx *Tx) DeleteBucket(name []byte) error {
	if tx.done {
		return ErrTxDone
	} else if len(name) == 0 {
		return ErrNoBucketName
	} else if len(name) > MaxNameLength {
		return ErrNameTooLong
	} else if !tx.Writable() {
		return ErrTxNotWritable
	}
	b := tx.Bucket(name)
	if b != nil {
		return tx.txn.Drop(b.dbi, 1)
	}
	return ErrBucketNotFound
}

// OnCommit adds a handler function to be executed after the transaction successfully commits.
func (tx *Tx) OnCommit(fn func()) {
	tx.mux.Lock()
	tx.commitHandlers = append(tx.commitHandlers, fn)
	tx.mux.Unlock()
}

// Rollback closes the transaction and ignores all previous updates.
func (tx *Tx) Rollback() error {
	tx.mux.Lock()
	defer tx.mux.Unlock()
	if tx.managed {
		return ErrTxManaged
	} else if tx.done {
		return ErrTxDone
	}
	tx.done = true
	tx.txn.Abort()
	if !tx.Writable() {
		for c := range tx.cursors {
			c.Close()
		}
	}
	tx.cursors = nil
	tx.commitHandlers = nil
	if tx.closeCallback != nil {
		tx.closeCallback()
	}
	return nil
}

// Commit commits all the operations of a transaction into the database and writes to the disk.
// The transaction handle is freed. It and its cursors must not be used again after this call.
func (tx *Tx) Commit() error {
	tx.mux.Lock()
	defer tx.mux.Unlock()
	if tx.managed {
		return ErrTxManaged
	} else if tx.done {
		return ErrTxDone
	}
	tx.done = true
	err := tx.txn.Commit()
	if err != nil {
		fmt.Println("BMDB: error committing:", err)
	} else {
		for _, hdl := range tx.commitHandlers {
			hdl()
		}
	}
	if !tx.Writable() {
		for c := range tx.cursors {
			c.Close()
		}
	}
	tx.cursors = nil
	tx.commitHandlers = nil
	if tx.closeCallback != nil {
		tx.closeCallback()
	}
	return err
}

// Writable returns whether the transaction can perform write operations.
func (tx *Tx) Writable() bool {
	return tx.writable
}

func (tx *Tx) close() {
	if tx.done {
		return
	}
	tx.done = true
	tx.mux.Lock()
	defer tx.mux.Unlock()
	tx.txn.Abort()
	if !tx.Writable() {
		for c := range tx.cursors {
			c.Close()
		}
	}
	tx.cursors = nil
	if tx.closeCallback != nil {
		tx.closeCallback()
	}
}

func (tx *Tx) registerCursor(c *Cursor) {
	tx.mux.Lock()
	tx.cursors[c] = struct{}{}
	tx.mux.Unlock()
}

func (tx *Tx) activeCursorsCount() int {
	tx.mux.RLock()
	n := len(tx.cursors)
	tx.mux.RUnlock()
	return n
}
<|endoftext|>


<commit_before>package nra

import "golang.org/x/net/context"

// Tx represents a transaction.
type Tx struct {
	Tracer TxTracer

	id   int64
	name string
	url  string
	ss   *SegmentStack
}

// NewTx returns a new transaction.
func NewTx(name string) *Tx {
	return &Tx{
		Tracer: &NRTxTracer{},
		name:   name,
		ss:     NewSegmentStack(),
	}
}

// NewRequestTx returns a new transaction with a request url.
func NewRequestTx(name string, url string) *Tx {
	return &Tx{
		Tracer: &NRTxTracer{},
		name:   name,
		url:    url,
		ss:     NewSegmentStack(),
	}
}

// Start starts a transaction, setting the id.
func (t *Tx) Start() error {
	if t.id != 0 {
		return ErrTxAlreadyStarted
	}
	t.id = t.Tracer.BeginTransaction()
	if err := t.Tracer.SetTransactionName(t.id, t.name); err != nil {
		return err
	}
	if t.url != "" {
		return t.Tracer.SetTransactionRequestURL(t.id, t.url)
	}
	return nil
}

// End ends a transaction.
func (t *Tx) End() error {
	for t.ss.Peek() != rootSegment {
		t.EndSegment()
	}
	return t.Tracer.EndTransaction(t.id)
}

// StartGeneric starts a generic segment.
func (t *Tx) StartGeneric(name string) {
	id := t.Tracer.BeginGenericSegment(t.id, t.ss.Peek(), name)
	t.ss.Push(id)
}

// StartDatastore starts a datastore segment.
func (t *Tx) StartDatastore(table, operation, sql, rollupName string) {
	id := t.Tracer.BeginDatastoreSegment(t.id, t.ss.Peek(), table, operation, sql, rollupName)
	t.ss.Push(id)
}

// StartExternal starts an external segment.
func (t *Tx) StartExternal(host, name string) {
	id := t.Tracer.BeginExternalSegment(t.id, t.ss.Peek(), host, name)
	t.ss.Push(id)
}

// EndSegment ends the segment at the top of the stack.
func (t *Tx) EndSegment() error {
	if id, ok := t.ss.Pop(); ok {
		return t.Tracer.EndSegment(t.id, id)
	}
	return nil
}

// WithTx inserts a nra.Tx into the provided context.
func WithTx(ctx context.Context, t *Tx) context.Context {
	return context.WithValue(ctx, txKey, t)
}

// FromContext returns a nra.Tx from the context.
func FromContext(ctx context.Context) (*Tx, bool) {
	t, ok := ctx.Value(txKey).(*Tx)
	return t, ok
}

type key int

const (
	txKey key = iota
)
<commit_msg>Extract a Tx interface and allow injecting a tracer<commit_after>package nra

import "golang.org/x/net/context"

// Tx represents a transaction.
type Tx interface {
	Start() error
	End() error
	StartGeneric(name string)
	StartDatastore(table, operation, sql, rollupName string)
	StartExternal(host, name string)
	EndSegment() error
}

type tx struct {
	Tracer TxTracer

	id   int64
	name string
	url  string
	ss   *SegmentStack
}

// NewTx returns a new transaction.
func NewTx(name string, tracer TxTracer) Tx {
	if tracer == nil {
		tracer = &NRTxTracer{}
	}
	return &tx{
		Tracer: tracer,
		name:   name,
		ss:     NewSegmentStack(),
	}
}

// NewRequestTx returns a new transaction with a request url.
func NewRequestTx(name string, url string, tracer TxTracer) Tx {
	if tracer == nil {
		tracer = &NRTxTracer{}
	}
	return &tx{
		Tracer: tracer,
		name:   name,
		url:    url,
		ss:     NewSegmentStack(),
	}
}

// Start starts a transaction, setting the id.
func (t *tx) Start() error {
	if t.id != 0 {
		return ErrTxAlreadyStarted
	}
	t.id = t.Tracer.BeginTransaction()
	if err := t.Tracer.SetTransactionName(t.id, t.name); err != nil {
		return err
	}
	if t.url != "" {
		return t.Tracer.SetTransactionRequestURL(t.id, t.url)
	}
	return nil
}

// End ends a transaction.
func (t *tx) End() error {
	for t.ss.Peek() != rootSegment {
		t.EndSegment()
	}
	return t.Tracer.EndTransaction(t.id)
}

// StartGeneric starts a generic segment.
func (t *tx) StartGeneric(name string) {
	id := t.Tracer.BeginGenericSegment(t.id, t.ss.Peek(), name)
	t.ss.Push(id)
}

// StartDatastore starts a datastore segment.
func (t *tx) StartDatastore(table, operation, sql, rollupName string) {
	id := t.Tracer.BeginDatastoreSegment(t.id, t.ss.Peek(), table, operation, sql, rollupName)
	t.ss.Push(id)
}

// StartExternal starts an external segment.
func (t *tx) StartExternal(host, name string) {
	id := t.Tracer.BeginExternalSegment(t.id, t.ss.Peek(), host, name)
	t.ss.Push(id)
}

// EndSegment ends the segment at the top of the stack.
func (t *tx) EndSegment() error {
	if id, ok := t.ss.Pop(); ok {
		return t.Tracer.EndSegment(t.id, id)
	}
	return nil
}

// WithTx inserts a nra.Tx into the provided context.
func WithTx(ctx context.Context, t Tx) context.Context {
	return context.WithValue(ctx, txKey, t)
}

// FromContext returns a nra.Tx from the context.
func FromContext(ctx context.Context) (Tx, bool) {
	t, ok := ctx.Value(txKey).(Tx)
	return t, ok
}

type key int

const (
	txKey key = iota
)
<|endoftext|>


<commit_before>package crosswd

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"strings"

	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/charmap"
)

// .puz constants
const (
	Magic      = "ACROSS&DOWN\x00"
	CksumMagic = "ICHEATED"
	Blank      = '.'
	Empty      = '-'
)

// Direction is a relative direction.
type Direction int

// Direction enumeration
const (
	NoDir Direction = iota
	Up
	Down
	Left
	Right
)

// Opposite returns the opposite direction of d.
func (d Direction) Opposite() Direction {
	switch d {
	case Left:
		return Right
	case Right:
		return Left
	case Up:
		return Down
	case Down:
		return Up
	}
	return NoDir
}

// Delta returns a unit vector in the direction d.
func (d Direction) Delta() Coord {
	switch d {
	case Up:
		return Coord{0, -1}
	case Down:
		return Coord{0, 1}
	case Left:
		return Coord{-1, 0}
	case Right:
		return Coord{1, 0}
	}
	return Coord{}
}

// Coord represents a 2D coordinate.
type Coord struct{ X, Y int }

// Grid represents a 2D array stored contiguously.
type Grid struct {
	elts  []byte
	cells [][]byte
}

// NewGrid returns a new Grid of size width x height.
func NewGrid(width, height int) *Grid {
	if width < 1 {
		width = 1
	}
	if height < 1 {
		height = 1
	}
	g := &Grid{}
	g.elts = make([]byte, width*height)
	g.cells = make([][]byte, height)
	for i := range g.cells {
		g.cells[i] = g.elts[i*width : (i+1)*width : (i+1)*width]
	}
	return g
}

// Size returns the grid dimensions.
func (g *Grid) Size() Coord {
	if len(g.cells) == 0 {
		return Coord{}
	}
	return Coord{len(g.cells), len(g.cells[0])}
}

// Valid returns whether a point is within the grid range.
func (g *Grid) Valid(p Coord) bool {
	return p.Y >= 0 && p.Y < len(g.cells) && p.X >= 0 && p.X < len(g.cells[0])
}

// At returns the value at p if valid and whether p is valid.
func (g *Grid) At(p Coord) (byte, bool) {
	if !g.Valid(p) {
		return 0, false
	}
	return g.cells[p.Y][p.X], true
}

// Set stores c at point p if valid and returns whether g was updated
func (g *Grid) Set(p Coord, c byte) bool {
	if !g.Valid(p) {
		return false
	}
	g.cells[p.Y][p.X] = c
	return true
}

// Header holds .puz file header data
type Header struct {
	Cksum       uint16
	Magic       [len(Magic)]byte
	BaseCksum   uint16
	MaskedCksum [8]byte
	Version     [4]byte
	Unused      [2]byte
	Unknown     [2]byte
	Reserved    [12]byte
	Width       uint8
	Height      uint8
	NumClues    uint16
	BitMask1    [2]byte // normally set to 0x0001
	BitMask2    [2]byte // 0x0004 = scrambled
}

// Puzzle holds the state of a crossword puzzle
type Puzzle struct {
	Header Header
	*Grid
	solution  *Grid
	Title     string
	Author    string
	Copyright string
	Clues     []string
	Notes     string
	Extra     []byte

	cellID  map[Coord]int
	idCell  map[int]Coord
	clueNum map[Direction]map[int]int
	enc     *encoding.Encoder
}

// New creates a Puzzle instance
func New() *Puzzle {
	return &Puzzle{
		cellID:  map[Coord]int{},
		idCell:  map[int]Coord{},
		clueNum: map[Direction]map[int]int{Right: {}, Down: {}},
		enc:     charmap.ISO8859_1.NewEncoder(),
	}
}

// Read reads crossword data in .puz format
func (p *Puzzle) Read(r io.Reader) error {
	if err := binary.Read(r, binary.LittleEndian, &p.Header); err != nil {
		return err
	}
	if string(p.Header.Magic[:]) != Magic {
		return errors.New("invalid magic")
	}
	width, height := int(p.Header.Width), int(p.Header.Height)
	p.solution = NewGrid(width, height)
	if _, err := io.ReadFull(r, p.solution.elts); err != nil {
		return err
	}
	p.Grid = NewGrid(width, height)
	if _, err := io.ReadFull(r, p.elts); err != nil {
		return err
	}
	rest, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	dec := charmap.ISO8859_1.NewDecoder()
	inFields := strings.SplitN(string(rest), "\x00", int(5+p.Header.NumClues))
	outFields := make([]string, 4+p.Header.NumClues)
	copy(outFields, inFields)
	p.Title, _ = dec.String(outFields[0])
	p.Author, _ = dec.String(outFields[1])
	p.Copyright, _ = dec.String(outFields[2])
	for i := 0; i < int(p.Header.NumClues); i++ {
		clue, _ := dec.String(outFields[3+i])
		p.Clues = append(p.Clues, clue)
	}
	p.Notes, _ = dec.String(outFields[3+p.Header.NumClues])
	if len(inFields) > len(outFields) {
		p.Extra = []byte(inFields[len(inFields)-1])
	}
	if p.Cksum() != p.Header.Cksum {
		return errors.New("checksum does not match")
	}
	return nil
}

// Write writes crossword data in .puz format
func (p *Puzzle) Write(w io.Writer) error {
	p.Header.BaseCksum = p.BaseCksum()
	p.Header.MaskedCksum = p.MaskedCksum()
	p.Header.Cksum = p.Cksum()

	if err := binary.Write(w, binary.LittleEndian, p.Header); err != nil {
		return err
	}
	if _, err := w.Write(p.solution.elts); err != nil {
		return err
	}
	if _, err := w.Write(p.elts); err != nil {
		return err
	}
	if _, err := w.Write(p.encode(p.Title + "\x00")); err != nil {
		return err
	}
	if _, err := w.Write(p.encode(p.Author + "\x00")); err != nil {
		return err
	}
	if _, err := w.Write(p.encode(p.Copyright + "\x00")); err != nil {
		return err
	}
	for _, clue := range p.Clues {
		if _, err := w.Write(p.encode(clue + "\x00")); err != nil {
			return err
		}
	}
	if _, err := w.Write(p.encode(p.Notes + "\x00")); err != nil {
		return err
	}
	if _, err := w.Write(p.Extra); err != nil {
		return err
	}
	return nil
}

// NextCell returns the location one square from pos in dir direction.  If
// doSkip is true, skip blank squares and wrap around the grid, otherwise, pos
// is returned unmodified.
func (p *Puzzle) NextCell(pos Coord, dir Direction, doSkip bool) Coord {
	dlt := dir.Delta()
	if dlt == (Coord{}) {
		return pos
	}

	size := p.Size()
	nextPos := pos
	for {
		nextPos.X += dlt.X
		nextPos.Y += dlt.Y
		if doSkip {
			x := nextPos.X + ((nextPos.Y+size.Y)/size.Y - 1)
			y := nextPos.Y + ((nextPos.X+size.X)/size.X - 1)
			nextPos.X = (x%size.X + size.X) % size.X
			nextPos.Y = (y%size.Y + size.Y) % size.Y
		}
		c, ok := p.At(nextPos)
		if !ok {
			return pos
		}
		if c == Blank {
			if !doSkip {
				return pos
			}
		} else {
			return nextPos
		}
	}
}

// WordExtent returns the position of the last cell of the word that includes
// pos in direction dir.
func (p *Puzzle) WordExtent(pos Coord, dir Direction) Coord {
	for {
		end := p.NextCell(pos, dir, false)
		if end == pos {
			return end
		}
		pos = end
	}
}

// WordExtents returns the positions of the first and last cells of the word
// that includes pos along direction dir.
func (p *Puzzle) WordExtents(pos Coord, dir Direction) (Coord, Coord) {
	start, end := p.WordExtent(pos, dir.Opposite()), p.WordExtent(pos, dir)
	if start.X > end.X || start.Y > end.Y {
		return end, start
	}
	return start, end
}

// NextWord returns the position of the first cell of the word after the one
// that includes pos in direction dir, wrapping if necessary.
func (p *Puzzle) NextWord(pos Coord, dir Direction) Coord {
	end := p.WordExtent(pos, dir)
	nextWordCell := p.NextCell(end, dir, true)
	nextWordStart, _ := p.WordExtents(nextWordCell, dir)
	return nextWordStart
}

// WordID returns the ID number of the word that includes pos along direction
// dir.
func (p *Puzzle) WordID(pos Coord, dir Direction) int {
	return p.cellID[p.WordExtent(pos, dir.Opposite())]
}

// WordStart returns the position of the cell with ID id if valid and whether
// id is valid.
func (p *Puzzle) WordStart(id int) (Coord, bool) {
	pos, ok := p.idCell[id]
	return pos, ok
}

// Clue returns the clue for the word that contains pos in direction dir, or an
// empty string if invalid.
func (p *Puzzle) Clue(pos Coord, dir Direction) string {
	id := p.WordID(pos, dir)
	clue := ""
	if num, ok := p.clueNum[dir][id]; ok && num >= 0 && num < len(p.Clues) {
		clue = p.Clues[num]
	}
	return clue
}

// Setup initializes the puzzle.
func (p *Puzzle) Setup() {
	id := 1
	cnum := 0
	sz := p.Size()
	for y := 0; y < sz.Y; y++ {
		for x := 0; x < sz.X; x++ {
			pos := Coord{x, y}
			if c, ok := p.At(pos); !ok || c == Blank {
				continue
			}
			for _, dir := range []Direction{Right, Down} {
				start, end := p.WordExtents(pos, dir)
				if start == pos && end != pos {
					cid, seen := p.cellID[pos]
					if !seen {
						p.cellID[pos] = id
						p.idCell[id] = pos
						cid = id
						id++
					}
					p.clueNum[dir][cid] = cnum
					cnum++
				}
			}
		}
	}
}

// Verify returns whether the working grid matches the solition.
func (p *Puzzle) Verify() bool {
	return bytes.Equal(p.elts, p.solution.elts)
}

// BaseCksum calculates base checksum
func (p *Puzzle) BaseCksum() uint16 {
	buf := bytes.NewBuffer([]byte{})
	binary.Write(buf, binary.LittleEndian, p.Header.Width)
	binary.Write(buf, binary.LittleEndian, p.Header.Height)
	binary.Write(buf, binary.LittleEndian, p.Header.NumClues)
	binary.Write(buf, binary.LittleEndian, p.Header.BitMask1)
	binary.Write(buf, binary.LittleEndian, p.Header.BitMask2)
	return calcCksum(buf.Bytes(), 0)
}

// TextCksum calculates checksum of text fields
func (p *Puzzle) TextCksum(cksum uint16) uint16 {
	cksum = calcCksum(p.encode(p.Title+"\x00"), cksum)
	cksum = calcCksum(p.encode(p.Author+"\x00"), cksum)
	cksum = calcCksum(p.encode(p.Copyright+"\x00"), cksum)
	for _, clue := range p.Clues {
		cksum = calcCksum(p.encode(clue), cksum)
	}
	cksum = calcCksum(p.encode(p.Notes+"\x00"), cksum)
	return cksum
}

// Cksum calculates full checksum
func (p *Puzzle) Cksum() uint16 {
	cksum := p.BaseCksum()
	cksum = calcCksum(p.solution.elts, cksum)
	cksum = calcCksum(p.elts, cksum)
	if string(p.Header.Version[:]) >= "1.3" {
		cksum = p.TextCksum(cksum)
	}
	return cksum
}

// MaskedCksum calculates masked checksum
func (p *Puzzle) MaskedCksum() [8]byte {
	cksum := [8]byte{}
	for i, cs := range []uint16{
		p.BaseCksum(),
		calcCksum(p.solution.elts, 0),
		calcCksum(p.elts, 0),
		p.TextCksum(0),
	} {
		cksum[i] = byte(cs) ^ CksumMagic[i]
		cksum[i+4] = byte(cs>>8) ^ CksumMagic[i+4]
	}
	return cksum
}

func (p *Puzzle) encode(str string) []byte {
	s, err := p.enc.String(str)
	if err != nil {
		return []byte{}
	}
	return []byte(s)
}

func calcCksum(data []byte, cksum uint16) uint16 {
	for _, b := range data {
		cksum = (cksum >> 1) | ((cksum & 1) << 15)
		cksum += uint16(b)
	}
	return cksum
}
<commit_msg>A bit of tidying.<commit_after>package crosswd

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"strings"

	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/charmap"
)

// .puz constants
const (
	Magic      = "ACROSS&DOWN\x00"
	CksumMagic = "ICHEATED"
	Blank      = '.'
	Empty      = '-'
)

// Direction is a relative direction.
type Direction int

// Direction enumeration
const (
	NoDir Direction = iota
	Up
	Down
	Left
	Right
)

// Opposite returns the opposite direction of d.
func (d Direction) Opposite() Direction {
	switch d {
	case Left:
		return Right
	case Right:
		return Left
	case Up:
		return Down
	case Down:
		return Up
	}
	return NoDir
}

// Delta returns a unit vector in the direction d.
func (d Direction) Delta() Coord {
	switch d {
	case Up:
		return Coord{0, -1}
	case Down:
		return Coord{0, 1}
	case Left:
		return Coord{-1, 0}
	case Right:
		return Coord{1, 0}
	}
	return Coord{}
}

// Coord represents a 2D coordinate.
type Coord struct{ X, Y int }

// Grid represents a 2D array stored contiguously.
type Grid struct {
	elts  []byte
	cells [][]byte
}

// NewGrid returns a new Grid of size width x height.
func NewGrid(width, height int) *Grid {
	if width < 1 {
		width = 1
	}
	if height < 1 {
		height = 1
	}
	g := &Grid{}
	g.elts = make([]byte, width*height)
	g.cells = make([][]byte, height)
	for i := range g.cells {
		g.cells[i] = g.elts[i*width : (i+1)*width : (i+1)*width]
	}
	return g
}

// Size returns the grid dimensions.
func (g *Grid) Size() Coord {
	if len(g.cells) == 0 {
		return Coord{}
	}
	return Coord{len(g.cells), len(g.cells[0])}
}

// Valid returns whether a point is within the grid range.
func (g *Grid) Valid(p Coord) bool {
	return p.Y >= 0 && p.Y < len(g.cells) && p.X >= 0 && p.X < len(g.cells[0])
}

// At returns the value at p if valid and whether p is valid.
func (g *Grid) At(p Coord) (byte, bool) {
	if !g.Valid(p) {
		return 0, false
	}
	return g.cells[p.Y][p.X], true
}

// Set stores c at point p if valid and returns whether g was updated
func (g *Grid) Set(p Coord, c byte) bool {
	if !g.Valid(p) {
		return false
	}
	g.cells[p.Y][p.X] = c
	return true
}

// Header holds .puz file header data
type Header struct {
	Cksum       uint16
	Magic       [len(Magic)]byte
	HeaderCksum uint16
	MagicCksum  [8]byte
	Version     [4]byte
	Unused      [2]byte
	Unknown     [2]byte
	Reserved    [12]byte
	Width       uint8
	Height      uint8
	NumClues    uint16
	BitMask1    [2]byte // normally set to 0x0001
	BitMask2    [2]byte // 0x0004 = scrambled
}

// Puzzle holds the state of a crossword puzzle
type Puzzle struct {
	Header Header
	*Grid
	solution  *Grid
	Title     string
	Author    string
	Copyright string
	Clues     []string
	Notes     string
	Extra     []byte

	cellID  map[Coord]int
	idCell  map[int]Coord
	clueNum map[Direction]map[int]int
	enc     *encoding.Encoder
}

// New creates a Puzzle instance
func New() *Puzzle {
	return &Puzzle{
		cellID:  map[Coord]int{},
		idCell:  map[int]Coord{},
		clueNum: map[Direction]map[int]int{Right: {}, Down: {}},
		enc:     charmap.ISO8859_1.NewEncoder(),
	}
}

// Read reads crossword data in .puz format
func (p *Puzzle) Read(r io.Reader) error {
	if err := binary.Read(r, binary.LittleEndian, &p.Header); err != nil {
		return err
	}
	if string(p.Header.Magic[:]) != Magic {
		return errors.New("invalid magic value in file")
	}
	width, height := int(p.Header.Width), int(p.Header.Height)
	p.solution = NewGrid(width, height)
	if _, err := io.ReadFull(r, p.solution.elts); err != nil {
		return err
	}
	p.Grid = NewGrid(width, height)
	if _, err := io.ReadFull(r, p.elts); err != nil {
		return err
	}
	rest, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}
	dec := charmap.ISO8859_1.NewDecoder()
	inFields := strings.SplitN(string(rest), "\x00", int(5+p.Header.NumClues))
	outFields := make([]string, 4+p.Header.NumClues)
	copy(outFields, inFields)
	p.Title, _ = dec.String(outFields[0])
	p.Author, _ = dec.String(outFields[1])
	p.Copyright, _ = dec.String(outFields[2])
	for i := 0; i < int(p.Header.NumClues); i++ {
		clue, _ := dec.String(outFields[3+i])
		p.Clues = append(p.Clues, clue)
	}
	p.Notes, _ = dec.String(outFields[3+p.Header.NumClues])
	if len(inFields) > len(outFields) {
		p.Extra = []byte(inFields[len(inFields)-1])
	}
	if p.HeaderCksum() != p.Header.HeaderCksum {
		return errors.New("base checksum does not match")
	}
	if p.MagicCksum() != p.Header.MagicCksum {
		return errors.New("magic checksum does not match")
	}
	if p.Cksum() != p.Header.Cksum {
		return errors.New("global checksum does not match")
	}
	return nil
}

// Write writes crossword data in .puz format
func (p *Puzzle) Write(w io.Writer) error {
	p.Header.HeaderCksum = p.HeaderCksum()
	p.Header.MagicCksum = p.MagicCksum()
	p.Header.Cksum = p.Cksum()

	if err := binary.Write(w, binary.LittleEndian, p.Header); err != nil {
		return err
	}
	if _, err := w.Write(p.solution.elts); err != nil {
		return err
	}
	if _, err := w.Write(p.elts); err != nil {
		return err
	}
	if _, err := w.Write(p.encode(p.Title + "\x00")); err != nil {
		return err
	}
	if _, err := w.Write(p.encode(p.Author + "\x00")); err != nil {
		return err
	}
	if _, err := w.Write(p.encode(p.Copyright + "\x00")); err != nil {
		return err
	}
	for _, clue := range p.Clues {
		if _, err := w.Write(p.encode(clue + "\x00")); err != nil {
			return err
		}
	}
	if _, err := w.Write(p.encode(p.Notes + "\x00")); err != nil {
		return err
	}
	if _, err := w.Write(p.Extra); err != nil {
		return err
	}
	return nil
}

// NextCell returns the location one square from pos in dir direction.  If
// doSkip is true, skip blank squares and wrap around the grid, otherwise, pos
// is returned unmodified.
func (p *Puzzle) NextCell(pos Coord, dir Direction, doSkip bool) Coord {
	dlt := dir.Delta()
	if dlt == (Coord{}) {
		return pos
	}

	size := p.Size()
	nextPos := pos
	for {
		nextPos.X += dlt.X
		nextPos.Y += dlt.Y
		if doSkip {
			x := nextPos.X + ((nextPos.Y+size.Y)/size.Y - 1)
			y := nextPos.Y + ((nextPos.X+size.X)/size.X - 1)
			nextPos.X = (x%size.X + size.X) % size.X
			nextPos.Y = (y%size.Y + size.Y) % size.Y
		}
		c, ok := p.At(nextPos)
		if !ok {
			return pos
		}
		if c == Blank {
			if !doSkip {
				return pos
			}
		} else {
			return nextPos
		}
	}
}

// WordExtent returns the position of the last cell of the word that includes
// pos in direction dir.
func (p *Puzzle) WordExtent(pos Coord, dir Direction) Coord {
	for {
		end := p.NextCell(pos, dir, false)
		if end == pos {
			return end
		}
		pos = end
	}
}

// WordExtents returns the positions of the first and last cells of the word
// that includes pos along direction dir.
func (p *Puzzle) WordExtents(pos Coord, dir Direction) (Coord, Coord) {
	start, end := p.WordExtent(pos, dir.Opposite()), p.WordExtent(pos, dir)
	if start.X > end.X || start.Y > end.Y {
		return end, start
	}
	return start, end
}

// NextWord returns the position of the first cell of the word after the one
// that includes pos in direction dir, wrapping if necessary.
func (p *Puzzle) NextWord(pos Coord, dir Direction) Coord {
	end := p.WordExtent(pos, dir)
	nextWordCell := p.NextCell(end, dir, true)
	nextWordStart, _ := p.WordExtents(nextWordCell, dir)
	return nextWordStart
}

// WordID returns the ID number of the word that includes pos along direction
// dir.
func (p *Puzzle) WordID(pos Coord, dir Direction) int {
	return p.cellID[p.WordExtent(pos, dir.Opposite())]
}

// WordStart returns the position of the cell with ID id if valid and whether
// id is valid.
func (p *Puzzle) WordStart(id int) (Coord, bool) {
	pos, ok := p.idCell[id]
	return pos, ok
}

// Clue returns the clue for the word that contains pos in direction dir, or an
// empty string if invalid.
func (p *Puzzle) Clue(pos Coord, dir Direction) string {
	id := p.WordID(pos, dir)
	clue := ""
	if num, ok := p.clueNum[dir][id]; ok && num >= 0 && num < len(p.Clues) {
		clue = p.Clues[num]
	}
	return clue
}

// Setup initializes the puzzle.
func (p *Puzzle) Setup() {
	id := 1
	cnum := 0
	sz := p.Size()
	for y := 0; y < sz.Y; y++ {
		for x := 0; x < sz.X; x++ {
			pos := Coord{x, y}
			if c, ok := p.At(pos); !ok || c == Blank {
				continue
			}
			for _, dir := range []Direction{Right, Down} {
				start, end := p.WordExtents(pos, dir)
				if start == pos && end != pos {
					cid, seen := p.cellID[pos]
					if !seen {
						p.cellID[pos] = id
						p.idCell[id] = pos
						cid = id
						id++
					}
					p.clueNum[dir][cid] = cnum
					cnum++
				}
			}
		}
	}
}

// Verify returns whether the working grid matches the solition.
func (p *Puzzle) Verify() bool {
	return bytes.Equal(p.elts, p.solution.elts)
}

// HeaderCksum calculates base checksum
func (p *Puzzle) HeaderCksum() uint16 {
	buf := bytes.NewBuffer([]byte{})
	binary.Write(buf, binary.LittleEndian, p.Header.Width)
	binary.Write(buf, binary.LittleEndian, p.Header.Height)
	binary.Write(buf, binary.LittleEndian, p.Header.NumClues)
	binary.Write(buf, binary.LittleEndian, p.Header.BitMask1)
	binary.Write(buf, binary.LittleEndian, p.Header.BitMask2)
	return calcCksum(buf.Bytes(), 0)
}

// TextCksum calculates checksum of text fields
func (p *Puzzle) TextCksum(cksum uint16) uint16 {
	cksum = calcCksum(p.encode(p.Title+"\x00"), cksum)
	cksum = calcCksum(p.encode(p.Author+"\x00"), cksum)
	cksum = calcCksum(p.encode(p.Copyright+"\x00"), cksum)
	for _, clue := range p.Clues {
		cksum = calcCksum(p.encode(clue), cksum)
	}
	cksum = calcCksum(p.encode(p.Notes+"\x00"), cksum)
	return cksum
}

// Cksum calculates full checksum
func (p *Puzzle) Cksum() uint16 {
	cksum := p.HeaderCksum()
	cksum = calcCksum(p.solution.elts, cksum)
	cksum = calcCksum(p.elts, cksum)
	if string(p.Header.Version[:]) >= "1.3" {
		cksum = p.TextCksum(cksum)
	}
	return cksum
}

// MagicCksum calculates magic checksum
func (p *Puzzle) MagicCksum() [8]byte {
	cksum := [8]byte{}
	for i, cs := range []uint16{
		p.HeaderCksum(),
		calcCksum(p.solution.elts, 0),
		calcCksum(p.elts, 0),
		p.TextCksum(0),
	} {
		cksum[i] = byte(cs) ^ CksumMagic[i]
		cksum[i+4] = byte(cs>>8) ^ CksumMagic[i+4]
	}
	return cksum
}

func (p *Puzzle) encode(str string) []byte {
	s, err := p.enc.String(str)
	if err != nil {
		return []byte{}
	}
	return []byte(s)
}

func calcCksum(data []byte, cksum uint16) uint16 {
	for _, b := range data {
		cksum = (cksum >> 1) | ((cksum & 1) << 15) + uint16(b)
	}
	return cksum
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/gizak/termui"
	"github.com/luan/idope/fetcher"
)

type UI struct {
	selectedIndex int
	listContent   []string
	listOffset    int

	listWidget *termui.List
}

func NewUI() *UI {
	return &UI{}
}

func (ui *UI) Render() {
	ui.listWidget.Items = ui.selectItem()
	termui.Render(termui.Body)
}

func (ui *UI) Setup() {
	err := termui.Init()
	if err != nil {
		panic(err)
	}

	list := termui.NewList()
	list.BorderLabel = "LRPs"
	list.ItemFgColor = termui.ColorYellow
	ui.listWidget = list
	termui.Body.AddRows(
		termui.NewRow(
			termui.NewCol(9, 0, ui.listWidget),
		),
	)
	ui.listWidget.Height = termui.TermHeight()
	termui.Body.Align()

	ui.Render()
	ui.bindEvents()
}

func (ui *UI) Close() {
	termui.Close()
}

func (ui *UI) Loop() {
	termui.Loop()
}

func colorizeState(state string) string {
	switch state {
	case "UNCLAIMED":
		return "[UNCLAIMED](fg-white)"
	case "CLAIMED":
		return "[CLAIMED](fg-yellow)"
	case "RUNNING":
		return "[RUNNING](fg-green)"
	case "CRASHED":
		return "[CRASHED](fg-red)"
	default:
		return state
	}
}

func lrpToStrings(lrp *fetcher.LRP) []string {
	ret := []string{}
	ret = append(ret, fmt.Sprintf("guid: [%s](fg-bold)\t[instances:](fg-white) [%d](fg-white,fg-bold) ", lrp.Desired.ProcessGuid[:8], lrp.Desired.Instances))
	for _, actual := range lrp.ActualLRPsByIndex() {
		state := colorizeState(actual.ActualLRP.State)
		ret = append(ret, fmt.Sprintf("\t[%d](fg-white) %s %s ", actual.ActualLRP.Index, actual.ActualLRP.CellId, state))
	}
	return ret
}

func (ui *UI) SetState(state *fetcher.Data) {
	ui.listContent = []string{}
	lrps := state.LRPs.SortedByProcessGuid()
	for _, lrp := range lrps {
		content := lrpToStrings(lrp)
		ui.listContent = append(ui.listContent, content...)
	}
	ui.Render()
}

func (ui *UI) bindEvents() {
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/sys/kbd/j", ui.handleDown)
	termui.Handle("/sys/kbd/<down>", ui.handleDown)
	termui.Handle("/sys/kbd/k", ui.handleUp)
	termui.Handle("/sys/kbd/<up>", ui.handleUp)
	termui.Handle("/sys/kbd/g", ui.handleTop)
	termui.Handle("/sys/kbd/<home>", ui.handleTop)
	termui.Handle("/sys/kbd/G", ui.handleBottom)
	termui.Handle("/sys/kbd/<end>", ui.handleBottom)

	termui.Handle("/sys/wnd/resize", func(termui.Event) {
		ui.listWidget.Height = termui.TermHeight()
		termui.Body.Align()
		ui.Render()
	})
}

func (ui *UI) handleBottom(_ termui.Event) {
	visibleHeight := ui.listWidget.InnerHeight()
	totalHeight := len(ui.listContent)
	if totalHeight < visibleHeight {
		visibleHeight = totalHeight
	}
	ui.selectedIndex = visibleHeight - 1
	ui.listOffset = totalHeight - visibleHeight
	ui.Render()
}

func (ui *UI) handleTop(_ termui.Event) {
	ui.selectedIndex = 0
	ui.listOffset = 0
	ui.Render()
}

func (ui *UI) handleDown(_ termui.Event) {
	visibleHeight := ui.listWidget.InnerHeight()
	totalHeight := len(ui.listContent)
	if totalHeight < visibleHeight {
		visibleHeight = totalHeight
	}

	if ui.selectedIndex < visibleHeight-1 {
		ui.selectedIndex++
	} else if ui.listOffset < totalHeight-visibleHeight-1 {
		ui.listOffset++
	}
	ui.Render()
}

func (ui *UI) handleUp(_ termui.Event) {
	if ui.selectedIndex > 0 {
		ui.selectedIndex--
	} else if ui.listOffset > 0 {
		ui.listOffset--
	}
	ui.Render()
}

func (ui *UI) selectItem() []string {
	if ui.listWidget.InnerHeight() == 0 {
		return []string{}
	}
	index := ui.selectedIndex
	visibleContent := ui.listContent[ui.listOffset:]

	ret := make([]string, len(visibleContent))
	for i, item := range visibleContent {
		if i == index {
			ret[i] = fmt.Sprintf(" [➤](fg-cyan,fg-bold) %s", item)
		} else {
			ret[i] = fmt.Sprintf("   %s", item)
		}
	}
	return ret
}
<commit_msg>show metrics<commit_after>package main

import (
	"fmt"
	"strings"

	humanize "github.com/dustin/go-humanize"
	"github.com/gizak/termui"
	"github.com/luan/idope/fetcher"
)

type UI struct {
	selectedIndex int
	listContent   []string
	listOffset    int

	listWidget *termui.List
}

func NewUI() *UI {
	return &UI{}
}

func (ui *UI) Render() {
	ui.listWidget.Items = ui.selectItem()
	termui.Render(termui.Body)
}

func (ui *UI) Setup() {
	err := termui.Init()
	if err != nil {
		panic(err)
	}

	list := termui.NewList()
	list.BorderLabel = "LRPs"
	list.ItemFgColor = termui.ColorYellow
	ui.listWidget = list
	termui.Body.AddRows(
		termui.NewRow(
			termui.NewCol(9, 0, ui.listWidget),
		),
	)
	ui.listWidget.Height = termui.TermHeight()
	termui.Body.Align()

	ui.Render()
	ui.bindEvents()
}

func (ui *UI) Close() {
	termui.Close()
}

func (ui *UI) Loop() {
	termui.Loop()
}

func colorizeState(state string) string {
	switch state {
	case "UNCLAIMED":
		return "[UNCLAIMED](fg-white)"
	case "CLAIMED":
		return "[CLAIMED](fg-yellow)"
	case "RUNNING":
		return "[RUNNING](fg-green)"
	case "CRASHED":
		return "[CRASHED](fg-red)"
	default:
		return state
	}
}

func fmtBytes(s uint64) string {
	return strings.Replace(humanize.Bytes(s), " ", "", -1)
}

func lrpToStrings(lrp *fetcher.LRP) []string {
	ret := []string{}
	ret = append(ret,
		fmt.Sprintf(
			"guid: [%s](fg-bold)\t[instances:](fg-white) [%d](fg-white,fg-bold) ",
			lrp.Desired.ProcessGuid[:8], lrp.Desired.Instances,
		),
	)
	for _, actual := range lrp.ActualLRPsByCPU() {
		state := colorizeState(actual.ActualLRP.State)
		ret = append(ret,
			fmt.Sprintf(
				"\t[%2d](fg-white) %s %12s [%5.1f%%](fg-magenta) [%6s](fg-cyan)/[%-6s](fg-cyan,fg-bold) [%6s](fg-red)/[%-6s](fg-red,fg-bold)",
				actual.ActualLRP.Index, actual.ActualLRP.CellId, state,
				actual.Metrics.CPU*100,
				fmtBytes(actual.Metrics.Memory), fmtBytes(uint64(lrp.Desired.MemoryMb*1000*1000)),
				fmtBytes(actual.Metrics.Disk), fmtBytes(uint64(lrp.Desired.DiskMb*1000*1000)),
			))
	}
	return ret
}

func (ui *UI) SetState(state *fetcher.Data) {
	ui.listContent = []string{}
	lrps := state.LRPs.SortedByProcessGuid()
	for _, lrp := range lrps {
		content := lrpToStrings(lrp)
		ui.listContent = append(ui.listContent, content...)
	}
	ui.Render()
}

func (ui *UI) bindEvents() {
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/sys/kbd/j", ui.handleDown)
	termui.Handle("/sys/kbd/<down>", ui.handleDown)
	termui.Handle("/sys/kbd/k", ui.handleUp)
	termui.Handle("/sys/kbd/<up>", ui.handleUp)
	termui.Handle("/sys/kbd/g", ui.handleTop)
	termui.Handle("/sys/kbd/<home>", ui.handleTop)
	termui.Handle("/sys/kbd/G", ui.handleBottom)
	termui.Handle("/sys/kbd/<end>", ui.handleBottom)

	termui.Handle("/sys/wnd/resize", func(termui.Event) {
		ui.listWidget.Height = termui.TermHeight()
		termui.Body.Align()
		ui.Render()
	})
}

func (ui *UI) handleBottom(_ termui.Event) {
	visibleHeight := ui.listWidget.InnerHeight()
	totalHeight := len(ui.listContent)
	if totalHeight < visibleHeight {
		visibleHeight = totalHeight
	}
	ui.selectedIndex = visibleHeight - 1
	ui.listOffset = totalHeight - visibleHeight
	ui.Render()
}

func (ui *UI) handleTop(_ termui.Event) {
	ui.selectedIndex = 0
	ui.listOffset = 0
	ui.Render()
}

func (ui *UI) handleDown(_ termui.Event) {
	visibleHeight := ui.listWidget.InnerHeight()
	totalHeight := len(ui.listContent)
	if totalHeight < visibleHeight {
		visibleHeight = totalHeight
	}

	if ui.selectedIndex < visibleHeight-1 {
		ui.selectedIndex++
	} else if ui.listOffset < totalHeight-visibleHeight-1 {
		ui.listOffset++
	}
	ui.Render()
}

func (ui *UI) handleUp(_ termui.Event) {
	if ui.selectedIndex > 0 {
		ui.selectedIndex--
	} else if ui.listOffset > 0 {
		ui.listOffset--
	}
	ui.Render()
}

func (ui *UI) selectItem() []string {
	if ui.listWidget.InnerHeight() == 0 {
		return []string{}
	}
	index := ui.selectedIndex
	visibleContent := ui.listContent[ui.listOffset:]

	ret := make([]string, len(visibleContent))
	for i, item := range visibleContent {
		if i == index {
			ret[i] = fmt.Sprintf(" [➤](fg-cyan,fg-bold) %s", item)
		} else {
			ret[i] = fmt.Sprintf("   %s", item)
		}
	}
	return ret
}
<|endoftext|>


<commit_before>// Copyright 2015 The rkt 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 main

import (
	"strings"
)

const (
	// fileDepMkTemplate holds a template for file-based
	// dependency tracking make file.
	fileDepMkTemplate = `# generated by !!!DEPS_GEN_APP_NAME!!!

define _DEPS_GEN_GET_ALL_FILES_
!!!DEPS_GEN_FILES_GENERATOR!!!
endef

_DEPS_GEN_ALL_FILES_STORED_ := !!!DEPS_GEN_ALL_FILES_STORED!!!

_DEPS_GEN_SPACE_ :=
_DEPS_GEN_SPACE_ +=

_DEPS_GEN_F1_ := $(sort $(strip $(_DEPS_GEN_ALL_FILES_STORED_)))
_DEPS_GEN_F2_ := $(sort $(strip $(call _DEPS_GEN_GET_ALL_FILES_)))

ifeq ($(_DEPS_GEN_F1_),$(_DEPS_GEN_F2_))

!!!DEPS_GEN_TARGET!!!: $(_DEPS_GEN_ALL_FILES_STORED_)

else

$(info Invalidating !!!DEPS_GEN_TARGET!!!)
$(info Prerequisites stored in deps file that are not in currently on disk: $(filter-out $(_DEPS_GEN_F2_),$(_DEPS_GEN_F1_)))
$(info Prerequisites currently on disk that are not stored in deps file: $(filter-out $(_DEPS_GEN_F1_),$(_DEPS_GEN_F2_)))

# invalidate the target
!!!DEPS_GEN_TARGET!!!: _DEPS_GEN_INVALIDATE_
.PHONY: _DEPS_GEN_INVALIDATE_

endif

$(call undefine-namespaces,_DEPS_GEN)
`

	// kvStoredPrefix is used to prefix the variable name we want
	// to store (so actual variable checked at runtime is FOO and
	// its stored value from previous run is $(kvStoredPrefix)FOO.
	kvStoredPrefix = "_DEPS_GEN_STORED_"
	// kvDepMkTemplate holds a template for key-value-based
	// dependency tracking make file.
	kvDepMkTemplate = `# generated by !!!DEPS_GEN_APP_NAME!!!
_DEPS_GEN_VARIABLES_ := !!!DEPS_GEN_VARIABLES!!!
!!!DEPS_GEN_STORED_VALUES!!!
_DEPS_GEN_DO_INVALIDATE_ := no

$(foreach v,$(_DEPS_GEN_VARIABLES_), \
        $(if $(call equal,$($v),$(!!!DEPS_GEN_STORED_PREFIX!!!$v)), \
                , \
                $(eval _DEPS_GEN_DO_INVALIDATE_ := yes) \
                $(eval _DEPS_GEN_DIFFS_ += $v)))

ifeq ($(_DEPS_GEN_DO_INVALIDATE_),yes)

$(info Invalidating !!!DEPS_GEN_TARGET!!!)
$(foreach k,$(_DEPS_GEN_DIFFS_), \
        $(info Differing key: $k) \
        $(info Value stored in deps file: $(!!!DEPS_GEN_STORED_PREFIX!!!$v)) \
        $(info Value currently used: $($v)))

# invalidate the target
!!!DEPS_GEN_TARGET!!!: _DEPS_GEN_INVALIDATE_
.PHONY: _DEPS_GEN_INVALIDATE_

endif

$(call undefine-namespaces,_DEPS_GEN)
`
)

// GenerateFileDeps returns contents of make file describing
// dependencies of given target on given files and checking if files
// weren't added or removed in directories where given files are.
func GenerateFileDeps(target, filesGenerator string, files []string) string {
	return replacePlaceholders(fileDepMkTemplate,
		"DEPS_GEN_APP_NAME", appName(),
		"DEPS_GEN_FILES_GENERATOR", filesGenerator,
		"DEPS_GEN_ALL_FILES_STORED", strings.Join(files, " "),
		"DEPS_GEN_TARGET", target,
	)
}

func GenerateKvDeps(target string, keysValues map[string]string) string {
	variables := make([]string, 0, len(keysValues))
	storedValues := make([]string, 0, len(keysValues))
	for k, v := range keysValues {
		variables = append(variables, k)
		storedValues = append(storedValues, kvStoredPrefix+k+" := "+v)
	}

	return replacePlaceholders(kvDepMkTemplate,
		"DEPS_GEN_APP_NAME", appName(),
		"DEPS_GEN_VARIABLES", strings.Join(variables, " "),
		"DEPS_GEN_STORED_VALUES", strings.Join(storedValues, "\n"),
		"DEPS_GEN_STORED_PREFIX", kvStoredPrefix,
		"DEPS_GEN_TARGET", target,
	)
}
<commit_msg>build: Fix key-value depsgen reporting about invalidating build<commit_after>// Copyright 2015 The rkt 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 main

import (
	"strings"
)

const (
	// fileDepMkTemplate holds a template for file-based
	// dependency tracking make file.
	fileDepMkTemplate = `# generated by !!!DEPS_GEN_APP_NAME!!!

define _DEPS_GEN_GET_ALL_FILES_
!!!DEPS_GEN_FILES_GENERATOR!!!
endef

_DEPS_GEN_ALL_FILES_STORED_ := !!!DEPS_GEN_ALL_FILES_STORED!!!

_DEPS_GEN_SPACE_ :=
_DEPS_GEN_SPACE_ +=

_DEPS_GEN_F1_ := $(sort $(strip $(_DEPS_GEN_ALL_FILES_STORED_)))
_DEPS_GEN_F2_ := $(sort $(strip $(call _DEPS_GEN_GET_ALL_FILES_)))

ifeq ($(_DEPS_GEN_F1_),$(_DEPS_GEN_F2_))

!!!DEPS_GEN_TARGET!!!: $(_DEPS_GEN_ALL_FILES_STORED_)

else

$(info Invalidating !!!DEPS_GEN_TARGET!!!)
$(info Prerequisites stored in deps file that are not in currently on disk: $(filter-out $(_DEPS_GEN_F2_),$(_DEPS_GEN_F1_)))
$(info Prerequisites currently on disk that are not stored in deps file: $(filter-out $(_DEPS_GEN_F1_),$(_DEPS_GEN_F2_)))

# invalidate the target
!!!DEPS_GEN_TARGET!!!: _DEPS_GEN_INVALIDATE_
.PHONY: _DEPS_GEN_INVALIDATE_

endif

$(call undefine-namespaces,_DEPS_GEN)
`

	// kvStoredPrefix is used to prefix the variable name we want
	// to store (so actual variable checked at runtime is FOO and
	// its stored value from previous run is $(kvStoredPrefix)FOO.
	kvStoredPrefix = "_DEPS_GEN_STORED_"
	// kvDepMkTemplate holds a template for key-value-based
	// dependency tracking make file.
	kvDepMkTemplate = `# generated by !!!DEPS_GEN_APP_NAME!!!
_DEPS_GEN_VARIABLES_ := !!!DEPS_GEN_VARIABLES!!!
!!!DEPS_GEN_STORED_VALUES!!!
_DEPS_GEN_DO_INVALIDATE_ := no

$(foreach v,$(_DEPS_GEN_VARIABLES_), \
        $(if $(call equal,$($v),$(!!!DEPS_GEN_STORED_PREFIX!!!$v)), \
                , \
                $(eval _DEPS_GEN_DO_INVALIDATE_ := yes) \
                $(eval _DEPS_GEN_DIFFS_ += $v)))

ifeq ($(_DEPS_GEN_DO_INVALIDATE_),yes)

$(info Invalidating !!!DEPS_GEN_TARGET!!!)
$(foreach k,$(_DEPS_GEN_DIFFS_), \
        $(info Differing key: $k) \
        $(info Value stored in deps file: $(!!!DEPS_GEN_STORED_PREFIX!!!$k)) \
        $(info Value currently used: $($k)))

# invalidate the target
!!!DEPS_GEN_TARGET!!!: _DEPS_GEN_INVALIDATE_
.PHONY: _DEPS_GEN_INVALIDATE_

endif

$(call undefine-namespaces,_DEPS_GEN)
`
)

// GenerateFileDeps returns contents of make file describing
// dependencies of given target on given files and checking if files
// weren't added or removed in directories where given files are.
func GenerateFileDeps(target, filesGenerator string, files []string) string {
	return replacePlaceholders(fileDepMkTemplate,
		"DEPS_GEN_APP_NAME", appName(),
		"DEPS_GEN_FILES_GENERATOR", filesGenerator,
		"DEPS_GEN_ALL_FILES_STORED", strings.Join(files, " "),
		"DEPS_GEN_TARGET", target,
	)
}

func GenerateKvDeps(target string, keysValues map[string]string) string {
	variables := make([]string, 0, len(keysValues))
	storedValues := make([]string, 0, len(keysValues))
	for k, v := range keysValues {
		variables = append(variables, k)
		storedValues = append(storedValues, kvStoredPrefix+k+" := "+v)
	}

	return replacePlaceholders(kvDepMkTemplate,
		"DEPS_GEN_APP_NAME", appName(),
		"DEPS_GEN_VARIABLES", strings.Join(variables, " "),
		"DEPS_GEN_STORED_VALUES", strings.Join(storedValues, "\n"),
		"DEPS_GEN_STORED_PREFIX", kvStoredPrefix,
		"DEPS_GEN_TARGET", target,
	)
}
<|endoftext|>


<commit_before>package ts3sqlib

import (
	"bufio"
	"log"
	"net"
	"strings"
	"sync"
	"time"
)

var (
	timeout = 5 * time.Second
)

type SqConn struct {
	conn      net.Conn
	logger    *log.Logger
	sendMutex *sync.Mutex
	timeout   time.Duration
}

func Dial(address string, logger *log.Logger) (conn *SqConn, err error) {
	conn = nil

	if !strings.Contains(address, ":") {
		address += ":9987"
	}

	connection, err := net.Dial("tcp", address)
	if err != nil {
		return
	}

	conn = &SqConn{
		conn:      connection,
		logger:    logger,
		sendMutex: &sync.Mutex{},
		timeout:   1000 * time.Millisecond,
	}
	return
}

func (c *SqConn) Close() {
	c.conn.Close()
}

func (c *SqConn) Send(msg string) (answer string, err error) {
	c.sendMutex.Lock()
	defer c.sendMutex.Unlock()

	answer = ""

	_, err = c.conn.Write([]byte(msg)) //If the return value is smaller than
	if err != nil {                    //the length of msg, it's an error.
		return
	}

	//wait for answer...
	err = c.conn.SetReadDeadline(time.Now().Add(timeout))

	line := ""

	for !isError(line) {
		line, err = bufio.NewReader(c.conn).ReadString('\n')
		if err != nil {
			return
		}
		answer += line
	}
	err = toError(line)

	return
}
<commit_msg>adding some functions and commentary<commit_after>package ts3sqlib

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"strings"
	"sync"
	"time"
)

var (
	timeout = 5 * time.Second //the timeout of the connection
)

//SqConn contains the connection to a ts3 server.
type SqConn struct {
	conn       net.Conn
	logger     *log.Logger
	sendMutex  *sync.Mutex
	timeout    time.Duration
	receiving  bool
	recvNotify chan string
	recvChan   chan string
}

//Dial creates a new SqConn and connects to the ts3 server with the given
//address and returns a pointer to it and an error.
func Dial(address string, logger *log.Logger) (conn *SqConn, err error) {
	conn = nil

	if !strings.Contains(address, ":") {
		address += ":9987"
	}

	connection, err := net.Dial("tcp", address)
	if err != nil {
		return
	}

	conn = &SqConn{
		conn:       connection,
		logger:     logger,
		sendMutex:  &sync.Mutex{},
		timeout:    1000 * time.Millisecond,
		receiving:  true,
		recvNotify: make(chan string),
		recvChan:   make(chan string),
	}

	go conn.recv() //goroutine that splits the incoming messages into notify
	//and normal messages.

	return
}

func (c *SqConn) recv() {
	line := ""
	var err error
	for c.receiving {
		//read line
		line, err = bufio.NewReader(c.conn).ReadString('\n')

		if err != nil {
			panic(err)
		}

		//decide if its notify or not and put it to the correct channel
		if strings.HasPrefix(line, "notify") {
			c.recvNotify <- line
		} else {
			c.recvChan <- line
		}
	}
}

//RecvNotify returns a notify message or blocks until one arrives.
func (c *SqConn) RecvNotify() (answer string, err error) {
	answer = ""
	err = nil

	if c == nil {
		err = fmt.Errorf("no SqConn")
		return
	}

	answer = <-c.recvNotify
	return
}

//Close closes the connection to the ts3 server.
func (c *SqConn) Close() {
	c.conn.Close()
}

//Send sends a message to the server and returns the answer.
func (c *SqConn) Send(msg string) (answer string, err error) {
	c.sendMutex.Lock()
	defer c.sendMutex.Unlock()

	answer = ""

	_, err = c.conn.Write([]byte(msg)) //If the return value is smaller than
	if err != nil {                    //the length of msg, it's an error.
		return
	}

	//wait for answer...
	err = c.conn.SetReadDeadline(time.Now().Add(timeout))

	line := ""

	for !isError(line) {
		/*line, err = bufio.NewReader(c.conn).ReadString('\n')
		if err != nil {
			return
		}*/
		answer += line
		line = <-c.recvChan
	}
	err = toError(line)

	return
}
<|endoftext|>


<commit_before>package csv

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	pilosa "github.com/pilosa/go-pilosa"
)

// Format is the format of the data in the CSV file.
type Format uint

const (
	// RowIDColumnID formatted data is ROW_ID,COLUMN_ID.
	RowIDColumnID Format = iota
	// RowIDColumnKey formatted data is ROW_ID,COLUMN_KEY.
	RowIDColumnKey
	// RowKeyColumnID formatted data is ROW_KEY,COLUMN_ID.
	RowKeyColumnID
	// RowKeyColumnKey formatted data is ROW_KEY,COLUMN_ID.
	RowKeyColumnKey
	// ColumnID formatted data is COLUMN_ID. Valid only for value import.
	ColumnID
	// ColumnKey formatted data is COLUMN_KEY. Valud only for value import.
	ColumnKey
)

// ColumnUnmarshaller creates a RecordUnmarshaller for importing columns with the given format.
func ColumnUnmarshaller(format Format) RecordUnmarshaller {
	return ColumnUnmarshallerWithTimestamp(format, "")
}

// ColumnUnmarshallerWithTimestamp creates a RecordUnmarshaller for importing columns with the given format and timestamp format.
func ColumnUnmarshallerWithTimestamp(format Format, timestampFormat string) RecordUnmarshaller {
	return func(text string) (pilosa.Record, error) {
		var err error
		column := pilosa.Column{}
		parts := strings.Split(text, ",")
		if len(parts) < 2 {
			return nil, errors.New("Invalid CSV line")
		}

		hasRowKey := format == RowKeyColumnID || format == RowKeyColumnKey
		hasColumnKey := format == RowIDColumnKey || format == RowKeyColumnKey

		if hasRowKey {
			column.RowKey = parts[0]
		} else {
			column.RowID, err = strconv.ParseUint(parts[0], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid row ID")
			}
		}

		if hasColumnKey {
			column.ColumnKey = parts[1]
		} else {
			column.ColumnID, err = strconv.ParseUint(parts[1], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid column ID")
			}
		}

		timestamp := 0
		if len(parts) == 3 {
			if timestampFormat == "" {
				timestamp, err = strconv.Atoi(parts[2])
				if err != nil {
					return nil, err
				}
			} else {
				t, err := time.Parse(timestampFormat, parts[2])
				if err != nil {
					return nil, err
				}
				timestamp = int(t.Unix() * int64(time.Second))
			}
		}
		column.Timestamp = int64(timestamp)

		return column, nil
	}
}

// RecordUnmarshaller is a function which creates a Record from a CSV file line with column data.
type RecordUnmarshaller func(text string) (pilosa.Record, error)

// Iterator reads records from a Reader.
// Each line should contain a single record in the following form:
// field1,field2,...
type Iterator struct {
	reader       io.Reader
	line         int
	scanner      *bufio.Scanner
	unmarshaller RecordUnmarshaller
}

// NewIterator creates a CSVIterator from a Reader.
func NewIterator(reader io.Reader, unmarshaller RecordUnmarshaller) *Iterator {
	return &Iterator{
		reader:       reader,
		line:         0,
		scanner:      bufio.NewScanner(reader),
		unmarshaller: unmarshaller,
	}
}

// NewColumnIterator creates a new iterator for column data.
func NewColumnIterator(format Format, reader io.Reader) *Iterator {
	return NewIterator(reader, ColumnUnmarshaller(format))
}

// NewColumnIteratorWithTimestampFormat creates a new iterator for column data with timestamp.
func NewColumnIteratorWithTimestampFormat(format Format, reader io.Reader, timestampFormat string) *Iterator {
	return NewIterator(reader, ColumnUnmarshallerWithTimestamp(format, timestampFormat))
}

// NewValueIterator creates a new iterator for value data.
func NewValueIterator(format Format, reader io.Reader) *Iterator {
	return NewIterator(reader, FieldValueUnmarshaller(format))
}

// NextRecord iterates on lines of a Reader.
// Returns io.EOF on end of iteration.
func (c *Iterator) NextRecord() (pilosa.Record, error) {
	if ok := c.scanner.Scan(); ok {
		c.line++
		text := strings.TrimSpace(c.scanner.Text())
		if text != "" {
			rc, err := c.unmarshaller(text)
			if err != nil {
				return nil, fmt.Errorf("%s at line: %d", err.Error(), c.line)
			}
			return rc, nil
		}
	}
	err := c.scanner.Err()
	if err != nil {
		return nil, err
	}
	return nil, io.EOF
}

// FieldValueUnmarshaller is a function which creates a Record from a CSV file line with value data.
func FieldValueUnmarshaller(format Format) RecordUnmarshaller {
	return func(text string) (pilosa.Record, error) {
		parts := strings.Split(text, ",")
		if len(parts) < 2 {
			return nil, errors.New("Invalid CSV")
		}
		value, err := strconv.ParseInt(parts[1], 10, 64)
		if err != nil {
			return nil, errors.New("Invalid value")
		}
		switch format {
		case ColumnID:
			columnID, err := strconv.ParseUint(parts[0], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid column ID at line: %d")
			}
			return pilosa.FieldValue{
				ColumnID: uint64(columnID),
				Value:    value,
			}, nil
		case ColumnKey:
			return pilosa.FieldValue{
				ColumnKey: parts[0],
				Value:     value,
			}, nil
		default:
			return nil, fmt.Errorf("Invalid format: %d", format)
		}
	}
}
<commit_msg>treat timestamp as int64 instead of int<commit_after>package csv

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	pilosa "github.com/pilosa/go-pilosa"
)

// Format is the format of the data in the CSV file.
type Format uint

const (
	// RowIDColumnID formatted data is ROW_ID,COLUMN_ID.
	RowIDColumnID Format = iota
	// RowIDColumnKey formatted data is ROW_ID,COLUMN_KEY.
	RowIDColumnKey
	// RowKeyColumnID formatted data is ROW_KEY,COLUMN_ID.
	RowKeyColumnID
	// RowKeyColumnKey formatted data is ROW_KEY,COLUMN_ID.
	RowKeyColumnKey
	// ColumnID formatted data is COLUMN_ID. Valid only for value import.
	ColumnID
	// ColumnKey formatted data is COLUMN_KEY. Valud only for value import.
	ColumnKey
)

// ColumnUnmarshaller creates a RecordUnmarshaller for importing columns with the given format.
func ColumnUnmarshaller(format Format) RecordUnmarshaller {
	return ColumnUnmarshallerWithTimestamp(format, "")
}

// ColumnUnmarshallerWithTimestamp creates a RecordUnmarshaller for importing columns with the given format and timestamp format.
func ColumnUnmarshallerWithTimestamp(format Format, timestampFormat string) RecordUnmarshaller {
	return func(text string) (pilosa.Record, error) {
		var err error
		column := pilosa.Column{}
		parts := strings.Split(text, ",")
		if len(parts) < 2 {
			return nil, errors.New("Invalid CSV line")
		}

		hasRowKey := format == RowKeyColumnID || format == RowKeyColumnKey
		hasColumnKey := format == RowIDColumnKey || format == RowKeyColumnKey

		if hasRowKey {
			column.RowKey = parts[0]
		} else {
			column.RowID, err = strconv.ParseUint(parts[0], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid row ID")
			}
		}

		if hasColumnKey {
			column.ColumnKey = parts[1]
		} else {
			column.ColumnID, err = strconv.ParseUint(parts[1], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid column ID")
			}
		}

		timestamp := int64(0)
		if len(parts) == 3 {
			if timestampFormat == "" {
				if tsInt, err := strconv.Atoi(parts[2]); err != nil {
					return nil, err
				} else {
					timestamp = int64(tsInt)
				}
			} else {
				t, err := time.Parse(timestampFormat, parts[2])
				if err != nil {
					return nil, err
				}
				timestamp = t.Unix() * int64(time.Second) // Casting a duration to int64 gives the number of nanoseconds in that duration.
			}
		}
		column.Timestamp = timestamp

		return column, nil
	}
}

// RecordUnmarshaller is a function which creates a Record from a CSV file line with column data.
type RecordUnmarshaller func(text string) (pilosa.Record, error)

// Iterator reads records from a Reader.
// Each line should contain a single record in the following form:
// field1,field2,...
type Iterator struct {
	reader       io.Reader
	line         int
	scanner      *bufio.Scanner
	unmarshaller RecordUnmarshaller
}

// NewIterator creates a CSVIterator from a Reader.
func NewIterator(reader io.Reader, unmarshaller RecordUnmarshaller) *Iterator {
	return &Iterator{
		reader:       reader,
		line:         0,
		scanner:      bufio.NewScanner(reader),
		unmarshaller: unmarshaller,
	}
}

// NewColumnIterator creates a new iterator for column data.
func NewColumnIterator(format Format, reader io.Reader) *Iterator {
	return NewIterator(reader, ColumnUnmarshaller(format))
}

// NewColumnIteratorWithTimestampFormat creates a new iterator for column data with timestamp.
func NewColumnIteratorWithTimestampFormat(format Format, reader io.Reader, timestampFormat string) *Iterator {
	return NewIterator(reader, ColumnUnmarshallerWithTimestamp(format, timestampFormat))
}

// NewValueIterator creates a new iterator for value data.
func NewValueIterator(format Format, reader io.Reader) *Iterator {
	return NewIterator(reader, FieldValueUnmarshaller(format))
}

// NextRecord iterates on lines of a Reader.
// Returns io.EOF on end of iteration.
func (c *Iterator) NextRecord() (pilosa.Record, error) {
	if ok := c.scanner.Scan(); ok {
		c.line++
		text := strings.TrimSpace(c.scanner.Text())
		if text != "" {
			rc, err := c.unmarshaller(text)
			if err != nil {
				return nil, fmt.Errorf("%s at line: %d", err.Error(), c.line)
			}
			return rc, nil
		}
	}
	err := c.scanner.Err()
	if err != nil {
		return nil, err
	}
	return nil, io.EOF
}

// FieldValueUnmarshaller is a function which creates a Record from a CSV file line with value data.
func FieldValueUnmarshaller(format Format) RecordUnmarshaller {
	return func(text string) (pilosa.Record, error) {
		parts := strings.Split(text, ",")
		if len(parts) < 2 {
			return nil, errors.New("Invalid CSV")
		}
		value, err := strconv.ParseInt(parts[1], 10, 64)
		if err != nil {
			return nil, errors.New("Invalid value")
		}
		switch format {
		case ColumnID:
			columnID, err := strconv.ParseUint(parts[0], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid column ID at line: %d")
			}
			return pilosa.FieldValue{
				ColumnID: uint64(columnID),
				Value:    value,
			}, nil
		case ColumnKey:
			return pilosa.FieldValue{
				ColumnKey: parts[0],
				Value:     value,
			}, nil
		default:
			return nil, fmt.Errorf("Invalid format: %d", format)
		}
	}
}
<|endoftext|>


<commit_before>// A Go wapper for the pocket API
package pocket

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

const EndPoint = "https://getpocket.com/v3/get"

type Client struct {
	consumer_key string
	access_token string
	endpoint     string
	c            *http.Client
}

type Pocket struct {
	Status   int      `json:"status"`
	Complete int      `json:"complete"`
	List     ItemList `json:"list"`
	Since    int      `json:"since"`
}

type ItemList map[string]Lists

type Lists struct {
	Item_id        string `json:"item_id"`
	Resolved_id    string `json:"resolved_id"`
	Given_url      string `json:"given_url"`
	Given_title    string `json:"given_title"`
	Favorite       string `json:"favorite"`
	Status         string `json:"status"`
	Time_added     string `json:"time_added"`
	Time_updated   string `json:"time_updated"`
	Time_favorited string `json:"fime_favorited"`
	Resolved_title string `json:"resolved_title"`
	Resolved_url   string `json:"resolved_url"`
	Excerpt        string `json:"excerpt"`
	Is_article     string `json:"is_article"`
	Is_index       string `json:"is_index"`
	Has_video      string `json:"has_video"`
	Has_image      string `json:"has_image"`
	Word_count     string `json:"word_count"`
}

type RequestOption struct {
	State       string
	Favorite    string
	Tag         string
	ContentType string
	Sort        string
	DetailType  string
	Search      string
	Domain      string
	Since       string
	Count       int
	Offset      int
}

func NewClient(consumer_key, access_token string) *Client {
	return &Client{
		consumer_key,
		access_token,
		EndPoint,
		http.DefaultClient,
	}
}

func (c *Client) PocketList(r map[string]interface{}) (ItemList, error) {
	p := url.Values{}
	p.Set("consumer_key", c.consumer_key)
	p.Set("access_token", c.access_token)

	p = requestOption(r, p)

	res, err := c.c.PostForm(c.endpoint, p)

	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var pocket Pocket

	err = json.NewDecoder(res.Body).Decode(&pocket)
	if err != nil {
		return nil, err
	}
	return pocket.List, nil
}

func requestOption(r map[string]interface{}, p url.Values) url.Values {
	for k, v := range r {
		switch k {
		case "State":
			p.Set("state", fmt.Sprint(v))
		case "Favorite":
			p.Set("favorite", fmt.Sprint(v))
		case "Tag":
			p.Set("tag", fmt.Sprint(v))
		case "ContentType":
			p.Set("contentType", fmt.Sprint(v))
		case "Sort":
			p.Set("sort", fmt.Sprint(v))
		case "DetailType":
			p.Set("detailType", fmt.Sprint(v))
		case "Search":
			p.Set("search", fmt.Sprint(v))
		case "Domain":
			p.Set("domain", fmt.Sprint(v))
		case "Since":
			p.Set("since", fmt.Sprint(v))
		case "Count":
			p.Set("count", fmt.Sprint(v))
		case "Offset":
			p.Set("offset", fmt.Sprint(v))
		}
	}
	return p
}
<commit_msg>Improve response error<commit_after>// A Go wapper for the pocket API
package pocket

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
)

const EndPoint = "https://getpocket.com/v3/get"

type Client struct {
	consumer_key string
	access_token string
	endpoint     string
	c            *http.Client
}

type Pocket struct {
	Status   int      `json:"status"`
	Complete int      `json:"complete"`
	List     ItemList `json:"list"`
	Since    int      `json:"since"`
}

type ItemList map[string]Lists

type Lists struct {
	Item_id        string `json:"item_id"`
	Resolved_id    string `json:"resolved_id"`
	Given_url      string `json:"given_url"`
	Given_title    string `json:"given_title"`
	Favorite       string `json:"favorite"`
	Status         string `json:"status"`
	Time_added     string `json:"time_added"`
	Time_updated   string `json:"time_updated"`
	Time_favorited string `json:"fime_favorited"`
	Resolved_title string `json:"resolved_title"`
	Resolved_url   string `json:"resolved_url"`
	Excerpt        string `json:"excerpt"`
	Is_article     string `json:"is_article"`
	Is_index       string `json:"is_index"`
	Has_video      string `json:"has_video"`
	Has_image      string `json:"has_image"`
	Word_count     string `json:"word_count"`
}

type RequestOption struct {
	State       string
	Favorite    string
	Tag         string
	ContentType string
	Sort        string
	DetailType  string
	Search      string
	Domain      string
	Since       string
	Count       int
	Offset      int
}

func NewClient(consumer_key, access_token string) *Client {
	return &Client{
		consumer_key,
		access_token,
		EndPoint,
		http.DefaultClient,
	}
}

func (c *Client) PocketList(r map[string]interface{}) (ItemList, error) {
	p := url.Values{}
	p.Set("consumer_key", c.consumer_key)
	p.Set("access_token", c.access_token)

	p = requestOption(r, p)

	res, err := c.c.PostForm(c.endpoint, p)

	if err != nil {
		return nil, err
	}

	if res.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("HTTP request failed with %s", res.Status))
	}

	defer res.Body.Close()

	var pocket Pocket

	err = json.NewDecoder(res.Body).Decode(&pocket)
	if err != nil {
		return nil, err
	}
	return pocket.List, nil
}

func requestOption(r map[string]interface{}, p url.Values) url.Values {
	for k, v := range r {
		switch k {
		case "State":
			p.Set("state", fmt.Sprint(v))
		case "Favorite":
			p.Set("favorite", fmt.Sprint(v))
		case "Tag":
			p.Set("tag", fmt.Sprint(v))
		case "ContentType":
			p.Set("contentType", fmt.Sprint(v))
		case "Sort":
			p.Set("sort", fmt.Sprint(v))
		case "DetailType":
			p.Set("detailType", fmt.Sprint(v))
		case "Search":
			p.Set("search", fmt.Sprint(v))
		case "Domain":
			p.Set("domain", fmt.Sprint(v))
		case "Since":
			p.Set("since", fmt.Sprint(v))
		case "Count":
			p.Set("count", fmt.Sprint(v))
		case "Offset":
			p.Set("offset", fmt.Sprint(v))
		}
	}
	return p
}
<|endoftext|>


<commit_before>package acceptance_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"

	"net"
	"time"
)

var _ = Describe("Http is closed", func() {

	var (
		CONNECTION_TIMEOUT = 11 * time.Second
	)

	It("for apps", func() {
		appName := generator.PrefixedRandomName("CATS-APP-")
		Expect(cf.Cf(
			"push", appName,
			"--no-start",
			"-b", config.StaticFileBuildpackName,
			"-p", "../../../example-apps/static-app",
			"-d", config.AppsDomain,
		).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("start", appName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

		uri := appName + "." + config.AppsDomain + ":80"
		_, err := net.DialTimeout("tcp", uri, CONNECTION_TIMEOUT)
		Expect(err.(net.Error).Timeout()).To(BeTrue())
	})

	It("for api", func() {
		uri := "api." + config.SystemDomain + ":80"
		_, err := net.DialTimeout("tcp", uri, CONNECTION_TIMEOUT)
		Expect(err.(net.Error).Timeout()).To(BeTrue())

	})

})
<commit_msg>Fix http is closed test panic<commit_after>package acceptance_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"

	"net"
	"time"
)

var _ = Describe("Http client", func() {

	var (
		CONNECTION_TIMEOUT = 11 * time.Second
	)

	It("that tries to connect to apps", func() {
		appName := generator.PrefixedRandomName("CATS-APP-")
		Expect(cf.Cf(
			"push", appName,
			"--no-start",
			"-b", config.StaticFileBuildpackName,
			"-p", "../../../example-apps/static-app",
			"-d", config.AppsDomain,
		).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("start", appName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

		uri := appName + "." + config.AppsDomain + ":80"
		_, err := net.DialTimeout("tcp", uri, CONNECTION_TIMEOUT)
		Expect(err).ToNot(BeNil(), "should not connect")
		Expect(err.(net.Error).Timeout()).To(BeTrue(), "should timeout")
	})

	It("that tries to connect to api", func() {
		uri := "api." + config.SystemDomain + ":80"
		_, err := net.DialTimeout("tcp", uri, CONNECTION_TIMEOUT)
		Expect(err).ToNot(BeNil(), "should not connect")
		Expect(err.(net.Error).Timeout()).To(BeTrue(), "should timeout")

	})

})
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// A collection of tests for a file system backed by a GCS bucket, where in
// most cases we interact with the file system directly for creating and
// mofiying files (rather than through the side channel of the GCS bucket
// itself).
//
// These tests are registered by RegisterFSTests.

package fstesting

import (
	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////////////////
// Read-write interaction
////////////////////////////////////////////////////////////////////////

type readWriteTest struct {
	fsTest
}

func (t *readWriteTest) DoesFoo() {
	AssertTrue(false, "TODO")
}
<commit_msg>Added some test names.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// A collection of tests for a file system backed by a GCS bucket, where in
// most cases we interact with the file system directly for creating and
// mofiying files (rather than through the side channel of the GCS bucket
// itself).
//
// These tests are registered by RegisterFSTests.

package fstesting

import (
	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////////////////
// Read-write interaction
////////////////////////////////////////////////////////////////////////

type readWriteTest struct {
	fsTest
}

func (t *readWriteTest) OpenNonExistent_CreateFlagNotSet() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Seek() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Stat() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Sync() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Truncate() {
	AssertTrue(false, "TODO")
}
<|endoftext|>