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

package mux

import (
	"fmt"
	"net/http"
	"path"

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
	// Filters to be executed, in order.
	filters []Filter
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	var route *Route
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		route = match.Route
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}
	if route != nil && route.parent != nil {
		handler = route.parent.buildFilteredHandler(handler)
	} else {
		handler = r.buildFilteredHandler(handler)
	}

	handler.ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// ----------------------------------------------------------------------------
// Filters
// ----------------------------------------------------------------------------

type Filter func(http.Handler) http.Handler

func (r *Router) AddFilters(filters ...Filter) {
	r.filters = append(r.filters, filters...)
}

func (r *Router) buildFilteredHandler(handler http.Handler) http.Handler {
	for i := len(r.filters) - 1; i >= 0; i-- {
		handler = r.filters[i](handler)
	}

	if r.parent != nil {
		handler = r.parent.buildFilteredHandler(handler)
	}

	return handler
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairs(pairs ...string) (map[string]string, error) {
	length := len(pairs)
	if length%2 != 0 {
		return nil, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMap returns true if the given key/value pairs exist in a given map.
func matchMap(toCheck map[string]string, toMatch map[string][]string,
	canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<commit_msg>comment exported functions<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

import (
	"fmt"
	"net/http"
	"path"

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
	// Filters to be executed, in order.
	filters []Filter
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	var route *Route
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		route = match.Route
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}
	if route != nil && route.parent != nil {
		handler = route.parent.buildFilteredHandler(handler)
	} else {
		handler = r.buildFilteredHandler(handler)
	}

	handler.ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// ----------------------------------------------------------------------------
// Filters
// ----------------------------------------------------------------------------

// Filter stores a filter to be applied
type Filter func(http.Handler) http.Handler

// AddFilters registers new filters to a Router
func (r *Router) AddFilters(filters ...Filter) {
	r.filters = append(r.filters, filters...)
}

func (r *Router) buildFilteredHandler(handler http.Handler) http.Handler {
	for i := len(r.filters) - 1; i >= 0; i-- {
		handler = r.filters[i](handler)
	}

	if r.parent != nil {
		handler = r.parent.buildFilteredHandler(handler)
	}

	return handler
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairs(pairs ...string) (map[string]string, error) {
	length := len(pairs)
	if length%2 != 0 {
		return nil, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMap returns true if the given key/value pairs exist in a given map.
func matchMap(toCheck map[string]string, toMatch map[string][]string,
	canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<|endoftext|>


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

package mux

import (
	"errors"
	"fmt"
	"net/http"
	"path"
	"regexp"

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}
	handler.ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

func (r *Router) buildVars(m map[string]string) map[string]string {
	if r.parent != nil {
		m = r.parent.buildVars(m)
	}
	return m
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// BuildVars registers a new route with a custom function for modifying
// route variables before building a URL.
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
	return r.NewRoute().BuildVarsFunc(f)
}

// Walk walks the router and all its sub-routers, calling walkFn for each route
// in the tree. The routes are walked in the order they were added. Sub-routers
// are explored depth-first.
func (r *Router) Walk(walkFn WalkFunc) error {
	return r.walk(walkFn, []*Route{})
}

// SkipRouter is used as a return value from WalkFuncs to indicate that the
// router that walk is about to descend down to should be skipped.
var SkipRouter = errors.New("skip this router")

// WalkFunc is the type of the function called for each route visited by Walk.
// At every invocation, it is given the current route, and the current router,
// and a list of ancestor routes that lead to the current route.
type WalkFunc func(route *Route, router *Router, ancestors []*Route) error

func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
	for _, t := range r.routes {
		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
			continue
		}

		err := walkFn(t, r, ancestors)
		if err == SkipRouter {
			continue
		}
		for _, sr := range t.matchers {
			if h, ok := sr.(*Router); ok {
				err := h.walk(walkFn, ancestors)
				if err != nil {
					return err
				}
			}
		}
		if h, ok := t.handler.(*Router); ok {
			ancestors = append(ancestors, t)
			err := h.walk(walkFn, ancestors)
			if err != nil {
				return err
			}
			ancestors = ancestors[:len(ancestors)-1]
		}
	}
	return nil
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

func checkPairs(pairs ...string) (int, error) {
	length := len(pairs)
	if length%2 != 0 {
		return length, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	return length, nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]*regexp.Regexp, length/2)
	for i := 0; i < length; i += 2 {
		regex, err := regexp.Compile(pairs[i+1])
		if err != nil {
			return nil, err
		}
		m[pairs[i]] = regex
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMapWithString returns true if the given key/value pairs exist in a given map.
func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}

// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
// the given regex
func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != nil {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v.MatchString(value) {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<commit_msg>Export setVars<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

import (
	"errors"
	"fmt"
	"net/http"
	"path"
	"regexp"

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	if r.Match(req, &match) {
		handler = match.Handler
		SetVars(req, match.Vars)
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}
	handler.ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

func (r *Router) buildVars(m map[string]string) map[string]string {
	if r.parent != nil {
		m = r.parent.buildVars(m)
	}
	return m
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// BuildVars registers a new route with a custom function for modifying
// route variables before building a URL.
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
	return r.NewRoute().BuildVarsFunc(f)
}

// Walk walks the router and all its sub-routers, calling walkFn for each route
// in the tree. The routes are walked in the order they were added. Sub-routers
// are explored depth-first.
func (r *Router) Walk(walkFn WalkFunc) error {
	return r.walk(walkFn, []*Route{})
}

// SkipRouter is used as a return value from WalkFuncs to indicate that the
// router that walk is about to descend down to should be skipped.
var SkipRouter = errors.New("skip this router")

// WalkFunc is the type of the function called for each route visited by Walk.
// At every invocation, it is given the current route, and the current router,
// and a list of ancestor routes that lead to the current route.
type WalkFunc func(route *Route, router *Router, ancestors []*Route) error

func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
	for _, t := range r.routes {
		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
			continue
		}

		err := walkFn(t, r, ancestors)
		if err == SkipRouter {
			continue
		}
		for _, sr := range t.matchers {
			if h, ok := sr.(*Router); ok {
				err := h.walk(walkFn, ancestors)
				if err != nil {
					return err
				}
			}
		}
		if h, ok := t.handler.(*Router); ok {
			ancestors = append(ancestors, t)
			err := h.walk(walkFn, ancestors)
			if err != nil {
				return err
			}
			ancestors = ancestors[:len(ancestors)-1]
		}
	}
	return nil
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func SetVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

func checkPairs(pairs ...string) (int, error) {
	length := len(pairs)
	if length%2 != 0 {
		return length, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	return length, nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]*regexp.Regexp, length/2)
	for i := 0; i < length; i += 2 {
		regex, err := regexp.Compile(pairs[i+1])
		if err != nil {
			return nil, err
		}
		m[pairs[i]] = regex
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMapWithString returns true if the given key/value pairs exist in a given map.
func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}

// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
// the given regex
func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != nil {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v.MatchString(value) {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Package proxymux implements a reverse proxy multiplexer which can be used to
// serve responses from multiple distinct backend servers within a single URL
// hierarchy.
package proxymux

import (
	"github.com/nickstenning/trie"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"sync"
)

type Mux struct {
	mu            sync.RWMutex
	nextBackendId int
	backends      map[int]*httputil.ReverseProxy
	trie          *trie.Trie
}

type muxEntry struct {
	prefix    bool
	backendId int
}

// NewMux makes a new empty Mux.
func NewMux() *Mux {
	return &Mux{
		trie:     trie.NewTrie(),
		backends: make(map[int]*httputil.ReverseProxy),
	}
}

// ServeHTTP dispatches the request to a backend with a registered route
// matching the request path, or 404s.
func (mux *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id, ok := mux.Lookup(r.URL.Path)
	if !ok {
		http.NotFound(w, r)
		return
	}

	proxy, ok := mux.GetBackend(id)
	if !ok {
		http.NotFound(w, r)
		return
	}

	proxy.ServeHTTP(w, r)
}

// AddBackend adds a backend for the provided target url, and returns the
// generated backend id. The url should have a scheme, host, and optionally a
// port and path. If the url has a path, then requests will be rewritten onto
// that path, i.e. if a request is for
//
//   /bar
//
// and the matching backend has a target url of
//
//   /foo
//
// then the resulting request will be for
//
//   /foo/bar
func (mux *Mux) AddBackend(target *url.URL) (backendId int) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	backendId = mux.nextBackendId

	proxy := httputil.NewSingleHostReverseProxy(target)
	// Allow the proxy to keep more than the default (2) keepalive connections per
	// upstream.
	proxy.Transport = &http.Transport{MaxIdleConnsPerHost: 20}

	mux.backends[backendId] = proxy
	mux.nextBackendId++
	return
}

// GetBackend retrieves the registered backend with the given id.
func (mux *Mux) GetBackend(backendId int) (proxy *httputil.ReverseProxy, ok bool) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()

	b, ok := mux.backends[backendId]
	if !ok {
		return nil, false
	}

	return b, true
}

// Lookup takes a path and looks up its registered entry in the mux trie,
// returning the id of the matching backend, if any.
func (mux *Mux) Lookup(path string) (backendId int, ok bool) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()

	entry, ok := findlongestmatch(mux.trie, path)
	return entry.backendId, ok
}

func (mux *Mux) Register(path string, prefix bool, backendId int) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	mux.trie.Set(splitpath(path), muxEntry{
		prefix:    prefix,
		backendId: backendId,
	})
}

// splitpath turns a slash-delimited string into a lookup path (a slice
// containing the strings between slashes). Any leading slashes are stripped
// before the string is split.
func splitpath(path string) []string {
	for strings.HasPrefix(path, "/") {
		path = path[1:]
	}
	if path == "" {
		return []string{}
	}
	return strings.Split(path, "/")
}

// findlongestmatch will search the passed trie for the longest route matching
// the passed path, taking into account whether or not each muxEntry is a prefix
// route.
//
// The function first attempts an exact match, and if it fails to find one will
// then chop slash-delimited sections off the end of the path in an attempt to
// find a matching exact or prefix route.
func findlongestmatch(t *trie.Trie, path string) (entry muxEntry, ok bool) {
	origpath := splitpath(path)
	copypath := origpath

	// This search algorithm is potentially abusable -- it will take a
	// (relatively) long time to establish that a path with an enormous number of
	// slashes in doesn't have a corresponding route. The obvious fix is for the
	// trie to keep track of how long its longest root-to-leaf path is and
	// shortcut the lookup by chopping the appropriate number of elements off the
	// end of the lookup.
	//
	// Worrying about the above is probably premature optimization, so I leave the
	// mitigation described as an exercise for the reader.
	for len(copypath) >= 0 {
		val, ok := t.Get(copypath)
		if !ok {
			if len(copypath) > 0 {
				copypath = copypath[:len(copypath)-1]
				continue
			}
			break
		}

		ent, ok := val.(muxEntry)
		if !ok {
			log.Printf("findlongestmatch: got value (%v) from trie that wasn't a muxEntry!", val)
			break
		}

		if len(copypath) == len(origpath) {
			return ent, true
		}

		if ent.prefix {
			return ent, true
		}

		if len(copypath) > 0 {
			copypath = copypath[:len(copypath)-1]
			continue
		}

		// Fell through without finding anything or explicitly calling continue, so:
		break
	}
	return muxEntry{}, false
}
<commit_msg>Add Register docstring<commit_after>// Package proxymux implements a reverse proxy multiplexer which can be used to
// serve responses from multiple distinct backend servers within a single URL
// hierarchy.
package proxymux

import (
	"github.com/nickstenning/trie"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"sync"
)

type Mux struct {
	mu            sync.RWMutex
	nextBackendId int
	backends      map[int]*httputil.ReverseProxy
	trie          *trie.Trie
}

type muxEntry struct {
	prefix    bool
	backendId int
}

// NewMux makes a new empty Mux.
func NewMux() *Mux {
	return &Mux{
		trie:     trie.NewTrie(),
		backends: make(map[int]*httputil.ReverseProxy),
	}
}

// ServeHTTP dispatches the request to a backend with a registered route
// matching the request path, or 404s.
func (mux *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id, ok := mux.Lookup(r.URL.Path)
	if !ok {
		http.NotFound(w, r)
		return
	}

	proxy, ok := mux.GetBackend(id)
	if !ok {
		http.NotFound(w, r)
		return
	}

	proxy.ServeHTTP(w, r)
}

// AddBackend adds a backend for the provided target url, and returns the
// generated backend id. The url should have a scheme, host, and optionally a
// port and path. If the url has a path, then requests will be rewritten onto
// that path, i.e. if a request is for
//
//   /bar
//
// and the matching backend has a target url of
//
//   /foo
//
// then the resulting request will be for
//
//   /foo/bar
func (mux *Mux) AddBackend(target *url.URL) (backendId int) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	backendId = mux.nextBackendId

	proxy := httputil.NewSingleHostReverseProxy(target)
	// Allow the proxy to keep more than the default (2) keepalive connections per
	// upstream.
	proxy.Transport = &http.Transport{MaxIdleConnsPerHost: 20}

	mux.backends[backendId] = proxy
	mux.nextBackendId++
	return
}

// GetBackend retrieves the registered backend with the given id.
func (mux *Mux) GetBackend(backendId int) (proxy *httputil.ReverseProxy, ok bool) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()

	b, ok := mux.backends[backendId]
	if !ok {
		return nil, false
	}

	return b, true
}

// Lookup takes a path and looks up its registered entry in the mux trie,
// returning the id of the matching backend, if any.
func (mux *Mux) Lookup(path string) (backendId int, ok bool) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()

	entry, ok := findlongestmatch(mux.trie, path)
	return entry.backendId, ok
}

// Register registers the specified route (either an exact or a prefix route)
// and associates it with the specified backend. Requests through the mux for
// paths matching the route will be proxied to that backend.
func (mux *Mux) Register(path string, prefix bool, backendId int) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	mux.trie.Set(splitpath(path), muxEntry{
		prefix:    prefix,
		backendId: backendId,
	})
}

// splitpath turns a slash-delimited string into a lookup path (a slice
// containing the strings between slashes). Any leading slashes are stripped
// before the string is split.
func splitpath(path string) []string {
	for strings.HasPrefix(path, "/") {
		path = path[1:]
	}
	if path == "" {
		return []string{}
	}
	return strings.Split(path, "/")
}

// findlongestmatch will search the passed trie for the longest route matching
// the passed path, taking into account whether or not each muxEntry is a prefix
// route.
//
// The function first attempts an exact match, and if it fails to find one will
// then chop slash-delimited sections off the end of the path in an attempt to
// find a matching exact or prefix route.
func findlongestmatch(t *trie.Trie, path string) (entry muxEntry, ok bool) {
	origpath := splitpath(path)
	copypath := origpath

	// This search algorithm is potentially abusable -- it will take a
	// (relatively) long time to establish that a path with an enormous number of
	// slashes in doesn't have a corresponding route. The obvious fix is for the
	// trie to keep track of how long its longest root-to-leaf path is and
	// shortcut the lookup by chopping the appropriate number of elements off the
	// end of the lookup.
	//
	// Worrying about the above is probably premature optimization, so I leave the
	// mitigation described as an exercise for the reader.
	for len(copypath) >= 0 {
		val, ok := t.Get(copypath)
		if !ok {
			if len(copypath) > 0 {
				copypath = copypath[:len(copypath)-1]
				continue
			}
			break
		}

		ent, ok := val.(muxEntry)
		if !ok {
			log.Printf("findlongestmatch: got value (%v) from trie that wasn't a muxEntry!", val)
			break
		}

		if len(copypath) == len(origpath) {
			return ent, true
		}

		if ent.prefix {
			return ent, true
		}

		if len(copypath) > 0 {
			copypath = copypath[:len(copypath)-1]
			continue
		}

		// Fell through without finding anything or explicitly calling continue, so:
		break
	}
	return muxEntry{}, false
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type NrkRadio struct {
	Url string
}

type RadioPlaylist struct {
	Tracks []RadioTrack
}

type RadioTrack struct {
	Track  string `json:"title"`
	Artist string `json:"description"`
	Type   string `json:"type"`
}

func (playlist *RadioPlaylist) Previous() (*RadioTrack, error) {
	if len(playlist.Tracks) > 0 {
		return &playlist.Tracks[0], nil
	}
	return nil, fmt.Errorf("Previous track not found")
}

func (playlist *RadioPlaylist) Current() (*RadioTrack, error) {
	if len(playlist.Tracks) > 1 {
		return &playlist.Tracks[1], nil
	}
	return nil, fmt.Errorf("Current track not found")
}

func (playlist *RadioPlaylist) Next() (*RadioTrack, error) {
	if len(playlist.Tracks) > 2 {
		return &playlist.Tracks[2], nil
	}
	return nil, fmt.Errorf("Next track not found")
}

func (track *RadioTrack) IsMusic() bool {
	return track.Type == "Music"
}

func (radio *NrkRadio) Playlist() (*RadioPlaylist, error) {
	resp, err := http.Get(radio.Url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	var tracks []RadioTrack
	if err := json.Unmarshal(body, &tracks); err != nil {
		return nil, err
	}
	return &RadioPlaylist{Tracks: tracks}, nil
}
<commit_msg>Add name to NrkRadio struct<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type NrkRadio struct {
	Name string
	Url  string
}

type RadioPlaylist struct {
	Tracks []RadioTrack
}

type RadioTrack struct {
	Track  string `json:"title"`
	Artist string `json:"description"`
	Type   string `json:"type"`
}

func (playlist *RadioPlaylist) Previous() (*RadioTrack, error) {
	if len(playlist.Tracks) > 0 {
		return &playlist.Tracks[0], nil
	}
	return nil, fmt.Errorf("Previous track not found")
}

func (playlist *RadioPlaylist) Current() (*RadioTrack, error) {
	if len(playlist.Tracks) > 1 {
		return &playlist.Tracks[1], nil
	}
	return nil, fmt.Errorf("Current track not found")
}

func (playlist *RadioPlaylist) Next() (*RadioTrack, error) {
	if len(playlist.Tracks) > 2 {
		return &playlist.Tracks[2], nil
	}
	return nil, fmt.Errorf("Next track not found")
}

func (track *RadioTrack) IsMusic() bool {
	return track.Type == "Music"
}

func (radio *NrkRadio) Playlist() (*RadioPlaylist, error) {
	resp, err := http.Get(radio.Url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	var tracks []RadioTrack
	if err := json.Unmarshal(body, &tracks); err != nil {
		return nil, err
	}
	return &RadioPlaylist{Tracks: tracks}, nil
}
<|endoftext|>


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

// Package owm implements a wrapper for the OpenWeatherMap API.
//
// Read more about the OpenWeatherMap API here: http://openweathermap.org/api.
package owm

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"
)

type weatherLine struct {
	Id          int
	Main        string
	Description string
	Icon        string
}

// Weather represents the current weather at a specific location.
//
// It is returned by the WeatherBy* methods of Client.
type Weather struct {
	Coord struct {
		Lat float64
		Lon float64
	}
	Sys struct {
		Type    int
		Id      int
		Country string
		Sunrise int
		Sunset  int
	}
	Weather []weatherLine
	Base    string
	Main    struct {
		Temp      float64
		Humidity  int
		TempMin   float64 `json:"temp_min"`
		TempMax   float64 `json:"temp_max"`
		Pressure  float64
		SeaLevel  float64 `json:"sea_level"`
		GrndLevel float64 `json:"grnd_level"`
	}
	Wind struct {
		Speed float64
		Deg   float64
		Gust  float64
	}
	Clouds struct {
		All int
	}
	Dt   int
	Id   int
	Name string
	Cod  int
}

type weatherSet struct {
	Cnt     int
	Weather []Weather `json:"list"`
}

// Forecast represents the weather forecast for a specific location.
//
// It is returned by the ForecastBy* methods of Client.
type Forecast struct {
	Cod  string
	City struct {
		Id    int
		Name  string
		Coord struct {
			Lon float64
			Lat float64
		}
		Country string
	}
	Cnt     int
	Weather []Weather `json:"list"`
}

// Client represents an OpenWeatherMap API client.
type Client struct {
	key     string
	baseURL string
}

// NewClient returns a new Client given an API key.
//
// Pass an empty string as the key argument to use the client without an API key.
func NewClient(key string) *Client {
	return &Client{key, "http://api.openweathermap.org/data/2.5/"}
}

func (c *Client) data(url string) (data []byte, err error) {
	res, err := http.Get(url)
	if err != nil {
		err = errors.New("owm: error while getting weather data")
		return
	}
	data, err = ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		err = errors.New("owm: error while getting weather data")
		return
	}
	return
}

func (c *Client) weather(url string) (w Weather, err error) {
	if c.key != "" {
		url += "&APPID=" + c.key
	}
	data, err := c.data(url)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
		return
	}
	err = json.Unmarshal(data, &w)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
		return
	}
	return
}

// WeatherByName decodes the current weather given the city name and the units.
func (c *Client) WeatherByName(name string, units string) (w Weather, err error) {
	w, err = c.weather(c.baseURL +
		"weather" +
		"?q=" + name +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	return
}

// WeatherById decodes the current weather given the city id and the units.
func (c *Client) WeatherById(id int, units string) (w Weather, err error) {
	w, err = c.weather(c.baseURL +
		"weather" +
		"?id=" + strconv.Itoa(id) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	return
}

// WeatherByCoord decodes the current weather given the city coordinates and the units.
func (c *Client) WeatherByCoord(lat, lon float64, units string) (w Weather, err error) {
	w, err = c.weather(c.baseURL +
		"weather" +
		"?lat=" + strconv.FormatFloat(lat, 'f', 2, 64) +
		"&lon=" + strconv.FormatFloat(lon, 'f', 2, 64) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	return
}

func (c *Client) weatherSet(url string) (ws weatherSet, err error) {
	if c.key != "" {
		url += "&APPID=" + c.key
	}
	data, err := c.data(url)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
		return
	}
	err = json.Unmarshal(data, &ws)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
		return
	}
	return
}

// WeatherByZone decodes a slice of current weathers given the zone coordinates, map zoom and the units.
func (c *Client) WeatherByZone(lat1, lon1, lat2, lon2 float64, zoom int, units string) (w []Weather, err error) {
	ws, err := c.weatherSet(c.baseURL +
		"box/city" +
		"?bbox=" +
		strconv.FormatFloat(lat1, 'f', 2, 64) + "," +
		strconv.FormatFloat(lon1, 'f', 2, 64) + "," +
		strconv.FormatFloat(lat2, 'f', 2, 64) + "," +
		strconv.FormatFloat(lon2, 'f', 2, 64) + "," +
		strconv.Itoa(zoom) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	w = ws.Weather
	return
}

// WeatherByRadius decodes a slice of current weathers given the center coordinates, radius and the units.
func (c *Client) WeatherByRadius(lat, lon, radius float64, units string) (w []Weather, err error) {
	ws, err := c.weatherSet(c.baseURL +
		"find" +
		"?lat=" + strconv.FormatFloat(lat, 'f', 2, 64) + "," +
		"&lon=" + strconv.FormatFloat(lon, 'f', 2, 64) + "," +
		"&cnt=" + strconv.FormatFloat(radius, 'f', 2, 64) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	w = ws.Weather
	return
}

// WeatherByIds decodes a slice of current weathers given a slice of city ids and the units.
func (c *Client) WeatherByIds(id []int, units string) (w []Weather, err error) {
	var ids string
	for i := range id {
		ids += strconv.Itoa(id[i]) + ","
	}
	ws, err := c.weatherSet(c.baseURL +
		"group" +
		"?id=" + ids[:len(ids)-1] +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	w = ws.Weather
	return
}

func (c *Client) forecast(url string) (f Forecast, err error) {
	if c.key != "" {
		url += "&APPID=" + c.key
	}
	data, err := c.data(url)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
		return
	}
	err = json.Unmarshal(data, &f)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
		return
	}
	return
}

// ForecastByName decodes the current forecast given the city name and the units.
func (c *Client) ForecastByName(name string, units string) (f Forecast, err error) {
	f, err = c.forecast(c.baseURL +
		"forecast" +
		"?q=" + name +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	return
}

// ForecastById decodes the current forecast given the city id and the units.
func (c *Client) ForecastById(id int, units string) (f Forecast, err error) {
	f, err = c.forecast(c.baseURL +
		"forecast" +
		"?id=" + strconv.Itoa(id) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	return
}

// ForecastByCoord decodes the current forecast given the city coordinates and the units.
func (c *Client) ForecastByCoord(lat, lon float64, units string) (f Forecast, err error) {
	f, err = c.forecast(c.baseURL +
		"forecast" +
		"?lat=" + strconv.FormatFloat(lat, 'f', 2, 64) +
		"?lon=" + strconv.FormatFloat(lon, 'f', 2, 64) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather")
	}
	return
}
<commit_msg>refactoring<commit_after>// Copyright 2014 Vasco Costa. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package owm implements a wrapper for the OpenWeatherMap API.
//
// Read more about the OpenWeatherMap API here: http://openweathermap.org/api.
package owm

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"
)

type weatherLine struct {
	Id          int
	Main        string
	Description string
	Icon        string
}

// Weather represents the current weather at a specific location.
//
// It is returned by the WeatherBy* methods of Client.
type Weather struct {
	Coord struct {
		Lat float64
		Lon float64
	}
	Sys struct {
		Type    int
		Id      int
		Country string
		Sunrise int
		Sunset  int
	}
	Weather []weatherLine
	Base    string
	Main    struct {
		Temp      float64
		Humidity  int
		TempMin   float64 `json:"temp_min"`
		TempMax   float64 `json:"temp_max"`
		Pressure  float64
		SeaLevel  float64 `json:"sea_level"`
		GrndLevel float64 `json:"grnd_level"`
	}
	Wind struct {
		Speed float64
		Deg   float64
		Gust  float64
	}
	Clouds struct {
		All int
	}
	Dt   int
	Id   int
	Name string
	Cod  int
}

type weatherSet struct {
	Cnt     int
	Weather []Weather `json:"list"`
}

// Forecast represents the weather forecast for a specific location.
//
// It is returned by the ForecastBy* methods of Client.
type Forecast struct {
	Cod  string
	City struct {
		Id    int
		Name  string
		Coord struct {
			Lon float64
			Lat float64
		}
		Country string
	}
	Cnt     int
	Weather []Weather `json:"list"`
}

// Client represents an OpenWeatherMap API client.
type Client struct {
	key     string
	baseURL string
}

// NewClient returns a new Client given an API key.
//
// Pass an empty string as the key argument to use the client without an API key.
func NewClient(key string) *Client {
	return &Client{key, "http://api.openweathermap.org/data/2.5/"}
}

func (c *Client) data(url string) (data []byte, err error) {
	res, err := http.Get(url)
	if err != nil {
		err = errors.New("owm: error while fetching weather data")
		return
	}
	data, err = ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		err = errors.New("owm: error while fetching weather data")
		return
	}
	return
}

func (c *Client) weather(url string) (w Weather, err error) {
	if c.key != "" {
		url += "&APPID=" + c.key
	}
	data, err := c.data(url)
	if err != nil {
		err = errors.New("owm: error while fetching weather data")
		return
	}
	err = json.Unmarshal(data, &w)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
		return
	}
	return
}

func (c *Client) weatherSet(url string) (ws weatherSet, err error) {
	if c.key != "" {
		url += "&APPID=" + c.key
	}
	data, err := c.data(url)
	if err != nil {
		err = errors.New("owm: error while fetching weather data")
		return
	}
	err = json.Unmarshal(data, &ws)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
		return
	}
	return
}

func (c *Client) forecast(url string) (f Forecast, err error) {
	if c.key != "" {
		url += "&APPID=" + c.key
	}
	data, err := c.data(url)
	if err != nil {
		err = errors.New("owm: error while fetching forecast data")
		return
	}
	err = json.Unmarshal(data, &f)
	if err != nil {
		err = errors.New("owm: error while decoding forecast data")
		return
	}
	return
}

// WeatherByName decodes the current weather given the city name and the units.
func (c *Client) WeatherByName(name string, units string) (w Weather, err error) {
	w, err = c.weather(c.baseURL +
		"weather" +
		"?q=" + name +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
	}
	return
}

// WeatherById decodes the current weather given the city id and the units.
func (c *Client) WeatherById(id int, units string) (w Weather, err error) {
	w, err = c.weather(c.baseURL +
		"weather" +
		"?id=" + strconv.Itoa(id) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
	}
	return
}

// WeatherByCoord decodes the current weather given the city coordinates and the units.
func (c *Client) WeatherByCoord(lat, lon float64, units string) (w Weather, err error) {
	w, err = c.weather(c.baseURL +
		"weather" +
		"?lat=" + strconv.FormatFloat(lat, 'f', 2, 64) +
		"&lon=" + strconv.FormatFloat(lon, 'f', 2, 64) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
	}
	return
}

// WeatherByZone decodes a slice of current weathers given the zone coordinates, map zoom and the units.
func (c *Client) WeatherByZone(lat1, lon1, lat2, lon2 float64, zoom int, units string) (w []Weather, err error) {
	ws, err := c.weatherSet(c.baseURL +
		"box/city" +
		"?bbox=" +
		strconv.FormatFloat(lat1, 'f', 2, 64) + "," +
		strconv.FormatFloat(lon1, 'f', 2, 64) + "," +
		strconv.FormatFloat(lat2, 'f', 2, 64) + "," +
		strconv.FormatFloat(lon2, 'f', 2, 64) + "," +
		strconv.Itoa(zoom) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
	}
	w = ws.Weather
	return
}

// WeatherByRadius decodes a slice of current weathers given the center coordinates, radius and the units.
func (c *Client) WeatherByRadius(lat, lon, radius float64, units string) (w []Weather, err error) {
	ws, err := c.weatherSet(c.baseURL +
		"find" +
		"?lat=" + strconv.FormatFloat(lat, 'f', 2, 64) + "," +
		"&lon=" + strconv.FormatFloat(lon, 'f', 2, 64) + "," +
		"&cnt=" + strconv.FormatFloat(radius, 'f', 2, 64) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
	}
	w = ws.Weather
	return
}

// WeatherByIds decodes a slice of current weathers given a slice of city ids and the units.
func (c *Client) WeatherByIds(id []int, units string) (w []Weather, err error) {
	var ids string
	for i := range id {
		ids += strconv.Itoa(id[i]) + ","
	}
	ws, err := c.weatherSet(c.baseURL +
		"group" +
		"?id=" + ids[:len(ids)-1] +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding weather data")
	}
	w = ws.Weather
	return
}

// ForecastByName decodes the current forecast given the city name and the units.
func (c *Client) ForecastByName(name string, units string) (f Forecast, err error) {
	f, err = c.forecast(c.baseURL +
		"forecast" +
		"?q=" + name +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding forecast data")
	}
	return
}

// ForecastById decodes the current forecast given the city id and the units.
func (c *Client) ForecastById(id int, units string) (f Forecast, err error) {
	f, err = c.forecast(c.baseURL +
		"forecast" +
		"?id=" + strconv.Itoa(id) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding forecast data")
	}
	return
}

// ForecastByCoord decodes the current forecast given the city coordinates and the units.
func (c *Client) ForecastByCoord(lat, lon float64, units string) (f Forecast, err error) {
	f, err = c.forecast(c.baseURL +
		"forecast" +
		"?lat=" + strconv.FormatFloat(lat, 'f', 2, 64) +
		"?lon=" + strconv.FormatFloat(lon, 'f', 2, 64) +
		"&units=" + units)
	if err != nil {
		err = errors.New("owm: error while decoding forecast data")
	}
	return
}
<|endoftext|>


<commit_before>/*
    If we list all the natural numbers below 10 that are multiples of 3 or 5, we
    get 3, 5, 6 and 9. The sum of these multiples is 23.

    Find the sum of all the multiples of 3 or 5 below 1000.
*/

package main

import (
	"os"
	"fmt"
	"strconv"
)

func main() {
	s := 0
	n, _ := strconv.Atoi(os.Args[1])
	for i := 0; i < n; i++ {
		if (i % 3 == 0) || (i % 5 == 0) {
			s += i
		}
	}
	fmt.Println(s)
}

<commit_msg>p01.go: Added license and cleaned up comments.<commit_after>// Copyright 2011 Karl Sackett <karl.sackett@gmail.com>
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

// p01.go
// Find the sum of all the multiples of 3 or 5 below 1000.

package main

import (
	"os"
	"fmt"
	"strconv"
)

func main() {
	s := 0
	n, _ := strconv.Atoi(os.Args[1])
	for i := 0; i < n; i++ {
		if (i % 3 == 0) || (i % 5 == 0) {
			s += i
		}
	}
	fmt.Println(s)
}

<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strconv"

	paoDb "github.com/arbrown/pao/db"
	"github.com/arbrown/pao/game"
	"github.com/arbrown/pao/settings"
	_ "github.com/lib/pq"
)

var (
	a *paoDb.Auth
)

func main() {
	fmt.Printf("Hello, Pao\n")
	removeGameChan := make(chan *game.Game)
	games := make(map[string]*game.Game)
	s, err := settings.GetSettings()
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Printf("Settings: %+v\n", s)
	}
	a, err = paoDb.NewAuth(s)
	if err != nil {
		fmt.Println("Could not create auth")
		fmt.Println(err.Error())
	}
	// create db connection
	db, err := sql.Open(s.DbConfig.Driver, s.DbConfig.ConnectionString)
	if err != nil {
		db = nil
		fmt.Printf("Could not open database: %s\n", err)
	} else {
		paoDb.Init(db)
	}

	httpMux := http.NewServeMux()
	httpMux.Handle("/listGames", listGamesHandler{games: games})
	httpMux.Handle("/game", gameHandler{games: games, removeGameChan: removeGameChan, db: db})
	httpMux.HandleFunc("/login", a.PostLogin)
	httpMux.HandleFunc("/register", a.PostRegister)
	httpMux.HandleFunc("/logout", a.HandleLogout)
	httpMux.HandleFunc("/cu", a.Cu)
	httpMux.HandleFunc("/leaderBoard", paoDb.GetLeaderBoard)

	go func() {
		for {
			select {
			case g := <-removeGameChan:
				fmt.Printf("Removing game: %v\n", g.ID)
				delete(games, g.ID)
				break
			}
		}
	}()

	host, port := os.Getenv("HOST"), os.Getenv("PORT")
	if port == "" {
		port = "2015"
	}

	bind := fmt.Sprintf("%s:%s", host, port)

	httpMux.Handle("/", http.FileServer(http.Dir("./client/")))
	err = http.ListenAndServe(bind, httpMux)
	if err != nil {
		panic("ListenAndServe:" + err.Error())
	}
}

