<commit_before>package echo

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"reflect"
	"runtime"
	"strings"
	"sync"

	"github.com/mattn/go-colorable"
	"golang.org/x/net/websocket"
)

type (
	Echo struct {
		Router           *router
		prefix           string
		middleware       []MiddlewareFunc
		maxParam         byte
		notFoundHandler  HandlerFunc
		httpErrorHandler HTTPErrorHandler
		binder           BindFunc
		renderer         Renderer
		uris             map[Handler]string
		pool             sync.Pool
		debug            bool
	}
	HTTPError struct {
		Code    int
		Message string
	}
	Middleware     interface{}
	MiddlewareFunc func(HandlerFunc) HandlerFunc
	Handler        interface{}
	HandlerFunc    func(*Context) error

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

	BindFunc func(*http.Request, interface{}) error

	// Renderer is the interface that wraps the Render method.
	//
	// Render renders the HTML template with given name and specified data.
	// It writes the output to w.
	Renderer interface {
		Render(w io.Writer, name string, data interface{}) 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"
	ApplicationProtobuf = "application/protobuf"
	ApplicationMsgpack  = "application/msgpack"
	TextPlain           = "text/plain"
	TextHTML            = "text/html"
	ApplicationForm     = "application/x-www-form-urlencoded"
	MultipartForm       = "multipart/form-data"

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

	Accept             = "Accept"
	AcceptEncoding     = "Accept-Encoding"
	ContentDisposition = "Content-Disposition"
	ContentEncoding    = "Content-Encoding"
	ContentLength      = "Content-Length"
	ContentType        = "Content-Type"
	Authorization      = "Authorization"
)

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

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

	UnsupportedMediaType  = errors.New("echo ⇒ unsupported media type")
	RendererNotRegistered = errors.New("echo ⇒ renderer not registered")
)

func NewHTTPError(code int, msg ...string) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	for _, m := range msg {
		he.Message = m
	}
	return he
}

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

// New creates an Echo instance.
func New() (e *Echo) {
	e = &Echo{
		uris: make(map[Handler]string),
	}
	e.Router = NewRouter(e)
	e.pool.New = func() interface{} {
		return NewContext(nil, new(Response), e)
	}

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

	e.SetMaxParam(5)
	e.notFoundHandler = func(c *Context) error {
		return NewHTTPError(http.StatusNotFound)
	}
	e.SetHTTPErrorHandler(func(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()
		}
		http.Error(c.Response, msg, code)
	})
	e.SetBinder(func(r *http.Request, v interface{}) error {
		ct := r.Header.Get(ContentType)
		err := UnsupportedMediaType
		if strings.HasPrefix(ct, ApplicationJSON) {
			err = json.NewDecoder(r.Body).Decode(v)
		} else if strings.HasPrefix(ct, ApplicationForm) {
			err = nil
		}
		return err
	})
	return
}

// Group creates a new sub router with prefix. It inherits all properties from
// the parent. Passing middleware overrides parent middleware.
func (e *Echo) Group(pfx string, m ...Middleware) *Echo {
	g := *e
	g.prefix = g.prefix + pfx
	if len(m) > 0 {
		g.middleware = nil
		g.Use(m...)
	}
	return &g
}

// SetMaxParam sets the maximum number of path parameters allowed for the application.
// Default value is 5, good enough for many use cases.
func (e *Echo) SetMaxParam(n uint8) {
	e.maxParam = n
}

// SetHTTPErrorHandler registers an 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 BindFunc) {
	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 sets debug mode.
func (e *Echo) SetDebug(on bool) {
	e.debug = on
}

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

// Use adds handler to the middleware chain.
func (e *Echo) Use(m ...Middleware) {
	for _, h := range m {
		e.middleware = append(e.middleware, wrapMiddleware(h))
	}
}

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

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

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

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

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

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

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

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

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

// WebSocket adds a WebSocket route > handler to the router.
func (e *Echo) WebSocket(path string, h HandlerFunc) {
	e.Get(path, func(c *Context) (err error) {
		wss := websocket.Server{
			Handler: func(ws *websocket.Conn) {
				c.Socket = ws
				c.Response.status = http.StatusSwitchingProtocols
				err = h(c)
			},
		}
		wss.ServeHTTP(c.Response.writer, c.Request)
		return err
	})
}

func (e *Echo) add(method, path string, h Handler) {
	key := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
	e.uris[key] = path
	e.Router.Add(method, e.prefix+path, wrapHandler(h), e)
}

// Index serves index file.
func (e *Echo) Index(file string) {
	e.ServeFile("/", file)
}

// Favicon serves the default favicon - GET /favicon.ico.
func (e *Echo) Favicon(file string) {
	e.ServeFile("/favicon.ico", file)
}

// Static serves static files.
func (e *Echo) Static(path, root string) {
	fs := http.StripPrefix(path, http.FileServer(http.Dir(root)))
	e.Get(path+"*", func(c *Context) error {
		fs.ServeHTTP(c.Response, c.Request)
		return nil
	})
}

// ServeFile serves a file.
func (e *Echo) ServeFile(path, file string) {
	e.Get(path, func(c *Context) error {
		http.ServeFile(c.Response, c.Request, file)
		return nil
	})
}

// URI generates a URI from handler.
func (e *Echo) URI(h Handler, params ...interface{}) string {
	uri := new(bytes.Buffer)
	lp := len(params)
	n := 0
	key := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
	if path, ok := e.uris[key]; ok {
		for i, l := 0, len(path); i < l; i++ {
			if path[i] == ':' && n < lp {
				for ; i < l && path[i] != '/'; i++ {
				}
				uri.WriteString(fmt.Sprintf("%v", params[n]))
				n++
			}
			if i < l {
				uri.WriteByte(path[i])
			}
		}
	}
	return uri.String()
}

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

func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := e.pool.Get().(*Context)
	h, echo := e.Router.Find(r.Method, r.URL.Path, c)
	if echo != nil {
		e = echo
	}
	c.reset(w, r, e)
	if h == nil {
		h = e.notFoundHandler
	}

	// Chain middleware with handler in the end
	for i := len(e.middleware) - 1; i >= 0; i-- {
		h = e.middleware[i](h)
	}

	// Execute chain
	if he := h(c); he != nil {
		e.httpErrorHandler(he, c)
	}

	e.pool.Put(c)
}

// Run runs a server.
func (e *Echo) Run(addr string) {
	log.Fatal(http.ListenAndServe(addr, e))
}

// RunTLS runs a server with TLS configuration.
func (e *Echo) RunTLS(addr, certFile, keyFile string) {
	log.Fatal(http.ListenAndServeTLS(addr, certFile, keyFile, e))
}

// RunServer runs a custom server.
func (e *Echo) RunServer(server *http.Server) {
	server.Handler = e
	log.Fatal(server.ListenAndServe())
}

// RunTLSServer runs a custom server with TLS configuration.
func (e *Echo) RunTLSServer(server *http.Server, certFile, keyFile string) {
	server.Handler = e
	log.Fatal(server.ListenAndServeTLS(certFile, keyFile))
}

// wraps middleware
func wrapMiddleware(m Middleware) MiddlewareFunc {
	switch m := m.(type) {
	case MiddlewareFunc:
		return m
	case func(HandlerFunc) HandlerFunc:
		return m
	case HandlerFunc:
		return wrapHandlerFuncMW(m)
	case func(*Context) error:
		return wrapHandlerFuncMW(m)
	case func(http.Handler) http.Handler:
		return func(h HandlerFunc) HandlerFunc {
			return func(c *Context) (err error) {
				m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					c.Response.writer = w
					c.Request = r
					err = h(c)
				})).ServeHTTP(c.Response.writer, c.Request)
				return
			}
		}
	case http.Handler:
		return wrapHTTPHandlerFuncMW(m.ServeHTTP)
	case http.HandlerFunc:
		return wrapHTTPHandlerFuncMW(m)
	case func(http.ResponseWriter, *http.Request):
		return wrapHTTPHandlerFuncMW(m)
	default:
		panic("echo => unknown middleware")
	}
}

// Wraps HandlerFunc middleware
func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
	return func(h HandlerFunc) HandlerFunc {
		return func(c *Context) error {
			if err := m(c); err != nil {
				return err
			}
			return h(c)
		}
	}
}

// Wraps http.HandlerFunc middleware
func wrapHTTPHandlerFuncMW(m http.HandlerFunc) MiddlewareFunc {
	return func(h HandlerFunc) HandlerFunc {
		return func(c *Context) error {
			if !c.Response.committed {
				m.ServeHTTP(c.Response.writer, c.Request)
			}
			return h(c)
		}
	}
}

// wraps handler
func wrapHandler(h Handler) HandlerFunc {
	switch h := h.(type) {
	case HandlerFunc:
		return h
	case func(*Context) error:
		return h
	case http.Handler, http.HandlerFunc:
		return func(c *Context) error {
			h.(http.Handler).ServeHTTP(c.Response, c.Request)
			return nil
		}
	case func(http.ResponseWriter, *http.Request):
		return func(c *Context) error {
			h(c.Response, c.Request)
			return nil
		}
	default:
		panic("echo ⇒ unknown handler")
	}
}

func init() {
	log.SetOutput(colorable.NewColorableStdout())
}
<commit_msg>Initiated HTTP2 support<commit_after>package echo

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"reflect"
	"runtime"
	"strings"
	"sync"

	"github.com/mattn/go-colorable"
	"golang.org/x/net/websocket"
	"github.com/bradfitz/http2"
)

type (
	Echo struct {
		Router           *router
		prefix           string
		middleware       []MiddlewareFunc
		http2            bool
		maxParam         byte
		notFoundHandler  HandlerFunc
		httpErrorHandler HTTPErrorHandler
		binder           BindFunc
		renderer         Renderer
		uris             map[Handler]string
		pool             sync.Pool
		debug            bool
	}
	HTTPError struct {
		Code    int
		Message string
	}
	Middleware     interface{}
	MiddlewareFunc func(HandlerFunc) HandlerFunc
	Handler        interface{}
	HandlerFunc    func(*Context) error

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

	BindFunc func(*http.Request, interface{}) error

	// Renderer is the interface that wraps the Render method.
	//
	// Render renders the HTML template with given name and specified data.
	// It writes the output to w.
	Renderer interface {
		Render(w io.Writer, name string, data interface{}) 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"
	ApplicationProtobuf = "application/protobuf"
	ApplicationMsgpack  = "application/msgpack"
	TextPlain           = "text/plain"
	TextHTML            = "text/html"
	ApplicationForm     = "application/x-www-form-urlencoded"
	MultipartForm       = "multipart/form-data"

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

	Accept             = "Accept"
	AcceptEncoding     = "Accept-Encoding"
	ContentDisposition = "Content-Disposition"
	ContentEncoding    = "Content-Encoding"
	ContentLength      = "Content-Length"
	ContentType        = "Content-Type"
	Authorization      = "Authorization"
)

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

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

	UnsupportedMediaType  = errors.New("echo ⇒ unsupported media type")
	RendererNotRegistered = errors.New("echo ⇒ renderer not registered")
)

func NewHTTPError(code int, msg ...string) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	for _, m := range msg {
		he.Message = m
	}
	return he
}

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

// New creates an Echo instance.
func New() (e *Echo) {
	e = &Echo{
		uris: make(map[Handler]string),
	}
	e.Router = NewRouter(e)
	e.pool.New = func() interface{} {
		return NewContext(nil, new(Response), e)
	}

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

	e.HTTP2(true)
	e.SetMaxParam(5)
	e.notFoundHandler = func(c *Context) error {
		return NewHTTPError(http.StatusNotFound)
	}
	e.SetHTTPErrorHandler(func(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()
		}
		http.Error(c.Response, msg, code)
	})
	e.SetBinder(func(r *http.Request, v interface{}) error {
		ct := r.Header.Get(ContentType)
		err := UnsupportedMediaType
		if strings.HasPrefix(ct, ApplicationJSON) {
			err = json.NewDecoder(r.Body).Decode(v)
		} else if strings.HasPrefix(ct, ApplicationForm) {
			err = nil
		}
		return err
	})
	return
}

