<commit_before>// Package httpmux provides an http request multiplexer.
package httpmux

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

	"github.com/julienschmidt/httprouter"
	"golang.org/x/net/context"
)

type (
	// Handler is the http request multiplexer backed by httprouter.Router.
	Handler struct {
		prefix string            // prefix for all paths
		mw     []Middleware      // list of mw set by Use
		routes map[string]*route // map of pattern to route for subtrees
		router *httprouter.Router
	}

	route struct {
		Method  string
		Handler http.HandlerFunc
	}

	// Middleware is an http handler that can optionally
	// call the next handler in the chain based on
	// the request or any other conditions.
	Middleware func(next http.Handler) http.Handler

	// MiddlewareFunc is an adapter for Middleware that takes
	// handler functions.
	MiddlewareFunc func(next http.HandlerFunc) http.HandlerFunc

	// Config is the Handler configuration.
	Config struct {
		// Prefix is the prefix for all paths in the handler.
		// Empty value is allowed and defaults to "/".
		Prefix string

		// Middleware is the initial list of middlewares to be
		// automatically assigned to all handlers.
		Middleware []Middleware

		// Enables automatic redirection if the current route can't be matched but a
		// handler for the path with (without) the trailing slash exists.
		// For example if /foo/ is requested but a route only exists for /foo, the
		// client is redirected to /foo with http status code 301 for GET requests
		// and 307 for all other request methods.
		RedirectTrailingSlash bool

		// If enabled, the router tries to fix the current request path, if no
		// handle is registered for it.
		// First superfluous path elements like ../ or // are removed.
		// Afterwards the router does a case-insensitive lookup of the cleaned path.
		// If a handle can be found for this route, the router makes a redirection
		// to the corrected path with status code 301 for GET requests and 307 for
		// all other request methods.
		// For example /FOO and /..//Foo could be redirected to /foo.
		// RedirectTrailingSlash is independent of this option.
		RedirectFixedPath bool

		// If enabled, the router checks if another method is allowed for the
		// current route, if the current request can not be routed.
		// If this is the case, the request is answered with 'Method Not Allowed'
		// and HTTP status code 405.
		// If no other Method is allowed, the request is delegated to the NotFound
		// handler.
		HandleMethodNotAllowed bool

		// Configurable http.Handler which is called when no matching route is
		// found. If it is not set, http.NotFound is used.
		NotFound http.Handler

		// Configurable http.Handler which is called when a request
		// cannot be routed and HandleMethodNotAllowed is true.
		// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
		MethodNotAllowed http.Handler

		// Function to handle panics recovered from http handlers.
		// It should be used to generate a error page and return the http error code
		// 500 (Internal Server Error).
		// The handler can be used to keep your server from crashing because of
		// unrecovered panics.
		PanicHandler func(http.ResponseWriter, *http.Request, interface{})
	}
)

// Use appends f to the list of middlewares.
func (c *Config) Use(mw ...Middleware) {
	c.Middleware = append(c.Middleware, mw...)
}

// UseFunc appends f to the list of middlewares.
func (c *Config) UseFunc(mw ...MiddlewareFunc) {
	for _, f := range mw {
		ff := func(next http.Handler) http.Handler {
			return f(next.ServeHTTP)
		}
		c.Middleware = append(c.Middleware, ff)
	}
}

// DefaultConfig is the default Handler configuration used by New.
var DefaultConfig = Config{
	RedirectTrailingSlash:  true,
	RedirectFixedPath:      true,
	HandleMethodNotAllowed: true,
}

// New creates and initializes a new Handler using default settings.
func New() *Handler {
	c := DefaultConfig
	return NewHandler(&c)
}

// NewHandler creates and initializes a new Handler with the given config.
func NewHandler(c *Config) *Handler {
	h := &Handler{
		prefix: c.Prefix,
		mw:     c.Middleware,
		routes: make(map[string]*route),
	}
	router := httprouter.New()
	router.RedirectTrailingSlash = c.RedirectTrailingSlash
	router.RedirectFixedPath = c.RedirectFixedPath
	router.HandleMethodNotAllowed = c.HandleMethodNotAllowed
	if c.NotFound != nil {
		router.NotFound = h.chain(c.NotFound.ServeHTTP)
	}
	if c.MethodNotAllowed != nil {
		router.MethodNotAllowed = h.chain(c.MethodNotAllowed.ServeHTTP)
	}
	router.PanicHandler = c.PanicHandler
	h.router = router
	return h
}

// DELETE is a shortcut for mux.Handle("DELETE", path, handle)
func (h *Handler) DELETE(pattern string, f http.HandlerFunc) { h.Handle("DELETE", pattern, f) }

// GET is a shortcut for mux.Handle("GET", path, handle)
func (h *Handler) GET(pattern string, f http.HandlerFunc) { h.Handle("GET", pattern, f) }

// HEAD is a shortcut for mux.Handle("HEAD", path, handle)
func (h *Handler) HEAD(pattern string, f http.HandlerFunc) { h.Handle("HEAD", pattern, f) }

// OPTIONS is a shortcut for mux.Handle("OPTIONS", path, handle)
func (h *Handler) OPTIONS(pattern string, f http.HandlerFunc) { h.Handle("OPTIONS", pattern, f) }

// PATCH is a shortcut for mux.Handle("PATCH", path, handle)
func (h *Handler) PATCH(pattern string, f http.HandlerFunc) { h.Handle("PATCH", pattern, f) }

// POST is a shortcut for mux.Handle("POST", path, handle)
func (h *Handler) POST(pattern string, f http.HandlerFunc) { h.Handle("POST", pattern, f) }

// PUT is a shortcut for mux.Handle("PUT", path, handle)
func (h *Handler) PUT(pattern string, f http.HandlerFunc) { h.Handle("PUT", pattern, f) }

// Handle registers a new request handler with the given method and pattern.
func (h *Handler) Handle(method, pattern string, f http.Handler) {
	h.HandleFunc(method, pattern, f.ServeHTTP)
}

// HandleFunc registers a new request handler with the given method and pattern.
func (h *Handler) HandleFunc(method, pattern string, f http.HandlerFunc) {
	p := path.Join(h.prefix, pattern)
	if len(pattern) > 1 && pattern[len(pattern)-1] == '/' {
		p += "/"
	}
	ff := h.wrap(f.ServeHTTP)
	h.routes[pattern] = &route{Method: method, Handler: f}
	h.router.Handle(method, p, ff)
}

func (h *Handler) wrap(next http.HandlerFunc) httprouter.Handle {
	next = h.chain(next)
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		if c, ok := r.Body.(*ctxBody); !ok {
			c = &ctxBody{
				ReadCloser: r.Body,
				ctx:        context.Background(),
			}
			r.Body = c
			defer func() {
				r.Body = c.ReadCloser
			}()
		}
		ctx := context.WithValue(Context(r), paramsID, p)
		SetContext(ctx, r)
		next(w, r)
	}
}

// ServeFiles serves files from the given file system root.
//
// The pattern must end with "/*filepath" to have files served from
// the local path /path/to/dir/*filepath.
//
// For example, if root is "/etc" and *filepath is "passwd", the local
// file "/etc/passwd" is served. Because an http.FileServer is used
// internally it's possible that http.NotFound is called instead
// of httpmux's NotFound handler.
//
// To use the operating system's file system implementation, use
// http.Dir: mux.ServeFiles("/src/*filepath", http.Dir("/var/www")).
func (h *Handler) ServeFiles(pattern string, root http.FileSystem) {
	if !strings.HasSuffix(pattern, "/*filepath") {
		panic("pattern must end with /*filepath in path '" + pattern + "'")
	}
	fs := http.FileServer(root)
	h.GET(pattern, func(w http.ResponseWriter, r *http.Request) {
		r.URL.Path = Params(r).ByName("filepath")
		fs.ServeHTTP(w, r)
	})
}

// Use appends the given middlewares to the internal chain.
func (h *Handler) Use(mw ...Middleware) {
	h.mw = append(h.mw, mw...)
}

// UseFunc appends the given middlewares to the internal chain.
func (h *Handler) UseFunc(mw ...MiddlewareFunc) {
	for _, f := range mw {
		ff := func(next http.Handler) http.Handler {
			return f(next.ServeHTTP)
		}
		h.mw = append(h.mw, ff)
	}
}

// Append appends a handler to this handler, under the given pattern. All
// middleware from the root tree propagates to the subtree. However,
// the subtree's configuration such as prefix and fallback handlers,
// like NotFound and MethodNotAllowed, are ignored by the root tree
// in favor of its own configuration.
func (h *Handler) Append(pattern string, subtree *Handler) {
	for pp, route := range subtree.routes {
		pp = path.Join(h.prefix, pattern, pp)
		f := subtree.chain(route.Handler)
		h.router.Handle(route.Method, pp, h.wrap(f))
	}
}

// ServeHTTP implements the http.Handler interface.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.router.ServeHTTP(w, r)
}

// ctxBody is the object we save in the request's Body field.
type ctxBody struct {
	io.ReadCloser
	ctx context.Context
}

// chain generates the middleware chain and appends f at the end.
func (h *Handler) chain(f http.HandlerFunc) http.HandlerFunc {
	var handler http.HandlerFunc
	for i := len(h.mw) - 1; i >= 0; i-- {
		handler = h.mw[i](f).ServeHTTP
		f = handler
	}
	return f
}

// Context returns the context from the given request, or a new
// context.Background if it doesn't exist.
func Context(r *http.Request) context.Context {
	if c, ok := r.Body.(*ctxBody); ok {
		return c.ctx
	}
	return context.Background()
}

// SetContext updates the given context in the request if the request
// has been previously instrumented by httpmux.
func SetContext(ctx context.Context, r *http.Request) {
	if c, ok := r.Body.(*ctxBody); ok {
		c.ctx = ctx
	}
}

type paramsType int

var paramsID paramsType

// Params returns the httprouter.Params from the request context.
func Params(r *http.Request) httprouter.Params {
	if p, ok := Context(r).Value(paramsID).(httprouter.Params); ok {
		return p
	}
	return httprouter.Params{}
}
<commit_msg>Update docs<commit_after>// Package httpmux provides an http request multiplexer.
package httpmux

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

	"github.com/julienschmidt/httprouter"
	"golang.org/x/net/context"
)

type (
	// Handler is the http request multiplexer backed by httprouter.Router.
	Handler struct {
		prefix string            // prefix for all paths
		mw     []Middleware      // list of mw set by Use
		routes map[string]*route // map of pattern to route for subtrees
		router *httprouter.Router
	}

	route struct {
		Method  string
		Handler http.HandlerFunc
	}

	// Middleware is an http handler that can optionally
	// call the next handler in the chain based on
	// the request or any other conditions.
	Middleware func(next http.Handler) http.Handler

	// MiddlewareFunc is an adapter for Middleware that takes
	// handler functions.
	MiddlewareFunc func(next http.HandlerFunc) http.HandlerFunc

	// Config is the Handler configuration.
	Config struct {
		// Prefix is the prefix for all paths in the handler.
		// Empty value is allowed and defaults to "/".
		Prefix string

		// Middleware is the initial list of middlewares to be
		// automatically assigned to all handlers.
		//
		// Note that middleware for the configurable handlers
		// such as NotFound and MethodNotAllowed can only be
		// configured here.
		Middleware []Middleware

		// Enables automatic redirection if the current route can't be matched but a
		// handler for the path with (without) the trailing slash exists.
		// For example if /foo/ is requested but a route only exists for /foo, the
		// client is redirected to /foo with http status code 301 for GET requests
		// and 307 for all other request methods.
		RedirectTrailingSlash bool

		// If enabled, the router tries to fix the current request path, if no
		// handle is registered for it.
		// First superfluous path elements like ../ or // are removed.
		// Afterwards the router does a case-insensitive lookup of the cleaned path.
		// If a handle can be found for this route, the router makes a redirection
		// to the corrected path with status code 301 for GET requests and 307 for
		// all other request methods.
		// For example /FOO and /..//Foo could be redirected to /foo.
		// RedirectTrailingSlash is independent of this option.
		RedirectFixedPath bool

		// If enabled, the router checks if another method is allowed for the
		// current route, if the current request can not be routed.
		// If this is the case, the request is answered with 'Method Not Allowed'
		// and HTTP status code 405.
		// If no other Method is allowed, the request is delegated to the NotFound
		// handler.
		HandleMethodNotAllowed bool

		// Configurable http.Handler which is called when no matching route is
		// found. If it is not set, http.NotFound is used.
		NotFound http.Handler

		// Configurable http.Handler which is called when a request
		// cannot be routed and HandleMethodNotAllowed is true.
		// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
		MethodNotAllowed http.Handler

		// Function to handle panics recovered from http handlers.
		// It should be used to generate a error page and return the http error code
		// 500 (Internal Server Error).
		// The handler can be used to keep your server from crashing because of
		// unrecovered panics.
		//
		// No middleware is applied to the PanicHandler.
		PanicHandler func(http.ResponseWriter, *http.Request, interface{})
	}
)