type gameHandler struct {
	games          map[string]*game.Game
	removeGameChan chan *game.Game
	db             *sql.DB
}

type listGamesHandler struct {
	games map[string]*game.Game
}

type gameResponse struct {
	ID      string
	Players []string
}

func (lgh listGamesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var resp []gameResponse
	for id, game := range lgh.games {
		var players []string
		if game.CurrentPlayer != nil {
			players = append(players, game.CurrentPlayer.Name)
		}
		if game.NextPlayer != nil {
			players = append(players, game.NextPlayer.Name)
		}
		resp = append(resp, gameResponse{ID: id, Players: players})
	}
	js, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func (gh gameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var user = a.GetUser(w, r)
	fmt.Printf("105: user: %+v\n", user)
	id := r.FormValue("id")
	name := r.FormValue("name")
	fmt.Println(id)
	if name == "" {
		name = "Anonymous Coward"
	}
	if id != "" {
		// Does the game exist?
		fmt.Printf("All Games: %v\n", gh.games)
		if existingGame, ok := gh.games[id]; ok {
			fmt.Println("Trying to join existing game")
			existingGame.Join(w, r, name, user)
		} else {
			// make the id requested
			g := game.NewGame(id, gh.removeGameChan, gh.db)
			fmt.Printf("Made new game %s\n", id)
			gh.games[g.ID] = g
			g.Join(w, r, name, user)
		}
	} else {
		// no id specified, make the game
		newID := 0
		fmt.Printf("128: user: %+v\n", user)
		for _, exists := gh.games[strconv.Itoa(newID)]; exists; _, exists = gh.games[strconv.Itoa(newID)] {
			newID++
		}
		g := game.NewGame(strconv.Itoa(newID), gh.removeGameChan, gh.db)
		fmt.Printf("Made new game %d\n", newID)
		gh.games[g.ID] = g
		fmt.Printf("Trying to join new game as: %+v\n", user)
		if ok := g.Join(w, r, name, user); !ok {
			delete(gh.games, g.ID)
		}
	}
}
<commit_msg>Change database backend to sqlite3<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strconv"

	paoDb "github.com/arbrown/pao/db"
	"github.com/arbrown/pao/game"
	"github.com/arbrown/pao/settings"
	_ "github.com/mattn/go-sqlite3"
)

