<commit_before>package robo

import (
	"net/http"
)

// Objects implementing the Handler interface are capable of serving
// HTTP requests. It is expected to follow the same core conventions as
// the "net/http" equivalent.
type Handler interface {
	ServeRoboHTTP(w ResponseWriter, r *Request)
}

// The HandlerFunc type serves as an adaptor to turn plain functions into
// an implementation of the Handler interface.
type HandlerFunc func(w ResponseWriter, r *Request)

func (h HandlerFunc) ServeRoboHTTP(w ResponseWriter, r *Request) {
	h(w, r)
}

// The httpHandler type adds a ServeRoboHTTP method to implementations of
// the http.Handler interface.
type httpHandler struct {
	h http.Handler
}

func (h httpHandler) ServeRoboHTTP(w ResponseWriter, r *Request) {
	h.h.ServeHTTP(w, r.Request)
}

// The ResponseWriter type mirrors http.ResponseWriter.
type ResponseWriter interface {
	http.ResponseWriter
}

// The Request type extends an http.Request instance with additional
// functionality.
type Request struct {
	*http.Request

	// named URL parameters for this request and route
	params map[string]string

	// reference to the queue
	queue *queue
}

// Next yields execution to the next matching handler, if there is one,
// blocking until said handler has returned.
func (r *Request) Next(w ResponseWriter) {
	r.queue.serveNext(w, r.Request)
}

// Param returns the value of a named URL parameter.
func (r *Request) Param(name string) string {
	if r.params != nil {
		return r.params[name]
	}
	return ""
}

// Mux is a HTTP router. It multiplexes incoming requests to different
// handlers based on user-provided rules on methods and paths.
//
// The zero value for a Mux is a Mux without any registered handlers,
// ready to use.
type Mux struct {
	routes []route
}

// NewMux returns a new Mux instance.
func NewMux() *Mux {
	return new(Mux)
}

// Any registers a new set of handlers listening to all requests for
// the specified URL pattern.
func (m *Mux) Any(pattern string, handlers ...interface{}) {
	m.add("", pattern, handlers)
}

// Get registers a new set of handlers listening to GET requests for
// the specified URL pattern.
func (m *Mux) Get(pattern string, handlers ...interface{}) {
	m.add("GET", pattern, handlers)
}

// Head registers a new set of handlers listening to HEAD requests for
// the specified URL pattern.
func (m *Mux) Head(pattern string, handlers ...interface{}) {
	m.add("HEAD", pattern, handlers)
}

// Post registers a new set of handlers listening to POST requests for
// the specified URL pattern.
func (m *Mux) Post(pattern string, handlers ...interface{}) {
	m.add("POST", pattern, handlers)
}

// Put registers a new set of handlers listening to PUT requests for
// the specified URL pattern.
func (m *Mux) Put(pattern string, handlers ...interface{}) {
	m.add("PUT", pattern, handlers)
}

// Patch registers a new set of handlers listening to PATCH requests for
// the specified URL pattern.
func (m *Mux) Patch(pattern string, handlers ...interface{}) {
	m.add("PATCH", pattern, handlers)
}

// Delete registers a new set of handlers listening to DELETE requests for
// the specified URL pattern.
func (m *Mux) Delete(pattern string, handlers ...interface{}) {
	m.add("DELETE", pattern, handlers)
}

// Options registers a new set of handlers listening to OPTIONS requests for
// the specified URL pattern.
func (m *Mux) Options(pattern string, handlers ...interface{}) {
	m.add("OPTIONS", pattern, handlers)
}

// add registers a set of handlers for the given HTTP method ("" matching
// any method) and URL pattern.
func (m *Mux) add(method, pattern string, handlers ...interface{}) {
	if len(handlers) == 0 {
		panic("no handlers provided")
	}

	// validate the provided set of handlers
	clean := make([]Handler, 0, len(handlers))

	for _, h := range handlers {
		switch h := h.(type) {
		case Handler:
			clean = append(clean, h)
		case func(w ResponseWriter, r *Request):
			clean = append(clean, HandlerFunc(h))
		case http.Handler:
			clean = append(clean, httpHandler{h})
		case func(w http.ResponseWriter, r *http.Request):
			clean = append(clean, httpHandler{http.HandlerFunc(h)})
		default:
			panic("not a valid handler")
		}
	}

	m.routes = append(m.routes, newRoute(method, pattern, clean))
}

// newRoute initializes a new route.
func newRoute(method, rawPattern string, handlers []Handler) route {
	pattern, err := compilePattern(rawPattern)
	if err != nil {
		panic(err)
	}

	return route{method, pattern, handlers}
}

// ServeRoboHTTP dispatches the request to matching routes registered with
// the Mux instance.
func (m *Mux) ServeRoboHTTP(w ResponseWriter, r *Request) {
	q := queue{nil, nil, m.routes}
	q.serveNext(w, r.Request)
}

// ServeHTTP dispatches the request to matching routes registered with
// the Mux instance.
func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	m.ServeRoboHTTP(w, &Request{Request: r})
}

// The route type describes a registered route.
type route struct {
	method   string
	pattern  pattern
	handlers []Handler
}

// check tests whether the route matches a provided method and path. The
// parameter map will always be non-nil when the first is true.
func (r *route) check(method, path string) (bool, map[string]string) {
	if r.method != method && r.method != "" {
		return false, nil
	}

	ok, list := r.pattern.match(path, nil)
	if !ok {
		return false, nil
	}

	// only build the parameter map if we have to
	if len(list) > 0 {
		params := make(map[string]string)
		for i := 0; i < len(list); i += 2 {
			params[list[i]] = list[i+1]
		}
		return true, params
	}

	return true, nil
}

// The queue type holds the routing state of an incoming request.
type queue struct {
	// remaining handlers, and parameter map, for the current route
	handlers []Handler
	params   map[string]string

	// remaining routes to be tested
	routes []route
}

// ServeNext attempts to serve an HTTP request using the next matching
// route/handler in the queue.
func (q *queue) serveNext(w ResponseWriter, hr *http.Request) {
	// does the current route still have handlers left?
	if len(q.handlers) > 0 {
		h := q.handlers[0]
		q.handlers = q.handlers[1:]

		h.ServeRoboHTTP(w, &Request{hr, q.params, q})
		return
	}

	// look for the next matching route
	for len(q.routes) > 0 {
		r := q.routes[0]
		q.routes = q.routes[1:]

		// does this route match the request at hand?
		ok, params := r.check(hr.Method, hr.URL.Path)
		if !ok {
			continue
		}

		q.handlers = r.handlers[1:]
		q.params = params

		// invoke the route's first handler
		r.handlers[0].ServeRoboHTTP(w, &Request{hr, q.params, q})
		return
	}

	// when we run out of routes, send a 404 message
	http.Error(w, "Not found.\n", 404)
}
<commit_msg>Fix Mux handler registration<commit_after>package robo

import (
	"net/http"
)

// Objects implementing the Handler interface are capable of serving
// HTTP requests. It is expected to follow the same core conventions as
// the "net/http" equivalent.
type Handler interface {
	ServeRoboHTTP(w ResponseWriter, r *Request)
}

// The HandlerFunc type serves as an adaptor to turn plain functions into
// an implementation of the Handler interface.
type HandlerFunc func(w ResponseWriter, r *Request)

func (h HandlerFunc) ServeRoboHTTP(w ResponseWriter, r *Request) {
	h(w, r)
}

// The httpHandler type adds a ServeRoboHTTP method to implementations of
// the http.Handler interface.
type httpHandler struct {
	h http.Handler
}

func (h httpHandler) ServeRoboHTTP(w ResponseWriter, r *Request) {
	h.h.ServeHTTP(w, r.Request)
}

// The ResponseWriter type mirrors http.ResponseWriter.
type ResponseWriter interface {
	http.ResponseWriter
}

// The Request type extends an http.Request instance with additional
// functionality.
type Request struct {
	*http.Request

	// named URL parameters for this request and route
	params map[string]string

	// reference to the queue
	queue *queue
}

// Next yields execution to the next matching handler, if there is one,
// blocking until said handler has returned.
func (r *Request) Next(w ResponseWriter) {
	r.queue.serveNext(w, r.Request)
}

// Param returns the value of a named URL parameter.
func (r *Request) Param(name string) string {
	if r.params != nil {
		return r.params[name]
	}
	return ""
}

// Mux is a HTTP router. It multiplexes incoming requests to different
// handlers based on user-provided rules on methods and paths.
//
// The zero value for a Mux is a Mux without any registered handlers,
// ready to use.
type Mux struct {
	routes []route
}

// NewMux returns a new Mux instance.
func NewMux() *Mux {
	return new(Mux)
}

// Any registers a new set of handlers listening to all requests for
// the specified URL pattern.
func (m *Mux) Any(pattern string, handlers ...interface{}) {
	m.add("", pattern, handlers...)
}

// Get registers a new set of handlers listening to GET requests for
// the specified URL pattern.
func (m *Mux) Get(pattern string, handlers ...interface{}) {
	m.add("GET", pattern, handlers...)
}

// Head registers a new set of handlers listening to HEAD requests for
// the specified URL pattern.
func (m *Mux) Head(pattern string, handlers ...interface{}) {
	m.add("HEAD", pattern, handlers...)
}

// Post registers a new set of handlers listening to POST requests for
// the specified URL pattern.
func (m *Mux) Post(pattern string, handlers ...interface{}) {
	m.add("POST", pattern, handlers...)
}

// Put registers a new set of handlers listening to PUT requests for
// the specified URL pattern.
func (m *Mux) Put(pattern string, handlers ...interface{}) {
	m.add("PUT", pattern, handlers...)
}

// Patch registers a new set of handlers listening to PATCH requests for
// the specified URL pattern.
func (m *Mux) Patch(pattern string, handlers ...interface{}) {
	m.add("PATCH", pattern, handlers...)
}

// Delete registers a new set of handlers listening to DELETE requests for
// the specified URL pattern.
func (m *Mux) Delete(pattern string, handlers ...interface{}) {
	m.add("DELETE", pattern, handlers...)
}

// Options registers a new set of handlers listening to OPTIONS requests for
// the specified URL pattern.
func (m *Mux) Options(pattern string, handlers ...interface{}) {
	m.add("OPTIONS", pattern, handlers...)
}

// add registers a set of handlers for the given HTTP method ("" matching
// any method) and URL pattern.
func (m *Mux) add(method, pattern string, handlers ...interface{}) {
	if len(handlers) == 0 {
		panic("no handlers provided")
	}

	// validate the provided set of handlers
	clean := make([]Handler, 0, len(handlers))

	for _, h := range handlers {
		switch h := h.(type) {
		case Handler:
			clean = append(clean, h)
		case func(w ResponseWriter, r *Request):
			clean = append(clean, HandlerFunc(h))
		case http.Handler:
			clean = append(clean, httpHandler{h})
		case func(w http.ResponseWriter, r *http.Request):
			clean = append(clean, httpHandler{http.HandlerFunc(h)})
		default:
			panic("not a valid handler")
		}
	}

	m.routes = append(m.routes, newRoute(method, pattern, clean))
}