// Group creates a new sub router with prefix. It inherits all properties from
// the parent. Passing middleware overrides parent middleware.
func (e *Echo) Group(pfx string, m ...Middleware) *Echo {
	g := *e
	g.prefix = g.prefix + pfx
	if len(m) > 0 {
		g.middleware = nil
		g.Use(m...)
	}
	return &g
}

// HTTP2 enables HTTP2 support.
func (e *Echo) HTTP2(on bool) {
	e.http2 = on
}

// SetMaxParam sets the maximum number of path parameters allowed for the application.
// Default value is 5, good enough for many use cases.
func (e *Echo) SetMaxParam(n uint8) {
	e.maxParam = n
}

// SetHTTPErrorHandler registers an 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 BindFunc) {
	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 sets debug mode.
func (e *Echo) SetDebug(on bool) {
	e.debug = on
}

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

// Use adds handler to the middleware chain.
func (e *Echo) Use(m ...Middleware) {
	for _, h := range m {
		e.middleware = append(e.middleware, wrapMiddleware(h))
	}
}

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

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

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

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

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

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

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

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

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

// WebSocket adds a WebSocket route > handler to the router.
func (e *Echo) WebSocket(path string, h HandlerFunc) {
	e.Get(path, func(c *Context) (err error) {
		wss := websocket.Server{
			Handler: func(ws *websocket.Conn) {
				c.Socket = ws
				c.Response.status = http.StatusSwitchingProtocols
				err = h(c)
			},
		}
		wss.ServeHTTP(c.Response.writer, c.Request)
		return err
	})
}

func (e *Echo) add(method, path string, h Handler) {
	key := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
	e.uris[key] = path
	e.Router.Add(method, e.prefix+path, wrapHandler(h), e)
}

// Index serves index file.
func (e *Echo) Index(file string) {
	e.ServeFile("/", file)
}

// Favicon serves the default favicon - GET /favicon.ico.
func (e *Echo) Favicon(file string) {
	e.ServeFile("/favicon.ico", file)
}

// Static serves static files.
func (e *Echo) Static(path, root string) {
	fs := http.StripPrefix(path, http.FileServer(http.Dir(root)))
	e.Get(path+"*", func(c *Context) error {
		fs.ServeHTTP(c.Response, c.Request)
		return nil
	})
}

// ServeFile serves a file.
func (e *Echo) ServeFile(path, file string) {
	e.Get(path, func(c *Context) error {
		http.ServeFile(c.Response, c.Request, file)
		return nil
	})
}

// URI generates a URI from handler.
func (e *Echo) URI(h Handler, params ...interface{}) string {
	uri := new(bytes.Buffer)
	lp := len(params)
	n := 0
	key := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
	if path, ok := e.uris[key]; ok {
		for i, l := 0, len(path); i < l; i++ {
			if path[i] == ':' && n < lp {
				for ; i < l && path[i] != '/'; i++ {
				}
				uri.WriteString(fmt.Sprintf("%v", params[n]))
				n++
			}
			if i < l {
				uri.WriteByte(path[i])
			}
		}
	}
	return uri.String()
}

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

func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := e.pool.Get().(*Context)
	h, echo := e.Router.Find(r.Method, r.URL.Path, c)
	if echo != nil {
		e = echo
	}
	c.reset(w, r, e)
	if h == nil {
		h = e.notFoundHandler
	}

	// Chain middleware with handler in the end
	for i := len(e.middleware) - 1; i >= 0; i-- {
		h = e.middleware[i](h)
	}

	// Execute chain
	if he := h(c); he != nil {
		e.httpErrorHandler(he, c)
	}

	e.pool.Put(c)
}

// Run runs a server.
func (e *Echo) Run(addr string) {
	s := &http.Server{Addr: addr}
	e.run(s)
}

// RunTLS runs a server with TLS configuration.
func (e *Echo) RunTLS(addr, certFile, keyFile string) {
	s := &http.Server{Addr: addr}
	e.run(s, certFile, keyFile)
}

// RunServer runs a custom server.
func (e *Echo) RunServer(srv *http.Server) {
	e.run(srv)
}

// RunTLSServer runs a custom server with TLS configuration.
func (e *Echo) RunTLSServer(srv *http.Server, certFile, keyFile string) {
	e.run(srv, certFile, keyFile)
}

func (e *Echo) run(s *http.Server, f ...string) {
	s.Handler = e
	if e.http2 {
		http2.ConfigureServer(s, nil)
	}
	if len(f) == 0 {
		log.Fatal(s.ListenAndServe())
	} else if len(f) == 2 {
		log.Fatal(s.ListenAndServeTLS(f[0], f[1]))
	} else {
		log.Fatal("echo: invalid TLS configuration")
	}
}

// wraps middleware
func wrapMiddleware(m Middleware) MiddlewareFunc {
	switch m := m.(type) {
	case MiddlewareFunc:
		return m
	case func(HandlerFunc) HandlerFunc:
		return m
	case HandlerFunc:
		return wrapHandlerFuncMW(m)
	case func(*Context) error:
		return wrapHandlerFuncMW(m)
	case func(http.Handler) http.Handler:
		return func(h HandlerFunc) HandlerFunc {
			return func(c *Context) (err error) {
				m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					c.Response.writer = w
					c.Request = r
					err = h(c)
				})).ServeHTTP(c.Response.writer, c.Request)
				return
			}
		}
	case http.Handler:
		return wrapHTTPHandlerFuncMW(m.ServeHTTP)
	case http.HandlerFunc:
		return wrapHTTPHandlerFuncMW(m)
	case func(http.ResponseWriter, *http.Request):
		return wrapHTTPHandlerFuncMW(m)
	default:
		panic("echo => unknown middleware")
	}
}

// Wraps HandlerFunc middleware
func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
	return func(h HandlerFunc) HandlerFunc {
		return func(c *Context) error {
			if err := m(c); err != nil {
				return err
			}
			return h(c)
		}
	}
}

// Wraps http.HandlerFunc middleware
func wrapHTTPHandlerFuncMW(m http.HandlerFunc) MiddlewareFunc {
	return func(h HandlerFunc) HandlerFunc {
		return func(c *Context) error {
			if !c.Response.committed {
				m.ServeHTTP(c.Response.writer, c.Request)
			}
			return h(c)
		}
	}
}

// wraps handler
func wrapHandler(h Handler) HandlerFunc {
	switch h := h.(type) {
	case HandlerFunc:
		return h
	case func(*Context) error:
		return h
	case http.Handler, http.HandlerFunc:
		return func(c *Context) error {
			h.(http.Handler).ServeHTTP(c.Response, c.Request)
			return nil
		}
	case func(http.ResponseWriter, *http.Request):
		return func(c *Context) error {
			h(c.Response, c.Request)
			return nil
		}
	default:
		panic("echo ⇒ unknown handler")
	}
}

func init() {
	log.SetOutput(colorable.NewColorableStdout())
}
<|endoftext|>


<commit_before>package ebuf

// Editing Operations
const (
	Insert = iota
	Delete
)

// Op represents editing operation type
type Op struct {
	Type, Pos, Len int
}

// Insert inserts bytes to specified position
func (b *Buffer) Insert(pos int, bs []byte) {
	b.InsertWithTempCursors(pos, bs, nil)
}

// InsertWithTempCursors inserts bytes to specified position, keeping a slice of cursors valid
func (b *Buffer) InsertWithTempCursors(pos int, bs []byte, tempCursors []*int) {
	r := b.States[b.Current].Rope.Insert(pos, bs)
	b.dropStates()
	b.States = append(b.States, State{
		Rope: r,
		LastOp: Op{
			Type: Insert,
			Pos:  pos,
			Len:  len(bs),
		},
		Skip: b.skipping,
	})
	b.Current++
	// update cursors
	for cursor := range b.Cursors {
		if *cursor >= pos {
			*cursor += len(bs)
		}
	}
	for _, cursor := range tempCursors {
		if *cursor >= pos {
			*cursor += len(bs)
		}
	}
}

// Delete deletes specified lengthed bytes from specified position
func (b *Buffer) Delete(pos, length int) {
	b.DeleteWithTempCursors(pos, length, nil)
}

// DeleteWithTempCursors deletes specified lengthed bytes from specified position, keeping a slice of cursors valid
func (b *Buffer) DeleteWithTempCursors(pos, length int, tempCursors []*int) {
	r := b.States[b.Current].Rope.Delete(pos, length)
	b.dropStates()
	b.States = append(b.States, State{
		Rope: r,
		LastOp: Op{
			Type: Delete,
			Pos:  pos,
			Len:  length,
		},
		Skip: b.skipping,
	})
	b.Current++
	// update cursors
	for cursor := range b.Cursors {
		if *cursor > pos && *cursor < pos+length {
			*cursor = pos
		} else if *cursor >= pos+length {
			*cursor -= length
		}
	}
	for _, cursor := range tempCursors {
		if *cursor > pos && *cursor < pos+length {
			*cursor = pos
		} else if *cursor >= pos+length {
			*cursor -= length
		}
	}
}

func (b *Buffer) dropStates() {
	b.States = b.States[:b.Current+1]
}
<commit_msg>use bool to represent operation type<commit_after>package ebuf

// Editing Operations
const (
	Insert = true
	Delete = false
)

// Op represents editing operation type
type Op struct {
	Type     bool
	Pos, Len int
}

// Insert inserts bytes to specified position
func (b *Buffer) Insert(pos int, bs []byte) {
	b.InsertWithTempCursors(pos, bs, nil)
}

// InsertWithTempCursors inserts bytes to specified position, keeping a slice of cursors valid
func (b *Buffer) InsertWithTempCursors(pos int, bs []byte, tempCursors []*int) {
	r := b.States[b.Current].Rope.Insert(pos, bs)
	b.dropStates()
	b.States = append(b.States, State{
		Rope: r,
		LastOp: Op{
			Type: Insert,
			Pos:  pos,
			Len:  len(bs),
		},
		Skip: b.skipping,
	})
	b.Current++
	// update cursors
	for cursor := range b.Cursors {
		if *cursor >= pos {
			*cursor += len(bs)
		}
	}
	for _, cursor := range tempCursors {
		if *cursor >= pos {
			*cursor += len(bs)
		}
	}
}

// Delete deletes specified lengthed bytes from specified position
func (b *Buffer) Delete(pos, length int) {
	b.DeleteWithTempCursors(pos, length, nil)
}

// DeleteWithTempCursors deletes specified lengthed bytes from specified position, keeping a slice of cursors valid
func (b *Buffer) DeleteWithTempCursors(pos, length int, tempCursors []*int) {
	r := b.States[b.Current].Rope.Delete(pos, length)
	b.dropStates()
	b.States = append(b.States, State{
		Rope: r,
		LastOp: Op{
			Type: Delete,
			Pos:  pos,
			Len:  length,
		},
		Skip: b.skipping,
	})
	b.Current++
	// update cursors
	for cursor := range b.Cursors {
		if *cursor > pos && *cursor < pos+length {
			*cursor = pos
		} else if *cursor >= pos+length {
			*cursor -= length
		}
	}
	for _, cursor := range tempCursors {
		if *cursor > pos && *cursor < pos+length {
			*cursor = pos
		} else if *cursor >= pos+length {
			*cursor -= length
		}
	}
}

func (b *Buffer) dropStates() {
	b.States = b.States[:b.Current+1]
}
<|endoftext|>