var (
	a *paoDb.Auth
)

func main() {
	fmt.Printf("Hello, Pao\n")
	removeGameChan := make(chan *game.Game)
	games := make(map[string]*game.Game)
	s, err := settings.GetSettings()
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Printf("Settings: %+v\n", s)
	}
	// create db connection
	db, err := sql.Open(s.DbConfig.Driver, s.DbConfig.ConnectionString)
	if err != nil {
		db = nil
		fmt.Printf("Could not open database: %s\n", err)
	} else {
		paoDb.Init(db)
	}
	a, err = paoDb.NewAuth(s)
	if err != nil {
		fmt.Println("Could not create auth")
		fmt.Println(err.Error())
	}

	httpMux := http.NewServeMux()
	httpMux.Handle("/listGames", listGamesHandler{games: games})
	httpMux.Handle("/game", gameHandler{games: games, removeGameChan: removeGameChan, db: db})
	httpMux.HandleFunc("/login", a.PostLogin)
	httpMux.HandleFunc("/register", a.PostRegister)
	httpMux.HandleFunc("/logout", a.HandleLogout)
	httpMux.HandleFunc("/cu", a.Cu)
	httpMux.HandleFunc("/leaderBoard", paoDb.GetLeaderBoard)

	go func() {
		for {
			select {
			case g := <-removeGameChan:
				fmt.Printf("Removing game: %v\n", g.ID)
				delete(games, g.ID)
				break
			}
		}
	}()

	host, port := os.Getenv("HOST"), os.Getenv("PORT")
	if port == "" {
		port = "2015"
	}

	bind := fmt.Sprintf("%s:%s", host, port)

	httpMux.Handle("/", http.FileServer(http.Dir("./client/")))
	err = http.ListenAndServe(bind, httpMux)
	if err != nil {
		panic("ListenAndServe:" + err.Error())
	}
}