// Use appends f to the list of middlewares.
func (c *Config) Use(mw ...Middleware) {
	c.Middleware = append(c.Middleware, mw...)
}

// UseFunc appends f to the list of middlewares.
func (c *Config) UseFunc(mw ...MiddlewareFunc) {
	for _, f := range mw {
		ff := func(next http.Handler) http.Handler {
			return f(next.ServeHTTP)
		}
		c.Middleware = append(c.Middleware, ff)
	}
}

// DefaultConfig is the default Handler configuration used by New.
var DefaultConfig = Config{
	RedirectTrailingSlash:  true,
	RedirectFixedPath:      true,
	HandleMethodNotAllowed: true,
}

// New creates and initializes a new Handler using default settings.
func New() *Handler {
	c := DefaultConfig
	return NewHandler(&c)
}

// NewHandler creates and initializes a new Handler with the given config.
func NewHandler(c *Config) *Handler {
	h := &Handler{
		prefix: c.Prefix,
		mw:     c.Middleware,
		routes: make(map[string]*route),
	}
	router := httprouter.New()
	router.RedirectTrailingSlash = c.RedirectTrailingSlash
	router.RedirectFixedPath = c.RedirectFixedPath
	router.HandleMethodNotAllowed = c.HandleMethodNotAllowed
	if c.NotFound != nil {
		router.NotFound = h.chain(c.NotFound.ServeHTTP)
	}
	if c.MethodNotAllowed != nil {
		router.MethodNotAllowed = h.chain(c.MethodNotAllowed.ServeHTTP)
	}
	router.PanicHandler = c.PanicHandler
	h.router = router
	return h
}

// DELETE is a shortcut for mux.Handle("DELETE", path, handle)
func (h *Handler) DELETE(pattern string, f http.HandlerFunc) { h.Handle("DELETE", pattern, f) }

// GET is a shortcut for mux.Handle("GET", path, handle)
func (h *Handler) GET(pattern string, f http.HandlerFunc) { h.Handle("GET", pattern, f) }

// HEAD is a shortcut for mux.Handle("HEAD", path, handle)
func (h *Handler) HEAD(pattern string, f http.HandlerFunc) { h.Handle("HEAD", pattern, f) }

// OPTIONS is a shortcut for mux.Handle("OPTIONS", path, handle)
func (h *Handler) OPTIONS(pattern string, f http.HandlerFunc) { h.Handle("OPTIONS", pattern, f) }

// PATCH is a shortcut for mux.Handle("PATCH", path, handle)
func (h *Handler) PATCH(pattern string, f http.HandlerFunc) { h.Handle("PATCH", pattern, f) }

// POST is a shortcut for mux.Handle("POST", path, handle)
func (h *Handler) POST(pattern string, f http.HandlerFunc) { h.Handle("POST", pattern, f) }

// PUT is a shortcut for mux.Handle("PUT", path, handle)
func (h *Handler) PUT(pattern string, f http.HandlerFunc) { h.Handle("PUT", pattern, f) }

// Handle registers a new request handler with the given method and pattern.
func (h *Handler) Handle(method, pattern string, f http.Handler) {
	h.HandleFunc(method, pattern, f.ServeHTTP)
}

// HandleFunc registers a new request handler with the given method and pattern.
func (h *Handler) HandleFunc(method, pattern string, f http.HandlerFunc) {
	p := path.Join(h.prefix, pattern)
	if len(pattern) > 1 && pattern[len(pattern)-1] == '/' {
		p += "/"
	}
	ff := h.wrap(f.ServeHTTP)
	h.routes[pattern] = &route{Method: method, Handler: f}
	h.router.Handle(method, p, ff)
}

func (h *Handler) wrap(next http.HandlerFunc) httprouter.Handle {
	next = h.chain(next)
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		if c, ok := r.Body.(*ctxBody); !ok {
			c = &ctxBody{
				ReadCloser: r.Body,
				ctx:        context.Background(),
			}
			r.Body = c
			defer func() {
				r.Body = c.ReadCloser
			}()
		}
		ctx := context.WithValue(Context(r), paramsID, p)
		SetContext(ctx, r)
		next(w, r)
	}
}

// ServeFiles serves files from the given file system root.
//
// The pattern must end with "/*filepath" to have files served from
// the local path /path/to/dir/*filepath.
//
// For example, if root is "/etc" and *filepath is "passwd", the local
// file "/etc/passwd" is served. Because an http.FileServer is used
// internally it's possible that http.NotFound is called instead
// of httpmux's NotFound handler.
//
// To use the operating system's file system implementation, use
// http.Dir: mux.ServeFiles("/src/*filepath", http.Dir("/var/www")).
func (h *Handler) ServeFiles(pattern string, root http.FileSystem) {
	if !strings.HasSuffix(pattern, "/*filepath") {
		panic("pattern must end with /*filepath in path '" + pattern + "'")
	}
	fs := http.FileServer(root)
	h.GET(pattern, func(w http.ResponseWriter, r *http.Request) {
		r.URL.Path = Params(r).ByName("filepath")
		fs.ServeHTTP(w, r)
	})
}

// Use appends the given middlewares to the internal chain.
func (h *Handler) Use(mw ...Middleware) {
	h.mw = append(h.mw, mw...)
}

// UseFunc appends the given middlewares to the internal chain.
func (h *Handler) UseFunc(mw ...MiddlewareFunc) {
	for _, f := range mw {
		ff := func(next http.Handler) http.Handler {
			return f(next.ServeHTTP)
		}
		h.mw = append(h.mw, ff)
	}
}

// Append appends a handler to this handler, under the given pattern. All
// middleware from the root tree propagates to the subtree. However,
// the subtree's configuration such as prefix and fallback handlers,
// like NotFound and MethodNotAllowed, are ignored by the root tree
// in favor of its own configuration.
func (h *Handler) Append(pattern string, subtree *Handler) {
	for pp, route := range subtree.routes {
		pp = path.Join(h.prefix, pattern, pp)
		f := subtree.chain(route.Handler)
		h.router.Handle(route.Method, pp, h.wrap(f))
	}
}

// ServeHTTP implements the http.Handler interface.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.router.ServeHTTP(w, r)
}

// ctxBody is the object we save in the request's Body field.
type ctxBody struct {
	io.ReadCloser
	ctx context.Context
}

// chain generates the middleware chain and appends f at the end.
func (h *Handler) chain(f http.HandlerFunc) http.HandlerFunc {
	var handler http.HandlerFunc
	for i := len(h.mw) - 1; i >= 0; i-- {
		handler = h.mw[i](f).ServeHTTP
		f = handler
	}
	return f
}

// Context returns the context from the given request, or a new
// context.Background if it doesn't exist.
func Context(r *http.Request) context.Context {
	if c, ok := r.Body.(*ctxBody); ok {
		return c.ctx
	}
	return context.Background()
}

// SetContext updates the given context in the request if the request
// has been previously instrumented by httpmux.
func SetContext(ctx context.Context, r *http.Request) {
	if c, ok := r.Body.(*ctxBody); ok {
		c.ctx = ctx
	}
}

type paramsType int

var paramsID paramsType

// Params returns the httprouter.Params from the request context.
func Params(r *http.Request) httprouter.Params {
	if p, ok := Context(r).Value(paramsID).(httprouter.Params); ok {
		return p
	}
	return httprouter.Params{}
}
<|endoftext|>


<commit_before>package doorman

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ory/ladon"
	manager "github.com/ory/ladon/manager/memory"
	log "github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"

	"github.com/leplatrem/iam/utilities"
)

// DefaultPoliciesFilename is the default policies filename.
const DefaultPoliciesFilename string = "policies.yaml"

const maxInt int64 = 1<<63 - 1

// Tags map tag names to principals.
type Tags map[string]Principals

// LadonDoorman is the backend in charge of checking requests against policies.
type LadonDoorman struct {
	policiesSources []string
	jwtIssuer       string
	ladons          map[string]ladon.Ladon
	tags            map[string]Tags
}

// Configuration represents the policies file content.
type Configuration struct {
	Audience string
	Tags     Tags
	Policies []*ladon.DefaultPolicy
}

// New instantiates a new doorman.
func New(policies []string, issuer string) (*LadonDoorman, error) {
	// If not specified, read default file in current directory `./policies.yaml`
	if len(policies) == 0 {
		here, _ := os.Getwd()
		filename := filepath.Join(here, DefaultPoliciesFilename)
		policies = []string{filename}
	}

	w := &LadonDoorman{
		policiesSources: policies,
		jwtIssuer:       issuer,
		ladons:          map[string]ladon.Ladon{},
		tags:            map[string]Tags{},
	}
	if err := w.loadPolicies(); err != nil {
		return nil, err
	}
	return w, nil
}

// JWTIssuer returns the URL of the JWT issuer (if configured)
func (doorman *LadonDoorman) JWTIssuer() string {
	return doorman.jwtIssuer
}

// IsAllowed is responsible for deciding if subject can perform action on a resource with a context.
func (doorman *LadonDoorman) IsAllowed(audience string, request *Request) bool {
	l, ok := doorman.ladons[audience]
	if !ok {
		return false
	}

	// Instantiate objects from the ladon API.
	context := ladon.Context{}
	for key, value := range request.Context {
		context[key] = value
	}

	r := &ladon.Request{
		Resource: request.Resource,
		Action:   request.Action,
		Context:  context,
	}

	// For each principal, use it as the subject and query ladon backend.
	for _, principal := range request.Principals {
		r.Subject = principal
		if err := l.IsAllowed(r); err == nil {
			return true
		}
	}
	return false
}

// ExpandPrincipals will match the tags defined in the configuration for this audience
// against each of the specified principals.
func (doorman *LadonDoorman) ExpandPrincipals(audience string, principals Principals) Principals {
	result := principals[:]

	tags, ok := doorman.tags[audience]
	if !ok {
		return result
	}

	for tag, members := range tags {
		for _, member := range members {
			for _, principal := range principals {
				if principal == member {
					prefixed := fmt.Sprintf("tag:%s", tag)
					result = append(result, prefixed)
				}
			}
		}
	}
	return result
}

// LoadPolicies (re)loads configuration and policies from the YAML files.
func (doorman *LadonDoorman) loadPolicies() error {
	// Clear every existing policy, and load new ones.
	for audience := range doorman.ladons {
		delete(doorman.ladons, audience)
	}
	// Load each configuration file.
	for _, filename := range doorman.policiesSources {
		log.Info("Load configuration ", filename)
		config, err := loadConfiguration(filename)
		if err != nil {
			return err
		}

		l := ladon.Ladon{
			Manager: manager.NewMemoryManager(),
			AuditLogger: newAuditLogger(),
		}
		for _, pol := range config.Policies {
			log.Info("Load policy ", pol.GetID()+": ", pol.GetDescription())
			err := l.Manager.Create(pol)
			if err != nil {
				return err
			}
		}
		_, exists := doorman.ladons[config.Audience]
		if exists {
			return fmt.Errorf("duplicated audience %q (filename %q)", config.Audience, filename)
		}
		doorman.ladons[config.Audience] = l
		doorman.tags[config.Audience] = config.Tags
	}
	return nil
}

func loadConfiguration(filename string) (*Configuration, error) {
	yamlFile, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	if len(yamlFile) == 0 {
		return nil, fmt.Errorf("empty file %q", filename)
	}
	// Ladon does not support un/marshaling YAML.
	// https://github.com/ory/ladon/issues/83
	var generic interface{}
	if err := yaml.Unmarshal(yamlFile, &generic); err != nil {
		return nil, err
	}
	asJSON := utilities.Yaml2JSON(generic)
	jsonData, err := json.Marshal(asJSON)
	if err != nil {
		return nil, err
	}

	var config Configuration
	if err := json.Unmarshal(jsonData, &config); err != nil {
		return nil, err
	}

	if config.Audience == "" {
		return nil, fmt.Errorf("empty audience in %q", filename)
	}

	if len(config.Policies) == 0 {
		log.Warningf("no policies found in %q", filename)
	}

	return &config, nil
}
<commit_msg>Reuse auditlogger instance<commit_after>package doorman

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ory/ladon"
	manager "github.com/ory/ladon/manager/memory"
	log "github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"

	"github.com/leplatrem/iam/utilities"
)

// DefaultPoliciesFilename is the default policies filename.
const DefaultPoliciesFilename string = "policies.yaml"

const maxInt int64 = 1<<63 - 1

// Tags map tag names to principals.
type Tags map[string]Principals

// LadonDoorman is the backend in charge of checking requests against policies.
type LadonDoorman struct {
	policiesSources []string
	jwtIssuer       string
	ladons          map[string]ladon.Ladon
	tags            map[string]Tags
	auditLogger     *auditLogger
}

// Configuration represents the policies file content.
type Configuration struct {
	Audience string
	Tags     Tags
	Policies []*ladon.DefaultPolicy
}