<commit_before>package serializer

import (
	"time"

	"github.com/jinzhu/gorm"
	"github.com/mingrammer/meetup-api/api/model"
)

type CategorySerialzer struct {
	ID    uint `json:"id"`
	Title string `json:"title"`
}

type OwnerSerializer struct {
	ID        uint `json:"id"`
	Name      string `json:"name"`
	AvatarURL string `json:"avatar"`
}

type PlaceSerializer struct {
	PlaceTitle     string `json:"title"`
	PlaceLatitude  float64 `json:"lat"`
	PlaceLongitude float64 `json:"lon"`
}

type DatetimeSerializer struct {
	DateStart *time.Time `json:"start"`
	DateEnd   *time.Time `json:"end"`
}

type EventSerialzer struct {
	Title       string `json:"title"`
	Description string `json:"description"`
	Place       PlaceSerializer `json:"place"`
	Datetime    DatetimeSerializer `json:"datetime"`
	Category    CategorySerialzer `json:"category"`
	Owner       OwnerSerializer `json:"owner"`
	CreatedAt   *time.Time `json:"created_at"`
	UpdatedAt   *time.Time `json:"updated_at"`
}

func SerializeEvent(db *gorm.DB, event *model.Event) *EventSerialzer {
	owner := model.User{}
	db.Find(&owner, event.OwnerID)
	category := model.Category{}
	db.Find(&category, event.CategoryID)
	eventSerialzer := EventSerialzer{
		Title:       event.Title,
		Description: event.Description,
		Place: PlaceSerializer{
			PlaceTitle:     event.Place.PlaceTitle,
			PlaceLatitude:  event.Place.PlaceLat,
			PlaceLongitude: event.Place.PlaceLon,
		},
		Datetime: DatetimeSerializer{
			DateStart: event.Datetime.DateStart,
			DateEnd:   event.Datetime.DateEnd,

		},
		Category: CategorySerialzer{
			ID:    category.ID,
			Title: category.Title,
		},
		Owner: OwnerSerializer{
			ID:        owner.ID,
			Name:      owner.Name,
			AvatarURL: owner.AvatarURL,
		},
		CreatedAt: event.CreatedAt,
		UpdatedAt: event.UpdatedAt,
	}
	return &eventSerialzer
}
<commit_msg>Add id field to event serializer<commit_after>package serializer

import (
	"time"

	"github.com/jinzhu/gorm"
	"github.com/mingrammer/meetup-api/api/model"
)

type CategorySerialzer struct {
	ID    uint `json:"id"`
	Title string `json:"title"`
}

type OwnerSerializer struct {
	ID        uint `json:"id"`
	Name      string `json:"name"`
	AvatarURL string `json:"avatar"`
}

type PlaceSerializer struct {
	PlaceTitle     string `json:"title"`
	PlaceLatitude  float64 `json:"lat"`
	PlaceLongitude float64 `json:"lon"`
}

type DatetimeSerializer struct {
	DateStart *time.Time `json:"start"`
	DateEnd   *time.Time `json:"end"`
}