type gameHandler struct {
	games          map[string]*game.Game
	removeGameChan chan *game.Game
	db             *sql.DB
}

type listGamesHandler struct {
	games map[string]*game.Game
}

type gameResponse struct {
	ID      string
	Players []string
}

func (lgh listGamesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var resp []gameResponse
	for id, game := range lgh.games {
		var players []string
		if game.CurrentPlayer != nil {
			players = append(players, game.CurrentPlayer.Name)
		}
		if game.NextPlayer != nil {
			players = append(players, game.NextPlayer.Name)
		}
		resp = append(resp, gameResponse{ID: id, Players: players})
	}
	js, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func (gh gameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var user = a.GetUser(w, r)
	fmt.Printf("105: user: %+v\n", user)
	id := r.FormValue("id")
	name := r.FormValue("name")
	fmt.Println(id)
	if name == "" {
		name = "Anonymous Coward"
	}
	if id != "" {
		// Does the game exist?
		fmt.Printf("All Games: %v\n", gh.games)
		if existingGame, ok := gh.games[id]; ok {
			fmt.Println("Trying to join existing game")
			existingGame.Join(w, r, name, user)
		} else {
			// make the id requested
			g := game.NewGame(id, gh.removeGameChan, gh.db)
			fmt.Printf("Made new game %s\n", id)
			gh.games[g.ID] = g
			g.Join(w, r, name, user)
		}
	} else {
		// no id specified, make the game
		newID := 0
		fmt.Printf("128: user: %+v\n", user)
		for _, exists := gh.games[strconv.Itoa(newID)]; exists; _, exists = gh.games[strconv.Itoa(newID)] {
			newID++
		}
		g := game.NewGame(strconv.Itoa(newID), gh.removeGameChan, gh.db)
		fmt.Printf("Made new game %d\n", newID)
		gh.games[g.ID] = g
		fmt.Printf("Trying to join new game as: %+v\n", user)
		if ok := g.Join(w, r, name, user); !ok {
			delete(gh.games, g.ID)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"

	"github.com/imwally/pinboard"
)

var (
	addFlag    = flag.String("add", "", "url of bookmark to add")
	delFlag    = flag.String("rm", "", "url of bookmark to delete")
	privFlag   = flag.Bool("private", false, "private bookmark")
	readFlag   = flag.Bool("readlater", false, "read later bookmark")
	extFlag    = flag.String("text", "", "longer description of bookmark")
	tagFlag    = flag.String("tag", "", "tags for bookmark")
	longFlag   = flag.Bool("l", false, "display long format")
	titleFlag  = flag.String("title", "", "title of the bookmark")
	showFlag   = flag.Int("show", 0, "show the most recent bookmarks")

	token string
)

// Add checks flag values and encodes the GET URL for adding a bookmark.
func Add(p pinboard.Post) {
    p.URL = *addFlag
    p.Description = *titleFlag

    if *privFlag {
        p.Shared = "no"
    }

    if *readFlag {
        p.Toread = "yes"
    }

    if *extFlag != "" {
        p.Extended = *extFlag
    }

    if *tagFlag != "" {
        p.Tags = *tagFlag
    }

    p.Encode()
    err := p.Add()
    if err != nil {
        fmt.Println(err)
    }
}

// Delete will delete the URL value of the -d flag.
func Delete(p pinboard.Post) {
    p.URL = *delFlag
    p.Encode()
    err := p.Delete()
    if err != nil {
        fmt.Println(err)
    }
}

// Show will list the most recent bookmarks. The -show flag indicates how many
// bookmarks to show with a max of up to 100 bookmarks.
func Show(p pinboard.Post) {
    if *tagFlag != "" {
        p.Tag = *tagFlag
    }

    p.Count = *showFlag
    p.Encode()

    recent := p.ShowRecent()

    if *longFlag {
        for _, v := range recent.Posts {
            var shared string
            if v.Shared == "no" {
                shared = "*"
            }
            fmt.Println(shared + v.Description)
            fmt.Println(v.Href)
            fmt.Println(v.Tags, "\n")
        }
    } else {
        for _, v := range recent.Posts {
            fmt.Println(v.Href)
        }
    }
}

// TokenIsSet will check to make sure an authentication token is set before
// making an API calls.
func TokenIsSet() bool {
    if token == "" {
        return false
    }
    return true
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Println(err)
	}

	content, err := ioutil.ReadFile(u.HomeDir + "/.pinboard")
	if err != nil {
        fmt.Println("No authorization token found. Please add your authorization token to ~/.pinboard")
	}

	token = string(content)
}

func main() {

    if TokenIsSet() {
        var p pinboard.Post
        p.Token = token

        flag.Parse()

        if flag.NFlag() < 1 {
            fmt.Fprintf(os.Stderr, "No command given.\n")
            flag.Usage()
            return
        }

        if *addFlag != "" {
            Add(p)
        }

        if *delFlag != "" {
            Delete(p)
        }

        if *showFlag > 0 {
            Show(p)
        }
    }

}
<commit_msg>main commands removed from flags<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"

	"github.com/imwally/pinboard"
)

var (
	privFlag   = flag.Bool("private", false, "private bookmark")
	readFlag   = flag.Bool("readlater", false, "read later bookmark")
	extFlag    = flag.String("text", "", "longer description of bookmark")
	tagFlag    = flag.String("tag", "", "tags for bookmark")
	longFlag   = flag.Bool("l", false, "display long format")
	titleFlag  = flag.String("title", "", "title of the bookmark")

	token string
)

// Add checks flag values and encodes the GET URL for adding a bookmark.
func Add(p pinboard.Post) {

    p.Description = *titleFlag

    if *privFlag {
        p.Shared = "no"
    }

    if *readFlag {
        p.Toread = "yes"
    }

    if *extFlag != "" {
        p.Extended = *extFlag
    }

    if *tagFlag != "" {
        p.Tags = *tagFlag
    }

    p.Encode()
    err := p.Add()
    if err != nil {
        fmt.Println(err)
    }
}

// Delete will delete the URL value of the -d flag.
func Delete(p pinboard.Post) {
    p.Encode()
    err := p.Delete()
    if err != nil {
        fmt.Println(err)
    }
}

// Show will list the most recent bookmarks. The -show flag indicates how many
// bookmarks to show with a max of up to 100 bookmarks.
func Show(p pinboard.Post) {
    if *tagFlag != "" {
        p.Tag = *tagFlag
    }

    p.Encode()

    recent := p.ShowRecent()

    if *longFlag {
        for _, v := range recent.Posts {
            var shared string
            if v.Shared == "no" {
                shared = "*"
            }
            fmt.Println(shared + v.Description)
            fmt.Println(v.Href)
            fmt.Println(v.Tags, "\n")
        }
    } else {
        for _, v := range recent.Posts {
            fmt.Println(v.Href)
        }
    }
}

// TokenIsSet will check to make sure an authentication token is set before
// making an API calls.
func TokenIsSet() bool {
    if token == "" {
        return false
    }
    return true
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Println(err)
	}

	content, err := ioutil.ReadFile(u.HomeDir + "/.pinboard")
	if err != nil {
        fmt.Println("No authorization token found. Please add your authorization token to ~/.pinboard")
	}

	token = string(content)
}