// New instantiates a new doorman.
func New(policies []string, issuer string) (*LadonDoorman, error) {
	// If not specified, read default file in current directory `./policies.yaml`
	if len(policies) == 0 {
		here, _ := os.Getwd()
		filename := filepath.Join(here, DefaultPoliciesFilename)
		policies = []string{filename}
	}

	w := &LadonDoorman{
		policiesSources: policies,
		jwtIssuer:       issuer,
		ladons:          map[string]ladon.Ladon{},
		tags:            map[string]Tags{},
		auditLogger:     newAuditLogger()
	}
	if err := w.loadPolicies(); err != nil {
		return nil, err
	}
	return w, nil
}

// JWTIssuer returns the URL of the JWT issuer (if configured)
func (doorman *LadonDoorman) JWTIssuer() string {
	return doorman.jwtIssuer
}

// IsAllowed is responsible for deciding if subject can perform action on a resource with a context.
func (doorman *LadonDoorman) IsAllowed(audience string, request *Request) bool {
	l, ok := doorman.ladons[audience]
	if !ok {
		return false
	}

	// Instantiate objects from the ladon API.
	context := ladon.Context{}
	for key, value := range request.Context {
		context[key] = value
	}

	r := &ladon.Request{
		Resource: request.Resource,
		Action:   request.Action,
		Context:  context,
	}

	// For each principal, use it as the subject and query ladon backend.
	for _, principal := range request.Principals {
		r.Subject = principal
		if err := l.IsAllowed(r); err == nil {
			return true
		}
	}
	return false
}

// ExpandPrincipals will match the tags defined in the configuration for this audience
// against each of the specified principals.
func (doorman *LadonDoorman) ExpandPrincipals(audience string, principals Principals) Principals {
	result := principals[:]

	tags, ok := doorman.tags[audience]
	if !ok {
		return result
	}

	for tag, members := range tags {
		for _, member := range members {
			for _, principal := range principals {
				if principal == member {
					prefixed := fmt.Sprintf("tag:%s", tag)
					result = append(result, prefixed)
				}
			}
		}
	}
	return result
}

// LoadPolicies (re)loads configuration and policies from the YAML files.
func (doorman *LadonDoorman) loadPolicies() error {
	// Clear every existing policy, and load new ones.
	for audience := range doorman.ladons {
		delete(doorman.ladons, audience)
	}
	// Load each configuration file.
	for _, filename := range doorman.policiesSources {
		log.Info("Load configuration ", filename)
		config, err := loadConfiguration(filename)
		if err != nil {
			return err
		}

		l := ladon.Ladon{
			Manager: manager.NewMemoryManager(),
			AuditLogger: doorman.auditLogger,
		}
		for _, pol := range config.Policies {
			log.Info("Load policy ", pol.GetID()+": ", pol.GetDescription())
			err := l.Manager.Create(pol)
			if err != nil {
				return err
			}
		}
		_, exists := doorman.ladons[config.Audience]
		if exists {
			return fmt.Errorf("duplicated audience %q (filename %q)", config.Audience, filename)
		}
		doorman.ladons[config.Audience] = l
		doorman.tags[config.Audience] = config.Tags
	}
	return nil
}

func loadConfiguration(filename string) (*Configuration, error) {
	yamlFile, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	if len(yamlFile) == 0 {
		return nil, fmt.Errorf("empty file %q", filename)
	}
	// Ladon does not support un/marshaling YAML.
	// https://github.com/ory/ladon/issues/83
	var generic interface{}
	if err := yaml.Unmarshal(yamlFile, &generic); err != nil {
		return nil, err
	}
	asJSON := utilities.Yaml2JSON(generic)
	jsonData, err := json.Marshal(asJSON)
	if err != nil {
		return nil, err
	}

	var config Configuration
	if err := json.Unmarshal(jsonData, &config); err != nil {
		return nil, err
	}

	if config.Audience == "" {
		return nil, fmt.Errorf("empty audience in %q", filename)
	}

	if len(config.Policies) == 0 {
		log.Warningf("no policies found in %q", filename)
	}

	return &config, nil
}
<|endoftext|>


<commit_before>package congress

import (
	"fmt"
	"github.com/sunlightlabs/go-sunlight/internal"
)

/**
 * Congress Legislator object. Issued for members of the Congress
 */
type Legislator struct {
	BioguideId  string `json:"bioguide_id"`
	Birthday    string `json:"birthday"`
	Chamber     string `json:"chamber"`
	ContactForm string `json:"contact_form"`
	CrpId       string `json:"crp_id"`
	District    int    `json:"district"`
	FacebookId  string `json:"facebook_id"`
	Fax         string `json:"fax"`

	FecIds     []string `json:"fec_ids"`
	FirstName  string   `json:"first_name"`
	MiddleName string   `json:"middle_name"`
	LastName   string   `json:"last_name"`
	Gender     string   `json:"gender"`

	GovtrackId string `json:"govtrack_id"`
	ICPSRId    int    `json:"icpsr_id"`
	InOffice   bool   `json:"in_office"`

	NameSuffix string `json:"name_suffix"`
	Nickname   string `json:"nickname"`
	OcEmail    string `json:"oc_email"`
	Office     string `json:"office"`
	Party      string `json:"party"`

	Phone     string `json:"phone"`
	State     string `json:"state"`
	StateName string `json:"state_name"`
	TermEnd   string `json:"term_end"`
	TermStart string `json:"term_start"`
	ThomasId  string `json:"thomas_id"`
	Title     string `json:"title"`

	TwitterId   string `json:"twitter_id"`
	VotesmartId int    `json:"votesmart_id"`
	Website     string `json:"website"`
	YoutubeId   string `json:"youtube_id"`
}

type LegislatorResult struct {
	Result
	Results []Legislator `json:"results"`
}

func (l Legislator) GetSponsoredBills() (*BillResult, error) {
	bills, err := BillSearch(map[string]string{
		"sponsor_id": l.BioguideId,
	})
	if err != nil {
		return nil, err
	}
	return bills, nil
}

func GetLegislators(criteria map[string]string) (*LegislatorResult, error) {
	l := LegislatorResult{}
	err := internal.GetURL(&l, congressRoot, criteria, "legislators")
	if err != nil {
		return nil, err
	}
	return &l, nil
}

func GetLegislatorsByLatLon(lat float32, lon float32) (*LegislatorResult, error) {
	var params = map[string]string{
		"latitude":  fmt.Sprintf("%f", lat),
		"longitude": fmt.Sprintf("%f", lon),
	}

	l := LegislatorResult{}
	err := internal.GetURL(&l, congressRoot, params, "legislators", "locate")
	if err != nil {
		return nil, err
	}
	return &l, nil
}
<commit_msg>Change out lat/lon to be a string?<commit_after>package congress

import (
	"github.com/sunlightlabs/go-sunlight/internal"
)

/**
 * Congress Legislator object. Issued for members of the Congress
 */
type Legislator struct {
	BioguideId  string `json:"bioguide_id"`
	Birthday    string `json:"birthday"`
	Chamber     string `json:"chamber"`
	ContactForm string `json:"contact_form"`
	CrpId       string `json:"crp_id"`
	District    int    `json:"district"`
	FacebookId  string `json:"facebook_id"`
	Fax         string `json:"fax"`

	FecIds     []string `json:"fec_ids"`
	FirstName  string   `json:"first_name"`
	MiddleName string   `json:"middle_name"`
	LastName   string   `json:"last_name"`
	Gender     string   `json:"gender"`

	GovtrackId string `json:"govtrack_id"`
	ICPSRId    int    `json:"icpsr_id"`
	InOffice   bool   `json:"in_office"`

	NameSuffix string `json:"name_suffix"`
	Nickname   string `json:"nickname"`
	OcEmail    string `json:"oc_email"`
	Office     string `json:"office"`
	Party      string `json:"party"`

	Phone     string `json:"phone"`
	State     string `json:"state"`
	StateName string `json:"state_name"`
	TermEnd   string `json:"term_end"`
	TermStart string `json:"term_start"`
	ThomasId  string `json:"thomas_id"`
	Title     string `json:"title"`

	TwitterId   string `json:"twitter_id"`
	VotesmartId int    `json:"votesmart_id"`
	Website     string `json:"website"`
	YoutubeId   string `json:"youtube_id"`
}

type LegislatorResult struct {
	Result
	Results []Legislator `json:"results"`
}

func (l Legislator) GetSponsoredBills() (*BillResult, error) {
	bills, err := BillSearch(map[string]string{
		"sponsor_id": l.BioguideId,
	})
	if err != nil {
		return nil, err
	}
	return bills, nil
}

func GetLegislators(criteria map[string]string) (*LegislatorResult, error) {
	l := LegislatorResult{}
	err := internal.GetURL(&l, congressRoot, criteria, "legislators")
	if err != nil {
		return nil, err
	}
	return &l, nil
}

func GetLegislatorsByLatLon(lat string, lon string, params map[string]string) (*LegislatorResult, error) {
	// was float32, seems to be a mistake.
	// var params = map[string]string{
	// 	"latitude":  fmt.Sprintf("%f", lat),
	// 	"longitude": fmt.Sprintf("%f", lon),
	// }

	params["latitude"] = lat
	params["longitude"] = lon

	l := LegislatorResult{}
	err := internal.GetURL(&l, congressRoot, params, "legislators", "locate")
	if err != nil {
		return nil, err
	}
	return &l, nil
}
<|endoftext|>


<commit_before>package consistent_hash

import (
	"testing"
	"fmt"
	"sort"
	"strconv"
	"hash/crc32"
	"math/rand"
	"encoding/base64"
)

func TestBuildCH(t *testing.T) {
	fmt.Printf("\n---\nTEST BUILD, INSERT AND FIND\n")
	mult := 100
	ch := NewConsistentHash(mult)
	items := []string{"127.0.0.1","17.0.1.1","1.1.0.1","27.99.0.111","64.0.8.8","8.8.8.8","10.100.0.100",
		"128.4.4.4","28.28.1.1","28.10.0.10","12.9.0.10","11.11.8.1","13.10.0.19","128.19.19.19"}
	for _,item := range items {
		insert_err := ch.Insert(item)
		if insert_err != nil {
			t.Errorf(insert_err.Error())
		}
	}
	// make sure the len is correct
	if len(ch.SumList) != (mult * len(items)) {
		e := fmt.Sprintf("SumList len should be %d, but is %d",(mult*len(items)),len(ch.SumList))
		t.Errorf(e)
	}
	// make sure the list is indeed sorted
	sl := make([]int,len(ch.SumList))
	for k,v := range ch.SumList {
		sl[k] = int(v)
	}
	sort.Ints(sl)
	for k,v := range sl {
		if v != int(ch.SumList[k]) {
			e := fmt.Sprintf("sorted list differs at position %d",k)
			t.Errorf(e)
		}
	}
	count := make(map [string] int)
	for _,sum := range ch.SumList {
		count[ch.Source[sum]]++
	}
	for k,c := range count {
		if c != mult {
			e := fmt.Sprintf("%s appears %d times, not % times",k,c,mult)
			t.Errorf(e)
		}
	}
	nearest_hash,nh_err := ch.Find("hello")
	if nh_err != nil || nearest_hash == "" {
		t.Errorf("err returned on finding nearest hash for hello")
	}

	// test distribution
	dist := make(map [string] int)
	total := 10000
	for j := 0; j < total; j++ {
		b64 := base64.StdEncoding.EncodeToString([]byte(strconv.Itoa(int(rand.Int31()))))
		nearest_hash,nh_err := ch.Find(b64)
		if nh_err != nil || nearest_hash == "" {
			e := fmt.Sprintf("err returned on finding nearest hash for %s",b64)
			t.Errorf(e)
		}
		dist[nearest_hash]++
	}
	for k,v := range dist {
		fmt.Printf("%s %d (%f pct) \n",k,v,(float64(v)/float64(total))*100)
	}
}

func TestEmptyCH(t *testing.T) {
	fmt.Printf("\n---\nTEST EMPTY\n")
	ch := NewConsistentHash(0)
	if ch != nil {
		t.Errorf("should return nil when mult factor 0")
	}
	ch = NewConsistentHash(1)
	if ch == nil {
		t.Errorf("should return non-nil when mult factor nonzero")
	}
	_,err := ch.Find("hello")
	if err == nil {
		t.Errorf("should not find anything on empty hash")
	}
}

func TestCollision(t *testing.T) {
	fmt.Printf("\n---\nTEST COLLISION\n")
	ch := NewConsistentHash(1)
	insert_err := ch.Insert("hello")
	if insert_err != nil {
		t.Errorf(insert_err.Error())
	}
	insert_err  = ch.Insert("hello")
	if insert_err == nil {
		t.Errorf("should have caused collision")
	}
}