// newRoute initializes a new route.
func newRoute(method, rawPattern string, handlers []Handler) route {
	pattern, err := compilePattern(rawPattern)
	if err != nil {
		panic(err)
	}

	return route{method, pattern, handlers}
}

// ServeRoboHTTP dispatches the request to matching routes registered with
// the Mux instance.
func (m *Mux) ServeRoboHTTP(w ResponseWriter, r *Request) {
	q := queue{nil, nil, m.routes}
	q.serveNext(w, r.Request)
}

// ServeHTTP dispatches the request to matching routes registered with
// the Mux instance.
func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	m.ServeRoboHTTP(w, &Request{Request: r})
}

// The route type describes a registered route.
type route struct {
	method   string
	pattern  pattern
	handlers []Handler
}

// check tests whether the route matches a provided method and path. The
// parameter map will always be non-nil when the first is true.
func (r *route) check(method, path string) (bool, map[string]string) {
	if r.method != method && r.method != "" {
		return false, nil
	}

	ok, list := r.pattern.match(path, nil)
	if !ok {
		return false, nil
	}

	// only build the parameter map if we have to
	if len(list) > 0 {
		params := make(map[string]string)
		for i := 0; i < len(list); i += 2 {
			params[list[i]] = list[i+1]
		}
		return true, params
	}

	return true, nil
}

// The queue type holds the routing state of an incoming request.
type queue struct {
	// remaining handlers, and parameter map, for the current route
	handlers []Handler
	params   map[string]string

	// remaining routes to be tested
	routes []route
}

// ServeNext attempts to serve an HTTP request using the next matching
// route/handler in the queue.
func (q *queue) serveNext(w ResponseWriter, hr *http.Request) {
	// does the current route still have handlers left?
	if len(q.handlers) > 0 {
		h := q.handlers[0]
		q.handlers = q.handlers[1:]

		h.ServeRoboHTTP(w, &Request{hr, q.params, q})
		return
	}

	// look for the next matching route
	for len(q.routes) > 0 {
		r := q.routes[0]
		q.routes = q.routes[1:]

		// does this route match the request at hand?
		ok, params := r.check(hr.Method, hr.URL.Path)
		if !ok {
			continue
		}

		q.handlers = r.handlers[1:]
		q.params = params

		// invoke the route's first handler
		r.handlers[0].ServeRoboHTTP(w, &Request{hr, q.params, q})
		return
	}

	// when we run out of routes, send a 404 message
	http.Error(w, "Not found.\n", 404)
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"
	"net/http"

	"bitbucket.org/mundipagg/boletoapi/config"
	"github.com/mundipagg/goseq"
)

var logger *goseq.Logger

// Operation a operacao usada na API
var Operation string

// Recipient o nome do banco
var Recipient string

// Log struct com os elemtos do log
type Log struct {
	Operation   string
	Recipient   string
	NossoNumero uint
	logger      *goseq.Logger
}

//Install instala o "servico" de log do SEQ
func Install() error {
	_logger, err := goseq.GetLogger(config.Get().SEQUrl, config.Get().SEQAPIKey, 150)
	if err != nil {
		return err
	}
	_logger.SetDefaultProperties(map[string]interface{}{
		"Application": config.Get().ApplicationName,
		"Environment": config.Get().Environment,
		"Domain":      config.Get().SEQDomain,
	})
	logger = _logger
	return nil
}

func formatter(message string) string {
	return "[{Application}: {Operation}] - {MessageType} " + message
}

//CreateLog cria uma nova instancia do Log
func CreateLog() *Log {
	return &Log{
		logger: logger,
	}
}

// Request loga o request para algum banco
func (l Log) Request(content interface{}, url string, headers http.Header) {
	go (func() {
		props := l.defaultProperties("Request", content)
		props.AddProperty("Headers", headers)
		props.AddProperty("URL", url)
		msg := formatter("to {Recipient} ({URL})")

		l.logger.Information(msg, props)
	})()
}

// Response loga o response para algum banco
func (l Log) Response(content interface{}, url string) {
	go (func() {
		props := l.defaultProperties("Response", content)
		props.AddProperty("URL", url)
		msg := formatter("from {Recipient} ({URL})")

		l.logger.Information(msg, props)
	})()
}

//Info loga mensagem do level INFO
func Info(msg string) {
	go logger.Information(msg, goseq.NewProperties())
}

//Warn loga mensagem do leve Warning
func (l Log) Warn(content interface{}, msg string) {
	go (func() {
		props := l.defaultProperties("Warning", content)
		m := formatter(msg)

		l.logger.Warning(m, props)
	})()
}

// Fatal loga erros da aplicação
func (l Log) Fatal(content interface{}, msg string) {
	go (func() {
		props := l.defaultProperties("Error", content)
		m := formatter(msg)

		l.logger.Fatal(m, props)
	})()
}

func (l Log) defaultProperties(messageType string, content interface{}) goseq.Properties {
	props := goseq.NewProperties()
	props.AddProperty("MessageType", messageType)
	props.AddProperty("Content", content)
	props.AddProperty("Recipient", l.Recipient)
	props.AddProperty("Operation", l.Operation)
	props.AddProperty("NossoNumero", l.NossoNumero)
	return props
}

//Close fecha a conexao com o SEQ
func Close() {
	fmt.Println("Closing SEQ Connection")
	logger.Close()
}
<commit_msg>:construction: muda o metodo de log para receber um mapa[string]string<commit_after>package log

import (
	"fmt"

	"bitbucket.org/mundipagg/boletoapi/config"
	"github.com/mundipagg/goseq"
)

var logger *goseq.Logger

// Operation a operacao usada na API
var Operation string

// Recipient o nome do banco
var Recipient string

// Log struct com os elemtos do log
type Log struct {
	Operation   string
	Recipient   string
	NossoNumero uint
	logger      *goseq.Logger
}

//Install instala o "servico" de log do SEQ
func Install() error {
	_logger, err := goseq.GetLogger(config.Get().SEQUrl, config.Get().SEQAPIKey, 150)
	if err != nil {
		return err
	}
	_logger.SetDefaultProperties(map[string]interface{}{
		"Application": config.Get().ApplicationName,
		"Environment": config.Get().Environment,
		"Domain":      config.Get().SEQDomain,
	})
	logger = _logger
	return nil
}

func formatter(message string) string {
	return "[{Application}: {Operation}] - {MessageType} " + message
}

//CreateLog cria uma nova instancia do Log
func CreateLog() *Log {
	return &Log{
		logger: logger,
	}
}

// Request loga o request para algum banco
func (l Log) Request(content interface{}, url string, headers map[string]string) {
	go (func() {
		props := l.defaultProperties("Request", content)
		props.AddProperty("Headers", headers)
		props.AddProperty("URL", url)
		msg := formatter("to {Recipient} ({URL})")

		l.logger.Information(msg, props)
	})()
}

// Response loga o response para algum banco
func (l Log) Response(content interface{}, url string) {
	go (func() {
		props := l.defaultProperties("Response", content)
		props.AddProperty("URL", url)
		msg := formatter("from {Recipient} ({URL})")

		l.logger.Information(msg, props)
	})()
}

//Info loga mensagem do level INFO
func Info(msg string) {
	go logger.Information(msg, goseq.NewProperties())
}

//Warn loga mensagem do leve Warning
func (l Log) Warn(content interface{}, msg string) {
	go (func() {
		props := l.defaultProperties("Warning", content)
		m := formatter(msg)

		l.logger.Warning(m, props)
	})()
}

// Fatal loga erros da aplicação
func (l Log) Fatal(content interface{}, msg string) {
	go (func() {
		props := l.defaultProperties("Error", content)
		m := formatter(msg)

		l.logger.Fatal(m, props)
	})()
}

func (l Log) defaultProperties(messageType string, content interface{}) goseq.Properties {
	props := goseq.NewProperties()
	props.AddProperty("MessageType", messageType)
	props.AddProperty("Content", content)
	props.AddProperty("Recipient", l.Recipient)
	props.AddProperty("Operation", l.Operation)
	props.AddProperty("NossoNumero", l.NossoNumero)
	return props
}

//Close fecha a conexao com o SEQ
func Close() {
	fmt.Println("Closing SEQ Connection")
	logger.Close()
}
<|endoftext|>


<commit_before>package httpmux

import (
	"context"
	"net/http"

	muxpath "github.com/gogolfing/httpmux/path"
)

type variablesKey int

const variablesKeyValue variablesKey = 1

type Mux struct {
	root *Route

	AllowTrailingSlashes bool

	MethodNotAllowedHandler http.Handler
	NotFoundHandler         http.Handler
}

func New() *Mux {
	return &Mux{
		root: newRootRoute(),
	}
}

func (m *Mux) HandleFunc(path string, handlerFunc http.HandlerFunc, methods ...string) *Route {
	return m.Handle(path, http.HandlerFunc(handlerFunc), methods...)
}

func (m *Mux) Handle(path string, handler http.Handler, methods ...string) *Route {
	return m.SubRoute(path).Handle(handler, methods...)
}

func (m *Mux) Root() *Route {
	return m.SubRoute(muxpath.Slash)
}

func (m *Mux) SubRoute(path string) *Route {
	return m.root.SubRoute(path)
}

func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	handler, vars, err := m.root.findHandler(r, m.getFoundMatcher())
	if err != nil {
		m.serveError(w, r, err)
		return
	}
	r = m.mapVariables(r, vars)
	handler.ServeHTTP(w, r)
}

func (m *Mux) getFoundMatcher() foundMatcher {
	if m.AllowTrailingSlashes {
		return stringFoundMatcher(muxpath.Slash)
	}
	return stringFoundMatcher("")
}

func (m *Mux) serveError(w http.ResponseWriter, r *http.Request, err error) {
	handler := m.getErrorHandler(err)
	if handler == nil {
		return
	}
	handler.ServeHTTP(w, r)
}

func (m *Mux) getErrorHandler(err error) http.Handler {
	if handler, ok := err.(ErrMethodNotAllowed); ok {
		if m.MethodNotAllowedHandler != nil {
			return m.MethodNotAllowedHandler
		}
		return handler
	}
	if err == ErrNotFound {
		if m.NotFoundHandler != nil {
			return m.NotFoundHandler
		}
		return ErrNotFound
	}
	return nil
}