func main() {

	if TokenIsSet() {
		var p pinboard.Post
		p.Token = token

		cmd := os.Args[1]

		flag.Parse()

		if cmd == "add" {
			p.URL = os.Args[2]
			Add(p)
		}

		if cmd == "rm"  {
			p.URL = os.Args[2]
			Delete(p)
		}

		if cmd == "ls" {
			Show(p)
		}
	}

}
<|endoftext|>


<commit_before>package log

// singletons ftw?
var Log Interface = &Logger{
	Handler: HandlerFunc(handleStdLog),
	Level:   InfoLevel,
}

// SetHandler sets the handler. This is not thread-safe.
// The default handler outputs to the stdlib log.
func SetHandler(h Handler) {
	if logger, ok := Log.(*Logger); ok {
		logger.Handler = h
	}
}

// SetLevel sets the log level. This is not thread-safe.
func SetLevel(l Level) {
	if logger, ok := Log.(*Logger); ok {
		logger.Level = l
	}
}

// WithFields returns a new entry with `fields` set.
func WithFields(fields Fielder) *Entry {
	return Log.WithFields(fields)
}

// WithField returns a new entry with the `key` and `value` set.
func WithField(key string, value interface{}) *Entry {
	return Log.WithField(key, value)
}

// WithError returns a new entry with the "error" set to `err`.
func WithError(err error) *Entry {
	return Log.WithError(err)
}