func TestRemove(t *testing.T) {
	fmt.Printf("\n---\nTEST REMOVE\n")
	mult := 2
	ch := NewConsistentHash(mult)
	items := []string{"127.0.0.1","17.0.1.1","1.1.0.1","27.99.0.111","64.0.8.8","8.8.8.8","10.100.0.100",
		"128.4.4.4","28.28.1.1","28.10.0.10","12.9.0.10","11.11.8.1","13.10.0.19","128.19.19.19"}
	for _,item := range items {
		insert_err := ch.Insert(item)
		if insert_err != nil {
			t.Errorf(insert_err.Error())
		}
	}

	// remove something that isn't there
	_ = ch.Remove("hello")

	// make sure the len is correct
	if len(ch.SumList) != (mult * len(items)) {
		e := fmt.Sprintf("SumList len should be %d, but is %d",(mult*len(items)),len(ch.SumList))
		t.Errorf(e)
	}

	// remove something that is there
	_ = ch.Remove("28.28.1.1")

	// make sure the len is correct
	if len(ch.SumList) != (mult * (len(items)-1)) {
		e := fmt.Sprintf("SumList len should be %d, but is %d",(mult*len(items)),len(ch.SumList))
		t.Errorf(e)
	}

	sum1 := crc32.ChecksumIEEE([]byte(mult_elt("28.28.1.1",1)))
	sum2 := crc32.ChecksumIEEE([]byte(mult_elt("28.28.1.1",2)))
	for _,v := range ch.SumList {
		if v == sum1 || v == sum2 {
			t.Errorf("found element in SumList that should have been deleted")
		}
	}

	mult = 1
	ch = NewConsistentHash(mult)
	items = []string{"127.0.0.1","17.0.1.1","1.1.0.1","27.99.0.111","64.0.8.8","8.8.8.8","10.100.0.100",
		"128.4.4.4","28.28.1.1","28.10.0.10","12.9.0.10","11.11.8.1","13.10.0.19","128.19.19.19"}
	for _,item := range items {
		insert_err := ch.Insert(item)
		if insert_err != nil {
			t.Errorf(insert_err.Error())
		}
	}

	// find the target for a source. then remove that target. then reinsert it and make sure
	// source maps once to it once again
	nearest,err := ch.Find("helloooo")
	if err != nil {
		t.Errorf(err.Error())
	}
	fmt.Printf("initially source maps to target %s\n",nearest)
	_ = ch.Remove(nearest)
	nearest2,err2 := ch.Find("helloooo")
	if err2 != nil {
		t.Errorf(err2.Error())
	}
	fmt.Printf("after removal of %s, source now maps to %s\n",nearest,nearest2)
	insert_err := ch.Insert(nearest)
	if insert_err != nil {
		t.Errorf(insert_err.Error())
	}
	nearest3,err3 := ch.Find("helloooo")
	if err3 != nil {
		t.Errorf(err3.Error())
	}
	fmt.Printf("after reinsertion of %s, source now maps to %s\n",nearest,nearest3)
	if (nearest != nearest3) {
		t.Errorf("was not able to round trip removal and addition of target")
	}
}<commit_msg>go vet found bad printf<commit_after>package consistent_hash

import (
	"testing"
	"fmt"
	"sort"
	"strconv"
	"hash/crc32"
	"math/rand"
	"encoding/base64"
)

func TestBuildCH(t *testing.T) {
	fmt.Printf("\n---\nTEST BUILD, INSERT AND FIND\n")
	mult := 100
	ch := NewConsistentHash(mult)
	items := []string{"127.0.0.1","17.0.1.1","1.1.0.1","27.99.0.111","64.0.8.8","8.8.8.8","10.100.0.100",
		"128.4.4.4","28.28.1.1","28.10.0.10","12.9.0.10","11.11.8.1","13.10.0.19","128.19.19.19"}
	for _,item := range items {
		insert_err := ch.Insert(item)
		if insert_err != nil {
			t.Errorf(insert_err.Error())
		}
	}
	// make sure the len is correct
	if len(ch.SumList) != (mult * len(items)) {
		e := fmt.Sprintf("SumList len should be %d, but is %d",(mult*len(items)),len(ch.SumList))
		t.Errorf(e)
	}
	// make sure the list is indeed sorted
	sl := make([]int,len(ch.SumList))
	for k,v := range ch.SumList {
		sl[k] = int(v)
	}
	sort.Ints(sl)
	for k,v := range sl {
		if v != int(ch.SumList[k]) {
			e := fmt.Sprintf("sorted list differs at position %d",k)
			t.Errorf(e)
		}
	}
	count := make(map [string] int)
	for _,sum := range ch.SumList {
		count[ch.Source[sum]]++
	}
	for k,c := range count {
		if c != mult {
			e := fmt.Sprintf("%s appears %d times, not %d times",k,c,mult)
			t.Errorf(e)
		}
	}
	nearest_hash,nh_err := ch.Find("hello")
	if nh_err != nil || nearest_hash == "" {
		t.Errorf("err returned on finding nearest hash for hello")
	}

	// test distribution
	dist := make(map [string] int)
	total := 10000
	for j := 0; j < total; j++ {
		b64 := base64.StdEncoding.EncodeToString([]byte(strconv.Itoa(int(rand.Int31()))))
		nearest_hash,nh_err := ch.Find(b64)
		if nh_err != nil || nearest_hash == "" {
			e := fmt.Sprintf("err returned on finding nearest hash for %s",b64)
			t.Errorf(e)
		}
		dist[nearest_hash]++
	}
	for k,v := range dist {
		fmt.Printf("%s %d (%f pct) \n",k,v,(float64(v)/float64(total))*100)
	}
}

func TestEmptyCH(t *testing.T) {
	fmt.Printf("\n---\nTEST EMPTY\n")
	ch := NewConsistentHash(0)
	if ch != nil {
		t.Errorf("should return nil when mult factor 0")
	}
	ch = NewConsistentHash(1)
	if ch == nil {
		t.Errorf("should return non-nil when mult factor nonzero")
	}
	_,err := ch.Find("hello")
	if err == nil {
		t.Errorf("should not find anything on empty hash")
	}
}

func TestCollision(t *testing.T) {
	fmt.Printf("\n---\nTEST COLLISION\n")
	ch := NewConsistentHash(1)
	insert_err := ch.Insert("hello")
	if insert_err != nil {
		t.Errorf(insert_err.Error())
	}
	insert_err  = ch.Insert("hello")
	if insert_err == nil {
		t.Errorf("should have caused collision")
	}
}

func TestRemove(t *testing.T) {
	fmt.Printf("\n---\nTEST REMOVE\n")
	mult := 2
	ch := NewConsistentHash(mult)
	items := []string{"127.0.0.1","17.0.1.1","1.1.0.1","27.99.0.111","64.0.8.8","8.8.8.8","10.100.0.100",
		"128.4.4.4","28.28.1.1","28.10.0.10","12.9.0.10","11.11.8.1","13.10.0.19","128.19.19.19"}
	for _,item := range items {
		insert_err := ch.Insert(item)
		if insert_err != nil {
			t.Errorf(insert_err.Error())
		}
	}

	// remove something that isn't there
	_ = ch.Remove("hello")

	// make sure the len is correct
	if len(ch.SumList) != (mult * len(items)) {
		e := fmt.Sprintf("SumList len should be %d, but is %d",(mult*len(items)),len(ch.SumList))
		t.Errorf(e)
	}

	// remove something that is there
	_ = ch.Remove("28.28.1.1")

	// make sure the len is correct
	if len(ch.SumList) != (mult * (len(items)-1)) {
		e := fmt.Sprintf("SumList len should be %d, but is %d",(mult*len(items)),len(ch.SumList))
		t.Errorf(e)
	}

	sum1 := crc32.ChecksumIEEE([]byte(mult_elt("28.28.1.1",1)))
	sum2 := crc32.ChecksumIEEE([]byte(mult_elt("28.28.1.1",2)))
	for _,v := range ch.SumList {
		if v == sum1 || v == sum2 {
			t.Errorf("found element in SumList that should have been deleted")
		}
	}

	mult = 1
	ch = NewConsistentHash(mult)
	items = []string{"127.0.0.1","17.0.1.1","1.1.0.1","27.99.0.111","64.0.8.8","8.8.8.8","10.100.0.100",
		"128.4.4.4","28.28.1.1","28.10.0.10","12.9.0.10","11.11.8.1","13.10.0.19","128.19.19.19"}
	for _,item := range items {
		insert_err := ch.Insert(item)
		if insert_err != nil {
			t.Errorf(insert_err.Error())
		}
	}

	// find the target for a source. then remove that target. then reinsert it and make sure
	// source maps once to it once again
	nearest,err := ch.Find("helloooo")
	if err != nil {
		t.Errorf(err.Error())
	}
	fmt.Printf("initially source maps to target %s\n",nearest)
	_ = ch.Remove(nearest)
	nearest2,err2 := ch.Find("helloooo")
	if err2 != nil {
		t.Errorf(err2.Error())
	}
	fmt.Printf("after removal of %s, source now maps to %s\n",nearest,nearest2)
	insert_err := ch.Insert(nearest)
	if insert_err != nil {
		t.Errorf(insert_err.Error())
	}
	nearest3,err3 := ch.Find("helloooo")
	if err3 != nil {
		t.Errorf(err3.Error())
	}
	fmt.Printf("after reinsertion of %s, source now maps to %s\n",nearest,nearest3)
	if (nearest != nearest3) {
		t.Errorf("was not able to round trip removal and addition of target")
	}
}
<|endoftext|>


<commit_before>// Package hashmap implements a simple non-blocking (lock-free) hash map.
//
// The semantics of this hashmap are quite different from the go built-in.
// Aside from thread-safety, any values (including structs and slices) are
// allowed as keys, and a value of nil is indestinguishable from an element not
// being in the map.
package hashmap

import (
	a "sync/atomic"
	r "reflect"
)

var (
	defCap = uint32(32)
)

// A hashmap entry.
type entry struct {
	i uint32
	k interface{}
	v interface{}
}

type Hashmap struct {
	data []entry
	size uint32
	capc uint32
}

// Creates a hashmap with the default initial capacity (32). The hashmap will
// be grown to twice its size when the number of entries reaches 50% of the
// capacity.
func New() *Hashmap {
	return NewCap(defCap)
}

// Creates a hashmap with the specified initial capacity.
func NewCap(c uint32) *Hashmap {
	return &Hashmap{
		data: make([]entry, c),
		size: 0,
		capc: uint32(c),
	}
}

// Returns the capacity of this hashmap.
func (hm *Hashmap) Capacity() uint32 {
	return a.LoadUint32(&hm.capc)
}

// Returns the size of this hashmap. This is /not/ the number of elements
// stored - it is the number of keys allocated.
func (hm *Hashmap) Size() uint32 {
	return a.LoadUint32(&hm.size)
}

func (hm *Hashmap) Get(k interface{}) interface{} {
	// If the map changes capacity during the operation, we will detect
	// that and retry. Note that the only legal transformation of this
	// value is for it to increase (double), so we can easily check to see
	// if it has changed.
	c := hm.Capacity()

	// Guaranteed to be correct when c is correct.
	h := hash(k, c)

	// Since keys cannot be removed, we know that our target entry lies
	// somewhere 'after' the entry indexed by h, and that no nil keys lie
	// in between.
	for i := uint32(0); i < h+c; i++ {
		// Atomically fetch the data indexed by (i%c). Since there are
		// 16 bytes to fetch, this can't be done in a single atomic
		// operation; however, since a set key can never change, we
		// don't need perfect atomicity except when fetching the 64
		// bits of the value.

		// Load atomically.
		// ek := a.LoadUintptr((*uintptr)(u.Pointer(&hm.data[i%c].k)))
		// ev := a.LoadUintptr((*uintptr)(u.Pointer(&hm.data[i%c].v)))
		/*e := entry{
			k: nil,
			v: nil,
		}*/
		e := hm.data[i%c] // TODO atomic

		// Note that at this point, the data in e is incorrect if and
		// only if the capacity has changed (and the map has therefore
		// been expanded). We now check to see if that has happened,
		// and if so, abort.
		if c != hm.Capacity() {
			// This is the part that breaks our per-goroutine
			// progress guarantee.
			return hm.Get(k)
		}

		// The data in e may now be considered actionable. Since e is
		// stored in local memory, we don't have to worry about making
		// further operations atomic.

		// If e.k is nil, it's ok to claim that there's no such
		// available element.
		if e.k == nil { return nil }

		// Again, since we know that e.v matched e.k at some point,
		// it's ok to do this with no further checks.
		if r.DeepEqual(e.k, k) {
			return e.v
		}
	}

	// Really, this should never happen; it just means we've cycled through
	// the whole map, and none of the keys were nil
	return nil
}

// The key will be (shallowly) copied - the value will not.
func (hm *Hashmap) Set(k interface{}, v interface{}) {
	c := hm.Capacity()
	h := hash(k, c)
	for i := uint32(0); i < h+c; i++ {
		e := &hm.data[i%c]
		if e.k == nil {
			e.v = v
			e.k = k
			hm.size++
			// TODO Grow if necessary
			return
		}
		if r.DeepEqual(e.k, k) {
			e.v = v
			return
		}
	}
	panic("Hashmap full")
}