func (m *Mux) mapVariables(r *http.Request, vars []*Variable) *http.Request {
	if len(vars) == 0 {
		return r
	}

	ctx := context.WithValue(r.Context(), variablesKeyValue, vars)
	for _, v := range vars {
		ctx = context.WithValue(ctx, v.Name, v.Value)
	}
	return r.WithContext(ctx)
}

func VariablesFrom(c context.Context) []*Variable {
	vars, _ := c.Value(variablesKeyValue).([]*Variable)
	return vars
}

func VariableFrom(c context.Context, name string) *Variable {
	v, _ := VariableFromOk(c, name)
	return v
}

func VariableFromOk(c context.Context, name string) (*Variable, bool) {
	value, ok := c.Value(VarName(name)).(string)
	if !ok {
		return nil, ok
	}
	return &Variable{VarName(name), value}, ok
}
<commit_msg>Update Mux.Root() to return internal root Route<commit_after>package httpmux

import (
	"context"
	"net/http"

	muxpath "github.com/gogolfing/httpmux/path"
)

type variablesKey int

const variablesKeyValue variablesKey = 1

type Mux struct {
	root *Route

	AllowTrailingSlashes bool

	MethodNotAllowedHandler http.Handler
	NotFoundHandler         http.Handler
}

func New() *Mux {
	return &Mux{
		root: newRootRoute(),
	}
}

func (m *Mux) HandleFunc(path string, handlerFunc http.HandlerFunc, methods ...string) *Route {
	return m.Handle(path, http.HandlerFunc(handlerFunc), methods...)
}

func (m *Mux) Handle(path string, handler http.Handler, methods ...string) *Route {
	return m.SubRoute(path).Handle(handler, methods...)
}

func (m *Mux) Root() *Route {
	return m.root
}

func (m *Mux) SubRoute(path string) *Route {
	return m.root.SubRoute(path)
}

func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	handler, vars, err := m.root.findHandler(r, m.getFoundMatcher())
	if err != nil {
		m.serveError(w, r, err)
		return
	}
	r = m.mapVariables(r, vars)
	handler.ServeHTTP(w, r)
}

func (m *Mux) getFoundMatcher() foundMatcher {
	if m.AllowTrailingSlashes {
		return stringFoundMatcher(muxpath.Slash)
	}
	return stringFoundMatcher("")
}

func (m *Mux) serveError(w http.ResponseWriter, r *http.Request, err error) {
	handler := m.getErrorHandler(err)
	if handler == nil {
		return
	}
	handler.ServeHTTP(w, r)
}

func (m *Mux) getErrorHandler(err error) http.Handler {
	if handler, ok := err.(ErrMethodNotAllowed); ok {
		if m.MethodNotAllowedHandler != nil {
			return m.MethodNotAllowedHandler
		}
		return handler
	}
	if err == ErrNotFound {
		if m.NotFoundHandler != nil {
			return m.NotFoundHandler
		}
		return ErrNotFound
	}
	return nil
}

func (m *Mux) mapVariables(r *http.Request, vars []*Variable) *http.Request {
	if len(vars) == 0 {
		return r
	}

	ctx := context.WithValue(r.Context(), variablesKeyValue, vars)
	for _, v := range vars {
		ctx = context.WithValue(ctx, v.Name, v.Value)
	}
	return r.WithContext(ctx)
}

func VariablesFrom(c context.Context) []*Variable {
	vars, _ := c.Value(variablesKeyValue).([]*Variable)
	return vars
}

func VariableFrom(c context.Context, name string) *Variable {
	v, _ := VariableFromOk(c, name)
	return v
}

func VariableFromOk(c context.Context, name string) (*Variable, bool) {
	value, ok := c.Value(VarName(name)).(string)
	if !ok {
		return nil, ok
	}
	return &Variable{VarName(name), value}, ok
}
<|endoftext|>


<commit_before>package httpclient

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptrace"
	"net/http/httputil"
	"os"
	"strconv"
	"time"
)

// A transport that prints request and response

type LoggingTransport struct {
	t            *http.Transport
	requestBody  bool
	responseBody bool
	timing       bool
}

func (lt *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	dreq, _ := httputil.DumpRequest(req, lt.requestBody)
	//fmt.Println("REQUEST:", strconv.Quote(string(dreq)))
	fmt.Println("REQUEST:", string(dreq))
	fmt.Println("")

	var startTime time.Time
	var elapsed time.Duration

	if lt.timing {
		startTime = time.Now()
	}

	resp, err = lt.t.RoundTrip(req)

	if lt.timing {
		elapsed = time.Since(startTime)
	}

	if err != nil {
		if lt.requestBody {
			// don't print the body twice
			dreq, _ = httputil.DumpRequest(req, false)
		}
		fmt.Println("ERROR:", err, "REQUEST:", strconv.Quote(string(dreq)))
	}
	if resp != nil {
		dresp, _ := httputil.DumpResponse(resp, lt.responseBody)
		fmt.Println("RESPONSE:", string(dresp))
	}

	if elapsed > 0 {
		fmt.Println("ELAPSED TIME:", elapsed.Round(time.Millisecond))
	}

	fmt.Println("")
	return
}

func (lt *LoggingTransport) CancelRequest(req *http.Request) {
	dreq, _ := httputil.DumpRequest(req, false)
	fmt.Println("CANCEL REQUEST:", strconv.Quote(string(dreq)))
	lt.t.CancelRequest(req)
}

// Enable logging requests/response headers
//
// if requestBody == true, also log request body
// if responseBody == true, also log response body
// if timing == true, also log elapsed time
func StartLogging(requestBody, responseBody, timing bool) {
	http.DefaultTransport = &LoggingTransport{&http.Transport{}, requestBody, responseBody, timing}
}

// Disable logging requests/responses
func StopLogging() {
	http.DefaultTransport = &http.Transport{}
}

// Wrap input transport into a LoggingTransport
func LoggedTransport(t *http.Transport, requestBody, responseBody, timing bool) http.RoundTripper {
	return &LoggingTransport{t, requestBody, responseBody, timing}
}

// A Reader that "logs" progress

type ProgressReader struct {
	r         io.Reader
	c         [1]byte
	threshold int
	curr      int
}

func NewProgressReader(r io.Reader, c byte, threshold int) *ProgressReader {
	if c == 0 {
		c = '.'
	}
	if threshold <= 0 {
		threshold = 10240
	}
	p := &ProgressReader{r: r, c: [1]byte{c}, threshold: threshold, curr: 0}
	return p
}

func (p *ProgressReader) Read(b []byte) (int, error) {
	n, err := p.r.Read(b)

	p.curr += n

	if err == io.EOF {
		os.Stdout.Write([]byte{'\n'})
		os.Stdout.Sync()
	} else if p.curr >= p.threshold {
		p.curr -= p.threshold

		os.Stdout.Write(p.c[:])
		os.Stdout.Sync()
	}

	return n, err
}

func (p *ProgressReader) Close() error {
	if rc, ok := p.r.(io.ReadCloser); ok {
		return rc.Close()
	} else {
		return nil
	}
}

// A Logger that can be disabled

type DebugLog bool

func (d DebugLog) Println(args ...interface{}) {
	if d {
		log.Println(args...)
	}
}

func (d DebugLog) Printf(fmt string, args ...interface{}) {
	if d {
		log.Printf(fmt, args...)
	}
}

// A ClientTrace implementation that collects request time

type RequestTrace struct {
	DNS          time.Duration
	Connect      time.Duration
	Connected    bool
	TLSHandshake time.Duration
	Request      time.Duration
	Wait         time.Duration
	Response     time.Duration

	startTime time.Time
}

func (r *RequestTrace) Reset() {
	r.DNS = 0
	r.Connect = 0
	r.Connected = false
	r.TLSHandshake = 0
	r.Request = 0
	r.Wait = 0
}

func (r *RequestTrace) NewClientTrace(trace bool) *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GotConn: func(info httptrace.GotConnInfo) {
			r.Connected = info.WasIdle

			if trace {
				log.Println("GotConn", info.Conn.RemoteAddr(), "reused:", info.Reused, "wasIdle:", info.WasIdle)
			}
		},

		ConnectStart: func(network, addr string) {
			r.startTime = time.Now()

			if trace {
				log.Println("ConnectStart", network, addr)
			}
		},

		ConnectDone: func(network, addr string, err error) {
			r.Connect = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("ConnectDone", network, addr, err)
			}
		},

		DNSStart: func(info httptrace.DNSStartInfo) {
			r.startTime = time.Now()

			if trace {
				log.Println("DNSStart", info.Host)
			}
		},

		DNSDone: func(info httptrace.DNSDoneInfo) {
			r.DNS = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("DNSDone", info.Addrs)
			}
		},

		TLSHandshakeStart: func() {
			r.startTime = time.Now()

			if trace {
				log.Println("TLSHandshakeStart")
			}
		},

		TLSHandshakeDone: func(state tls.ConnectionState, err error) {
			r.TLSHandshake = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("TLSHandshakeDone", err)
			}
		},

		WroteHeaderField: func(string, []string) {
			if r.startTime.IsZero() {
				r.startTime = time.Now()

				if trace {
					log.Println("WroteHeader")
				}
			}
		},

		WroteRequest: func(info httptrace.WroteRequestInfo) {
			r.Request = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("WroteRequest")
			}
		},

		GotFirstResponseByte: func() {
			r.Wait = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("GotFirstResponseByte")
			}
		},
	}
}

// Call this after the response has been received to set the Response duration
// (there is no callback for this)

func (r *RequestTrace) Done() {
	r.Response = time.Since(r.startTime)
	r.startTime = time.Now()
}
<commit_msg>need to reset Response<commit_after>package httpclient

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptrace"
	"net/http/httputil"
	"os"
	"strconv"
	"time"
)

// A transport that prints request and response

type LoggingTransport struct {
	t            *http.Transport
	requestBody  bool
	responseBody bool
	timing       bool
}

func (lt *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	dreq, _ := httputil.DumpRequest(req, lt.requestBody)
	//fmt.Println("REQUEST:", strconv.Quote(string(dreq)))
	fmt.Println("REQUEST:", string(dreq))
	fmt.Println("")

	var startTime time.Time
	var elapsed time.Duration

	if lt.timing {
		startTime = time.Now()
	}

	resp, err = lt.t.RoundTrip(req)

	if lt.timing {
		elapsed = time.Since(startTime)
	}

	if err != nil {
		if lt.requestBody {
			// don't print the body twice
			dreq, _ = httputil.DumpRequest(req, false)
		}
		fmt.Println("ERROR:", err, "REQUEST:", strconv.Quote(string(dreq)))
	}
	if resp != nil {
		dresp, _ := httputil.DumpResponse(resp, lt.responseBody)
		fmt.Println("RESPONSE:", string(dresp))
	}

	if elapsed > 0 {
		fmt.Println("ELAPSED TIME:", elapsed.Round(time.Millisecond))
	}

	fmt.Println("")
	return
}