type EventSerialzer struct {
	ID          uint `json:"id"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Place       PlaceSerializer `json:"place"`
	Datetime    DatetimeSerializer `json:"datetime"`
	Category    CategorySerialzer `json:"category"`
	Owner       OwnerSerializer `json:"owner"`
	CreatedAt   *time.Time `json:"created_at"`
	UpdatedAt   *time.Time `json:"updated_at"`
}

func SerializeEvent(db *gorm.DB, event *model.Event) *EventSerialzer {
	owner := model.User{}
	db.Find(&owner, event.OwnerID)
	category := model.Category{}
	db.Find(&category, event.CategoryID)
	eventSerialzer := EventSerialzer{
		ID:          event.ID,
		Title:       event.Title,
		Description: event.Description,
		Place: PlaceSerializer{
			PlaceTitle:     event.Place.PlaceTitle,
			PlaceLatitude:  event.Place.PlaceLat,
			PlaceLongitude: event.Place.PlaceLon,
		},
		Datetime: DatetimeSerializer{
			DateStart: event.Datetime.DateStart,
			DateEnd:   event.Datetime.DateEnd,

		},
		Category: CategorySerialzer{
			ID:    category.ID,
			Title: category.Title,
		},
		Owner: OwnerSerializer{
			ID:        owner.ID,
			Name:      owner.Name,
			AvatarURL: owner.AvatarURL,
		},
		CreatedAt: event.CreatedAt,
		UpdatedAt: event.UpdatedAt,
	}
	return &eventSerialzer
}
<|endoftext|>


<commit_before>package auth

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/api/resolver/path"
	"github.com/micro/go-micro/v2/auth"
	"github.com/micro/go-micro/v2/logger"
)

// CombinedAuthHandler wraps a server and authenticates requests
func CombinedAuthHandler(namespace string, r resolver.Resolver, h http.Handler) http.Handler {
	if r == nil {
		r = path.NewResolver()
	}
	if len(namespace) == 0 {
		namespace = "go.micro"
	}

	return authHandler{
		handler:   h,
		resolver:  r,
		auth:      auth.DefaultAuth,
		namespace: namespace,
	}
}

type authHandler struct {
	handler   http.Handler
	auth      auth.Auth
	resolver  resolver.Resolver
	namespace string
}

func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Determine the namespace
	namespace, err := namespaceFromRequest(req)
	if err != nil {
		logger.Error(err)
		namespace = auth.DefaultNamespace
	}

	// Set the namespace in the header
	req.Header.Set(auth.NamespaceKey, namespace)

	// Extract the token from the request
	var token string
	if header := req.Header.Get("Authorization"); len(header) > 0 {
		// Extract the auth token from the request
		if strings.HasPrefix(header, auth.BearerScheme) {
			token = header[len(auth.BearerScheme):]
		}
	} else {
		// Get the token out the cookies if not provided in headers
		if c, err := req.Cookie("micro-token"); err == nil && c != nil {
			token = strings.TrimPrefix(c.Value, auth.TokenCookieName+"=")
			req.Header.Set("Authorization", auth.BearerScheme+token)
		}
	}

	// Get the account using the token, fallback to a blank account
	// since some endpoints can be unauthenticated, so the lack of an
	// account doesn't necesserially mean a forbidden request
	acc, err := h.auth.Inspect(token)
	if err != nil {
		acc = &auth.Account{Namespace: namespace}
	}

	// Check the accounts namespace matches the namespace we're operating
	// within. If not forbid the request and log the occurance.
	if acc.Namespace != namespace {
		logger.Warnf("Cross namespace request forbidden: account %v (%v) requested access to %v in the %v namespace", acc.ID, acc.Namespace, req.URL.Path, namespace)
		w.WriteHeader(http.StatusForbidden)
	}

	// Determine the name of the service being requested
	endpoint, err := h.resolver.Resolve(req)
	if err == resolver.ErrInvalidPath || err == resolver.ErrNotFound {
		// a file not served by the resolver has been requested (e.g. favicon.ico)
		endpoint = &resolver.Endpoint{Path: req.URL.Path}
	} else if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// construct the resource name, e.g. home => go.micro.web.home
	resName := h.namespace
	if len(endpoint.Name) > 0 {
		resName = resName + "." + endpoint.Name
	}

	// determine the resource path. there is an inconsistency in how resolvers
	// use method, some use it as Users.ReadUser (the rpc method), and others
	// use it as the HTTP method, e.g GET. TODO: Refactor this to make it consistent.
	resEndpoint := endpoint.Path
	if len(endpoint.Path) == 0 {
		resEndpoint = endpoint.Method
	}

	// Perform the verification check to see if the account has access to
	// the resource they're requesting
	res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint, Namespace: namespace}
	if err := h.auth.Verify(acc, res); err == nil {
		// The account has the necessary permissions to access the resource
		h.handler.ServeHTTP(w, req)
		return
	}

	// The account is set, but they don't have enough permissions, hence
	// we return a forbidden error.
	if len(acc.ID) > 0 {
		w.WriteHeader(http.StatusForbidden)
		return
	}

	// If there is no auth login url set, 401
	loginURL := h.auth.Options().LoginURL
	if loginURL == "" {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	// Redirect to the login path
	params := url.Values{"redirect_to": {req.URL.Path}}
	loginWithRedirect := fmt.Sprintf("%v?%v", loginURL, params.Encode())
	http.Redirect(w, req, loginWithRedirect, http.StatusTemporaryRedirect)
}

func namespaceFromRequest(req *http.Request) (string, error) {
	// determine the host, e.g. dev.micro.mu:8080
	host := req.URL.Hostname()
	if len(host) == 0 {
		// fallback to req.Host
		host, _, _ = net.SplitHostPort(req.Host)
	}

	logger.Infof("Host is %v", host)

	// check for an ip address
	if net.ParseIP(host) != nil {
		return auth.DefaultNamespace, nil
	}

	// check for dev enviroment
	if host == "localhost" || host == "127.0.0.1" {
		return auth.DefaultNamespace, nil
	}

	// if host is not a subdomain, deturn default namespace
	comps := strings.Split(host, ".")
	if len(comps) != 3 {
		return auth.DefaultNamespace, nil
	}

	// check for the micro.mu domain
	domain := fmt.Sprintf("%v.%v", comps[1], comps[2])
	if domain == "micro.mu" {
		return auth.DefaultNamespace, nil
	}

	// return the subdomain as the host
	return comps[0], nil
}
<commit_msg>Encode Endpoint in API auth wrapper<commit_after>package auth

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

	"github.com/micro/go-micro/v2/metadata"

	"github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/api/resolver/path"
	"github.com/micro/go-micro/v2/auth"
	"github.com/micro/go-micro/v2/logger"
)

// CombinedAuthHandler wraps a server and authenticates requests
func CombinedAuthHandler(namespace string, r resolver.Resolver, h http.Handler) http.Handler {
	if r == nil {
		r = path.NewResolver()
	}
	if len(namespace) == 0 {
		namespace = "go.micro"
	}

	return authHandler{
		handler:   h,
		resolver:  r,
		auth:      auth.DefaultAuth,
		namespace: namespace,
	}
}

type authHandler struct {
	handler   http.Handler
	auth      auth.Auth
	resolver  resolver.Resolver
	namespace string
}

func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Determine the namespace
	namespace, err := namespaceFromRequest(req)
	if err != nil {
		logger.Error(err)
		namespace = auth.DefaultNamespace
	}

	// Set the namespace in the header
	req.Header.Set(auth.NamespaceKey, namespace)

	// Extract the token from the request
	var token string
	if header := req.Header.Get("Authorization"); len(header) > 0 {
		// Extract the auth token from the request
		if strings.HasPrefix(header, auth.BearerScheme) {
			token = header[len(auth.BearerScheme):]
		}
	} else {
		// Get the token out the cookies if not provided in headers
		if c, err := req.Cookie("micro-token"); err == nil && c != nil {
			token = strings.TrimPrefix(c.Value, auth.TokenCookieName+"=")
			req.Header.Set("Authorization", auth.BearerScheme+token)
		}
	}

	// Get the account using the token, fallback to a blank account
	// since some endpoints can be unauthenticated, so the lack of an
	// account doesn't necesserially mean a forbidden request
	acc, err := h.auth.Inspect(token)
	if err != nil {
		acc = &auth.Account{Namespace: namespace}
	}

	// Check the accounts namespace matches the namespace we're operating
	// within. If not forbid the request and log the occurance.
	if acc.Namespace != namespace {
		logger.Warnf("Cross namespace request forbidden: account %v (%v) requested access to %v in the %v namespace", acc.ID, acc.Namespace, req.URL.Path, namespace)
		w.WriteHeader(http.StatusForbidden)
	}

	// Determine the name of the service being requested
	endpoint, err := h.resolver.Resolve(req)
	if err == resolver.ErrInvalidPath || err == resolver.ErrNotFound {
		// a file not served by the resolver has been requested (e.g. favicon.ico)
		endpoint = &resolver.Endpoint{Path: req.URL.Path}
	} else if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	} else if err == nil {
		// set the endpoint in the context so it can be used to resolve
		// the request later
		if bytes, err := json.Marshal(endpoint); err == nil {
			ctx := metadata.Set(req.Context(), "endpoint", string(bytes))
			*req = *req.WithContext(ctx)
		}
	}

	// construct the resource name, e.g. home => go.micro.web.home
	resName := h.namespace
	if len(endpoint.Name) > 0 {
		resName = resName + "." + endpoint.Name
	}

	// determine the resource path. there is an inconsistency in how resolvers
	// use method, some use it as Users.ReadUser (the rpc method), and others
	// use it as the HTTP method, e.g GET. TODO: Refactor this to make it consistent.
	resEndpoint := endpoint.Path
	if len(endpoint.Path) == 0 {
		resEndpoint = endpoint.Method
	}

	// Perform the verification check to see if the account has access to
	// the resource they're requesting
	res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint, Namespace: namespace}
	if err := h.auth.Verify(acc, res); err == nil {
		// The account has the necessary permissions to access the resource
		h.handler.ServeHTTP(w, req)
		return
	}

	// The account is set, but they don't have enough permissions, hence
	// we return a forbidden error.
	if len(acc.ID) > 0 {
		w.WriteHeader(http.StatusForbidden)
		return
	}

	// If there is no auth login url set, 401
	loginURL := h.auth.Options().LoginURL
	if loginURL == "" {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	// Redirect to the login path
	params := url.Values{"redirect_to": {req.URL.Path}}
	loginWithRedirect := fmt.Sprintf("%v?%v", loginURL, params.Encode())
	http.Redirect(w, req, loginWithRedirect, http.StatusTemporaryRedirect)
}

func namespaceFromRequest(req *http.Request) (string, error) {
	// needed to tmp debug host in prod. will be removed.
	logger.Infof("Host is '%v'; URL Host is '%v'; URL Hostname is '%v'", req.Host, req.URL.Host, req.URL.Hostname())

	// determine the host, e.g. dev.micro.mu:8080
	host := req.URL.Hostname()
	if len(host) == 0 {
		// fallback to req.Host
		host, _, _ = net.SplitHostPort(req.Host)
	}

	// check for an ip address
	if net.ParseIP(host) != nil {
		return auth.DefaultNamespace, nil
	}

	// check for dev enviroment
	if host == "localhost" || host == "127.0.0.1" {
		return auth.DefaultNamespace, nil
	}

	// if host is not a subdomain, deturn default namespace
	comps := strings.Split(host, ".")
	if len(comps) != 3 {
		return auth.DefaultNamespace, nil
	}

	// check for the micro.mu domain
	domain := fmt.Sprintf("%v.%v", comps[1], comps[2])
	if domain == "micro.mu" {
		return auth.DefaultNamespace, nil
	}

	// return the subdomain as the host
	return comps[0], nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package apiserver

// This file imports all of the facades so they get registered at runtime.
// When adding a new facade implementation, import it here so that its init()
// function will get called to register it.
import (
	_ "github.com/juju/juju/apiserver/action"
	_ "github.com/juju/juju/apiserver/addresser"
	_ "github.com/juju/juju/apiserver/agent"
	_ "github.com/juju/juju/apiserver/agenttools"
	_ "github.com/juju/juju/apiserver/annotations"
	_ "github.com/juju/juju/apiserver/backups"
	_ "github.com/juju/juju/apiserver/block"
	_ "github.com/juju/juju/apiserver/charmrevisionupdater"
	_ "github.com/juju/juju/apiserver/charms"
	_ "github.com/juju/juju/apiserver/cleaner"
	_ "github.com/juju/juju/apiserver/client"
	_ "github.com/juju/juju/apiserver/controller"
	_ "github.com/juju/juju/apiserver/deployer"
	_ "github.com/juju/juju/apiserver/discoverspaces"
	_ "github.com/juju/juju/apiserver/diskmanager"
	_ "github.com/juju/juju/apiserver/firewaller"
	_ "github.com/juju/juju/apiserver/highavailability"
	_ "github.com/juju/juju/apiserver/imagemanager"
	_ "github.com/juju/juju/apiserver/imagemetadata"
	_ "github.com/juju/juju/apiserver/instancepoller"
	_ "github.com/juju/juju/apiserver/keymanager"
	_ "github.com/juju/juju/apiserver/keyupdater"
	_ "github.com/juju/juju/apiserver/logger"
	_ "github.com/juju/juju/apiserver/machine"
	_ "github.com/juju/juju/apiserver/machinemanager"
	_ "github.com/juju/juju/apiserver/meterstatus"
	_ "github.com/juju/juju/apiserver/metricsadder"
	_ "github.com/juju/juju/apiserver/metricsdebug"
	_ "github.com/juju/juju/apiserver/metricsmanager"
	_ "github.com/juju/juju/apiserver/modelmanager"
	_ "github.com/juju/juju/apiserver/provisioner"
	_ "github.com/juju/juju/apiserver/proxyupdater"
	_ "github.com/juju/juju/apiserver/reboot"
	_ "github.com/juju/juju/apiserver/resumer"
	_ "github.com/juju/juju/apiserver/service"
	_ "github.com/juju/juju/apiserver/spaces"
	_ "github.com/juju/juju/apiserver/statushistory"
	_ "github.com/juju/juju/apiserver/storage"
	_ "github.com/juju/juju/apiserver/storageprovisioner"
	_ "github.com/juju/juju/apiserver/subnets"
	_ "github.com/juju/juju/apiserver/undertaker"
	_ "github.com/juju/juju/apiserver/unitassigner"
	_ "github.com/juju/juju/apiserver/uniter"
	_ "github.com/juju/juju/apiserver/upgrader"
	_ "github.com/juju/juju/apiserver/usermanager"
)
<commit_msg>apiserver/allfacades: add HookRetryStrategy<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package apiserver

// This file imports all of the facades so they get registered at runtime.
// When adding a new facade implementation, import it here so that its init()
// function will get called to register it.
import (
	_ "github.com/juju/juju/apiserver/action"
	_ "github.com/juju/juju/apiserver/addresser"
	_ "github.com/juju/juju/apiserver/agent"
	_ "github.com/juju/juju/apiserver/agenttools"
	_ "github.com/juju/juju/apiserver/annotations"
	_ "github.com/juju/juju/apiserver/backups"
	_ "github.com/juju/juju/apiserver/block"
	_ "github.com/juju/juju/apiserver/charmrevisionupdater"
	_ "github.com/juju/juju/apiserver/charms"
	_ "github.com/juju/juju/apiserver/cleaner"
	_ "github.com/juju/juju/apiserver/client"
	_ "github.com/juju/juju/apiserver/controller"
	_ "github.com/juju/juju/apiserver/deployer"
	_ "github.com/juju/juju/apiserver/discoverspaces"
	_ "github.com/juju/juju/apiserver/diskmanager"
	_ "github.com/juju/juju/apiserver/firewaller"
	_ "github.com/juju/juju/apiserver/highavailability"
	_ "github.com/juju/juju/apiserver/hookretrystrategy"
	_ "github.com/juju/juju/apiserver/imagemanager"
	_ "github.com/juju/juju/apiserver/imagemetadata"
	_ "github.com/juju/juju/apiserver/instancepoller"
	_ "github.com/juju/juju/apiserver/keymanager"
	_ "github.com/juju/juju/apiserver/keyupdater"
	_ "github.com/juju/juju/apiserver/logger"
	_ "github.com/juju/juju/apiserver/machine"
	_ "github.com/juju/juju/apiserver/machinemanager"
	_ "github.com/juju/juju/apiserver/meterstatus"
	_ "github.com/juju/juju/apiserver/metricsadder"
	_ "github.com/juju/juju/apiserver/metricsdebug"
	_ "github.com/juju/juju/apiserver/metricsmanager"
	_ "github.com/juju/juju/apiserver/modelmanager"
	_ "github.com/juju/juju/apiserver/provisioner"
	_ "github.com/juju/juju/apiserver/proxyupdater"
	_ "github.com/juju/juju/apiserver/reboot"
	_ "github.com/juju/juju/apiserver/resumer"
	_ "github.com/juju/juju/apiserver/service"
	_ "github.com/juju/juju/apiserver/spaces"
	_ "github.com/juju/juju/apiserver/statushistory"
	_ "github.com/juju/juju/apiserver/storage"
	_ "github.com/juju/juju/apiserver/storageprovisioner"
	_ "github.com/juju/juju/apiserver/subnets"
	_ "github.com/juju/juju/apiserver/undertaker"
	_ "github.com/juju/juju/apiserver/unitassigner"
	_ "github.com/juju/juju/apiserver/uniter"
	_ "github.com/juju/juju/apiserver/upgrader"
	_ "github.com/juju/juju/apiserver/usermanager"
)
<|endoftext|>


<commit_before>package djinn

import (
	"fmt"
	"html/template"
	"io"
	"regexp"
)

type (
	// The primary Djinn struct for templates and rendering, containing loaders,
	// template functions, cache, & configuration.
	Djinn struct {
		Loaders []TemplateLoader
		FuncMap map[string]interface{}
		Cache
		*conf
	}

	Node struct {
		Name string
		Src  string
	}
)

var (
	re_extends     *regexp.Regexp = regexp.MustCompile("{{ extends [\"']?([^'\"}']*)[\"']? }}")
	re_defineTag   *regexp.Regexp = regexp.MustCompile("{{ ?define \"([^\"]*)\" ?\"?([a-zA-Z0-9]*)?\"? ?}}")
	re_templateTag *regexp.Regexp = regexp.MustCompile("{{ ?template \"([^\"]*)\" ?([^ ]*)? ?}}")
)

<<<<<<< HEAD
// A blank instance with a default cache
func New() *Djinn {
	d := &Djinn{}
	d.Loaders = make([]TemplateLoader, 0)
	d.FuncMap = make(map[string]interface{})
	d.cache = NewTLRUCache(50)
	return d
}

func (d *Djinn) AddLoaders(loaders ...TemplateLoader) {
	for _, l := range loaders {
		d.Loaders = append(d.Loaders, l)
=======
// Empty returns an empty Djinn with no configuration.
func Empty() *Djinn {
	return &Djinn{
		Loaders: make([]TemplateLoader, 0),
		FuncMap: make(map[string]interface{}),
>>>>>>> develop
	}
}

<<<<<<< HEAD
func (d *Djinn) Render(w io.Writer, name string, data interface{}) error {
	if tmpl, ok := d.cache.Get(name); ok {
		err = tmpl.Execute(w, data)
	} else {
		tmpl, err := d.assemble(name)
		if err != nil {
			return err
		}
		if tmpl == nil {
			return Errf("Nil template named %s", name)
		}
		err = tmpl.Execute(w, data)
	}

	if err != nil {
		return err
	}

	return nil
}

func (d *Djinn) FetchTemplate(w io.Writer, name string) (*template.Template, error) {
	if tmpl, ok := d.cache.Get(name); ok {
		return tmpl, nil
	} else {
		return d.assemble(name)
=======
// New provides a Djinn with default configuration & cache set to on.
func New(opts ...Conf) *Djinn {
	j := Empty()
	j.conf = defaultconf()
	opts = append(opts, CacheOn(NewTLRUCache(100)))
	err := j.SetConf(opts...)
	if err != nil {
		panic(DjinnError("could not configure: %s", err))
>>>>>>> develop
	}
	return j
}

<<<<<<< HEAD
func (d *Djinn) get(name string) (string, error) {
	for _, l := range d.Loaders {
		t, err := l.Load(name)
		if err == nil {
			return t, nil
=======
// Render excutes the template specified by name, with the supplied writer and
// data. Template is searched for in the cache, if enabled, then from assembling
// the from the tempalte Djinn loaders. Returns any ocurring errors.
func (j *Djinn) Render(w io.Writer, name string, data interface{}) error {
	if j.CacheOn {
		if tmpl, ok := j.Cache.Get(name); ok {
			return tmpl.Execute(w, data)
>>>>>>> develop
		}
	}

<<<<<<< HEAD
func (d *Djinn) add(stack *[]*Node, name string) error {
	tplSrc, err := d.get(name)
=======
	tmpl, err := j.assemble(name)
>>>>>>> develop

	if err != nil {
		return err
	}

	if tmpl == nil {
		return DjinnError("nil template named %s", name)
	}

<<<<<<< HEAD
	extendsMatches := re_extends.FindStringSubmatch(tplSrc)
	if len(extendsMatches) == 2 {
		err := d.add(stack, extendsMatches[1])
		if err != nil {
			return err
		}
		tplSrc = re_extends.ReplaceAllString(tplSrc, "")
	}
=======
	return tmpl.Execute(w, data)
}
>>>>>>> develop

// Given a string name, Fetch attempts to get a *template.Template from cache
// or loaders, returning any error.
func (j *Djinn) Fetch(name string) (*template.Template, error) {
	if j.CacheOn {
		if tmpl, ok := j.Cache.Get(name); ok {
			return tmpl, nil
		}
	}
	return j.assemble(name)
}

func (d *Djinn) assemble(name string) (*template.Template, error) {
	stack := []*Node{}

	err := d.add(&stack, name)

	if err != nil {
		return nil, err
	}

	blocks := map[string]string{}
	blockId := 0

	var rootTemplate *template.Template

	for _, node := range stack {
		node.Src = re_defineTag.ReplaceAllStringFunc(node.Src, func(raw string) string {
			parsed := re_defineTag.FindStringSubmatch(raw)
			blockName := fmt.Sprintf("BLOCK_%d", blockId)
			blocks[parsed[1]] = blockName

			blockId += 1
			return "{{ define \"" + blockName + "\" }}"
		})
	}

	for i, node := range stack {
		node.Src = re_templateTag.ReplaceAllStringFunc(node.Src, func(raw string) string {
			parsed := re_templateTag.FindStringSubmatch(raw)
			origName := parsed[1]
			replacedName, ok := blocks[origName]

			dot := "."
			if len(parsed) == 3 && len(parsed[2]) > 0 {
				dot = parsed[2]
			}
			if ok {
				return fmt.Sprintf(`{{ template "%s" %s }}`, replacedName, dot)
			} else {
				return ""
			}
		})

		var thisTemplate *template.Template

		if i == 0 {
			thisTemplate = template.New(node.Name)
			rootTemplate = thisTemplate
		} else {
			thisTemplate = rootTemplate.New(node.Name)
		}

		thisTemplate.Funcs(d.FuncMap)

		_, err := thisTemplate.Parse(node.Src)
		if err != nil {
			return nil, err
		}
	}

<<<<<<< HEAD
	d.cache.Add(name, rootTemplate)
=======
	if j.CacheOn {
		j.Cache.Add(name, rootTemplate)
	}
>>>>>>> develop

	return rootTemplate, nil
}

func (j *Djinn) add(stack *[]*Node, name string) error {
	tplSrc, err := j.getTemplate(name)

	if err != nil {
		return err
	}

	if len(tplSrc) < 1 {
		return DjinnError("empty template named %s", name)
	}

	extendsMatches := re_extends.FindStringSubmatch(tplSrc)
	if len(extendsMatches) == 2 {
		err := j.add(stack, extendsMatches[1])
		if err != nil {
			return err
		}
		tplSrc = re_extends.ReplaceAllString(tplSrc, "")
	}

	node := &Node{
		Name: name,
		Src:  tplSrc,
	}

	*stack = append((*stack), node)

	return nil
}

func (j *Djinn) getTemplate(name string) (string, error) {
	for _, l := range j.Loaders {
		t, err := l.Load(name)
		if err == nil {
			return t, nil
		}
	}
	return "", DjinnError("template %s does not exist", name)
}
<commit_msg>prep merge develop<commit_after><|endoftext|>


<commit_before>package cloud

import (
	"context"
)

// Cloud offers all necessary operations to manage backups in the cloud.
type Cloud interface {
	// Send uploads the file to the cloud and return the backup archive
	// information.
	Send(ctx context.Context, filename string) (Backup, error)

	// List retrieves all the uploaded backups information in the cloud.
	List(ctx context.Context) ([]Backup, error)

	// Get retrieves a specific backup file and stores it locally in a file. The
	// filename storing the location of the file is returned.
	Get(ctx context.Context, id string) (filename string, err error)

	// Remove erase a specific backup from the cloud.
	Remove(ctx context.Context, id string) error
}
<commit_msg>Improve documentation of the cloud package<commit_after>package cloud

import (
	"context"
)

// Cloud offers all necessary operations to manage backups in the cloud.
type Cloud interface {
	// Send uploads the file to the cloud and return the backup archive
	// information. The upload operation can be cancelled anytime using the
	// context.
	Send(ctx context.Context, filename string) (Backup, error)

	// List retrieves all the uploaded backups information in the cloud. The
	// operation can be cancelled anytime using the context.
	List(ctx context.Context) ([]Backup, error)

	// Get retrieves a specific backup and stores it locally in a file. The
	// filename where the backup was saved is returned. The operation can be
	// cancelled anytime using the context.
	Get(ctx context.Context, id string) (filename string, err error)

	// Remove erase a specific backup from the cloud. The operation can be
	// cancelled anytime using the context.
	Remove(ctx context.Context, id string) error
}
<|endoftext|>


<commit_before>package kafka

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"io/ioutil"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/Shopify/sarama"
)

// Decoder is the interface that is required of plugins
type Decoder interface {
	Decode(topic string, data []byte) ([]byte, error)
}

// plainDecoder is the default Decoder
type plainDecoder struct{}

func (p plainDecoder) Decode(topic string, data []byte) ([]byte, error) { return data, nil }

//Client fetches from kafka
type Client struct {
	addrs   []string
	sarama  sarama.Client
	decoder Decoder
}

//Partition holds information about a kafka partition
type Partition struct {
	Topic     string `json:"topic"`
	Partition int32  `json:"partition"`
	Start     int64  `json:"start"`
	End       int64  `json:"end"`
	Offset    int64  `json:"offset"`
	Filter    string `json:"filter"`
}

//String turns a partition into a string
func (p *Partition) String() string {
	d, _ := json.Marshal(p)
	return string(d)
}

//Message holds information about a single kafka message
type Message struct {
	Partition Partition `json:"partition"`
	Value     []byte    `json:"msg"`
	Offset    int64     `json:"offset"`
}

// Opts are funcs that set attributes on Client
type Opt func(*Client)

//New returns a kafka Client.
func New(addrs []string, opts ...Opt) (*Client, error) {
	cfg, err := getConfig()
	if err != nil {
		return nil, err
	}

	s, err := sarama.NewClient(addrs, cfg)
	if err != nil {
		return nil, err
	}

	cli := &Client{
		sarama:  s,
		addrs:   addrs,
		decoder: &plainDecoder{},
	}

	for _, opt := range opts {
		opt(cli)
	}

	return cli, nil
}

// WithDecoder is used to insert a Decoder plugin
func WithDecoder(d Decoder) func(*Client) {
	return func(c *Client) {
		c.decoder = d
	}
}

func getConfig() (*sarama.Config, error) {
	cfg := sarama.NewConfig()
	tlsCfg, err := getTLSConfig()
	if err != nil || tlsCfg == nil {
		return cfg, err
	}

	cfg.Net.TLS.Enable = true
	cfg.Net.TLS.Config = tlsCfg
	return cfg, nil
}

func getTLSConfig() (*tls.Config, error) {
	certFile := os.Getenv("KCLI_CERT_FILE")
	keyFile := os.Getenv("KCLI_KEY_FILE")
	caCertFile := os.Getenv("KCLI_CA_CERT_FILE")
	if certFile == "" || keyFile == "" || caCertFile == "" {
		return nil, nil
	}

	cfg := tls.Config{}

	// Load client cert
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return &cfg, err
	}
	cfg.Certificates = []tls.Certificate{cert}

	// Load CA cert
	caCert, err := ioutil.ReadFile(caCertFile)
	if err != nil {
		return &cfg, err
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
	cfg.RootCAs = caCertPool

	cfg.BuildNameToCertificate()
	return &cfg, nil
}

//GetTopics gets topics (duh)
func (c *Client) GetTopics() ([]string, error) {
	return c.sarama.Topics()
}

//GetTopic gets a single kafka topic
func (c *Client) GetTopic(topic string) ([]Partition, error) {
	partitions, err := c.sarama.Partitions(topic)
	if err != nil {
		return nil, err
	}

	out := make([]Partition, len(partitions))

	for i, p := range partitions {
		n, err := c.sarama.GetOffset(topic, p, sarama.OffsetNewest)
		if err != nil {
			return nil, err
		}

		o, err := c.sarama.GetOffset(topic, p, sarama.OffsetOldest)
		if err != nil {
			return nil, err
		}
		out[i] = Partition{
			Topic:     topic,
			Partition: p,
			Start:     o,
			End:       n,
			Offset:    o,
		}
	}
	return out, nil
}

//GetPartition fetches a kafka partition.  It includes a callback func
//so that the caller can tell it when to stop consuming.
func (c *Client) GetPartition(part Partition, end int, f func([]byte) bool) ([]Message, error) {
	consumer, err := sarama.NewConsumer(c.addrs, nil)
	if err != nil {
		return nil, err
	}

	pc, err := consumer.ConsumePartition(part.Topic, part.Partition, part.Offset)
	if err != nil {
		return nil, err
	}

	defer func() {
		consumer.Close()
		pc.Close()
	}()

	var out []Message

	var msg *sarama.ConsumerMessage
	var i int
	var last bool
	for i < end && !last {
		select {
		case msg = <-pc.Messages():
			if f(msg.Value) {
				val, err := c.decoder.Decode(part.Topic, msg.Value)
				if err != nil {
					return nil, err
				}

				out = append(out, Message{
					Value:  val,
					Offset: msg.Offset,
					Partition: Partition{
						Offset:    msg.Offset,
						Partition: msg.Partition,
						Topic:     msg.Topic,
						End:       part.End,
					},
				})
				i++
			}
			last = msg.Offset == part.End-1
		case <-time.After(time.Second):
			break
		}
	}

	return out, nil
}

//Close disconnects from kafka
func (c *Client) Close() {
	c.sarama.Close()
}

type searchResult struct {
	partition Partition
	offset    int64
	error     error
}

//SearchTopic allows the caller to search across all partitions in a topic.
func (c *Client) SearchTopic(partitions []Partition, s string, firstResult bool, cb func(int64, int64)) ([]Partition, error) {
	ch := make(chan searchResult)
	n := int64(len(partitions))
	var stop bool
	f := func() bool {
		return stop
	}

	for _, p := range partitions {
		go func(partition Partition, ch chan searchResult) {
			i, err := c.search(partition, s, f, func(_, _ int64) {})
			ch <- searchResult{partition: partition, offset: i, error: err}
		}(p, ch)
	}

	var results []Partition

	nResults := len(partitions)
	if firstResult {
		nResults = 1
	}

	var i int64
	for i = 0; i < int64(len(partitions)); i++ {
		r := <-ch
		cb(i, n)
		if r.error != nil {
			return nil, r.error
		}
		if r.offset > -1 {
			r.partition.Offset = r.offset
			results = append(results, r.partition)
		}
		if len(results) == nResults {
			stop = true
			break
		}

	}

	sort.Slice(results, func(i, j int) bool {
		return results[j].Partition >= results[i].Partition
	})

	return results, nil
}

func (c *Client) search(info Partition, s string, stop func() bool, cb func(int64, int64)) (int64, error) {
	n := int64(-1)
	var i int64
	err := c.consume(info, info.End, func(d []byte) bool {
		cb(i, info.End)
		if strings.Contains(string(d), s) {
			n = i + info.Offset
			return true
		}
		i++
		return stop()
	})

	return n, err
}

//Search is for searching for a string in a single kafka partition.
//It stops at the first match.
func (c *Client) Search(info Partition, s string, cb func(i, j int64)) (int64, error) {
	return c.search(info, s, func() bool { return false }, cb)
}

//Fetch gets all messages in a partition up intil the 'end' offset.
func (c *Client) Fetch(info Partition, end int64, cb func(string)) error {
	return c.consume(info, end, func(msg []byte) bool {
		val, err := c.decoder.Decode(info.Topic, msg)
		if err != nil {
			return true
		}
		cb(string(val))
		return false
	})
}

func (c *Client) consume(info Partition, end int64, cb func([]byte) bool) error {
	consumer, err := sarama.NewConsumer(c.addrs, nil)
	if err != nil {
		return err
	}

	pc, err := consumer.ConsumePartition(info.Topic, info.Partition, info.Offset)
	if err != nil {
		return err
	}

	defer func() {
		consumer.Close()
		pc.Close()
	}()

	l := info.End - info.Offset
	if l < end {
		end = l
	}

	for i := int64(0); i < end; i++ {
		select {
		case msg := <-pc.Messages():
			if stop := cb(msg.Value); stop {
				return nil
			}
		case <-time.After(time.Second):
			break
		}
	}

	return nil
}
<commit_msg>one more golint fix<commit_after>package kafka

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"io/ioutil"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/Shopify/sarama"
)

// Decoder is the interface that is required of plugins
type Decoder interface {
	Decode(topic string, data []byte) ([]byte, error)
}

// plainDecoder is the default Decoder
type plainDecoder struct{}

func (p plainDecoder) Decode(topic string, data []byte) ([]byte, error) { return data, nil }

//Client fetches from kafka
type Client struct {
	addrs   []string
	sarama  sarama.Client
	decoder Decoder
}

//Partition holds information about a kafka partition
type Partition struct {
	Topic     string `json:"topic"`
	Partition int32  `json:"partition"`
	Start     int64  `json:"start"`
	End       int64  `json:"end"`
	Offset    int64  `json:"offset"`
	Filter    string `json:"filter"`
}

//String turns a partition into a string
func (p *Partition) String() string {
	d, _ := json.Marshal(p)
	return string(d)
}

//Message holds information about a single kafka message
type Message struct {
	Partition Partition `json:"partition"`
	Value     []byte    `json:"msg"`
	Offset    int64     `json:"offset"`
}

// Opt is a func that sets an  attribute on Client
type Opt func(*Client)

//New returns a kafka Client.
func New(addrs []string, opts ...Opt) (*Client, error) {
	cfg, err := getConfig()
	if err != nil {
		return nil, err
	}

	s, err := sarama.NewClient(addrs, cfg)
	if err != nil {
		return nil, err
	}

	cli := &Client{
		sarama:  s,
		addrs:   addrs,
		decoder: &plainDecoder{},
	}

	for _, opt := range opts {
		opt(cli)
	}

	return cli, nil
}

// WithDecoder is used to insert a Decoder plugin
func WithDecoder(d Decoder) func(*Client) {
	return func(c *Client) {
		c.decoder = d
	}
}

func getConfig() (*sarama.Config, error) {
	cfg := sarama.NewConfig()
	tlsCfg, err := getTLSConfig()
	if err != nil || tlsCfg == nil {
		return cfg, err
	}

	cfg.Net.TLS.Enable = true
	cfg.Net.TLS.Config = tlsCfg
	return cfg, nil
}

func getTLSConfig() (*tls.Config, error) {
	certFile := os.Getenv("KCLI_CERT_FILE")
	keyFile := os.Getenv("KCLI_KEY_FILE")
	caCertFile := os.Getenv("KCLI_CA_CERT_FILE")
	if certFile == "" || keyFile == "" || caCertFile == "" {
		return nil, nil
	}

	cfg := tls.Config{}

	// Load client cert
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return &cfg, err
	}
	cfg.Certificates = []tls.Certificate{cert}

	// Load CA cert
	caCert, err := ioutil.ReadFile(caCertFile)
	if err != nil {
		return &cfg, err
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)
	cfg.RootCAs = caCertPool

	cfg.BuildNameToCertificate()
	return &cfg, nil
}

//GetTopics gets topics (duh)
func (c *Client) GetTopics() ([]string, error) {
	return c.sarama.Topics()
}

//GetTopic gets a single kafka topic
func (c *Client) GetTopic(topic string) ([]Partition, error) {
	partitions, err := c.sarama.Partitions(topic)
	if err != nil {
		return nil, err
	}

	out := make([]Partition, len(partitions))

	for i, p := range partitions {
		n, err := c.sarama.GetOffset(topic, p, sarama.OffsetNewest)
		if err != nil {
			return nil, err
		}

		o, err := c.sarama.GetOffset(topic, p, sarama.OffsetOldest)
		if err != nil {
			return nil, err
		}
		out[i] = Partition{
			Topic:     topic,
			Partition: p,
			Start:     o,
			End:       n,
			Offset:    o,
		}
	}
	return out, nil
}

//GetPartition fetches a kafka partition.  It includes a callback func
//so that the caller can tell it when to stop consuming.
func (c *Client) GetPartition(part Partition, end int, f func([]byte) bool) ([]Message, error) {
	consumer, err := sarama.NewConsumer(c.addrs, nil)
	if err != nil {
		return nil, err
	}

	pc, err := consumer.ConsumePartition(part.Topic, part.Partition, part.Offset)
	if err != nil {
		return nil, err
	}

	defer func() {
		consumer.Close()
		pc.Close()
	}()

	var out []Message

	var msg *sarama.ConsumerMessage
	var i int
	var last bool
	for i < end && !last {
		select {
		case msg = <-pc.Messages():
			if f(msg.Value) {
				val, err := c.decoder.Decode(part.Topic, msg.Value)
				if err != nil {
					return nil, err
				}

				out = append(out, Message{
					Value:  val,
					Offset: msg.Offset,
					Partition: Partition{
						Offset:    msg.Offset,
						Partition: msg.Partition,
						Topic:     msg.Topic,
						End:       part.End,
					},
				})
				i++
			}
			last = msg.Offset == part.End-1
		case <-time.After(time.Second):
			break
		}
	}

	return out, nil
}

//Close disconnects from kafka
func (c *Client) Close() {
	c.sarama.Close()
}

type searchResult struct {
	partition Partition
	offset    int64
	error     error
}

//SearchTopic allows the caller to search across all partitions in a topic.
func (c *Client) SearchTopic(partitions []Partition, s string, firstResult bool, cb func(int64, int64)) ([]Partition, error) {
	ch := make(chan searchResult)
	n := int64(len(partitions))
	var stop bool
	f := func() bool {
		return stop
	}

	for _, p := range partitions {
		go func(partition Partition, ch chan searchResult) {
			i, err := c.search(partition, s, f, func(_, _ int64) {})
			ch <- searchResult{partition: partition, offset: i, error: err}
		}(p, ch)
	}

	var results []Partition

	nResults := len(partitions)
	if firstResult {
		nResults = 1
	}

	var i int64
	for i = 0; i < int64(len(partitions)); i++ {
		r := <-ch
		cb(i, n)
		if r.error != nil {
			return nil, r.error
		}
		if r.offset > -1 {
			r.partition.Offset = r.offset
			results = append(results, r.partition)
		}
		if len(results) == nResults {
			stop = true
			break
		}

	}

	sort.Slice(results, func(i, j int) bool {
		return results[j].Partition >= results[i].Partition
	})

	return results, nil
}

func (c *Client) search(info Partition, s string, stop func() bool, cb func(int64, int64)) (int64, error) {
	n := int64(-1)
	var i int64
	err := c.consume(info, info.End, func(d []byte) bool {
		cb(i, info.End)
		if strings.Contains(string(d), s) {
			n = i + info.Offset
			return true
		}
		i++
		return stop()
	})

	return n, err
}

//Search is for searching for a string in a single kafka partition.
//It stops at the first match.
func (c *Client) Search(info Partition, s string, cb func(i, j int64)) (int64, error) {
	return c.search(info, s, func() bool { return false }, cb)
}

//Fetch gets all messages in a partition up intil the 'end' offset.
func (c *Client) Fetch(info Partition, end int64, cb func(string)) error {
	return c.consume(info, end, func(msg []byte) bool {
		val, err := c.decoder.Decode(info.Topic, msg)
		if err != nil {
			return true
		}
		cb(string(val))
		return false
	})
}

func (c *Client) consume(info Partition, end int64, cb func([]byte) bool) error {
	consumer, err := sarama.NewConsumer(c.addrs, nil)
	if err != nil {
		return err
	}

	pc, err := consumer.ConsumePartition(info.Topic, info.Partition, info.Offset)
	if err != nil {
		return err
	}

	defer func() {
		consumer.Close()
		pc.Close()
	}()

	l := info.End - info.Offset
	if l < end {
		end = l
	}

	for i := int64(0); i < end; i++ {
		select {
		case msg := <-pc.Messages():
			if stop := cb(msg.Value); stop {
				return nil
			}
		case <-time.After(time.Second):
			break
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package piece

import (
	"bytes"
	"crypto/sha1" // nolint: gosec
	"hash"

	"github.com/cenkalti/rain/internal/filesection"
	"github.com/cenkalti/rain/internal/metainfo"
	"github.com/cenkalti/rain/storage"
)

const BlockSize = 16 * 1024

// Piece of a torrent.
type Piece struct {
	Index  uint32 // index in torrent
	Length uint32 // always equal to BlockSize except last piece.
	Blocks []Block
	Data   filesection.Sections // the place to write downloaded bytes
	Hash   []byte
}

func NewPieces(info *metainfo.Info, osFiles []storage.File) []Piece {
	// TODO init all to zero, call nextFile to init
	var (
		fileIndex  int   // index of the current file in torrent
		fileLength int64 = info.GetFiles()[fileIndex].Length
		fileEnd          = fileLength // absolute position of end of the file among all pieces
		fileOffset int64              // offset in file: [0, fileLength)
	)

	nextFile := func() {
		fileIndex++
		fileLength = info.GetFiles()[fileIndex].Length
		fileEnd += fileLength
		fileOffset = 0
	}
	fileLeft := func() int64 { return fileLength - fileOffset }

	// Construct pieces
	var total int64
	pieces := make([]Piece, info.NumPieces)
	for i := uint32(0); i < info.NumPieces; i++ {
		p := Piece{
			Index: i,
			Hash:  info.PieceHashes[i],
		}

		// Construct p.Files
		var pieceOffset uint32
		pieceLeft := func() uint32 { return info.PieceLength - pieceOffset }
		for left := pieceLeft(); left > 0; {
			n := uint32(minInt64(int64(left), fileLeft())) // number of bytes to write

			file := filesection.Section{
				File:   osFiles[fileIndex],
				Offset: fileOffset,
				Length: int64(n),
			}
			p.Data = append(p.Data, file)

			left -= n
			p.Length += n
			pieceOffset += n
			fileOffset += int64(n)
			total += int64(n)

			if total == info.TotalLength {
				break
			}
			if fileLeft() == 0 {
				nextFile()
			}
		}

		p.Blocks = p.newBlocks()
		pieces[i] = p
	}
	return pieces
}

func (p *Piece) newBlocks() []Block {
	div, mod := divMod32(p.Length, BlockSize)
	numBlocks := div
	if mod != 0 {
		numBlocks++
	}
	blocks := make([]Block, numBlocks)
	for j := uint32(0); j < div; j++ {
		blocks[j] = Block{
			Index:  j,
			Begin:  j * BlockSize,
			Length: BlockSize,
		}
	}
	if mod != 0 {
		blocks[numBlocks-1] = Block{
			Index:  numBlocks - 1,
			Begin:  (numBlocks - 1) * BlockSize,
			Length: mod,
		}
	}
	return blocks
}

func (p *Piece) GetBlock(begin uint32) *Block {
	idx, mod := divMod32(begin, BlockSize)
	if mod != 0 {
		return nil
	}
	if idx >= uint32(len(p.Blocks)) {
		return nil
	}
	return &p.Blocks[idx]
}

func (p *Piece) Verify(buf []byte) bool {
	return p.VerifyHash(buf, sha1.New()) // nolint: gosec
}

func (p *Piece) VerifyHash(buf []byte, h hash.Hash) bool {
	if uint32(len(buf)) != p.Length {
		return false
	}
	h.Write(buf)
	sum := h.Sum(nil)
	return bytes.Equal(sum, p.Hash)
}

func minInt64(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func divMod32(a, b uint32) (uint32, uint32) { return a / b, a % b }
<commit_msg>refactor<commit_after>package piece

import (
	"bytes"
	"crypto/sha1" // nolint: gosec
	"hash"

	"github.com/cenkalti/rain/internal/filesection"
	"github.com/cenkalti/rain/internal/metainfo"
	"github.com/cenkalti/rain/storage"
)

const BlockSize = 16 * 1024

// Piece of a torrent.
type Piece struct {
	Index  uint32 // index in torrent
	Length uint32 // always equal to BlockSize except last piece.
	Blocks []Block
	Data   filesection.Sections // the place to write downloaded bytes
	Hash   []byte
}

func NewPieces(info *metainfo.Info, osFiles []storage.File) []Piece {
	var (
		fileIndex  int   // index of the current file in torrent
		fileLength int64 // length of the file in fileIndex
		fileEnd    int64 // absolute position of end of the file among all pieces
		fileOffset int64 // offset in file: [0, fileLength)
	)

	nextFile := func() {
		fileIndex++
		fileLength = info.GetFiles()[fileIndex].Length
		fileEnd += fileLength
		fileOffset = 0
	}

	// Init first file
	fileIndex = -1
	nextFile()

	fileLeft := func() int64 { return fileLength - fileOffset }

	// Construct pieces
	var total int64
	pieces := make([]Piece, info.NumPieces)
	for i := uint32(0); i < info.NumPieces; i++ {
		p := Piece{
			Index: i,
			Hash:  info.PieceHashes[i],
		}

		// Construct p.Files
		var pieceOffset uint32
		pieceLeft := func() uint32 { return info.PieceLength - pieceOffset }
		for left := pieceLeft(); left > 0; {
			n := uint32(minInt64(int64(left), fileLeft())) // number of bytes to write

			file := filesection.Section{
				File:   osFiles[fileIndex],
				Offset: fileOffset,
				Length: int64(n),
			}
			p.Data = append(p.Data, file)

			left -= n
			p.Length += n
			pieceOffset += n
			fileOffset += int64(n)
			total += int64(n)

			if total == info.TotalLength {
				break
			}
			if fileLeft() == 0 {
				nextFile()
			}
		}

		p.Blocks = p.newBlocks()
		pieces[i] = p
	}
	return pieces
}

func (p *Piece) newBlocks() []Block {
	div, mod := divMod32(p.Length, BlockSize)
	numBlocks := div
	if mod != 0 {
		numBlocks++
	}
	blocks := make([]Block, numBlocks)
	for j := uint32(0); j < div; j++ {
		blocks[j] = Block{
			Index:  j,
			Begin:  j * BlockSize,
			Length: BlockSize,
		}
	}
	if mod != 0 {
		blocks[numBlocks-1] = Block{
			Index:  numBlocks - 1,
			Begin:  (numBlocks - 1) * BlockSize,
			Length: mod,
		}
	}
	return blocks
}

func (p *Piece) GetBlock(begin uint32) *Block {
	idx, mod := divMod32(begin, BlockSize)
	if mod != 0 {
		return nil
	}
	if idx >= uint32(len(p.Blocks)) {
		return nil
	}
	return &p.Blocks[idx]
}

func (p *Piece) Verify(buf []byte) bool {
	return p.VerifyHash(buf, sha1.New()) // nolint: gosec
}

func (p *Piece) VerifyHash(buf []byte, h hash.Hash) bool {
	if uint32(len(buf)) != p.Length {
		return false
	}
	h.Write(buf)
	sum := h.Sum(nil)
	return bytes.Equal(sum, p.Hash)
}

func minInt64(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func divMod32(a, b uint32) (uint32, uint32) { return a / b, a % b }
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors All rights reserved.

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

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

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

package store

import (
	"fmt"
	"regexp"
	"sort"
	"strings"

	"k8s.io/apimachinery/pkg/util/validation"

	v1 "k8s.io/api/core/v1"

	"k8s.io/kube-state-metrics/pkg/metric"
)

var (
	invalidLabelCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
	conditionStatuses  = []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionUnknown}
)

func boolFloat64(b bool) float64 {
	if b {
		return 1
	}
	return 0
}

// addConditionMetrics generates one metric for each possible condition
// status. For this function to work properly, the last label in the metric
// description must be the condition.
func addConditionMetrics(cs v1.ConditionStatus) []*metric.Metric {
	ms := make([]*metric.Metric, len(conditionStatuses))

	for i, status := range conditionStatuses {
		ms[i] = &metric.Metric{
			LabelValues: []string{strings.ToLower(string(status))},
			Value:       boolFloat64(cs == status),
		}
	}

	return ms
}

func kubeLabelsToPrometheusLabels(labels map[string]string) ([]string, []string) {
	return mapToPrometheusLabels(labels, "label")
}

func mapToPrometheusLabels(labels map[string]string, prefix string) ([]string, []string) {
	labelKeys := make([]string, 0, len(labels))
	for k := range labels {
		labelKeys = append(labelKeys, k)
	}
	sort.Strings(labelKeys)

	labelValues := make([]string, 0, len(labels))
	for i, k := range labelKeys {
		labelKeys[i] = prefix + "_" + sanitizeLabelName(k)
		labelValues = append(labelValues, labels[k])
	}
	return labelKeys, labelValues
}

func sanitizeLabelName(s string) string {
	return invalidLabelCharRE.ReplaceAllString(s, "_")
}

func isHugePageResourceName(name v1.ResourceName) bool {
	return strings.HasPrefix(string(name), v1.ResourceHugePagesPrefix)
}

func isAttachableVolumeResourceName(name v1.ResourceName) bool {
	return strings.HasPrefix(string(name), v1.ResourceAttachableVolumesPrefix)
}

func isExtendedResourceName(name v1.ResourceName) bool {
	if isNativeResource(name) || strings.HasPrefix(string(name), v1.DefaultResourceRequestsPrefix) {
		return false
	}
	// Ensure it satisfies the rules in IsQualifiedName() after converted into quota resource name
	nameForQuota := fmt.Sprintf("%s%s", v1.DefaultResourceRequestsPrefix, string(name))
	if errs := validation.IsQualifiedName(nameForQuota); len(errs) != 0 {
		return false
	}
	return true
}

func isNativeResource(name v1.ResourceName) bool {
	return !strings.Contains(string(name), "/") ||
		isPrefixedNativeResource(name)
}

func isPrefixedNativeResource(name v1.ResourceName) bool {
	return strings.Contains(string(name), v1.ResourceDefaultNamespacePrefix)
}
<commit_msg>internal/store/utils.go: Add helper func for resource version metrics<commit_after>/*
Copyright 2018 The Kubernetes Authors All rights reserved.

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

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

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

package store

import (
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"k8s.io/apimachinery/pkg/util/validation"

	v1 "k8s.io/api/core/v1"

	"k8s.io/kube-state-metrics/pkg/metric"
)

var (
	invalidLabelCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
	conditionStatuses  = []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionUnknown}
)

func resourceVersionMetric(rv string) []*metric.Metric {
	v, err := strconv.ParseFloat(rv, 64)
	if err != nil {
		return []*metric.Metric{}
	}

	return []*metric.Metric{
		{
			Value: v,
		},
	}

}

func boolFloat64(b bool) float64 {
	if b {
		return 1
	}
	return 0
}

// addConditionMetrics generates one metric for each possible condition
// status. For this function to work properly, the last label in the metric
// description must be the condition.
func addConditionMetrics(cs v1.ConditionStatus) []*metric.Metric {
	ms := make([]*metric.Metric, len(conditionStatuses))

	for i, status := range conditionStatuses {
		ms[i] = &metric.Metric{
			LabelValues: []string{strings.ToLower(string(status))},
			Value:       boolFloat64(cs == status),
		}
	}

	return ms
}

func kubeLabelsToPrometheusLabels(labels map[string]string) ([]string, []string) {
	return mapToPrometheusLabels(labels, "label")
}

func mapToPrometheusLabels(labels map[string]string, prefix string) ([]string, []string) {
	labelKeys := make([]string, 0, len(labels))
	for k := range labels {
		labelKeys = append(labelKeys, k)
	}
	sort.Strings(labelKeys)

	labelValues := make([]string, 0, len(labels))
	for i, k := range labelKeys {
		labelKeys[i] = prefix + "_" + sanitizeLabelName(k)
		labelValues = append(labelValues, labels[k])
	}
	return labelKeys, labelValues
}

func sanitizeLabelName(s string) string {
	return invalidLabelCharRE.ReplaceAllString(s, "_")
}

func isHugePageResourceName(name v1.ResourceName) bool {
	return strings.HasPrefix(string(name), v1.ResourceHugePagesPrefix)
}

func isAttachableVolumeResourceName(name v1.ResourceName) bool {
	return strings.HasPrefix(string(name), v1.ResourceAttachableVolumesPrefix)
}

func isExtendedResourceName(name v1.ResourceName) bool {
	if isNativeResource(name) || strings.HasPrefix(string(name), v1.DefaultResourceRequestsPrefix) {
		return false
	}
	// Ensure it satisfies the rules in IsQualifiedName() after converted into quota resource name
	nameForQuota := fmt.Sprintf("%s%s", v1.DefaultResourceRequestsPrefix, string(name))
	if errs := validation.IsQualifiedName(nameForQuota); len(errs) != 0 {
		return false
	}
	return true
}

func isNativeResource(name v1.ResourceName) bool {
	return !strings.Contains(string(name), "/") ||
		isPrefixedNativeResource(name)
}

func isPrefixedNativeResource(name v1.ResourceName) bool {
	return strings.Contains(string(name), v1.ResourceDefaultNamespacePrefix)
}
<|endoftext|>


<commit_before>// Package usage tracks micro usage
package usage

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/google/uuid"
	pb "github.com/micro/micro/v2/internal/usage/proto"
	"github.com/micro/micro/v2/internal/version"
)

var (
	// usage url
	u = "https://micro.mu/usage"
	// usage agent
	a = "micro/usage"
	// usage version
	v = version.V
	// 24 hour window
	w = 8.64e13
)

// New generates a new usage report to be filled in
func New(service string) *pb.Usage {
	id := fmt.Sprintf("micro.%s.%s.%s", service, version.V, uuid.New().String())
	srv := "micro." + service

	if len(service) == 0 {
		id = fmt.Sprintf("micro.%s.%s", version.V, uuid.New().String())
		srv = "micro"
	}

	sum := sha256.Sum256([]byte(id))

	return &pb.Usage{
		Service:   srv,
		Version:   v,
		Id:        fmt.Sprintf("%x", sum),
		Timestamp: uint64(time.Now().UnixNano()),
		Window:    uint64(w),
		Metrics: &pb.Metrics{
			Count: make(map[string]uint64),
		},
	}
}

// Report reports the current usage
func Report(ug *pb.Usage) error {
	if v := os.Getenv("MICRO_REPORT_USAGE"); v == "false" {
		return nil
	}

	// update timestamp/window
	now := uint64(time.Now().UnixNano())
	ug.Window = now - ug.Timestamp
	ug.Timestamp = now

	p, err := proto.Marshal(ug)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST", u, bytes.NewReader(p))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/protobuf")
	req.Header.Set("User-Agent", a)
	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer rsp.Body.Close()
	io.Copy(ioutil.Discard, rsp.Body)
	return nil
}
<commit_msg>report usage to go.micro<commit_after>// Package usage tracks micro usage
package usage

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/google/uuid"
	pb "github.com/micro/micro/v2/internal/usage/proto"
	"github.com/micro/micro/v2/internal/version"
)

var (
	// usage url
	u = "https://go.micro.mu/usage"
	// usage agent
	a = "micro/usage"
	// usage version
	v = version.V
	// 24 hour window
	w = 8.64e13
)

// New generates a new usage report to be filled in
func New(service string) *pb.Usage {
	id := fmt.Sprintf("micro.%s.%s.%s", service, version.V, uuid.New().String())
	srv := "micro." + service

	if len(service) == 0 {
		id = fmt.Sprintf("micro.%s.%s", version.V, uuid.New().String())
		srv = "micro"
	}

	sum := sha256.Sum256([]byte(id))

	return &pb.Usage{
		Service:   srv,
		Version:   v,
		Id:        fmt.Sprintf("%x", sum),
		Timestamp: uint64(time.Now().UnixNano()),
		Window:    uint64(w),
		Metrics: &pb.Metrics{
			Count: make(map[string]uint64),
		},
	}
}

// Report reports the current usage
func Report(ug *pb.Usage) error {
	if v := os.Getenv("MICRO_REPORT_USAGE"); v == "false" {
		return nil
	}

	// update timestamp/window
	now := uint64(time.Now().UnixNano())
	ug.Window = now - ug.Timestamp
	ug.Timestamp = now

	p, err := proto.Marshal(ug)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST", u, bytes.NewReader(p))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/protobuf")
	req.Header.Set("User-Agent", a)
	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer rsp.Body.Close()
	io.Copy(ioutil.Discard, rsp.Body)
	return nil
}
<|endoftext|>


<commit_before>package scanner

import (
	"encoding/json"
)

type Source struct {
	Name string `json:"name"`
	Url  string `json:"url"`
}

type ExternalScan struct {
	Coverage        *ExternalCoverage        `json:"coverage,omitempty"`
	Vulnerabilities *ExternalVulnerabilities `json:"vulnerabilities,omitempty"`
	Source          Source                   `json:"source"`
	Notes           string                   `json:"notes"`
	Raw             json.RawMessage          `json:"raw"`
}
<commit_msg>a pointer<commit_after>package scanner

import "encoding/json"

type Source struct {
	Name string `json:"name"`
	Url  string `json:"url"`
}

type ExternalScan struct {
	Coverage        *ExternalCoverage        `json:"coverage,omitempty"`
	Vulnerabilities *ExternalVulnerabilities `json:"vulnerabilities,omitempty"`
	Source          Source                   `json:"source"`
	Notes           string                   `json:"notes"`
	Raw             *json.RawMessage         `json:"raw,omitempty"`
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/JustinBeckwith/go-yelp/yelp"
	"github.com/guregu/null"
	"github.com/line/line-bot-sdk-go/linebot"
)

var o *yelp.AuthOptions

type UrlShortener struct {
	ShortUrl    string
	OriginalUrl string
}

func yelp_init() {
	rand.Seed(time.Now().UnixNano())

	// check environment variables
	o = &yelp.AuthOptions{
		ConsumerKey:       os.Getenv("CONSUMER_KEY"),
		ConsumerSecret:    os.Getenv("CONSUMER_SECRET"),
		AccessToken:       os.Getenv("ACCESS_TOKEN"),
		AccessTokenSecret: os.Getenv("ACCESS_TOKEN_SECRET"),
	}

	if o.ConsumerKey == "" || o.ConsumerSecret == "" || o.AccessToken == "" || o.AccessTokenSecret == "" {
		log.Fatal("Wrong environment setting about yelp-api-keys")
	}
}

func yelp_parse(bot *linebot.Client, token string, loc *linebot.LocationMessage, food string) {
	var err error

	// create a new yelp client with the auth keys
	client := yelp.New(o, nil)

	if loc == nil {
		// make a simple query for food and location
		results, err := client.DoSimpleSearch(food, "台北市通化街")
		if err != nil {
			log.Println(err)
			_, err = bot.ReplyMessage(token, linebot.NewTextMessage("查無資料！")).Do()
		} else {
			yelp_parse_result(bot, token, results)
		}
	} else {
		// Build an advanced set of search criteria that include
		// general options, and coordinate options.
		s := yelp.SearchOptions{
			GeneralOptions: &yelp.GeneralOptions{
				Term: food,
			},
			CoordinateOptions: &yelp.CoordinateOptions{
				Latitude:  null.FloatFrom(loc.Latitude),
				Longitude: null.FloatFrom(loc.Longitude),
			},
		}

		// Perform the search using the search options
		results, err := client.DoSearch(s)
		if err != nil {
			log.Println(err)
			_, err = bot.ReplyMessage(token, linebot.NewTextMessage("查無資料！")).Do()
		} else {
			yelp_parse_result(bot, token, results)
		}
	}
}

func yelp_parse_result(bot *linebot.Client, token string, results yelp.SearchResult) {
	var err error
//	var msgs []linebot.Message

	for j := 0; j < 3; j++ {
		i := 0
		if results.Total >= 20 {
			i = rand.Intn(20)
		} else if results.Total >= 10 {
			i = rand.Intn(10)
		} else if results.Total > j {
			i = j
		} else if results.Total <= j && results.Total != 0 {
			_, err = bot.ReplyMessage(token, linebot.NewTextMessage("已無更多資料！")).Do()
			break
		}
		urlOrig := UrlShortener{}
		urlOrig.short(results.Businesses[i].MobileURL)
		address := strings.Join(results.Businesses[i].Location.DisplayAddress, ",")
		var largeImageURL = strings.Replace(results.Businesses[i].ImageURL, "ms.jpg", "l.jpg", 1)

		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL), linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl), linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)) ).Do()
//		msgs = append(msgs, linebot.NewImageMessage(largeImageURL, largeImageURL))
//		msgs = append(msgs, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl))
//		msgs = append(msgs, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)))
//		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude))).Do()
	}

//	if len(msgs) > 0 {
//		_, err = bot.ReplyMessage(token, msgs).Do()
//	}
}

func getResponseData(urlOrig string) string {
	response, err := http.Get(urlOrig)
	if err != nil {
		log.Println(err)
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	return string(contents)
}

func isGdShortener(urlOrig string) (string, string) {
	escapedUrl := url.QueryEscape(urlOrig)
	isGdUrl := fmt.Sprintf("http://is.gd/create.php?url=%s&format=simple", escapedUrl)
	return getResponseData(isGdUrl), urlOrig
}

func (u *UrlShortener) short(urlOrig string) *UrlShortener {
	shortUrl, originalUrl := isGdShortener(urlOrig)
	u.ShortUrl = shortUrl
	u.OriginalUrl = originalUrl
	return u
}
<commit_msg>test location<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/JustinBeckwith/go-yelp/yelp"
	"github.com/guregu/null"
	"github.com/line/line-bot-sdk-go/linebot"
)

var o *yelp.AuthOptions

type UrlShortener struct {
	ShortUrl    string
	OriginalUrl string
}

func yelp_init() {
	rand.Seed(time.Now().UnixNano())

	// check environment variables
	o = &yelp.AuthOptions{
		ConsumerKey:       os.Getenv("CONSUMER_KEY"),
		ConsumerSecret:    os.Getenv("CONSUMER_SECRET"),
		AccessToken:       os.Getenv("ACCESS_TOKEN"),
		AccessTokenSecret: os.Getenv("ACCESS_TOKEN_SECRET"),
	}

	if o.ConsumerKey == "" || o.ConsumerSecret == "" || o.AccessToken == "" || o.AccessTokenSecret == "" {
		log.Fatal("Wrong environment setting about yelp-api-keys")
	}
}

func yelp_parse(bot *linebot.Client, token string, loc *linebot.LocationMessage, food string) {
	var err error

	// create a new yelp client with the auth keys
	client := yelp.New(o, nil)

	if loc == nil {
		// make a simple query for food and location
		results, err := client.DoSimpleSearch(food, "台北市通化街")
		if err == nil {
			yelp_parse_result(bot, token, results)
		}
	} else {
		// Build an advanced set of search criteria that include
		// general options, and coordinate options.
		s := yelp.SearchOptions{
			GeneralOptions: &yelp.GeneralOptions{
				Term: food,
			},
			CoordinateOptions: &yelp.CoordinateOptions{
				Latitude:  null.FloatFrom(loc.Latitude),
				Longitude: null.FloatFrom(loc.Longitude),
			},
		}

		// Perform the search using the search options
		results, err := client.DoSearch(s)
		if err == nil {
			yelp_parse_result(bot, token, results)
		}
	}
	if err != nil {
		log.Println(err)
		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("查無資料！")).Do()
	}
}

func yelp_parse_result(bot *linebot.Client, token string, results yelp.SearchResult) {
	var err error
//	var msgs []linebot.Message

	for j := 0; j < 3; j++ {
		i := 0
		if results.Total >= 20 {
			i = rand.Intn(20)
		} else if results.Total >= 10 {
			i = rand.Intn(10)
		} else if results.Total > j {
			i = j
		} else if results.Total <= j && results.Total != 0 {
			_, err = bot.ReplyMessage(token, linebot.NewTextMessage("已無更多資料！")).Do()
			break
		}
		urlOrig := UrlShortener{}
		urlOrig.short(results.Businesses[i].MobileURL)
		address := strings.Join(results.Businesses[i].Location.DisplayAddress, ",")
		var largeImageURL = strings.Replace(results.Businesses[i].ImageURL, "ms.jpg", "l.jpg", 1)

		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL), linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl), linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)) ).Do()
//		msgs = append(msgs, linebot.NewImageMessage(largeImageURL, largeImageURL))
//		msgs = append(msgs, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl))
//		msgs = append(msgs, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)))
//		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude))).Do()
	}

//	if len(msgs) > 0 {
//		_, err = bot.ReplyMessage(token, msgs).Do()
//	}
	if err != nil {
		log.Println(err)
	}
}

func getResponseData(urlOrig string) string {
	response, err := http.Get(urlOrig)
	if err != nil {
		log.Println(err)
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	return string(contents)
}

func isGdShortener(urlOrig string) (string, string) {
	escapedUrl := url.QueryEscape(urlOrig)
	isGdUrl := fmt.Sprintf("http://is.gd/create.php?url=%s&format=simple", escapedUrl)
	return getResponseData(isGdUrl), urlOrig
}

func (u *UrlShortener) short(urlOrig string) *UrlShortener {
	shortUrl, originalUrl := isGdShortener(urlOrig)
	u.ShortUrl = shortUrl
	u.OriginalUrl = originalUrl
	return u
}
<|endoftext|>