// Deletes the given key from the map, and returns true if it existed. Although
// this method is semantically equivalent to m.Set(k, nil), this method will
// not allocate another key if the key is not already in use, and should
// therefore be used instead.
func (hm *Hashmap) Del(k interface{}) bool {
	c := hm.Capacity()
	h := hash(k, c)
	for i := uint32(0); i < h+c; i++ {
		e := &hm.data[i%c]
		if r.DeepEqual(e.k, k) {
			//e.k = nil
			e.v = nil
			hm.size--
			return true
		}
	}
	return false
}

func (hm *Hashmap) Grow(c uint32) {
	// TODO
}

func hash(key interface{}, c uint32) uint32 {
	switch k := key.(type) {
	case int:
		return uint32(k) % c
	}
	return uint32(0)
}
<commit_msg>Fixing hm.size usage<commit_after>// Package hashmap implements a simple non-blocking (lock-free) hash map.
//
// The semantics of this hashmap are quite different from the go built-in.
// Aside from thread-safety, any values (including structs and slices) are
// allowed as keys, and a value of nil is indestinguishable from an element not
// being in the map.
package hashmap

import (
	a "sync/atomic"
	r "reflect"
)

var (
	defCap = uint32(32)
)

// A hashmap entry.
type entry struct {
	i uint32
	k interface{}
	v interface{}
}

type Hashmap struct {
	data []entry
	size uint32
	capc uint32
}

// Creates a hashmap with the default initial capacity (32). The hashmap will
// be grown to twice its size when the number of entries reaches 50% of the
// capacity.
func New() *Hashmap {
	return NewCap(defCap)
}

// Creates a hashmap with the specified initial capacity.
func NewCap(c uint32) *Hashmap {
	return &Hashmap{
		data: make([]entry, c),
		size: 0,
		capc: uint32(c),
	}
}

// Returns the capacity of this hashmap.
func (hm *Hashmap) Capacity() uint32 {
	return a.LoadUint32(&hm.capc)
}

// Returns the size of this hashmap. This is /not/ the number of elements
// stored - it is the number of keys allocated.
func (hm *Hashmap) Size() uint32 {
	return a.LoadUint32(&hm.size)
}

func (hm *Hashmap) Get(k interface{}) interface{} {
	// If the map changes capacity during the operation, we will detect
	// that and retry. Note that the only legal transformation of this
	// value is for it to increase (double), so we can easily check to see
	// if it has changed.
	c := hm.Capacity()

	// Guaranteed to be correct when c is correct.
	h := hash(k, c)

	// Since keys cannot be removed, we know that our target entry lies
	// somewhere 'after' the entry indexed by h, and that no nil keys lie
	// in between.
	for i := uint32(0); i < h+c; i++ {
		// Atomically fetch the data indexed by (i%c). Since there are
		// 16 bytes to fetch, this can't be done in a single atomic
		// operation; however, since a set key can never change, we
		// don't need perfect atomicity except when fetching the 64
		// bits of the value.

		// Load atomically.
		// ek := a.LoadUintptr((*uintptr)(u.Pointer(&hm.data[i%c].k)))
		// ev := a.LoadUintptr((*uintptr)(u.Pointer(&hm.data[i%c].v)))
		/*e := entry{
			k: nil,
			v: nil,
		}*/
		e := hm.data[i%c] // TODO atomic

		// Note that at this point, the data in e is incorrect if and
		// only if the capacity has changed (and the map has therefore
		// been expanded). We now check to see if that has happened,
		// and if so, abort.
		if c != hm.Capacity() {
			// This is the part that breaks our per-goroutine
			// progress guarantee.
			return hm.Get(k)
		}

		// The data in e may now be considered actionable. Since e is
		// stored in local memory, we don't have to worry about making
		// further operations atomic.

		// If e.k is nil, it's ok to claim that there's no such
		// available element.
		if e.k == nil { return nil }

		// Again, since we know that e.v matched e.k at some point,
		// it's ok to do this with no further checks.
		if r.DeepEqual(e.k, k) {
			return e.v
		}
	}

	// Really, this should never happen; it just means we've cycled through
	// the whole map, and none of the keys were nil
	return nil
}

// The key will be (shallowly) copied - the value will not.
func (hm *Hashmap) Set(k interface{}, v interface{}) {
	c := hm.Capacity()
	h := hash(k, c)
	for i := uint32(0); i < h+c; i++ {
		e := &hm.data[i%c]
		if e.k == nil {
			e.v = v
			e.k = k
			hm.size++
			// TODO Grow if necessary
			return
		}
		if r.DeepEqual(e.k, k) {
			e.v = v
			return
		}
	}
	panic("Hashmap full")
}

// Deletes the given key from the map, and returns true if it existed. Although
// this method is semantically equivalent to m.Set(k, nil), this method will
// not allocate another key if the key is not already in use, and should
// therefore be used instead.
func (hm *Hashmap) Del(k interface{}) bool {
	c := hm.Capacity()
	h := hash(k, c)
	for i := uint32(0); i < h+c; i++ {
		e := &hm.data[i%c]
		if r.DeepEqual(e.k, k) {
			//e.k = nil
			e.v = nil
			return true
		}
	}
	return false
}

func (hm *Hashmap) Grow(c uint32) {
	// TODO
}

func hash(key interface{}, c uint32) uint32 {
	switch k := key.(type) {
	case int:
		return uint32(k) % c
	}
	return uint32(0)
}
<|endoftext|>


<commit_before>// (c) 2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
	"fmt"

	"github.com/ava-labs/avalanchego/utils/metricutils"
	"github.com/ava-labs/avalanchego/utils/wrappers"
	"github.com/prometheus/client_golang/prometheus"
)

func newCallsMetric(namespace, name string) prometheus.Counter {
	return prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      fmt.Sprintf("%s_calls", name),
		Help:      fmt.Sprintf("Number of times %s has been called", name),
	})
}

type metrics struct {
	numBootstrappingCalls, numBootstrappedCalls, numCreateHandlersCalls,

	numTxRefreshes, numTxRefreshHits, numTxRefreshMisses prometheus.Counter

	apiRequestMetric metricutils.APIRequestMetrics
}

func (m *metrics) Initialize(
	namespace string,
	registerer prometheus.Registerer,
) error {
	m.numBootstrappingCalls = newCallsMetric(namespace, "bootstrapping")
	m.numBootstrappedCalls = newCallsMetric(namespace, "bootstrapped")
	m.numCreateHandlersCalls = newCallsMetric(namespace, "create_handlers")

	m.numTxRefreshes = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refreshes",
		Help:      "Number of times unique txs have been refreshed",
	})
	m.numTxRefreshHits = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_hits",
		Help:      "Number of times unique txs have not been unique, but were cached",
	})
	m.numTxRefreshMisses = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_misses",
		Help:      "Number of times unique txs have not been unique and weren't cached",
	})

	m.apiRequestMetric = metricutils.NewAPIMetrics(namespace)
	errs := wrappers.Errs{}
	errs.Add(
		registerer.Register(m.numBootstrappingCalls),
		registerer.Register(m.numBootstrappedCalls),
		registerer.Register(m.numCreateHandlersCalls),
		registerer.Register(m.numTxRefreshes),
		registerer.Register(m.numTxRefreshHits),
		registerer.Register(m.numTxRefreshMisses),

		m.apiRequestMetric.Register(registerer),
	)
	return errs.Err
}
<commit_msg>update<commit_after>// (c) 2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
	"fmt"

	"github.com/ava-labs/avalanchego/utils/metricutils"
	"github.com/ava-labs/avalanchego/utils/wrappers"
	"github.com/prometheus/client_golang/prometheus"
)

func newCallsMetric(namespace, name string) prometheus.Counter {
	return prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      fmt.Sprintf("%s_calls", name),
		Help:      fmt.Sprintf("Number of times %s has been called", name),
	})
}

type metrics struct {
	numBootstrappingCalls, numBootstrappedCalls, numCreateHandlersCalls,

	numTxRefreshes, numTxRefreshHits, numTxRefreshMisses prometheus.Counter

	apiRequestMetric metricutils.APIRequestMetrics
}

func (m *metrics) Initialize(
	namespace string,
	registerer prometheus.Registerer,
) error {
	m.numBootstrappingCalls = newCallsMetric(namespace, "bootstrapping")
	m.numBootstrappedCalls = newCallsMetric(namespace, "bootstrapped")
	m.numCreateHandlersCalls = newCallsMetric(namespace, "create_handlers")

	m.numTxRefreshes = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refreshes",
		Help:      "Number of times unique txs have been refreshed",
	})
	m.numTxRefreshHits = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_hits",
		Help:      "Number of times unique txs have not been unique, but were cached",
	})
	m.numTxRefreshMisses = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_misses",
		Help:      "Number of times unique txs have not been unique and weren't cached",
	})

	m.apiRequestMetric = metricutils.NewAPIMetrics(namespace)
	errs := wrappers.Errs{}
	errs.Add(
		registerer.Register(m.numBootstrappingCalls),
		registerer.Register(m.numBootstrappedCalls),
		registerer.Register(m.numCreateHandlersCalls),
		registerer.Register(m.numTxRefreshes),
		registerer.Register(m.numTxRefreshHits),
		registerer.Register(m.numTxRefreshMisses),

		m.apiRequestMetric.Register(registerer),
	)
	return errs.Err
}
<|endoftext|>


<commit_before>package genericsite

// Various elements of a webpage

import (
	"strings"
	"time"

	. "github.com/xyproto/browserspeak"
)

type Engine struct {
	state *UserState
}

func AddTopBox(page *Page, title, subtitle, searchURL, searchButtonText, backgroundTextureURL string, roundedLook bool, cs *ColorScheme) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}

	div := body.AddNewTag("div")
	div.AddAttr("id", "topbox")
	div.AddStyle("display", "block")
	div.AddStyle("width", "100%")
	div.AddStyle("margin", "0")
	div.AddStyle("padding", "0 0 1em 0")
	div.AddStyle("top", "0")
	div.AddStyle("left", "0")
	div.AddStyle("background-color", cs.Darkgray)
	div.AddStyle("position", "fixed")
	div.AddStyle("display", "block")

	titlebox := AddTitleBox(div, title, subtitle, cs)
	titlebox.AddAttr("id", "titlebox")
	titlebox.AddStyle("margin", "0 0 0 0")
	// Padding-top + height should be 5em, padding decides the position
	titlebox.AddStyle("padding", "1.8em 0 0 2.8em")
	titlebox.AddStyle("height", "3.2em")
	titlebox.AddStyle("width", "100%")
	titlebox.AddStyle("position", "fixed")
	titlebox.AddStyle("background-color", cs.Darkgray) // gray, could be a gradient
	titlebox.AddStyle("background", "url('"+backgroundTextureURL+"')")
	//titlebox.AddStyle("z-index", "2") // 2 is above the search box which is 1

	searchbox := AddSearchBox(titlebox, searchURL, searchButtonText, roundedLook)
	searchbox.AddAttr("id", "searchbox")
	searchbox.AddStyle("position", "relative")
	searchbox.AddStyle("float", "right")
	// The padding decides the position for this one
	searchbox.AddStyle("padding", "0 5em 0 0")
	searchbox.AddStyle("margin", "0")
	//searchbox.AddStyle("min-width", "10em")
	//searchbox.AddStyle("line-height", "10em")
	//searchbox.AddStyle("z-index", "1") // below the title

	return div, nil
}

// TODO: Place at the bottom of the content instead of at the bottom of the window
func AddFooter(page *Page, footerText, footerTextColor, footerColor string, elapsed time.Duration) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}
	div := body.AddNewTag("div")
	div.AddAttr("id", "notice")
	div.AddStyle("position", "fixed")
	div.AddStyle("bottom", "0")
	div.AddStyle("left", "0")
	div.AddStyle("width", "100%")
	div.AddStyle("display", "block")
	div.AddStyle("padding", "0")
	div.AddStyle("margin", "0")
	div.AddStyle("background-color", footerColor)
	div.AddStyle("font-size", "0.6em")
	div.AddStyle("text-align", "right")
	div.AddStyle("box-shadow", "1px -2px 3px rgba(0,0,0, .5)")

	innerdiv := div.AddNewTag("div")
	innerdiv.AddAttr("id", "innernotice")
	innerdiv.AddStyle("padding", "0 2em 0 0")
	innerdiv.AddStyle("margin", "0")
	innerdiv.AddStyle("color", footerTextColor)
	innerdiv.AddContent("Generated in " + elapsed.String() + " | " + footerText)

	return div, nil
}