func (lt *LoggingTransport) CancelRequest(req *http.Request) {
	dreq, _ := httputil.DumpRequest(req, false)
	fmt.Println("CANCEL REQUEST:", strconv.Quote(string(dreq)))
	lt.t.CancelRequest(req)
}

// Enable logging requests/response headers
//
// if requestBody == true, also log request body
// if responseBody == true, also log response body
// if timing == true, also log elapsed time
func StartLogging(requestBody, responseBody, timing bool) {
	http.DefaultTransport = &LoggingTransport{&http.Transport{}, requestBody, responseBody, timing}
}

// Disable logging requests/responses
func StopLogging() {
	http.DefaultTransport = &http.Transport{}
}

// Wrap input transport into a LoggingTransport
func LoggedTransport(t *http.Transport, requestBody, responseBody, timing bool) http.RoundTripper {
	return &LoggingTransport{t, requestBody, responseBody, timing}
}

// A Reader that "logs" progress

type ProgressReader struct {
	r         io.Reader
	c         [1]byte
	threshold int
	curr      int
}

func NewProgressReader(r io.Reader, c byte, threshold int) *ProgressReader {
	if c == 0 {
		c = '.'
	}
	if threshold <= 0 {
		threshold = 10240
	}
	p := &ProgressReader{r: r, c: [1]byte{c}, threshold: threshold, curr: 0}
	return p
}

func (p *ProgressReader) Read(b []byte) (int, error) {
	n, err := p.r.Read(b)

	p.curr += n

	if err == io.EOF {
		os.Stdout.Write([]byte{'\n'})
		os.Stdout.Sync()
	} else if p.curr >= p.threshold {
		p.curr -= p.threshold

		os.Stdout.Write(p.c[:])
		os.Stdout.Sync()
	}

	return n, err
}

func (p *ProgressReader) Close() error {
	if rc, ok := p.r.(io.ReadCloser); ok {
		return rc.Close()
	} else {
		return nil
	}
}

// A Logger that can be disabled

type DebugLog bool

func (d DebugLog) Println(args ...interface{}) {
	if d {
		log.Println(args...)
	}
}

func (d DebugLog) Printf(fmt string, args ...interface{}) {
	if d {
		log.Printf(fmt, args...)
	}
}

// A ClientTrace implementation that collects request time

type RequestTrace struct {
	DNS          time.Duration
	Connect      time.Duration
	Connected    bool
	TLSHandshake time.Duration
	Request      time.Duration
	Wait         time.Duration
	Response     time.Duration

	startTime time.Time
}

func (r *RequestTrace) Reset() {
	r.DNS = 0
	r.Connect = 0
	r.Connected = false
	r.TLSHandshake = 0
	r.Request = 0
	r.Wait = 0
	r.Response = 0
}

func (r *RequestTrace) NewClientTrace(trace bool) *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GotConn: func(info httptrace.GotConnInfo) {
			r.Connected = info.WasIdle

			if trace {
				log.Println("GotConn", info.Conn.RemoteAddr(), "reused:", info.Reused, "wasIdle:", info.WasIdle)
			}
		},

		ConnectStart: func(network, addr string) {
			r.startTime = time.Now()

			if trace {
				log.Println("ConnectStart", network, addr)
			}
		},

		ConnectDone: func(network, addr string, err error) {
			r.Connect = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("ConnectDone", network, addr, err)
			}
		},

		DNSStart: func(info httptrace.DNSStartInfo) {
			r.startTime = time.Now()

			if trace {
				log.Println("DNSStart", info.Host)
			}
		},

		DNSDone: func(info httptrace.DNSDoneInfo) {
			r.DNS = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("DNSDone", info.Addrs)
			}
		},

		TLSHandshakeStart: func() {
			r.startTime = time.Now()

			if trace {
				log.Println("TLSHandshakeStart")
			}
		},

		TLSHandshakeDone: func(state tls.ConnectionState, err error) {
			r.TLSHandshake = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("TLSHandshakeDone", err)
			}
		},

		WroteHeaderField: func(string, []string) {
			if r.startTime.IsZero() {
				r.startTime = time.Now()

				if trace {
					log.Println("WroteHeader")
				}
			}
		},

		WroteRequest: func(info httptrace.WroteRequestInfo) {
			r.Request = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("WroteRequest")
			}
		},

		GotFirstResponseByte: func() {
			r.Wait = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("GotFirstResponseByte")
			}
		},
	}
}

// Call this after the response has been received to set the Response duration
// (there is no callback for this)

func (r *RequestTrace) Done() {
	r.Response = time.Since(r.startTime)
	r.startTime = time.Now()
}
<|endoftext|>


<commit_before>package jsoniter

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"
	"unsafe"
)

var typeDecoders = map[string]ValDecoder{}
var fieldDecoders = map[string]ValDecoder{}
var typeEncoders = map[string]ValEncoder{}
var fieldEncoders = map[string]ValEncoder{}
var extensions = []Extension{}

type StructDescriptor struct {
	Type   reflect.Type
	Fields []*Binding
}

func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
	for _, binding := range structDescriptor.Fields {
		if binding.Field.Name == fieldName {
			return binding
		}
	}
	return nil
}

type Binding struct {
	Field     *reflect.StructField
	FromNames []string
	ToNames   []string
	Encoder   ValEncoder
	Decoder   ValDecoder
}

type Extension interface {
	UpdateStructDescriptor(structDescriptor *StructDescriptor)
	CreateDecoder(typ reflect.Type) ValDecoder
	CreateEncoder(typ reflect.Type) ValEncoder
	DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder
	DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder
}

type DummyExtension struct {
}

func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
}

func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder {
	return nil
}

func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder {
	return nil
}

func (extension *DummyExtension) DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder {
	return decoder
}

func (extension *DummyExtension) DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder {
	return encoder
}

type funcDecoder struct {
	fun DecoderFunc
}

func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
	decoder.fun(ptr, iter)
}

type funcEncoder struct {
	fun         EncoderFunc
	isEmptyFunc func(ptr unsafe.Pointer) bool
}

func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
	encoder.fun(ptr, stream)
}

func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) {
	WriteToStream(val, stream, encoder)
}

func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	if encoder.isEmptyFunc == nil {
		return false
	}
	return encoder.isEmptyFunc(ptr)
}

func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) {
	typeDecoders[typ] = &funcDecoder{fun}
}

func RegisterTypeDecoder(typ string, decoder ValDecoder) {
	typeDecoders[typ] = decoder
}

func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) {
	RegisterFieldDecoder(typ, field, &funcDecoder{fun})
}

func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) {
	fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder
}

func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc}
}

func RegisterTypeEncoder(typ string, encoder ValEncoder) {
	typeEncoders[typ] = encoder
}

func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc})
}

func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) {
	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder
}

func RegisterExtension(extension Extension) {
	extensions = append(extensions, extension)
}

func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	decoder := _getTypeDecoderFromExtension(typ)
	if decoder != nil {
		for _, extension := range extensions {
			decoder = extension.DecorateDecoder(typ, decoder)
		}
	}
	return decoder
}
func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	for _, extension := range extensions {
		decoder := extension.CreateDecoder(typ)
		if decoder != nil {
			return decoder
		}
	}
	typeName := typ.String()
	decoder := typeDecoders[typeName]
	if decoder != nil {
		return decoder
	}
	if typ.Kind() == reflect.Ptr {
		decoder := typeDecoders[typ.Elem().String()]
		if decoder != nil {
			return &optionalDecoder{typ.Elem(), decoder}
		}
	}
	return nil
}

func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	encoder := _getTypeEncoderFromExtension(typ)
	if encoder != nil {
		for _, extension := range extensions {
			encoder = extension.DecorateEncoder(typ, encoder)
		}
	}
	return encoder
}

func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	for _, extension := range extensions {
		encoder := extension.CreateEncoder(typ)
		if encoder != nil {
			return encoder
		}
	}
	typeName := typ.String()
	encoder := typeEncoders[typeName]
	if encoder != nil {
		return encoder
	}
	if typ.Kind() == reflect.Ptr {
		encoder := typeEncoders[typ.Elem().String()]
		if encoder != nil {
			return &optionalEncoder{encoder}
		}
	}
	return nil
}

func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) {
	headAnonymousBindings := []*Binding{}
	tailAnonymousBindings := []*Binding{}
	bindings := []*Binding{}
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		if field.Anonymous {
			if field.Type.Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type)
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
			} else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type.Elem())
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					binding.Encoder = &optionalEncoder{binding.Encoder}
					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
					binding.Decoder = &optionalDecoder{field.Type, binding.Decoder}
					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
			}
		} else {
			tagParts := strings.Split(field.Tag.Get("json"), ",")
			fieldNames := calcFieldNames(field.Name, tagParts[0], string(field.Tag))
			fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
			decoder := fieldDecoders[fieldCacheKey]
			if decoder == nil {
				var err error
				decoder, err = decoderOfType(cfg, field.Type)
				if err != nil {
					return nil, err
				}
			}
			encoder := fieldEncoders[fieldCacheKey]
			if encoder == nil {
				var err error
				encoder, err = encoderOfType(cfg, field.Type)
				if err != nil {
					return nil, err
				}
				// map is stored as pointer in the struct
				if field.Type.Kind() == reflect.Map {
					encoder = &optionalEncoder{encoder}
				}
			}
			binding := &Binding{
				Field:     &field,
				FromNames: fieldNames,
				ToNames:   fieldNames,
				Decoder:   decoder,
				Encoder:   encoder,
			}
			bindings = append(bindings, binding)
		}
	}
	structDescriptor := &StructDescriptor{
		Type:   typ,
		Fields: bindings,
	}
	for _, extension := range extensions {
		extension.UpdateStructDescriptor(structDescriptor)
	}
	for _, binding := range structDescriptor.Fields {
		shouldOmitEmpty := false
		tagParts := strings.Split(binding.Field.Tag.Get("json"), ",")
		for _, tagPart := range tagParts[1:] {
			if tagPart == "omitempty" {
				shouldOmitEmpty = true
			} else if tagPart == "string" {
				if binding.Field.Type.Kind() == reflect.String {
					binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg}
					binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg}
				} else {
					binding.Decoder = &stringModeNumberDecoder{binding.Decoder}
					binding.Encoder = &stringModeNumberEncoder{binding.Encoder}
				}
			}
		}
		binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder}
		binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty}
	}
	// insert anonymous bindings to the head
	structDescriptor.Fields = append(headAnonymousBindings, structDescriptor.Fields...)
	structDescriptor.Fields = append(structDescriptor.Fields, tailAnonymousBindings...)
	return structDescriptor, nil
}