// Debug level message.
func Debug(msg string) {
	Log.Debug(msg)
}

// Info level message.
func Info(msg string) {
	Log.Info(msg)
}

// Warn level message.
func Warn(msg string) {
	Log.Warn(msg)
}

// Error level message.
func Error(msg string) {
	Log.Error(msg)
}

// Fatal level message, followed by an exit.
func Fatal(msg string) {
	Log.Fatal(msg)
}

// Debugf level formatted message.
func Debugf(msg string, v ...interface{}) {
	Log.Debugf(msg, v...)
}

// Infof level formatted message.
func Infof(msg string, v ...interface{}) {
	Log.Infof(msg, v...)
}

// Warnf level formatted message.
func Warnf(msg string, v ...interface{}) {
	Log.Warnf(msg, v...)
}

// Errorf level formatted message.
func Errorf(msg string, v ...interface{}) {
	Log.Errorf(msg, v...)
}

// Fatalf level formatted message, followed by an exit.
func Fatalf(msg string, v ...interface{}) {
	Log.Fatalf(msg, v...)
}

// Trace returns a new entry with a Stop method to fire off
// a corresponding completion log, useful with defer.
func Trace(msg string) *Entry {
	return Log.Trace(msg)
}
<commit_msg>add SetLevelFromString()<commit_after>package log