func AddContent(page *Page, contentTitle, contentHTML string) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}

	div := body.AddNewTag("div")
	div.AddAttr("id", "content")
	div.AddStyle("z-index", "-1")
	div.AddStyle("color", "black") // content headline color
	div.AddStyle("min-height", "80%")
	div.AddStyle("min-width", "60%")
	div.AddStyle("float", "left")
	div.AddStyle("position", "relative")
	div.AddStyle("margin-left", "4%")
	div.AddStyle("margin-top", "9.5em")
	div.AddStyle("margin-right", "5em")
	div.AddStyle("padding-left", "4em")
	div.AddStyle("padding-right", "5em")
	div.AddStyle("padding-top", "1em")
	div.AddStyle("padding-bottom", "2em")
	div.AddStyle("background-color", "rgba(255,255,255,0.92)")                                                                               // light gray. Transparency with rgba() doesn't work in IE
	div.AddStyle("filter", "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#dcffffff', endColorstr='#dcffffff');") // for transparency in IE

	div.AddStyle("text-align", "justify")
	div.RoundedBox()

	h2 := div.AddNewTag("h2")
	h2.AddAttr("id", "textheader")
	h2.AddContent(contentTitle)
	h2.CustomSansSerif("Armata")

	p := div.AddNewTag("p")
	p.AddAttr("id", "textparagraph")
	p.AddStyle("margin-top", "0.5em")
	//p.CustomSansSerif("Junge")
	p.SansSerif()
	p.AddStyle("font-size", "1.0em")
	p.AddStyle("color", "black") // content text color
	p.AddContent(contentHTML)

	return div, nil
}

// Add a search box to the page, actionURL is the url to use as a get action,
// buttonText is the text on the search button
func AddSearchBox(tag *Tag, actionURL, buttonText string, roundedLook bool) *Tag {

	div := tag.AddNewTag("div")
	div.AddAttr("id", "searchboxdiv")
	div.AddStyle("text-align", "right")
	div.AddStyle("display", "inline-block")

	form := div.AddNewTag("form")
	form.AddAttr("id", "search")
	form.AddAttr("method", "get")
	form.AddAttr("action", actionURL)

	innerDiv := form.AddNewTag("div")
	innerDiv.AddAttr("id", "innerdiv")
	innerDiv.AddStyle("overflow", "hidden")
	innerDiv.AddStyle("padding-right", "0.5em")
	innerDiv.AddStyle("display", "inline-block")

	inputText := innerDiv.AddNewTag("input")
	inputText.AddAttr("id", "inputtext")
	inputText.AddAttr("name", "q")
	inputText.AddAttr("size", "25")
	inputText.AddStyle("padding", "0.25em")
	inputText.CustomSansSerif("Armata")
	inputText.AddStyle("background-color", "#f0f0f0")
	if roundedLook {
		inputText.RoundedBox()
	} else {
		inputText.AddStyle("border", "none")
	}

	// inputButton := form.AddNewTag("input")
	// inputButton.AddAttr("id", "inputbutton")
	// // The position is in the margin
	// inputButton.AddStyle("margin", "0.08em 0 0 0.4em")
	// inputButton.AddStyle("padding", "0.2em 0.6em 0.2em 0.6em")
	// inputButton.AddStyle("float", "right")
	// inputButton.AddAttr("type", "submit")
	// inputButton.AddAttr("value", buttonText)
	// inputButton.SansSerif()
	// //inputButton.AddStyle("overflow", "hidden")
	// if roundedLook {
	// 	inputButton.RoundedBox()
	// } else {
	// 	inputButton.AddStyle("border", "none")
	// }

	return div
}

func AddTitleBox(tag *Tag, title, subtitle string, cs *ColorScheme) *Tag {

	div := tag.AddNewTag("div")
	div.AddAttr("id", "titlebox")
	div.AddStyle("display", "block")
	div.AddStyle("position", "fixed")

	word1 := title
	word2 := ""
	if strings.Contains(title, " ") {
		word1 = strings.SplitN(title, " ", 2)[0]
		word2 = strings.SplitN(title, " ", 2)[1]
	}

	a := div.AddNewTag("a")
	a.AddAttr("id", "homelink")
	a.AddAttr("href", "/")
	a.AddStyle("text-decoration", "none")

	font0 := a.AddNewTag("div")
	font0.AddAttr("id", "whitetitle")
	font0.AddStyle("color", "white")
	//font0.CustomSansSerif("Armata")
	font0.SansSerif()
	font0.AddStyle("font-size", "2.0em")
	font0.AddStyle("font-weight", "bolder")
	font0.AddContent(word1)

	font1 := a.AddNewTag("div")
	font1.AddAttr("id", "bluetitle")
	font1.AddStyle("color", cs.nicecolor)
	//font1.CustomSansSerif("Armata")
	font1.SansSerif()
	font1.AddStyle("font-size", "2.0em")
	font1.AddStyle("font-weight", "bold")
	font1.AddStyle("overflow", "hidden")
	font1.AddContent(word2)

	font2 := a.AddNewTag("div")
	font2.AddAttr("id", "graytitle")
	font2.AddStyle("font-size", "0.5em")
	font2.AddStyle("color", "#707070")
	font2.CustomSansSerif("Armata")
	font2.AddStyle("font-size", "1.25em")
	font2.AddStyle("font-weight", "normal")
	font2.AddStyle("overflow", "hidden")
	font2.AddContent(subtitle)

	return div
}

// Takes a page and a colon-separated string slice of text:url, hiddenlinks is just a list of the url part
func AddMenuBox(page *Page, links, hiddenlinks []string, darkBackgroundTexture string) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}

	div := body.AddNewTag("div")
	div.AddAttr("id", "menubox")
	div.AddStyle("display", "block")
	div.AddStyle("width", "100%")
	div.AddStyle("margin", "0")
	div.AddStyle("padding", "0.1em 0 0.2em 0")
	div.AddStyle("position", "absolute")
	div.AddStyle("top", "5em")
	div.AddStyle("left", "0")
	div.AddStyle("background-color", "#0c0c0c") // dark gray, fallback
	div.AddStyle("background", "url('"+darkBackgroundTexture+"')")
	div.AddStyle("position", "fixed")
	div.AddStyle("box-shadow", "1px 3px 5px rgba(0,0,0, .8)")

	ul := div.AddNewTag("ul")
	ul.AddStyle("list-style-type", "none")
	ul.AddStyle("float", "left")
	ul.AddStyle("margin", "0")

	var a, li, sep *Tag
	var text, url, firstword string

	for i, text_url := range links {
		text, url = ColonSplit(text_url)

		firstword = text
		if strings.Contains(text, " ") {
			// Get the first word of the menu text
			firstword = strings.SplitN(text, " ", 2)[0]
		}

		li = ul.AddNewTag("li")

		// TODO: Make sure not duplicate ids are added for two menu entries named "Hi there" and "Hi you"
		li.AddAttr("id", "menu"+firstword)
		li.AddStyle("display", "inline")
		li.SansSerif()
		//li.CustomSansSerif("Armata")

		// Hide the menu items with matching urls
		for _, val := range hiddenlinks {
			if val == url {
				li.AddStyle("display", "none")
				break
			}
		}

		// For every element, but not the first one
		if i > 0 {
			// Insert a '|' character in a div
			sep = li.AddNewTag("div")
			sep.AddContent("|")
		}

		a = li.AddNewTag("a")
		a.AddAttr("class", "menulink")
		a.AddAttr("href", url)
		a.AddContent(text)
	}

	// For Login, Logout and Register
	// TODO: Implement this method too
	ul.AddLastContent("{{{yihaa}}}")

	sep.AddStyle("display", "inline")
	sep.AddStyle("color", "#a0a0a0")

	return div, nil
}
<commit_msg>Field rename<commit_after>package genericsite

// Various elements of a webpage

import (
	"strings"
	"time"

	. "github.com/xyproto/browserspeak"
)

type Engine struct {
	state *UserState
}

func AddTopBox(page *Page, title, subtitle, searchURL, searchButtonText, backgroundTextureURL string, roundedLook bool, cs *ColorScheme) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}

	div := body.AddNewTag("div")
	div.AddAttr("id", "topbox")
	div.AddStyle("display", "block")
	div.AddStyle("width", "100%")
	div.AddStyle("margin", "0")
	div.AddStyle("padding", "0 0 1em 0")
	div.AddStyle("top", "0")
	div.AddStyle("left", "0")
	div.AddStyle("background-color", cs.Darkgray)
	div.AddStyle("position", "fixed")
	div.AddStyle("display", "block")

	titlebox := AddTitleBox(div, title, subtitle, cs)
	titlebox.AddAttr("id", "titlebox")
	titlebox.AddStyle("margin", "0 0 0 0")
	// Padding-top + height should be 5em, padding decides the position
	titlebox.AddStyle("padding", "1.8em 0 0 2.8em")
	titlebox.AddStyle("height", "3.2em")
	titlebox.AddStyle("width", "100%")
	titlebox.AddStyle("position", "fixed")
	titlebox.AddStyle("background-color", cs.Darkgray) // gray, could be a gradient
	titlebox.AddStyle("background", "url('"+backgroundTextureURL+"')")
	//titlebox.AddStyle("z-index", "2") // 2 is above the search box which is 1

	searchbox := AddSearchBox(titlebox, searchURL, searchButtonText, roundedLook)
	searchbox.AddAttr("id", "searchbox")
	searchbox.AddStyle("position", "relative")
	searchbox.AddStyle("float", "right")
	// The padding decides the position for this one
	searchbox.AddStyle("padding", "0 5em 0 0")
	searchbox.AddStyle("margin", "0")
	//searchbox.AddStyle("min-width", "10em")
	//searchbox.AddStyle("line-height", "10em")
	//searchbox.AddStyle("z-index", "1") // below the title

	return div, nil
}

// TODO: Place at the bottom of the content instead of at the bottom of the window
func AddFooter(page *Page, footerText, footerTextColor, footerColor string, elapsed time.Duration) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}
	div := body.AddNewTag("div")
	div.AddAttr("id", "notice")
	div.AddStyle("position", "fixed")
	div.AddStyle("bottom", "0")
	div.AddStyle("left", "0")
	div.AddStyle("width", "100%")
	div.AddStyle("display", "block")
	div.AddStyle("padding", "0")
	div.AddStyle("margin", "0")
	div.AddStyle("background-color", footerColor)
	div.AddStyle("font-size", "0.6em")
	div.AddStyle("text-align", "right")
	div.AddStyle("box-shadow", "1px -2px 3px rgba(0,0,0, .5)")

	innerdiv := div.AddNewTag("div")
	innerdiv.AddAttr("id", "innernotice")
	innerdiv.AddStyle("padding", "0 2em 0 0")
	innerdiv.AddStyle("margin", "0")
	innerdiv.AddStyle("color", footerTextColor)
	innerdiv.AddContent("Generated in " + elapsed.String() + " | " + footerText)

	return div, nil
}

func AddContent(page *Page, contentTitle, contentHTML string) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}

	div := body.AddNewTag("div")
	div.AddAttr("id", "content")
	div.AddStyle("z-index", "-1")
	div.AddStyle("color", "black") // content headline color
	div.AddStyle("min-height", "80%")
	div.AddStyle("min-width", "60%")
	div.AddStyle("float", "left")
	div.AddStyle("position", "relative")
	div.AddStyle("margin-left", "4%")
	div.AddStyle("margin-top", "9.5em")
	div.AddStyle("margin-right", "5em")
	div.AddStyle("padding-left", "4em")
	div.AddStyle("padding-right", "5em")
	div.AddStyle("padding-top", "1em")
	div.AddStyle("padding-bottom", "2em")
	div.AddStyle("background-color", "rgba(255,255,255,0.92)")                                                                               // light gray. Transparency with rgba() doesn't work in IE
	div.AddStyle("filter", "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#dcffffff', endColorstr='#dcffffff');") // for transparency in IE

	div.AddStyle("text-align", "justify")
	div.RoundedBox()

	h2 := div.AddNewTag("h2")
	h2.AddAttr("id", "textheader")
	h2.AddContent(contentTitle)
	h2.CustomSansSerif("Armata")

	p := div.AddNewTag("p")
	p.AddAttr("id", "textparagraph")
	p.AddStyle("margin-top", "0.5em")
	//p.CustomSansSerif("Junge")
	p.SansSerif()
	p.AddStyle("font-size", "1.0em")
	p.AddStyle("color", "black") // content text color
	p.AddContent(contentHTML)

	return div, nil
}

// Add a search box to the page, actionURL is the url to use as a get action,
// buttonText is the text on the search button
func AddSearchBox(tag *Tag, actionURL, buttonText string, roundedLook bool) *Tag {

	div := tag.AddNewTag("div")
	div.AddAttr("id", "searchboxdiv")
	div.AddStyle("text-align", "right")
	div.AddStyle("display", "inline-block")

	form := div.AddNewTag("form")
	form.AddAttr("id", "search")
	form.AddAttr("method", "get")
	form.AddAttr("action", actionURL)

	innerDiv := form.AddNewTag("div")
	innerDiv.AddAttr("id", "innerdiv")
	innerDiv.AddStyle("overflow", "hidden")
	innerDiv.AddStyle("padding-right", "0.5em")
	innerDiv.AddStyle("display", "inline-block")

	inputText := innerDiv.AddNewTag("input")
	inputText.AddAttr("id", "inputtext")
	inputText.AddAttr("name", "q")
	inputText.AddAttr("size", "25")
	inputText.AddStyle("padding", "0.25em")
	inputText.CustomSansSerif("Armata")
	inputText.AddStyle("background-color", "#f0f0f0")
	if roundedLook {
		inputText.RoundedBox()
	} else {
		inputText.AddStyle("border", "none")
	}

	// inputButton := form.AddNewTag("input")
	// inputButton.AddAttr("id", "inputbutton")
	// // The position is in the margin
	// inputButton.AddStyle("margin", "0.08em 0 0 0.4em")
	// inputButton.AddStyle("padding", "0.2em 0.6em 0.2em 0.6em")
	// inputButton.AddStyle("float", "right")
	// inputButton.AddAttr("type", "submit")
	// inputButton.AddAttr("value", buttonText)
	// inputButton.SansSerif()
	// //inputButton.AddStyle("overflow", "hidden")
	// if roundedLook {
	// 	inputButton.RoundedBox()
	// } else {
	// 	inputButton.AddStyle("border", "none")
	// }

	return div
}