func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string {
	// ignore?
	if wholeTag == "-" {
		return []string{}
	}
	// rename?
	var fieldNames []string
	if tagProvidedFieldName == "" {
		fieldNames = []string{originalFieldName}
	} else {
		fieldNames = []string{tagProvidedFieldName}
	}
	// private?
	isNotExported := unicode.IsLower(rune(originalFieldName[0]))
	if isNotExported {
		fieldNames = []string{}
	}
	return fieldNames
}
<commit_msg>#80 fix embedded builtins<commit_after>package jsoniter

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"
	"unsafe"
)

var typeDecoders = map[string]ValDecoder{}
var fieldDecoders = map[string]ValDecoder{}
var typeEncoders = map[string]ValEncoder{}
var fieldEncoders = map[string]ValEncoder{}
var extensions = []Extension{}

type StructDescriptor struct {
	Type   reflect.Type
	Fields []*Binding
}

func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
	for _, binding := range structDescriptor.Fields {
		if binding.Field.Name == fieldName {
			return binding
		}
	}
	return nil
}

type Binding struct {
	Field     *reflect.StructField
	FromNames []string
	ToNames   []string
	Encoder   ValEncoder
	Decoder   ValDecoder
}

type Extension interface {
	UpdateStructDescriptor(structDescriptor *StructDescriptor)
	CreateDecoder(typ reflect.Type) ValDecoder
	CreateEncoder(typ reflect.Type) ValEncoder
	DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder
	DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder
}

type DummyExtension struct {
}

func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
}

func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder {
	return nil
}

func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder {
	return nil
}

func (extension *DummyExtension) DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder {
	return decoder
}

func (extension *DummyExtension) DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder {
	return encoder
}

type funcDecoder struct {
	fun DecoderFunc
}

func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
	decoder.fun(ptr, iter)
}

type funcEncoder struct {
	fun         EncoderFunc
	isEmptyFunc func(ptr unsafe.Pointer) bool
}

func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
	encoder.fun(ptr, stream)
}

func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) {
	WriteToStream(val, stream, encoder)
}

func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	if encoder.isEmptyFunc == nil {
		return false
	}
	return encoder.isEmptyFunc(ptr)
}

func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) {
	typeDecoders[typ] = &funcDecoder{fun}
}

func RegisterTypeDecoder(typ string, decoder ValDecoder) {
	typeDecoders[typ] = decoder
}

func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) {
	RegisterFieldDecoder(typ, field, &funcDecoder{fun})
}

func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) {
	fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder
}

func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc}
}

func RegisterTypeEncoder(typ string, encoder ValEncoder) {
	typeEncoders[typ] = encoder
}

func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc})
}

func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) {
	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder
}

func RegisterExtension(extension Extension) {
	extensions = append(extensions, extension)
}

func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	decoder := _getTypeDecoderFromExtension(typ)
	if decoder != nil {
		for _, extension := range extensions {
			decoder = extension.DecorateDecoder(typ, decoder)
		}
	}
	return decoder
}
func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	for _, extension := range extensions {
		decoder := extension.CreateDecoder(typ)
		if decoder != nil {
			return decoder
		}
	}
	typeName := typ.String()
	decoder := typeDecoders[typeName]
	if decoder != nil {
		return decoder
	}
	if typ.Kind() == reflect.Ptr {
		decoder := typeDecoders[typ.Elem().String()]
		if decoder != nil {
			return &optionalDecoder{typ.Elem(), decoder}
		}
	}
	return nil
}

func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	encoder := _getTypeEncoderFromExtension(typ)
	if encoder != nil {
		for _, extension := range extensions {
			encoder = extension.DecorateEncoder(typ, encoder)
		}
	}
	return encoder
}

func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	for _, extension := range extensions {
		encoder := extension.CreateEncoder(typ)
		if encoder != nil {
			return encoder
		}
	}
	typeName := typ.String()
	encoder := typeEncoders[typeName]
	if encoder != nil {
		return encoder
	}
	if typ.Kind() == reflect.Ptr {
		encoder := typeEncoders[typ.Elem().String()]
		if encoder != nil {
			return &optionalEncoder{encoder}
		}
	}
	return nil
}

func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) {
	headAnonymousBindings := []*Binding{}
	tailAnonymousBindings := []*Binding{}
	bindings := []*Binding{}
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		if field.Anonymous {
			if field.Type.Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type)
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
				continue
			} else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type.Elem())
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					binding.Encoder = &optionalEncoder{binding.Encoder}
					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
					binding.Decoder = &optionalDecoder{field.Type, binding.Decoder}
					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
				continue
			}
		}
		tagParts := strings.Split(field.Tag.Get("json"), ",")
		fieldNames := calcFieldNames(field.Name, tagParts[0], string(field.Tag))
		fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
		decoder := fieldDecoders[fieldCacheKey]
		if decoder == nil {
			var err error
			decoder, err = decoderOfType(cfg, field.Type)
			if err != nil {
				return nil, err
			}
		}
		encoder := fieldEncoders[fieldCacheKey]
		if encoder == nil {
			var err error
			encoder, err = encoderOfType(cfg, field.Type)
			if err != nil {
				return nil, err
			}
			// map is stored as pointer in the struct
			if field.Type.Kind() == reflect.Map {
				encoder = &optionalEncoder{encoder}
			}
		}
		binding := &Binding{
			Field:     &field,
			FromNames: fieldNames,
			ToNames:   fieldNames,
			Decoder:   decoder,
			Encoder:   encoder,
		}
		bindings = append(bindings, binding)
	}
	return createStructDescriptor(cfg, typ, bindings, headAnonymousBindings, tailAnonymousBindings), nil
}
func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, headAnonymousBindings []*Binding, tailAnonymousBindings []*Binding) *StructDescriptor {
	structDescriptor := &StructDescriptor{
		Type:   typ,
		Fields: bindings,
	}
	for _, extension := range extensions {
		extension.UpdateStructDescriptor(structDescriptor)
	}
	processTags(structDescriptor, cfg)
	// insert anonymous bindings to the head
	structDescriptor.Fields = append(headAnonymousBindings, structDescriptor.Fields...)
	structDescriptor.Fields = append(structDescriptor.Fields, tailAnonymousBindings...)
	return structDescriptor
}

func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) {
	for _, binding := range structDescriptor.Fields {
		shouldOmitEmpty := false
		tagParts := strings.Split(binding.Field.Tag.Get("json"), ",")
		for _, tagPart := range tagParts[1:] {
			if tagPart == "omitempty" {
				shouldOmitEmpty = true
			} else if tagPart == "string" {
				if binding.Field.Type.Kind() == reflect.String {
					binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg}
					binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg}
				} else {
					binding.Decoder = &stringModeNumberDecoder{binding.Decoder}
					binding.Encoder = &stringModeNumberEncoder{binding.Encoder}
				}
			}
		}
		binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder}
		binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty}
	}
}

func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string {
	// ignore?
	if wholeTag == "-" {
		return []string{}
	}
	// rename?
	var fieldNames []string
	if tagProvidedFieldName == "" {
		fieldNames = []string{originalFieldName}
	} else {
		fieldNames = []string{tagProvidedFieldName}
	}
	// private?
	isNotExported := unicode.IsLower(rune(originalFieldName[0]))
	if isNotExported {
		fieldNames = []string{}
	}
	return fieldNames
}
<|endoftext|>


<commit_before>package logger

import (
	"testing"

	"github.com/stretchr/testify/assert"
	router "gopkg.in/Clever/kayvee-go.v5/router"
)

func TestMockLoggerImplementsKayveeLogger(t *testing.T) {
	assert.Implements(t, (*KayveeLogger)(nil), &MockRouteCountLogger{}, "*MockRouteCountLogger should implement KayveeLogger")
}

func TestRouteCountsWithMockLogger(t *testing.T) {
	routes := map[string](router.Rule){
		"rule-one": router.Rule{
			Matchers: router.RuleMatchers{
				"foo": []string{"bar", "baz"},
			},
			Output: router.RuleOutput{
				"out": "#-%{foo}-",
			},
		},
		"rule-two": router.Rule{
			Matchers: router.RuleMatchers{
				"abc": []string{"def"},
			},
			Output: router.RuleOutput{
				"more": "x",
			},
		},
	}
	testRouter := router.NewFromRoutes(routes)

	mockLogger := NewMockCountLogger("testing")
	mockLogger.logger.logRouter = testRouter

	data0 := map[string]interface{}{
		"wrong": "stuff",
	}
	expected0 := map[string]int{}
	mockLogger.InfoD("log0", data0)
	actual0 := mockLogger.RuleCounts()
	assert.Equal(t, expected0, actual0)

	data1 := map[string]interface{}{
		"foo": "bar",
	}
	expected1 := map[string]int{
		"rule-one": 1,
	}
	mockLogger.InfoD("log1", data1)
	actual1 := mockLogger.RuleCounts()
	assert.Equal(t, expected1, actual1)

	data2 := map[string]interface{}{
		"foo": "bar",
		"abc": "def",
	}
	expected2 := map[string]int{
		"rule-one": 2,
		"rule-two": 1,
	}
	mockLogger.InfoD("log2", data2)
	actual2 := mockLogger.RuleCounts()
	assert.Equal(t, expected2, actual2)
}
<commit_msg>Updated unit test to work after rebase<commit_after>package logger

import (
	"testing"

	"github.com/stretchr/testify/assert"
	router "gopkg.in/Clever/kayvee-go.v5/router"
)

func TestMockLoggerImplementsKayveeLogger(t *testing.T) {
	assert.Implements(t, (*KayveeLogger)(nil), &MockRouteCountLogger{}, "*MockRouteCountLogger should implement KayveeLogger")
}

func TestRouteCountsWithMockLogger(t *testing.T) {
	routes := map[string](router.Rule){
		"rule-one": router.Rule{
			Matchers: router.RuleMatchers{
				"foo": []string{"bar", "baz"},
			},
			Output: router.RuleOutput{
				"out": "#-%{foo}-",
			},
		},
		"rule-two": router.Rule{
			Matchers: router.RuleMatchers{
				"abc": []string{"def"},
			},
			Output: router.RuleOutput{
				"more": "x",
			},
		},
	}
	testRouter, err := router.NewFromRoutes(routes)
	assert.NoError(t, err)

	mockLogger := NewMockCountLogger("testing")
	mockLogger.logger.logRouter = testRouter

	data0 := map[string]interface{}{
		"wrong": "stuff",
	}
	expected0 := map[string]int{}
	mockLogger.InfoD("log0", data0)
	actual0 := mockLogger.RuleCounts()
	assert.Equal(t, expected0, actual0)

	data1 := map[string]interface{}{
		"foo": "bar",
	}
	expected1 := map[string]int{
		"rule-one": 1,
	}
	mockLogger.InfoD("log1", data1)
	actual1 := mockLogger.RuleCounts()
	assert.Equal(t, expected1, actual1)

	data2 := map[string]interface{}{
		"foo": "bar",
		"abc": "def",
	}
	expected2 := map[string]int{
		"rule-one": 2,
		"rule-two": 1,
	}
	mockLogger.InfoD("log2", data2)
	actual2 := mockLogger.RuleCounts()
	assert.Equal(t, expected2, actual2)
}
<|endoftext|>