// singletons ftw?
var Log Interface = &Logger{
	Handler: HandlerFunc(handleStdLog),
	Level:   InfoLevel,
}

// SetHandler sets the handler. This is not thread-safe.
// The default handler outputs to the stdlib log.
func SetHandler(h Handler) {
	if logger, ok := Log.(*Logger); ok {
		logger.Handler = h
	}
}

// SetLevel sets the log level. This is not thread-safe.
func SetLevel(l Level) {
	if logger, ok := Log.(*Logger); ok {
		logger.Level = l
	}
}

// SetLevelFromString sets the log level from a string, panicing when invalid. This is not thread-safe.
func SetLevelFromString(s string) {
	if logger, ok := Log.(*Logger); ok {
		logger.Level = MustParseLevel(s)
	}
}

// WithFields returns a new entry with `fields` set.
func WithFields(fields Fielder) *Entry {
	return Log.WithFields(fields)
}

// WithField returns a new entry with the `key` and `value` set.
func WithField(key string, value interface{}) *Entry {
	return Log.WithField(key, value)
}

// WithError returns a new entry with the "error" set to `err`.
func WithError(err error) *Entry {
	return Log.WithError(err)
}

// Debug level message.
func Debug(msg string) {
	Log.Debug(msg)
}

// Info level message.
func Info(msg string) {
	Log.Info(msg)
}

// Warn level message.
func Warn(msg string) {
	Log.Warn(msg)
}

// Error level message.
func Error(msg string) {
	Log.Error(msg)
}

// Fatal level message, followed by an exit.
func Fatal(msg string) {
	Log.Fatal(msg)
}

// Debugf level formatted message.
func Debugf(msg string, v ...interface{}) {
	Log.Debugf(msg, v...)
}

// Infof level formatted message.
func Infof(msg string, v ...interface{}) {
	Log.Infof(msg, v...)
}

// Warnf level formatted message.
func Warnf(msg string, v ...interface{}) {
	Log.Warnf(msg, v...)
}

// Errorf level formatted message.
func Errorf(msg string, v ...interface{}) {
	Log.Errorf(msg, v...)
}

// Fatalf level formatted message, followed by an exit.
func Fatalf(msg string, v ...interface{}) {
	Log.Fatalf(msg, v...)
}

// Trace returns a new entry with a Stop method to fire off
// a corresponding completion log, useful with defer.
func Trace(msg string) *Entry {
	return Log.Trace(msg)
}
<|endoftext|>