func AddTitleBox(tag *Tag, title, subtitle string, cs *ColorScheme) *Tag {

	div := tag.AddNewTag("div")
	div.AddAttr("id", "titlebox")
	div.AddStyle("display", "block")
	div.AddStyle("position", "fixed")

	word1 := title
	word2 := ""
	if strings.Contains(title, " ") {
		word1 = strings.SplitN(title, " ", 2)[0]
		word2 = strings.SplitN(title, " ", 2)[1]
	}

	a := div.AddNewTag("a")
	a.AddAttr("id", "homelink")
	a.AddAttr("href", "/")
	a.AddStyle("text-decoration", "none")

	font0 := a.AddNewTag("div")
	font0.AddAttr("id", "whitetitle")
	font0.AddStyle("color", "white")
	//font0.CustomSansSerif("Armata")
	font0.SansSerif()
	font0.AddStyle("font-size", "2.0em")
	font0.AddStyle("font-weight", "bolder")
	font0.AddContent(word1)

	font1 := a.AddNewTag("div")
	font1.AddAttr("id", "bluetitle")
	font1.AddStyle("color", cs.Nicecolor)
	//font1.CustomSansSerif("Armata")
	font1.SansSerif()
	font1.AddStyle("font-size", "2.0em")
	font1.AddStyle("font-weight", "bold")
	font1.AddStyle("overflow", "hidden")
	font1.AddContent(word2)

	font2 := a.AddNewTag("div")
	font2.AddAttr("id", "graytitle")
	font2.AddStyle("font-size", "0.5em")
	font2.AddStyle("color", "#707070")
	font2.CustomSansSerif("Armata")
	font2.AddStyle("font-size", "1.25em")
	font2.AddStyle("font-weight", "normal")
	font2.AddStyle("overflow", "hidden")
	font2.AddContent(subtitle)

	return div
}

// Takes a page and a colon-separated string slice of text:url, hiddenlinks is just a list of the url part
func AddMenuBox(page *Page, links, hiddenlinks []string, darkBackgroundTexture string) (*Tag, error) {
	body, err := page.GetTag("body")
	if err != nil {
		return nil, err
	}

	div := body.AddNewTag("div")
	div.AddAttr("id", "menubox")
	div.AddStyle("display", "block")
	div.AddStyle("width", "100%")
	div.AddStyle("margin", "0")
	div.AddStyle("padding", "0.1em 0 0.2em 0")
	div.AddStyle("position", "absolute")
	div.AddStyle("top", "5em")
	div.AddStyle("left", "0")
	div.AddStyle("background-color", "#0c0c0c") // dark gray, fallback
	div.AddStyle("background", "url('"+darkBackgroundTexture+"')")
	div.AddStyle("position", "fixed")
	div.AddStyle("box-shadow", "1px 3px 5px rgba(0,0,0, .8)")

	ul := div.AddNewTag("ul")
	ul.AddStyle("list-style-type", "none")
	ul.AddStyle("float", "left")
	ul.AddStyle("margin", "0")

	var a, li, sep *Tag
	var text, url, firstword string

	for i, text_url := range links {
		text, url = ColonSplit(text_url)

		firstword = text
		if strings.Contains(text, " ") {
			// Get the first word of the menu text
			firstword = strings.SplitN(text, " ", 2)[0]
		}

		li = ul.AddNewTag("li")

		// TODO: Make sure not duplicate ids are added for two menu entries named "Hi there" and "Hi you"
		li.AddAttr("id", "menu"+firstword)
		li.AddStyle("display", "inline")
		li.SansSerif()
		//li.CustomSansSerif("Armata")

		// Hide the menu items with matching urls
		for _, val := range hiddenlinks {
			if val == url {
				li.AddStyle("display", "none")
				break
			}
		}

		// For every element, but not the first one
		if i > 0 {
			// Insert a '|' character in a div
			sep = li.AddNewTag("div")
			sep.AddContent("|")
		}

		a = li.AddNewTag("a")
		a.AddAttr("class", "menulink")
		a.AddAttr("href", url)
		a.AddContent(text)
	}

	// For Login, Logout and Register
	// TODO: Implement this method too
	ul.AddLastContent("{{{yihaa}}}")

	sep.AddStyle("display", "inline")
	sep.AddStyle("color", "#a0a0a0")

	return div, nil
}
<|endoftext|>


<commit_before>package restpc

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func Test_NewError_Twice(t *testing.T) {
	err := NewError(InvalidArgument, "something is missing", nil)
	assert.Equal(t, "something is missing", err.Message())
	assert.Equal(t, "something is missing", err.Error())
	assert.Equal(t, InvalidArgument, err.Code())

	err = NewError(Unavailable, "not sure what", err)
	assert.Equal(t, "something is missing", err.Message())
	assert.Equal(t, "something is missing", err.Error())
	assert.Equal(t, InvalidArgument, err.Code())
}

func unimplementedHandler(req Request) (*Response, error) {
	return nil, NewError(
		Unimplemented,
		"we didn't implement this",
		fmt.Errorf("just an unexposed message"),
	).Add("name", "June The Girl")
}

func TestErrorFull(t *testing.T) {
	handlerName := "unimplementedHandler"

	origErrorDispatcher := errorDispatcher
	defer func() {
		errorDispatcher = origErrorDispatcher
	}()
	var rpcErr RPCError
	var request Request
	errorDispatcher = func(requestArg Request, rpcErrArg RPCError) {
		rpcErr = rpcErrArg
		request = requestArg
	}
	handlerFunc := TranslateHandler(unimplementedHandler)
	w := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "", nil)
	handlerFunc(w, r)
	assert.Equal(t, http.StatusNotImplemented, w.Code)
	time.Sleep(500 * time.Millisecond)
	if rpcErr == nil {
		panic("rpcErr == nil")
	}
	if !strings.HasSuffix(request.HandlerName(), "."+handlerName) {
		t.Errorf("request.HandlerName()=%v", request.HandlerName())
		return
	}
	handlerNameFull := request.HandlerName()
	assert.Equal(t, Unimplemented, rpcErr.Code())
	assert.Equal(t, "we didn't implement this", rpcErr.Error())
	assert.Equal(t, "we didn't implement this", rpcErr.Message())
	assert.Equal(t, "just an unexposed message", rpcErr.Private().Error())
	assert.Equal(t, "June The Girl", rpcErr.Details()["name"])
	{
		tb := rpcErr.Traceback("")
		assert.Equal(t, 6, len(tb.Callers()))
		assert.Equal(t, 6, len(tb.Records()))
	}
	{
		tb := rpcErr.Traceback(handlerNameFull)
		assert.Equal(t, 6, len(tb.Callers()))
		records := tb.Records()
		if len(records) != 1 {
			for _, record := range records {
				t.Log(record)
			}
			t.Errorf("len(records) = %v", len(records))
			return
		}
		record := records[0]
		if !strings.HasSuffix(record.File(), "/error_test.go") {
			t.Errorf("record.File()=%v", record.File())
		}
		assert.Equal(t, handlerNameFull, record.Function())
		assert.Equal(t, handlerName, record.FunctionLocal())
		assert.Equal(t, 31, record.Line())
		mapRecords := tb.MapRecords()
		if len(mapRecords) != 1 {
			t.Errorf("len(mapRecords) = %v", len(mapRecords))
			return
		}
		mapRecord := mapRecords[0]
		assert.Equal(t, record.File(), mapRecord["file"])
		assert.Equal(t, record.Function(), mapRecord["function"])
		assert.Equal(t, record.FunctionLocal(), mapRecord["functionLocal"])
		assert.Equal(t, record.Line(), mapRecord["line"])
	}
}
<commit_msg>error_test.go: avoid multi-line NewError block which gives different traceback lines in different go versions<commit_after>package restpc

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func Test_NewError_Twice(t *testing.T) {
	err := NewError(InvalidArgument, "something is missing", nil)
	assert.Equal(t, "something is missing", err.Message())
	assert.Equal(t, "something is missing", err.Error())
	assert.Equal(t, InvalidArgument, err.Code())

	err = NewError(Unavailable, "not sure what", err)
	assert.Equal(t, "something is missing", err.Message())
	assert.Equal(t, "something is missing", err.Error())
	assert.Equal(t, InvalidArgument, err.Code())
}

func unimplementedHandler(req Request) (*Response, error) {
	err := fmt.Errorf("just an unexposed message")
	return nil, NewError(Unimplemented, "we didn't implement this", err).Add("name", "June The Girl")
}

func TestErrorFull(t *testing.T) {
	handlerName := "unimplementedHandler"

	origErrorDispatcher := errorDispatcher
	defer func() {
		errorDispatcher = origErrorDispatcher
	}()
	var rpcErr RPCError
	var request Request
	errorDispatcher = func(requestArg Request, rpcErrArg RPCError) {
		rpcErr = rpcErrArg
		request = requestArg
	}
	handlerFunc := TranslateHandler(unimplementedHandler)
	w := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "", nil)
	handlerFunc(w, r)
	assert.Equal(t, http.StatusNotImplemented, w.Code)
	time.Sleep(500 * time.Millisecond)
	if rpcErr == nil {
		panic("rpcErr == nil")
	}
	if !strings.HasSuffix(request.HandlerName(), "."+handlerName) {
		t.Errorf("request.HandlerName()=%v", request.HandlerName())
		return
	}
	handlerNameFull := request.HandlerName()
	assert.Equal(t, Unimplemented, rpcErr.Code())
	assert.Equal(t, "we didn't implement this", rpcErr.Error())
	assert.Equal(t, "we didn't implement this", rpcErr.Message())
	assert.Equal(t, "just an unexposed message", rpcErr.Private().Error())
	assert.Equal(t, "June The Girl", rpcErr.Details()["name"])
	{
		tb := rpcErr.Traceback("")
		assert.Equal(t, 6, len(tb.Callers()))
		assert.Equal(t, 6, len(tb.Records()))
	}
	{
		tb := rpcErr.Traceback(handlerNameFull)
		assert.Equal(t, 6, len(tb.Callers()))
		records := tb.Records()
		if len(records) != 1 {
			for _, record := range records {
				t.Log(record)
			}
			t.Errorf("len(records) = %v", len(records))
			return
		}
		record := records[0]
		if !strings.HasSuffix(record.File(), "/error_test.go") {
			t.Errorf("record.File()=%v", record.File())
		}
		assert.Equal(t, handlerNameFull, record.Function())
		assert.Equal(t, handlerName, record.FunctionLocal())
		assert.Equal(t, 28, record.Line())
		mapRecords := tb.MapRecords()
		if len(mapRecords) != 1 {
			t.Errorf("len(mapRecords) = %v", len(mapRecords))
			return
		}
		mapRecord := mapRecords[0]
		assert.Equal(t, record.File(), mapRecord["file"])
		assert.Equal(t, record.Function(), mapRecord["function"])
		assert.Equal(t, record.FunctionLocal(), mapRecord["functionLocal"])
		assert.Equal(t, record.Line(), mapRecord["line"])
	}
}
<|endoftext|>


<commit_before>package hateoas

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

func Handle(apiPath string, rh ResourceHandler) error {
	var err error

	location := fmt.Sprint(apiPath, "/", rh.ResourceName(), "/")
	rootPathLength := len(location)

	http.HandleFunc(location, errorWrapper(rootPathLength, rh))

	return err
}

func errorWrapper(rootPathLength int, rh ResourceHandler) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var err *Error

		id := r.URL.Path[rootPathLength:]

		if strings.Contains(id, "/") {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be fetched."
			err.DeveloperMessage = "Request for resource is incorrect. More than one path parameters (ID) is not supported for a resource."
		}

		if err == nil {
			err = handle(w, r, rh, id)
		}

		if err != nil {
			w.WriteHeader(err.Status)

			errJson, _ := json.MarshalIndent(err, "", "    ")
			fmt.Fprint(w, string(errJson))
		}
	}
}