<commit_before>package adapter

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/gliderlabs/logspout/router"
)

const (
	logglyAddr          = "https://logs-01.loggly.com"
	logglyEventEndpoint = "/bulk"
	logglyTagsHeader    = "X-LOGGLY-TAG"
	flushTimeout        = 10 * time.Second
)

// Adapter satisfies the router.LogAdapter interface by providing Stream which
// passes all messages to loggly.
type Adapter struct {
	token      string
	client     *http.Client
	tags       string
	log        *log.Logger
	queue      chan logglyMessage
	m          sync.Mutex
	bufferSize int
}

// New returns an Adapter that receives messages from logspout. Additionally,
// it launches a goroutine to buffer and flush messages to loggly.
func New(logglyToken, tags string, bufferSize int) *Adapter {

	adapter := &Adapter{
		client:     http.DefaultClient,
		bufferSize: bufferSize,
		log:        log.New(os.Stdout, "logspout-loggly", log.LstdFlags),
		queue:      make(chan logglyMessage),
		token:      logglyToken,
		tags:       tags,
	}

	go adapter.readQueue()

	return adapter
}

// Stream satisfies the router.LogAdapter interface and passes all messages to
// Loggly
func (l *Adapter) Stream(logstream chan *router.Message) {
	for m := range logstream {
		l.queue <- logglyMessage{
			Message:           m.Data,
			ContainerName:     m.Container.Name,
			ContainerID:       m.Container.ID,
			ContainerImage:    m.Container.Config.Image,
			ContainerHostname: m.Container.Config.Hostname,
		}
	}
}

func (l *Adapter) readQueue() {
	buffer := l.newBuffer()

	timeout := time.NewTimer(flushTimeout)

	for {
		select {
		case msg := <-l.queue:
			if len(buffer) == cap(buffer) {
				timeout.Stop()
				l.flushBuffer(buffer)
				buffer = l.newBuffer()
				timeout.Reset(flushTimeout)
			}

			buffer = append(buffer, msg)

		case <-timeout.C:
			if len(buffer) > 0 {
				l.flushBuffer(buffer)
				buffer = l.newBuffer()
			}
		}
	}
}

func (l *Adapter) newBuffer() []logglyMessage {
	return make([]logglyMessage, 0, l.bufferSize)
}

func (l *Adapter) flushBuffer(buffer []logglyMessage) {
	var data bytes.Buffer

	for _, msg := range buffer {
		j, _ := json.Marshal(msg)
		data.Write(j)
		data.WriteString("\n")
	}

	req, _ := http.NewRequest(
		"POST",
		fmt.Sprintf("%s%s/%s", logglyAddr, logglyEventEndpoint, l.token),
		&data,
	)

	go l.sendRequestToLoggly(req)
}

func (l *Adapter) sendRequestToLoggly(req *http.Request) {
	l.m.Lock()
	defer l.m.Unlock()
	resp, err := l.client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		l.log.Println(
			fmt.Errorf(
				"error from client: %s",
				err.Error(),
			),
		)
		return
	}

	if resp.StatusCode != http.StatusOK {
		l.log.Println(
			fmt.Errorf(
				"received a non 200 status code when sending message to loggly: %s",
				err.Error(),
			),
		)
	}
}
<commit_msg>remove mutex protecting http.Client<commit_after>package adapter

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/gliderlabs/logspout/router"
)

const (
	logglyAddr          = "https://logs-01.loggly.com"
	logglyEventEndpoint = "/bulk"
	logglyTagsHeader    = "X-LOGGLY-TAG"
	flushTimeout        = 10 * time.Second
)

// Adapter satisfies the router.LogAdapter interface by providing Stream which
// passes all messages to loggly.
type Adapter struct {
	token      string
	client     *http.Client
	tags       string
	log        *log.Logger
	queue      chan logglyMessage
	bufferSize int
}

// New returns an Adapter that receives messages from logspout. Additionally,
// it launches a goroutine to buffer and flush messages to loggly.
func New(logglyToken, tags string, bufferSize int) *Adapter {

	adapter := &Adapter{
		client:     http.DefaultClient,
		bufferSize: bufferSize,
		log:        log.New(os.Stdout, "logspout-loggly", log.LstdFlags),
		queue:      make(chan logglyMessage),
		token:      logglyToken,
		tags:       tags,
	}

	go adapter.readQueue()

	return adapter
}

// Stream satisfies the router.LogAdapter interface and passes all messages to
// Loggly
func (l *Adapter) Stream(logstream chan *router.Message) {
	for m := range logstream {
		l.queue <- logglyMessage{
			Message:           m.Data,
			ContainerName:     m.Container.Name,
			ContainerID:       m.Container.ID,
			ContainerImage:    m.Container.Config.Image,
			ContainerHostname: m.Container.Config.Hostname,
		}
	}
}

func (l *Adapter) readQueue() {
	buffer := l.newBuffer()

	timeout := time.NewTimer(flushTimeout)

	for {
		select {
		case msg := <-l.queue:
			if len(buffer) == cap(buffer) {
				timeout.Stop()
				l.flushBuffer(buffer)
				buffer = l.newBuffer()
				timeout.Reset(flushTimeout)
			}

			buffer = append(buffer, msg)

		case <-timeout.C:
			if len(buffer) > 0 {
				l.flushBuffer(buffer)
				buffer = l.newBuffer()
			}
		}
	}
}

func (l *Adapter) newBuffer() []logglyMessage {
	return make([]logglyMessage, 0, l.bufferSize)
}

func (l *Adapter) flushBuffer(buffer []logglyMessage) {
	var data bytes.Buffer

	for _, msg := range buffer {
		j, _ := json.Marshal(msg)
		data.Write(j)
		data.WriteString("\n")
	}

	req, _ := http.NewRequest(
		"POST",
		fmt.Sprintf("%s%s/%s", logglyAddr, logglyEventEndpoint, l.token),
		&data,
	)

	go l.sendRequestToLoggly(req)
}

func (l *Adapter) sendRequestToLoggly(req *http.Request) {
	resp, err := l.client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		l.log.Println(
			fmt.Errorf(
				"error from client: %s",
				err.Error(),
			),
		)
		return
	}

	if resp.StatusCode != http.StatusOK {
		l.log.Println(
			fmt.Errorf(
				"received a non 200 status code when sending message to loggly: %s",
				err.Error(),
			),
		)
	}
}
<|endoftext|>


<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	"fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	"net/http"
)

var _ = Describe("Logs Command", func() {
	Describe("help", func() {
		It("displays command usage to output", func() {
			session := helpers.CF("logs", "--help")
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("logs - Tail or show recent logs for an app"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf logs APP_NAME"))
			Eventually(session).Should(Say("OPTIONS:"))
			Eventually(session).Should(Say("--recent\\s+Dump recent logs instead of tailing"))
			Eventually(session).Should(Say("SEE ALSO:"))
			Eventually(session).Should(Say("app, apps, ssh"))
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})
			It("fails with no API endpoint message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint"))
			})
		})
		Context("not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})
			It("fails with not logged in message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("Not logged in. Use 'cf login' to log in.")) // TODO change to ERR
			})
		})
		Context("when no org is targeted", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF() // uses the "cf auth" command, which loses the targeted org and space (cf login does not)
			})
			It("fails with no org or space targeted message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("No org and space targeted, use 'cf target -o ORG -s SPACE' to target an org and space"))
				// TODO change to ERR above
			})
		})
		Context("when no space is targeted", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF() // uses the "cf auth" command, which loses the targeted org and space (cf login does not)
				helpers.TargetOrg(ReadOnlyOrg)
			})
			It("fails with no space targeted message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("No space targeted, use 'cf target -s' to target a space."))
				// TODO change to err above
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var (
			orgName   string
			spaceName string
		)
		BeforeEach(func() {
			//helpers.RunIfExperimental("the logs command refactor is still experimental")
			orgName = helpers.NewOrgName()
			spaceName = helpers.PrefixedRandomName("SPACE")
			setupCF(orgName, spaceName)
		})
		Context("when input is invalid", func() {
			Context("because no app name is provided", func() {
				It("gives an incorrect usage message", func() {
					session := helpers.CF("logs")
					Eventually(session).Should(Exit(1))
					Expect(session.Err).To(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
					Eventually(session).Should(Say("NAME:"))
					Eventually(session).Should(Say("logs - Tail or show recent logs for an app"))
					Eventually(session).Should(Say("USAGE:"))
					Eventually(session).Should(Say("cf logs APP_NAME"))
					Eventually(session).Should(Say("OPTIONS:"))
					Eventually(session).Should(Say("--recent\\s+Dump recent logs instead of tailing"))
					Eventually(session).Should(Say("SEE ALSO:"))
					Eventually(session).Should(Say("app, apps, ssh"))
				})
			})
			Context("because the app does not exist", func() {
				It("fails with an app not found message", func() {
					session := helpers.CF("logs", "dora")
					Eventually(session).Should(Exit(1))
					Eventually(session).Should(Say("FAILED"))
					Eventually(session).Should(Say("App dora not found"))
				})
			})
		})
		Context("when the specified app exists", func() {
			var appName string
			BeforeEach(func() {
				appName = helpers.PrefixedRandomName("app")
				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "-u", "http")).Should(Exit(0))
				})
			})

			Context("without the --recent flag", func() {
				It("streams logs out to the screen", func() {
					session := helpers.CF("logs", appName)
					defer session.Kill()

					userName, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Connected, tailing logs for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName))

					response, err := http.Get(fmt.Sprintf("http://%s.%s", appName, defaultSharedDomain()))
					Expect(err).NotTo(HaveOccurred())
					Expect(response.StatusCode).To(Equal(http.StatusOK))
					Eventually(session).Should(Say("%s \\[APP/PROC/WEB/0\\]OUT .*? \"GET / HTTP/1.1\" 200 11", helpers.ISO8601Regex))
				})
			})
			Context("with the --recent flag", func() {
				It("displays the most recent logs and closes the stream", func() {
					session := helpers.CF("logs", appName, "--recent")
					userName, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Connected, dumping recent logs for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName))
					Eventually(session).Should(Say("%s \\[API/0\\]\\s+OUT Created app with guid %s", helpers.ISO8601Regex, helpers.GUIDRegex))
				})
			})
		})
	})
})
<commit_msg>skip logs test for now<commit_after>package isolated