func handle(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
	var err *Error

    //TODO: remove this block
	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

    fmt.Println("Request received", r.RequestURI)

	switch r.Method {
	case "GET":
		if id == "" {
			fmt.Println("GET request (all)")
            err = handleGetAll(w, r, rh)
		} else {
			fmt.Println("GET request (single resource)", id)
            err = handleGetOne(w, r, rh, id)
		}
		break

	case "POST":
		if id == "" {
			fmt.Println("POST request (create)")
            err = handleCreate(w, r, rh)
		} else {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be created."
			err.DeveloperMessage = "Request for resource is incorrect. No path parameters are needed for creating a resource."
		}
		break

	case "PUT":
		if id == "" {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be updated."
			err.DeveloperMessage = "Request for resource is incorrect. A path parameter (ID) is needed for updating a resource."
		} else {
			fmt.Println("PUT request (update resource)", id)
            err = handleUpdate(w, r, rh, id)
		}
		break

	case "DELETE":
		if id == "" {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be deleted."
			err.DeveloperMessage = "Request for resource is incorrect. A path parameter (ID) is needed for deleting a resource."
		} else {
			fmt.Println("DELETE request (delete resource)", id)
            err = handleDelete(w, r, rh, id)
		}
		break
	}

	return err
}

func handleCreate(w http.ResponseWriter, r *http.Request, rh ResourceHandler) *Error {
    var err *Error

    err = &Error{}
    err.Status = 500
    err.Code = 1
    err.Message = "Create is under construction. Please check again later."
    err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

    return err
}

func handleUpdate(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
    var err *Error

    err = &Error{}
    err.Status = 500
    err.Code = 1
    err.Message = "Update is under construction. Please check again later."
    err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

    return err
}

func handleDelete(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
    var err *Error

    err = &Error{}
    err.Status = 500
    err.Code = 1
    err.Message = "Delete is under construction. Please check again later."
    err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

    return err
}

func handleGetAll(w http.ResponseWriter, r *http.Request, rh ResourceHandler) *Error {
    var err *Error

    err = &Error{}
    err.Status = 500
    err.Code = 1
    err.Message = "Get all is under construction. Please check again later."
    err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

    return err
}

func handleGetOne(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
    var err *Error

    err = &Error{}
    err.Status = 500
    err.Code = 1
    err.Message = "Get one is under construction. Please check again later."
    err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

    return err
}<commit_msg>fmt all<commit_after>package hateoas

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

func Handle(apiPath string, rh ResourceHandler) error {
	var err error

	location := fmt.Sprint(apiPath, "/", rh.ResourceName(), "/")
	rootPathLength := len(location)

	http.HandleFunc(location, errorWrapper(rootPathLength, rh))

	return err
}

func errorWrapper(rootPathLength int, rh ResourceHandler) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var err *Error

		id := r.URL.Path[rootPathLength:]

		if strings.Contains(id, "/") {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be fetched."
			err.DeveloperMessage = "Request for resource is incorrect. More than one path parameters (ID) is not supported for a resource."
		}

		if err == nil {
			err = handle(w, r, rh, id)
		}

		if err != nil {
			w.WriteHeader(err.Status)

			errJson, _ := json.MarshalIndent(err, "", "    ")
			fmt.Fprint(w, string(errJson))
		}
	}
}

func handle(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
	var err *Error

	//TODO: remove this block
	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

	fmt.Println("Request received", r.RequestURI)

	switch r.Method {
	case "GET":
		if id == "" {
			fmt.Println("GET request (all)")
			err = handleGetAll(w, r, rh)
		} else {
			fmt.Println("GET request (single resource)", id)
			err = handleGetOne(w, r, rh, id)
		}
		break

	case "POST":
		if id == "" {
			fmt.Println("POST request (create)")
			err = handleCreate(w, r, rh)
		} else {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be created."
			err.DeveloperMessage = "Request for resource is incorrect. No path parameters are needed for creating a resource."
		}
		break

	case "PUT":
		if id == "" {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be updated."
			err.DeveloperMessage = "Request for resource is incorrect. A path parameter (ID) is needed for updating a resource."
		} else {
			fmt.Println("PUT request (update resource)", id)
			err = handleUpdate(w, r, rh, id)
		}
		break

	case "DELETE":
		if id == "" {
			err = &Error{}
			err.Status = 500
			err.Code = 1
			err.Message = "Invalid request. Resource could not be deleted."
			err.DeveloperMessage = "Request for resource is incorrect. A path parameter (ID) is needed for deleting a resource."
		} else {
			fmt.Println("DELETE request (delete resource)", id)
			err = handleDelete(w, r, rh, id)
		}
		break
	}

	return err
}

func handleCreate(w http.ResponseWriter, r *http.Request, rh ResourceHandler) *Error {
	var err *Error

	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Create is under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

	return err
}

func handleUpdate(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
	var err *Error

	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Update is under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

	return err
}

func handleDelete(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
	var err *Error

	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Delete is under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

	return err
}

func handleGetAll(w http.ResponseWriter, r *http.Request, rh ResourceHandler) *Error {
	var err *Error

	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Get all is under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

	return err
}

func handleGetOne(w http.ResponseWriter, r *http.Request, rh ResourceHandler, id string) *Error {
	var err *Error

	err = &Error{}
	err.Status = 500
	err.Code = 1
	err.Message = "Get one is under construction. Please check again later."
	err.DeveloperMessage = "API is not ready yet. Please contact tomg@leoride.com for more information."

	return err
}
<|endoftext|>


<commit_before>package gomodel

import (
	"database/sql"
	"testing"

	"github.com/cosiner/gohper/errors"
	"github.com/cosiner/gohper/testing2"
)

func TestErrDuplicateKey(t *testing.T) {
	tt := testing2.Wrap(t)
	err := errors.Err(`Duplicate entry '14d1b6c34a001-1648e0754a001' for key 'PRIMARY'`) // for combined primary key
	ErrForDuplicateKey(err, func(key string) error {
		tt.Eq(key, "PRIMARY")
		return nil
	})
}

func TestErrForeignKey(t *testing.T) {
	tt := testing2.Wrap(t)
	err := errors.Err("CONSTRAINT `article_vote_ibfk_1` FOREIGN KEY (`article_id`) REFERENCES `article` (`article_id`)")
	ErrForForeignKey(err, func(key string) error {
		tt.Eq(key, "article_id")
		return nil
	})
}

func TestErrNoRows(t *testing.T) {
	tt := testing2.Wrap(t)
	err := errors.Err("Error No Rows")

	tt.Eq(err, ErrForNoRows(sql.ErrNoRows, err))
}
<commit_msg>fixed error test<commit_after>package gomodel

import (
	"testing"

	"github.com/cosiner/gohper/errors"
	"github.com/cosiner/gohper/testing2"
)

func TestError(t *testing.T) {
	tt := testing2.Wrap(t)
	err := errors.Err(`Duplicate entry '14d1b6c34a001-1648e0754a001' for key 'PRIMARY'`) // for combined primary key
	tt.Eq(PRIMARY_KEY, Error.DuplicateKey(err))

	err = errors.Err("CONSTRAINT `article_vote_ibfk_1` FOREIGN KEY (`article_id`) REFERENCES `article` (`article_id`)")
	tt.Eq("article_id", Error.ForeignKey(err))
}
<|endoftext|>


<commit_before>package logdoc_test

import (
	"encoding/json"
	"testing"

	"github.com/tmc/mongologtools/parser/internal/logdoc"
)

func TestLogDocParser(t *testing.T) {
	cases := []struct{ input, expected string }{
		{`{ foo: [ 42 ] }`, `{"foo":[42]}`},
		{`{ foo: [ 42, 43, 44 ] }`, `{"foo":[42,43,44]}`},
		{`{ _updated_at: { $lte: new Date(1412941647719) } }`, `{"_updated_at":{"$lte":{"$date":"2014-10-10T11:47:27.719Z"}}}`},
		{`{ _id: ObjectId("54e792daf1845f045f4c000e"), data: BinData(0,"aGVsbG8K") }`, `{"_id":{"$oid":"54e792daf1845f045f4c000e"},"data":{"$binary":"aGVsbG8K","$type":"00"}}`},
		{`{ t: Timestamp(1420000000, 1) }`, `{"t":{"$timestamp":{"t":1420000000,"i":1}}}`},
		{`{ some_text: /ese/i }`, `{"some_text":{"$regex":"ese","$options":"i"}}`},
		{`{ n: NumberLong(-9223372036854775808) }`, `{"n":{"$numberLong":"-9223372036854775808"}}`},
		{`{ $query: { _p_user: "_User$XOWpxhM06t", _created_at: { $gte: new Date(1430758114453) }, _p_swiped_user: { $in: [ "_User$H5uW6XZTM4", "_User$MSjlL4vwIs", "_User$J04ObUTPzc", "_User$j2ToPWWr9b", "_User$AM6zi0ZSbk", "_User$B7NycSBHGN", "_User$qntkZ1RGMS", "_User$yZi1WUgh53", "_User$C45ZweDNei", "_User$sYVqPmtWtv", "_User$moJoWODQzq", "_User$YUybni9dpa", "_User$t01gQNtkf4", "_User$w3afYlWFSB", "_User$uQc0wUkiBl", "_User$3C0D6G1Qvh", "_User$YtythybLMl", "_User$nNojFdVEt9", "_User$1w7YF9Sou2", "_User$xmYaMkbeZK", "_User$WWXc9MZSSG", "_User$T5logFfrTT", "_User$VIYqMyy7UT", "_User$YeQZ6P1YeY", "_User$rh49GFwRfc", "_User$F0nN6AbaFw" ] } }, $maxScan: 500000 }`, `{"$maxScan":500000,"$query":{"_created_at":{"$gte":{"$date":"2015-05-04T16:48:34.453Z"}},"_p_swiped_user":{"$in":["_User$H5uW6XZTM4","_User$MSjlL4vwIs","_User$J04ObUTPzc","_User$j2ToPWWr9b","_User$AM6zi0ZSbk","_User$B7NycSBHGN","_User$qntkZ1RGMS","_User$yZi1WUgh53","_User$C45ZweDNei","_User$sYVqPmtWtv","_User$moJoWODQzq","_User$YUybni9dpa","_User$t01gQNtkf4","_User$w3afYlWFSB","_User$uQc0wUkiBl","_User$3C0D6G1Qvh","_User$YtythybLMl","_User$nNojFdVEt9","_User$1w7YF9Sou2","_User$xmYaMkbeZK","_User$WWXc9MZSSG","_User$T5logFfrTT","_User$VIYqMyy7UT","_User$YeQZ6P1YeY","_User$rh49GFwRfc","_User$F0nN6AbaFw"]},"_p_user":"_User$XOWpxhM06t"}}`},
	}
	for i, testcase := range cases {
		doc, err := logdoc.ConvertLogToExtended([]byte(testcase.input))
		if err != nil {
			t.Fatalf("case %d: error parsing: %v", i, err)
		}
		buf, err := json.Marshal(doc)
		if err != nil {
			t.Fatalf("case %d: error marshaling: %v", i, err)
		}
		result := string(buf)
		if result != testcase.expected {
			t.Errorf("case %d: expected '%s'\nbut got '%s'", i, testcase.expected, result)
		}
	}
	for i, testcase := range cases {
		doc, err := logdoc.ConvertLogToExtendedPigeon([]byte(testcase.input))
		if err != nil {
			t.Fatalf("case %d: error parsing: %v", i, err)
		}
		buf, err := json.Marshal(doc)
		if err != nil {
			t.Fatalf("case %d: error marshaling: %v", i, err)
		}
		result := string(buf)
		if result != testcase.expected {
			t.Errorf("case %d: expected '%s'\nbut got '%s'", i, testcase.expected, result)
		}
	}
}
<commit_msg>Revert prematurely added test case<commit_after>package logdoc_test

import (
	"encoding/json"
	"testing"

	"github.com/tmc/mongologtools/parser/internal/logdoc"
)

func TestLogDocParser(t *testing.T) {
	cases := []struct{ input, expected string }{
		{`{ foo: [ 42 ] }`, `{"foo":[42]}`},
		{`{ _updated_at: { $lte: new Date(1412941647719) } }`, `{"_updated_at":{"$lte":{"$date":"2014-10-10T11:47:27.719Z"}}}`},
		{`{ _id: ObjectId("54e792daf1845f045f4c000e"), data: BinData(0,"aGVsbG8K") }`, `{"_id":{"$oid":"54e792daf1845f045f4c000e"},"data":{"$binary":"aGVsbG8K","$type":"00"}}`},
		{`{ t: Timestamp(1420000000, 1) }`, `{"t":{"$timestamp":{"t":1420000000,"i":1}}}`},
		{`{ some_text: /ese/i }`, `{"some_text":{"$regex":"ese","$options":"i"}}`},
		{`{ n: NumberLong(-9223372036854775808) }`, `{"n":{"$numberLong":"-9223372036854775808"}}`},
	}
	for i, testcase := range cases {
		doc, err := logdoc.ConvertLogToExtended([]byte(testcase.input))
		if err != nil {
			t.Fatalf("case %d: error parsing: %v", i, err)
		}
		buf, err := json.Marshal(doc)
		if err != nil {
			t.Fatalf("case %d: error marshaling: %v", i, err)
		}
		result := string(buf)
		if result != testcase.expected {
			t.Errorf("case %d: expected '%s'\nbut got '%s'", i, testcase.expected, result)
		}
	}
}
<|endoftext|>