import (
	"fmt"
	"net/http"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("Logs Command", func() {
	BeforeEach(func() {
		helpers.RunIfExperimental("logs command refactor is still experimental")
	})

	Describe("help", func() {
		It("displays command usage to output", func() {
			session := helpers.CF("logs", "--help")
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("logs - Tail or show recent logs for an app"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf logs APP_NAME"))
			Eventually(session).Should(Say("OPTIONS:"))
			Eventually(session).Should(Say("--recent\\s+Dump recent logs instead of tailing"))
			Eventually(session).Should(Say("SEE ALSO:"))
			Eventually(session).Should(Say("app, apps, ssh"))
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})
			It("fails with no API endpoint message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint"))
			})
		})
		Context("not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})
			It("fails with not logged in message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("Not logged in. Use 'cf login' to log in.")) // TODO change to ERR
			})
		})
		Context("when no org is targeted", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF() // uses the "cf auth" command, which loses the targeted org and space (cf login does not)
			})
			It("fails with no org or space targeted message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("No org and space targeted, use 'cf target -o ORG -s SPACE' to target an org and space"))
				// TODO change to ERR above
			})
		})
		Context("when no space is targeted", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF() // uses the "cf auth" command, which loses the targeted org and space (cf login does not)
				helpers.TargetOrg(ReadOnlyOrg)
			})
			It("fails with no space targeted message", func() {
				session := helpers.CF("logs", "dora")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Out).To(Say("No space targeted, use 'cf target -s' to target a space."))
				// TODO change to err above
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var (
			orgName   string
			spaceName string
		)
		BeforeEach(func() {
			//helpers.RunIfExperimental("the logs command refactor is still experimental")
			orgName = helpers.NewOrgName()
			spaceName = helpers.PrefixedRandomName("SPACE")
			setupCF(orgName, spaceName)
		})
		Context("when input is invalid", func() {
			Context("because no app name is provided", func() {
				It("gives an incorrect usage message", func() {
					session := helpers.CF("logs")
					Eventually(session).Should(Exit(1))
					Expect(session.Err).To(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
					Eventually(session).Should(Say("NAME:"))
					Eventually(session).Should(Say("logs - Tail or show recent logs for an app"))
					Eventually(session).Should(Say("USAGE:"))
					Eventually(session).Should(Say("cf logs APP_NAME"))
					Eventually(session).Should(Say("OPTIONS:"))
					Eventually(session).Should(Say("--recent\\s+Dump recent logs instead of tailing"))
					Eventually(session).Should(Say("SEE ALSO:"))
					Eventually(session).Should(Say("app, apps, ssh"))
				})
			})
			Context("because the app does not exist", func() {
				It("fails with an app not found message", func() {
					session := helpers.CF("logs", "dora")
					Eventually(session).Should(Exit(1))
					Eventually(session).Should(Say("FAILED"))
					Eventually(session).Should(Say("App dora not found"))
				})
			})
		})
		Context("when the specified app exists", func() {
			var appName string
			BeforeEach(func() {
				appName = helpers.PrefixedRandomName("app")
				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "-u", "http")).Should(Exit(0))
				})
			})

			Context("without the --recent flag", func() {
				It("streams logs out to the screen", func() {
					session := helpers.CF("logs", appName)
					defer session.Kill()

					userName, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Connected, tailing logs for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName))

					response, err := http.Get(fmt.Sprintf("http://%s.%s", appName, defaultSharedDomain()))
					Expect(err).NotTo(HaveOccurred())
					Expect(response.StatusCode).To(Equal(http.StatusOK))
					Eventually(session).Should(Say("%s \\[APP/PROC/WEB/0\\]OUT .*? \"GET / HTTP/1.1\" 200 11", helpers.ISO8601Regex))
				})
			})
			Context("with the --recent flag", func() {
				It("displays the most recent logs and closes the stream", func() {
					session := helpers.CF("logs", appName, "--recent")
					userName, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Connected, dumping recent logs for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName))
					Eventually(session).Should(Say("%s \\[API/0\\]\\s+OUT Created app with guid %s", helpers.ISO8601Regex, helpers.GUIDRegex))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 opengl

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/web"
)

// arrayBufferLayoutPart is a part of an array buffer layout.
type arrayBufferLayoutPart struct {
	// TODO: This struct should belong to a program and know it.
	name string
	num  int
}

// arrayBufferLayout is an array buffer layout.
//
// An array buffer in OpenGL is a buffer representing vertices and
// is passed to a vertex shader.
type arrayBufferLayout struct {
	parts []arrayBufferLayoutPart
	total int
}

// totalBytes returns the size in bytes for one element of the array buffer.
func (a *arrayBufferLayout) totalBytes() int {
	if a.total != 0 {
		return a.total
	}
	t := 0
	for _, p := range a.parts {
		t += float.SizeInBytes() * p.num
	}
	a.total = t
	return a.total
}

// newArrayBuffer creates OpenGL's buffer object for the array buffer.
func (a *arrayBufferLayout) newArrayBuffer(context *context) buffer {
	return context.newArrayBuffer(a.totalBytes() * graphics.IndicesNum)
}

// enable binds the array buffer the given program to use the array buffer.
func (a *arrayBufferLayout) enable(context *context, program program) {
	for _, p := range a.parts {
		context.enableVertexAttribArray(program, p.name)
	}
	total := a.totalBytes()
	offset := 0
	for _, p := range a.parts {
		context.vertexAttribPointer(program, p.name, p.num, float, total, offset)
		offset += float.SizeInBytes() * p.num
	}
}

// disable stops using the array buffer.
func (a *arrayBufferLayout) disable(context *context, program program) {
	// TODO: Disabling should be done in reversed order?
	for _, p := range a.parts {
		context.disableVertexAttribArray(program, p.name)
	}
}

// theArrayBufferLayout is the array buffer layout for Ebiten.
var theArrayBufferLayout = arrayBufferLayout{
	// Note that GL_MAX_VERTEX_ATTRIBS is at least 16.
	parts: []arrayBufferLayoutPart{
		{
			name: "vertex",
			num:  2,
		},
		{
			name: "tex",
			num:  2,
		},
		{
			name: "tex_region",
			num:  4,
		},
		{
			name: "color_scale",
			num:  4,
		},
	},
}

func init() {
	vertexFloatNum := theArrayBufferLayout.totalBytes() / float.SizeInBytes()
	if graphics.VertexFloatNum != vertexFloatNum {
		panic(fmt.Sprintf("vertex float num must be %d but %d", graphics.VertexFloatNum, vertexFloatNum))
	}
}

// openGLState is a state for
type openGLState struct {
	// arrayBuffer is OpenGL's array buffer (vertices data).
	arrayBuffer buffer

	// elementArrayBuffer is OpenGL's element array buffer (indices data).
	elementArrayBuffer buffer

	// program is OpenGL's program for rendering a texture.
	program program

	lastProgram                program
	lastViewportWidth          int
	lastViewportHeight         int
	lastColorMatrix            []float32
	lastColorMatrixTranslation []float32
	lastSourceWidth            int
	lastSourceHeight           int
	lastFilter                 *graphics.Filter
	lastAddress                *graphics.Address

	source      *Image
	destination *Image
}

var (
	zeroBuffer  buffer
	zeroProgram program
)

const (
	maxTriangles = graphics.IndicesNum / 3
	maxQuads     = maxTriangles / 2
)

// reset resets or initializes the OpenGL state.
func (s *openGLState) reset(context *context) error {
	if err := context.reset(); err != nil {
		return err
	}

	s.lastProgram = zeroProgram
	s.lastViewportWidth = 0
	s.lastViewportHeight = 0
	s.lastColorMatrix = nil
	s.lastColorMatrixTranslation = nil
	s.lastSourceWidth = 0
	s.lastSourceHeight = 0
	s.lastFilter = nil
	s.lastAddress = nil

	// When context lost happens, deleting programs or buffers is not necessary.
	// However, it is not assumed that reset is called only when context lost happens.
	// Let's delete them explicitly.
	if s.program != zeroProgram {
		context.deleteProgram(s.program)
	}

	// On browsers (at least Chrome), buffers are already detached from the context
	// and must not be deleted by DeleteBuffer.
	if !web.IsBrowser() {
		if s.arrayBuffer != zeroBuffer {
			context.deleteBuffer(s.arrayBuffer)
		}
		if s.elementArrayBuffer != zeroBuffer {
			context.deleteBuffer(s.elementArrayBuffer)
		}
	}

	shaderVertexModelviewNative, err := context.newShader(vertexShader, shaderStr(shaderVertexModelview))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer context.deleteShader(shaderVertexModelviewNative)

	shaderFragmentColorMatrixNative, err := context.newShader(fragmentShader, shaderStr(shaderFragmentColorMatrix))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer context.deleteShader(shaderFragmentColorMatrixNative)

	s.program, err = context.newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentColorMatrixNative,
	})
	if err != nil {
		return err
	}

	s.arrayBuffer = theArrayBufferLayout.newArrayBuffer(context)

	// Note that the indices passed to NewElementArrayBuffer is not under GC management
	// in opengl package due to unsafe-way.
	// See NewElementArrayBuffer in context_mobile.go.
	s.elementArrayBuffer = context.newElementArrayBuffer(graphics.IndicesNum * 2)

	return nil
}

// areSameFloat32Array returns a boolean indicating if a and b are deeply equal.
func areSameFloat32Array(a, b []float32) bool {
	if len(a) != len(b) {
		return false
	}
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// useProgram uses the program (programTexture).
func (d *Driver) useProgram(mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter, address graphics.Address) error {
	destination := d.state.destination
	if destination == nil {
		panic("destination image is not set")
	}
	source := d.state.source
	if source == nil {
		panic("source image is not set")
	}

	if err := destination.setViewport(); err != nil {
		return err
	}
	dstW := destination.width
	srcW, srcH := source.width, source.height

	d.context.blendFunc(mode)

	program := d.state.program
	if d.state.lastProgram != program {
		d.context.useProgram(program)
		if d.state.lastProgram != zeroProgram {
			theArrayBufferLayout.disable(&d.context, d.state.lastProgram)
		}
		theArrayBufferLayout.enable(&d.context, program)

		if d.state.lastProgram == zeroProgram {
			d.context.bindBuffer(arrayBuffer, d.state.arrayBuffer)
			d.context.bindBuffer(elementArrayBuffer, d.state.elementArrayBuffer)
			d.context.uniformInt(program, "texture", 0)
		}

		d.state.lastProgram = program
		d.state.lastViewportWidth = 0
		d.state.lastViewportHeight = 0
		d.state.lastColorMatrix = nil
		d.state.lastColorMatrixTranslation = nil
		d.state.lastSourceWidth = 0
		d.state.lastSourceHeight = 0
	}

	vw := destination.framebuffer.width
	vh := destination.framebuffer.height
	if d.state.lastViewportWidth != vw || d.state.lastSourceHeight != vh {
		d.context.uniformFloats(program, "viewport_size", []float32{float32(vw), float32(vh)})
		d.state.lastViewportWidth = vw
		d.state.lastViewportHeight = vh
	}

	esBody, esTranslate := colorM.UnsafeElements()

	if !areSameFloat32Array(d.state.lastColorMatrix, esBody) {
		d.context.uniformFloats(program, "color_matrix_body", esBody)
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		d.state.lastColorMatrix = esBody
	}
	if !areSameFloat32Array(d.state.lastColorMatrixTranslation, esTranslate) {
		d.context.uniformFloats(program, "color_matrix_translation", esTranslate)
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		d.state.lastColorMatrixTranslation = esTranslate
	}

	sw := graphics.NextPowerOf2Int(srcW)
	sh := graphics.NextPowerOf2Int(srcH)

	if d.state.lastSourceWidth != sw || d.state.lastSourceHeight != sh {
		d.context.uniformFloats(program, "source_size", []float32{float32(sw), float32(sh)})
		d.state.lastSourceWidth = sw
		d.state.lastSourceHeight = sh
	}

	if d.state.lastFilter == nil || *d.state.lastFilter != filter {
		d.context.uniformInt(program, "filter", int(filter))
		d.state.lastFilter = &filter
	}
	if d.state.lastAddress == nil || *d.state.lastAddress != address {
		d.context.uniformInt(program, "address", int(address))
		d.state.lastAddress = &address
	}

	if filter == graphics.FilterScreen {
		scale := float32(dstW) / float32(srcW)
		d.context.uniformFloat(program, "scale", scale)
	}

	// We don't have to call gl.ActiveTexture here: GL_TEXTURE0 is the default active texture
	// See also: https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml
	d.context.bindTexture(source.textureNative)

	d.state.source = nil
	d.state.destination = nil
	return nil
}
<commit_msg>graphicsdriver/opengl: Bug fix: misspelling on variables<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 opengl

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/web"
)

// arrayBufferLayoutPart is a part of an array buffer layout.
type arrayBufferLayoutPart struct {
	// TODO: This struct should belong to a program and know it.
	name string
	num  int
}

// arrayBufferLayout is an array buffer layout.
//
// An array buffer in OpenGL is a buffer representing vertices and
// is passed to a vertex shader.
type arrayBufferLayout struct {
	parts []arrayBufferLayoutPart
	total int
}

// totalBytes returns the size in bytes for one element of the array buffer.
func (a *arrayBufferLayout) totalBytes() int {
	if a.total != 0 {
		return a.total
	}
	t := 0
	for _, p := range a.parts {
		t += float.SizeInBytes() * p.num
	}
	a.total = t
	return a.total
}

// newArrayBuffer creates OpenGL's buffer object for the array buffer.
func (a *arrayBufferLayout) newArrayBuffer(context *context) buffer {
	return context.newArrayBuffer(a.totalBytes() * graphics.IndicesNum)
}

// enable binds the array buffer the given program to use the array buffer.
func (a *arrayBufferLayout) enable(context *context, program program) {
	for _, p := range a.parts {
		context.enableVertexAttribArray(program, p.name)
	}
	total := a.totalBytes()
	offset := 0
	for _, p := range a.parts {
		context.vertexAttribPointer(program, p.name, p.num, float, total, offset)
		offset += float.SizeInBytes() * p.num
	}
}

// disable stops using the array buffer.
func (a *arrayBufferLayout) disable(context *context, program program) {
	// TODO: Disabling should be done in reversed order?
	for _, p := range a.parts {
		context.disableVertexAttribArray(program, p.name)
	}
}

// theArrayBufferLayout is the array buffer layout for Ebiten.
var theArrayBufferLayout = arrayBufferLayout{
	// Note that GL_MAX_VERTEX_ATTRIBS is at least 16.
	parts: []arrayBufferLayoutPart{
		{
			name: "vertex",
			num:  2,
		},
		{
			name: "tex",
			num:  2,
		},
		{
			name: "tex_region",
			num:  4,
		},
		{
			name: "color_scale",
			num:  4,
		},
	},
}

func init() {
	vertexFloatNum := theArrayBufferLayout.totalBytes() / float.SizeInBytes()
	if graphics.VertexFloatNum != vertexFloatNum {
		panic(fmt.Sprintf("vertex float num must be %d but %d", graphics.VertexFloatNum, vertexFloatNum))
	}
}

// openGLState is a state for
type openGLState struct {
	// arrayBuffer is OpenGL's array buffer (vertices data).
	arrayBuffer buffer

	// elementArrayBuffer is OpenGL's element array buffer (indices data).
	elementArrayBuffer buffer

	// program is OpenGL's program for rendering a texture.
	program program

	lastProgram                program
	lastViewportWidth          int
	lastViewportHeight         int
	lastColorMatrix            []float32
	lastColorMatrixTranslation []float32
	lastSourceWidth            int
	lastSourceHeight           int
	lastFilter                 *graphics.Filter
	lastAddress                *graphics.Address

	source      *Image
	destination *Image
}

var (
	zeroBuffer  buffer
	zeroProgram program
)

const (
	maxTriangles = graphics.IndicesNum / 3
	maxQuads     = maxTriangles / 2
)

// reset resets or initializes the OpenGL state.
func (s *openGLState) reset(context *context) error {
	if err := context.reset(); err != nil {
		return err
	}

	s.lastProgram = zeroProgram
	s.lastViewportWidth = 0
	s.lastViewportHeight = 0
	s.lastColorMatrix = nil
	s.lastColorMatrixTranslation = nil
	s.lastSourceWidth = 0
	s.lastSourceHeight = 0
	s.lastFilter = nil
	s.lastAddress = nil

	// When context lost happens, deleting programs or buffers is not necessary.
	// However, it is not assumed that reset is called only when context lost happens.
	// Let's delete them explicitly.
	if s.program != zeroProgram {
		context.deleteProgram(s.program)
	}

	// On browsers (at least Chrome), buffers are already detached from the context
	// and must not be deleted by DeleteBuffer.
	if !web.IsBrowser() {
		if s.arrayBuffer != zeroBuffer {
			context.deleteBuffer(s.arrayBuffer)
		}
		if s.elementArrayBuffer != zeroBuffer {
			context.deleteBuffer(s.elementArrayBuffer)
		}
	}

	shaderVertexModelviewNative, err := context.newShader(vertexShader, shaderStr(shaderVertexModelview))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer context.deleteShader(shaderVertexModelviewNative)

	shaderFragmentColorMatrixNative, err := context.newShader(fragmentShader, shaderStr(shaderFragmentColorMatrix))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer context.deleteShader(shaderFragmentColorMatrixNative)

	s.program, err = context.newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentColorMatrixNative,
	})
	if err != nil {
		return err
	}

	s.arrayBuffer = theArrayBufferLayout.newArrayBuffer(context)

	// Note that the indices passed to NewElementArrayBuffer is not under GC management
	// in opengl package due to unsafe-way.
	// See NewElementArrayBuffer in context_mobile.go.
	s.elementArrayBuffer = context.newElementArrayBuffer(graphics.IndicesNum * 2)

	return nil
}

// areSameFloat32Array returns a boolean indicating if a and b are deeply equal.
func areSameFloat32Array(a, b []float32) bool {
	if len(a) != len(b) {
		return false
	}
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// useProgram uses the program (programTexture).
func (d *Driver) useProgram(mode graphics.CompositeMode, colorM *affine.ColorM, filter graphics.Filter, address graphics.Address) error {
	destination := d.state.destination
	if destination == nil {
		panic("destination image is not set")
	}
	source := d.state.source
	if source == nil {
		panic("source image is not set")
	}

	if err := destination.setViewport(); err != nil {
		return err
	}
	dstW := destination.width
	srcW, srcH := source.width, source.height

	d.context.blendFunc(mode)

	program := d.state.program
	if d.state.lastProgram != program {
		d.context.useProgram(program)
		if d.state.lastProgram != zeroProgram {
			theArrayBufferLayout.disable(&d.context, d.state.lastProgram)
		}
		theArrayBufferLayout.enable(&d.context, program)

		if d.state.lastProgram == zeroProgram {
			d.context.bindBuffer(arrayBuffer, d.state.arrayBuffer)
			d.context.bindBuffer(elementArrayBuffer, d.state.elementArrayBuffer)
			d.context.uniformInt(program, "texture", 0)
		}

		d.state.lastProgram = program
		d.state.lastViewportWidth = 0
		d.state.lastViewportHeight = 0
		d.state.lastColorMatrix = nil
		d.state.lastColorMatrixTranslation = nil
		d.state.lastSourceWidth = 0
		d.state.lastSourceHeight = 0
	}

	vw := destination.framebuffer.width
	vh := destination.framebuffer.height
	if d.state.lastViewportWidth != vw || d.state.lastViewportHeight != vh {
		d.context.uniformFloats(program, "viewport_size", []float32{float32(vw), float32(vh)})
		d.state.lastViewportWidth = vw
		d.state.lastViewportHeight = vh
	}

	esBody, esTranslate := colorM.UnsafeElements()

	if !areSameFloat32Array(d.state.lastColorMatrix, esBody) {
		d.context.uniformFloats(program, "color_matrix_body", esBody)
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		d.state.lastColorMatrix = esBody
	}
	if !areSameFloat32Array(d.state.lastColorMatrixTranslation, esTranslate) {
		d.context.uniformFloats(program, "color_matrix_translation", esTranslate)
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		d.state.lastColorMatrixTranslation = esTranslate
	}

	sw := graphics.NextPowerOf2Int(srcW)
	sh := graphics.NextPowerOf2Int(srcH)

	if d.state.lastSourceWidth != sw || d.state.lastSourceHeight != sh {
		d.context.uniformFloats(program, "source_size", []float32{float32(sw), float32(sh)})
		d.state.lastSourceWidth = sw
		d.state.lastSourceHeight = sh
	}

	if d.state.lastFilter == nil || *d.state.lastFilter != filter {
		d.context.uniformInt(program, "filter", int(filter))
		d.state.lastFilter = &filter
	}
	if d.state.lastAddress == nil || *d.state.lastAddress != address {
		d.context.uniformInt(program, "address", int(address))
		d.state.lastAddress = &address
	}

	if filter == graphics.FilterScreen {
		scale := float32(dstW) / float32(srcW)
		d.context.uniformFloat(program, "scale", scale)
	}

	// We don't have to call gl.ActiveTexture here: GL_TEXTURE0 is the default active texture
	// See also: https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml
	d.context.bindTexture(source.textureNative)

	d.state.source = nil
	d.state.destination = nil
	return nil
}
<|endoftext|>