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

// Package httprouter is a trie based high performance HTTP request router.
//
// A trivial example is:
//
//  package main
//
//  import (
//      "fmt"
//      "github.com/julienschmidt/httprouter"
//      "net/http"
//      "log"
//  )
//
//  func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
//      fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
//  }
//
//  func main() {
//      router := httprouter.New()
//      router.GET("/", Index)
//      router.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":8080", router))
//  }
//
// The router matches incoming requests by the request method and the path.
// If a handle is registered for this path and method, the router delegates the
// request to that function.
// For the methods GET, POST, PUT, PATCH and DELETE shortcut functions exist to
// register handles, for all other methods router.Handle can be used.
//
// The registered path, against which the router matches incoming requests, can
// contain two types of parameters:
//  Syntax    Type
//  :name     named parameter
//  *name     catch-all parameter
//
// Named parameters are dynamic path segments. They match anything until the
// next '/' or the path end:
//  Path: /blog/:category/:post
//
//  Requests:
//   /blog/go/request-routers            match: category="go", post="request-routers"
//   /blog/go/request-routers/           no match, but the router would redirect
//   /blog/go/                           no match
//   /blog/go/request-routers/comments   no match
//
// Catch-all parameters match anything until the path end, including the
// directory index (the '/' before the catch-all). Since they match anything
// until the end, catch-all parameters must always be the final path element.
//  Path: /files/*filepath
//
//  Requests:
//   /files/                             match: filepath="/"
//   /files/LICENSE                      match: filepath="/LICENSE"
//   /files/templates/article.html       match: filepath="/templates/article.html"
//   /files                              no match, but the router would redirect
//
// The value of parameters is saved as a slice of the Param struct, consisting
// each of a key and a value. The slice is passed to the Handle func as a third
// parameter.
// There are two ways to retrieve the value of a parameter:
//  // by the name of the parameter
//  user := ps.ByName("user") // defined by :user or *user
//
//  // by the index of the parameter. This way you can also get the name (key)
//  thirdKey   := ps[2].Key   // the name of the 3rd parameter
//  thirdValue := ps[2].Value // the value of the 3rd parameter
package httprouter

import (
	"net/http"
)

// Handle is a function that can be registered to a route to handle HTTP
// requests. Like http.HandlerFunc, but has a third parameter for the values of
// wildcards (variables).
type Handle func(http.ResponseWriter, *http.Request, Params)

// Param is a single URL parameter, consisting of a key and a value.
type Param struct {
	Key   string
	Value string
}

// Params is a Param-slice, as returned by the router.
// The slice is ordered, the first URL parameter is also the first slice value.
// It is therefore safe to read values by the index.
type Params []Param

// ByName returns the value of the first Param which key matches the given name.
// If no matching Param is found, an empty string is returned.
func (ps Params) ByName(name string) string {
	for i := range ps {
		if ps[i].Key == name {
			return ps[i].Value
		}
	}
	return ""
}

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type Router struct {
	trees map[string]*node

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

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

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

	// If enabled, the router automatically replies to OPTIONS requests.
	// Custom OPTIONS handlers take priority over automatic replies.
	HandleOPTIONS bool

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

	// Configurable http.Handler which is called when a request
	// cannot be routed and HandleMethodNotAllowed is true.
	// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
	// The "Allow" header with allowed request methods is set before the handler
	// is called.
	MethodNotAllowed http.Handler

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

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returns a new initialized Router.
// Path auto-correction, including trailing slashes, is enabled by default.
func New() *Router {
	return &Router{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
		HandleOPTIONS:          true,
	}
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle Handle) {
	r.Handle("GET", path, handle)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (r *Router) HEAD(path string, handle Handle) {
	r.Handle("HEAD", path, handle)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (r *Router) OPTIONS(path string, handle Handle) {
	r.Handle("OPTIONS", path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle Handle) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle Handle) {
	r.Handle("PUT", path, handle)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (r *Router) PATCH(path string, handle Handle) {
	r.Handle("PATCH", path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle Handle) {
	r.Handle("DELETE", path, handle)
}

// Handle registers a new request handle with the given path and method.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (r *Router) Handle(method, path string, handle Handle) {
	if path[0] != '/' {
		panic("path must begin with '/' in path '" + path + "'")
	}

	if r.trees == nil {
		r.trees = make(map[string]*node)
	}

	root := r.trees[method]
	if root == nil {
		root = new(node)
		r.trees[method] = root
	}

	root.addRoute(path, handle)
}

// HandlerFunc is an adapter which allows the usage of an http.HandlerFunc as a
// request handle.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handler(method, path, handler)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
//     router.ServeFiles("/src/*filepath", http.Dir("/var/www"))
func (r *Router) ServeFiles(path string, root http.FileSystem) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath in path '" + path + "'")
	}

	fileServer := http.FileServer(root)

	r.GET(path, func(w http.ResponseWriter, req *http.Request, ps Params) {
		req.URL.Path = ps.ByName("filepath")
		fileServer.ServeHTTP(w, req)
	})
}

func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(w, req, rcv)
	}
}

// Lookup allows the manual lookup of a method + path combo.
// This is e.g. useful to build a framework around this router.
// If the path was found, it returns the handle function and the path parameter
// values. Otherwise the third return value indicates whether a redirection to
// the same path with an extra / without the trailing slash should be performed.
func (r *Router) Lookup(method, path string) (Handle, Params, bool) {
	if root := r.trees[method]; root != nil {
		return root.getValue(path)
	}
	return nil, nil, false
}

func (r *Router) allowed(path, reqMethod string) (allow string) {
	if path == "*" { // server-wide
		for method := range r.trees {
			if method == "OPTIONS" {
				continue
			}

			// add request method to list of allowed methods
			if len(allow) == 0 {
				allow = method
			} else {
				allow += ", " + method
			}
		}
	} else { // specific path
		for method := range r.trees {
			// Skip the requested method - we already tried this one
			if method == reqMethod || method == "OPTIONS" {
				continue
			}

			handle, _, _ := r.trees[method].getValue(path)
			if handle != nil {
				// add request method to list of allowed methods
				if len(allow) == 0 {
					allow = method
				} else {
					allow += ", " + method
				}
			}
		}
	}
	if len(allow) > 0 {
		allow += ", OPTIONS"
	}
	return
}

// ServeHTTP makes the router implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if r.PanicHandler != nil {
		defer r.recv(w, req)
	}

	path := req.URL.Path

	if root := r.trees[req.Method]; root != nil {
		if handle, ps, tsr := root.getValue(path); handle != nil {
			handle(w, req, ps)
			return
		} else if req.Method != "CONNECT" && path != "/" {
			code := 301 // Permanent redirect, request with GET method
			if req.Method != "GET" {
				// Temporary redirect, request with same method
				// As of Go 1.3, Go does not support status code 308.
				code = 307
			}

			if tsr && r.RedirectTrailingSlash {
				if len(path) > 1 && path[len(path)-1] == '/' {
					req.URL.Path = path[:len(path)-1]
				} else {
					req.URL.Path = path + "/"
				}
				http.Redirect(w, req, req.URL.String(), code)
				return
			}

			// Try to fix the request path
			if r.RedirectFixedPath {
				fixedPath, found := root.findCaseInsensitivePath(
					CleanPath(path),
					r.RedirectTrailingSlash,
				)
				if found {
					req.URL.Path = string(fixedPath)
					http.Redirect(w, req, req.URL.String(), code)
					return
				}
			}
		}
	}

	if req.Method == "OPTIONS" {
		// Handle OPTIONS requests
		if r.HandleOPTIONS {
			if allow := r.allowed(path, req.Method); len(allow) > 0 {
				w.Header().Set("Allow", allow)
				return
			}
		}
	} else {
		// Handle 405
		if r.HandleMethodNotAllowed {
			if allow := r.allowed(path, req.Method); len(allow) > 0 {
				w.Header().Set("Allow", allow)
				if r.MethodNotAllowed != nil {
					r.MethodNotAllowed.ServeHTTP(w, req)
				} else {
					http.Error(w,
						http.StatusText(http.StatusMethodNotAllowed),
						http.StatusMethodNotAllowed,
					)
				}
				return
			}
		}
	}

	// Handle 404
	if r.NotFound != nil {
		r.NotFound.ServeHTTP(w, req)
	} else {
		http.NotFound(w, req)
	}
}
<commit_msg>Throw 405 if !handleOPTIONS and no OPTIONS handler set (#201)<commit_after>// Copyright 2013 Julien Schmidt. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

// Package httprouter is a trie based high performance HTTP request router.
//
// A trivial example is:
//
//  package main
//
//  import (
//      "fmt"
//      "github.com/julienschmidt/httprouter"
//      "net/http"
//      "log"
//  )
//
//  func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
//      fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
//  }
//
//  func main() {
//      router := httprouter.New()
//      router.GET("/", Index)
//      router.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":8080", router))
//  }
//
// The router matches incoming requests by the request method and the path.
// If a handle is registered for this path and method, the router delegates the
// request to that function.
// For the methods GET, POST, PUT, PATCH and DELETE shortcut functions exist to
// register handles, for all other methods router.Handle can be used.
//
// The registered path, against which the router matches incoming requests, can
// contain two types of parameters:
//  Syntax    Type
//  :name     named parameter
//  *name     catch-all parameter
//
// Named parameters are dynamic path segments. They match anything until the
// next '/' or the path end:
//  Path: /blog/:category/:post
//
//  Requests:
//   /blog/go/request-routers            match: category="go", post="request-routers"
//   /blog/go/request-routers/           no match, but the router would redirect
//   /blog/go/                           no match
//   /blog/go/request-routers/comments   no match
//
// Catch-all parameters match anything until the path end, including the
// directory index (the '/' before the catch-all). Since they match anything
// until the end, catch-all parameters must always be the final path element.
//  Path: /files/*filepath
//
//  Requests:
//   /files/                             match: filepath="/"
//   /files/LICENSE                      match: filepath="/LICENSE"
//   /files/templates/article.html       match: filepath="/templates/article.html"
//   /files                              no match, but the router would redirect
//
// The value of parameters is saved as a slice of the Param struct, consisting
// each of a key and a value. The slice is passed to the Handle func as a third
// parameter.
// There are two ways to retrieve the value of a parameter:
//  // by the name of the parameter
//  user := ps.ByName("user") // defined by :user or *user
//
//  // by the index of the parameter. This way you can also get the name (key)
//  thirdKey   := ps[2].Key   // the name of the 3rd parameter
//  thirdValue := ps[2].Value // the value of the 3rd parameter
package httprouter

import (
	"net/http"
)

// Handle is a function that can be registered to a route to handle HTTP
// requests. Like http.HandlerFunc, but has a third parameter for the values of
// wildcards (variables).
type Handle func(http.ResponseWriter, *http.Request, Params)

// Param is a single URL parameter, consisting of a key and a value.
type Param struct {
	Key   string
	Value string
}

// Params is a Param-slice, as returned by the router.
// The slice is ordered, the first URL parameter is also the first slice value.
// It is therefore safe to read values by the index.
type Params []Param

// ByName returns the value of the first Param which key matches the given name.
// If no matching Param is found, an empty string is returned.
func (ps Params) ByName(name string) string {
	for i := range ps {
		if ps[i].Key == name {
			return ps[i].Value
		}
	}
	return ""
}

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type Router struct {
	trees map[string]*node

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

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

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

	// If enabled, the router automatically replies to OPTIONS requests.
	// Custom OPTIONS handlers take priority over automatic replies.
	HandleOPTIONS bool

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

	// Configurable http.Handler which is called when a request
	// cannot be routed and HandleMethodNotAllowed is true.
	// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
	// The "Allow" header with allowed request methods is set before the handler
	// is called.
	MethodNotAllowed http.Handler

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

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returns a new initialized Router.
// Path auto-correction, including trailing slashes, is enabled by default.
func New() *Router {
	return &Router{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
		HandleOPTIONS:          true,
	}
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle Handle) {
	r.Handle("GET", path, handle)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (r *Router) HEAD(path string, handle Handle) {
	r.Handle("HEAD", path, handle)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (r *Router) OPTIONS(path string, handle Handle) {
	r.Handle("OPTIONS", path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle Handle) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle Handle) {
	r.Handle("PUT", path, handle)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (r *Router) PATCH(path string, handle Handle) {
	r.Handle("PATCH", path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle Handle) {
	r.Handle("DELETE", path, handle)
}

// Handle registers a new request handle with the given path and method.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (r *Router) Handle(method, path string, handle Handle) {
	if path[0] != '/' {
		panic("path must begin with '/' in path '" + path + "'")
	}

	if r.trees == nil {
		r.trees = make(map[string]*node)
	}

	root := r.trees[method]
	if root == nil {
		root = new(node)
		r.trees[method] = root
	}

	root.addRoute(path, handle)
}

// HandlerFunc is an adapter which allows the usage of an http.HandlerFunc as a
// request handle.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handler(method, path, handler)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
//     router.ServeFiles("/src/*filepath", http.Dir("/var/www"))
func (r *Router) ServeFiles(path string, root http.FileSystem) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath in path '" + path + "'")
	}

	fileServer := http.FileServer(root)

	r.GET(path, func(w http.ResponseWriter, req *http.Request, ps Params) {
		req.URL.Path = ps.ByName("filepath")
		fileServer.ServeHTTP(w, req)
	})
}

func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(w, req, rcv)
	}
}

// Lookup allows the manual lookup of a method + path combo.
// This is e.g. useful to build a framework around this router.
// If the path was found, it returns the handle function and the path parameter
// values. Otherwise the third return value indicates whether a redirection to
// the same path with an extra / without the trailing slash should be performed.
func (r *Router) Lookup(method, path string) (Handle, Params, bool) {
	if root := r.trees[method]; root != nil {
		return root.getValue(path)
	}
	return nil, nil, false
}

func (r *Router) allowed(path, reqMethod string) (allow string) {
	if path == "*" { // server-wide
		for method := range r.trees {
			if method == "OPTIONS" {
				continue
			}

			// add request method to list of allowed methods
			if len(allow) == 0 {
				allow = method
			} else {
				allow += ", " + method
			}
		}
	} else { // specific path
		for method := range r.trees {
			// Skip the requested method - we already tried this one
			if method == reqMethod || method == "OPTIONS" {
				continue
			}

			handle, _, _ := r.trees[method].getValue(path)
			if handle != nil {
				// add request method to list of allowed methods
				if len(allow) == 0 {
					allow = method
				} else {
					allow += ", " + method
				}
			}
		}
	}
	if len(allow) > 0 {
		allow += ", OPTIONS"
	}
	return
}

// ServeHTTP makes the router implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if r.PanicHandler != nil {
		defer r.recv(w, req)
	}

	path := req.URL.Path

	if root := r.trees[req.Method]; root != nil {
		if handle, ps, tsr := root.getValue(path); handle != nil {
			handle(w, req, ps)
			return
		} else if req.Method != "CONNECT" && path != "/" {
			code := 301 // Permanent redirect, request with GET method
			if req.Method != "GET" {
				// Temporary redirect, request with same method
				// As of Go 1.3, Go does not support status code 308.
				code = 307
			}

			if tsr && r.RedirectTrailingSlash {
				if len(path) > 1 && path[len(path)-1] == '/' {
					req.URL.Path = path[:len(path)-1]
				} else {
					req.URL.Path = path + "/"
				}
				http.Redirect(w, req, req.URL.String(), code)
				return
			}

			// Try to fix the request path
			if r.RedirectFixedPath {
				fixedPath, found := root.findCaseInsensitivePath(
					CleanPath(path),
					r.RedirectTrailingSlash,
				)
				if found {
					req.URL.Path = string(fixedPath)
					http.Redirect(w, req, req.URL.String(), code)
					return
				}
			}
		}
	}

	if req.Method == "OPTIONS" && r.HandleOPTIONS {
		// Handle OPTIONS requests
		if allow := r.allowed(path, req.Method); len(allow) > 0 {
			w.Header().Set("Allow", allow)
			return
		}
	} else {
		// Handle 405
		if r.HandleMethodNotAllowed {
			if allow := r.allowed(path, req.Method); len(allow) > 0 {
				w.Header().Set("Allow", allow)
				if r.MethodNotAllowed != nil {
					r.MethodNotAllowed.ServeHTTP(w, req)
				} else {
					http.Error(w,
						http.StatusText(http.StatusMethodNotAllowed),
						http.StatusMethodNotAllowed,
					)
				}
				return
			}
		}
	}

	// Handle 404
	if r.NotFound != nil {
		r.NotFound.ServeHTTP(w, req)
	} else {
		http.NotFound(w, req)
	}
}
<|endoftext|>


<commit_before>package webgo

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// Struct to define a route for each API
type Route struct {
	Name    string       // Just a label to name the route/API, this is not used anywhere
	Method  string       // Request type
	Pattern string       // URI
	Handler HandlerChain // Handler function with middlewares
	G       Globals      // App globals
}

// Inject httprouter params to the context
func InjectParams(route Route) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		// convert httprouter params to map of string
		params := make(map[string]string)
		for i := range ps {
			params[ps[i].Key] = ps[i].Value
		}

		// Injecting multiplexer params to every request context
		newHandlerChain := StackInject(route.Handler, "params", params)
		// Injecting globals to every request context
		newHandlerChain = StackInject(newHandlerChain, "globals", route.G)
		newHandlerChain.ServeHTTP(w, r)
	}
}

// Initiate Router settings
func InitRouter(routes []Route) *httprouter.Router {
	router := httprouter.New()

	// Handles all the route types
	for _, route := range routes {
		switch route.Method {
		case "OPTIONS":
			router.OPTIONS(
				route.Pattern,
				InjectParams(route))
		case "GET":
			router.GET(
				route.Pattern,
				InjectParams(route))
		case "POST":
			router.POST(
				route.Pattern,
				InjectParams(route))
		case "PUT":
			router.PUT(
				route.Pattern,
				InjectParams(route))
		case "DELETE":
			router.DELETE(
				route.Pattern,
				InjectParams(route))
		case "PATCH":
			router.PATCH(
				route.Pattern,
				InjectParams(route))
		}
	}
	return router
}

// ===
<commit_msg>made globals a pointer rather than a copy<commit_after>package webgo

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// Struct to define a route for each API
type Route struct {
	Name    string       // Just a label to name the route/API, this is not used anywhere
	Method  string       // Request type
	Pattern string       // URI
	Handler HandlerChain // Handler function with middlewares
	G       *Globals     // App globals
}

// Inject httprouter params to the context
func InjectParams(route Route) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		// convert httprouter params to map of string
		params := make(map[string]string)
		for i := range ps {
			params[ps[i].Key] = ps[i].Value
		}

		// Injecting multiplexer params to every request context
		newHandlerChain := StackInject(route.Handler, "params", params)
		// Injecting globals to every request context
		newHandlerChain = StackInject(newHandlerChain, "globals", route.G)
		newHandlerChain.ServeHTTP(w, r)
	}
}

// Initiate Router settings
func InitRouter(routes []Route) *httprouter.Router {
	router := httprouter.New()

	// Handles all the route types
	for _, route := range routes {
		switch route.Method {
		case "OPTIONS":
			router.OPTIONS(
				route.Pattern,
				InjectParams(route))
		case "GET":
			router.GET(
				route.Pattern,
				InjectParams(route))
		case "POST":
			router.POST(
				route.Pattern,
				InjectParams(route))
		case "PUT":
			router.PUT(
				route.Pattern,
				InjectParams(route))
		case "DELETE":
			router.DELETE(
				route.Pattern,
				InjectParams(route))
		case "PATCH":
			router.PATCH(
				route.Pattern,
				InjectParams(route))
		}
	}
	return router
}

// ===
<|endoftext|>


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

// Package routing provides high performance and powerful HTTP routing capabilities.
package tigo

import (
	"net/http"
	"sort"
	"strings"
	"sync"
	"github.com/valyala/fasthttp"
)

type (
	// Handler is the function for handling HTTP requests.
	Handler func(*Context) error

	// Router manages routes and dispatches HTTP requests to the handlers of the matching routes.
	Router struct {
		RouteGroup
		pool             sync.Pool
		routes           map[string]*Route
		stores           map[string]routeStore
		maxParams        int
		notFound         []Handler
		notFoundHandlers []Handler
		render   Render
	}

	// routeStore stores route paths and the corresponding handlers.
	routeStore interface {
		Add(key string, data interface{}) int
		Get(key string, pvalues []string) (data interface{}, pnames []string)
		String() string
	}
)

// Methods lists all supported HTTP methods by Router.
var Methods = []string{
	"CONNECT",
	"DELETE",
	"GET",
	"HEAD",
	"OPTIONS",
	"PATCH",
	"POST",
	"PUT",
	"TRACE",
}

// HandleRequest handles the HTTP request.
func (r *Router) HandleRequest(ctx *fasthttp.RequestCtx) {
	c := r.pool.Get().(*Context)
	c.init(ctx)
	c.handlers, c.pnames = r.find(string(ctx.Method()), string(ctx.Path()), c.pvalues)
	if err := c.Next(); err != nil {
		r.handleError(c, err)
	}
	r.pool.Put(c)
}

// Route returns the named route.
// Nil is returned if the named route cannot be found.
func (r *Router) Route(name string) *Route {
	return r.routes[name]
}

// Use appends the specified handlers to the router and shares them with all routes.
func (r *Router) Use(handlers ...Handler) {
	r.RouteGroup.Use(handlers...)
	r.notFoundHandlers = combineHandlers(r.handlers, r.notFound)
}

// NotFound specifies the handlers that should be invoked when the router cannot find any route matching a request.
// Note that the handlers registered via Use will be invoked first in this case.
func (r *Router) NotFound(handlers ...Handler) {
	r.notFound = handlers
	r.notFoundHandlers = combineHandlers(r.handlers, r.notFound)
}

// SetRender set render engine for Render()
func (r *Router) SetRender(render Render) {
	r.render = render
}

// handleError is the error handler for handling any unhandled errors.
func (r *Router) handleError(c *Context, err error) {
	if httpError, ok := err.(HTTPError); ok {
		c.Error(httpError.Error(), httpError.StatusCode())
	} else {
		c.Error(err.Error(), http.StatusInternalServerError)
	}
}

func (r *Router) add(method, path string, handlers []Handler) {
	store := r.stores[method]
	if store == nil {
		store = newStore()
		r.stores[method] = store
	}
	if n := store.Add(path, handlers); n > r.maxParams {
		r.maxParams = n
	}
}

func (r *Router) find(method, path string, pvalues []string) (handlers []Handler, pnames []string) {
	var hh interface{}
	if store := r.stores[method]; store != nil {
		hh, pnames = store.Get(path, pvalues)
	}
	if hh != nil {
		return hh.([]Handler), pnames
	}
	return r.notFoundHandlers, pnames
}

func (r *Router) findAllowedMethods(path string) map[string]bool {
	methods := make(map[string]bool)
	pvalues := make([]string, r.maxParams)
	for m, store := range r.stores {
		if handlers, _ := store.Get(path, pvalues); handlers != nil {
			methods[m] = true
		}
	}
	return methods
}

// NotFoundHandler returns a 404 HTTP error indicating a request has no matching route.
func NotFoundHandler(*Context) error {
	return NewHTTPError(http.StatusNotFound)
}

// MethodNotAllowedHandler handles the situation when a request has matching route without matching HTTP method.
// In this case, the handler will respond with an Allow HTTP header listing the allowed HTTP methods.
// Otherwise, the handler will do nothing and let the next handler (usually a NotFoundHandler) to handle the problem.
func MethodNotAllowedHandler(c *Context) error {
	methods := c.Router().findAllowedMethods(string(c.Path()))
	if len(methods) == 0 {
		return nil
	}
	methods["OPTIONS"] = true
	ms := make([]string, len(methods))
	i := 0
	for method := range methods {
		ms[i] = method
		i++
	}
	sort.Strings(ms)
	c.Response.Header.Set("Allow", strings.Join(ms, ", "))
	if string(c.Method()) != "OPTIONS" {
		c.Response.SetStatusCode(http.StatusMethodNotAllowed)
	}
	c.Abort()
	return nil
}
<commit_msg>add docs<commit_after>package tigo

import (
	"net/http"
	"sort"
	"strings"
	"sync"
	"github.com/valyala/fasthttp"
)

type (
	// Handler is the function for handling HTTP requests.
	Handler func(*Context) error

	// Router manages routes and dispatches HTTP requests to the handlers of the matching routes.
	Router struct {
		RouteGroup
		pool             sync.Pool
		routes           map[string]*Route
		stores           map[string]routeStore
		maxParams        int
		notFound         []Handler
		notFoundHandlers []Handler
		render   Render
	}

	// routeStore stores route paths and the corresponding handlers.
	routeStore interface {
		Add(key string, data interface{}) int
		Get(key string, pvalues []string) (data interface{}, pnames []string)
		String() string
	}
)

// Methods lists all supported HTTP methods by Router.
var Methods = []string{
	"CONNECT",
	"DELETE",
	"GET",
	"HEAD",
	"OPTIONS",
	"PATCH",
	"POST",
	"PUT",
	"TRACE",
}

// HandleRequest handles the HTTP request.
func (r *Router) HandleRequest(ctx *fasthttp.RequestCtx) {
	c := r.pool.Get().(*Context)
	c.init(ctx)
	c.handlers, c.pnames = r.find(string(ctx.Method()), string(ctx.Path()), c.pvalues)
	if err := c.Next(); err != nil {
		r.handleError(c, err)
	}
	r.pool.Put(c)
}

// Route returns the named route.
// Nil is returned if the named route cannot be found.
func (r *Router) Route(name string) *Route {
	return r.routes[name]
}

// Use appends the specified handlers to the router and shares them with all routes.
func (r *Router) Use(handlers ...Handler) {
	r.RouteGroup.Use(handlers...)
	r.notFoundHandlers = combineHandlers(r.handlers, r.notFound)
}

// NotFound specifies the handlers that should be invoked when the router cannot find any route matching a request.
// Note that the handlers registered via Use will be invoked first in this case.
func (r *Router) NotFound(handlers ...Handler) {
	r.notFound = handlers
	r.notFoundHandlers = combineHandlers(r.handlers, r.notFound)
}

// SetRender set render engine for Render()
func (r *Router) SetRender(render Render) {
	r.render = render
}

// handleError is the error handler for handling any unhandled errors.
func (r *Router) handleError(c *Context, err error) {
	if httpError, ok := err.(HTTPError); ok {
		c.Error(httpError.Error(), httpError.StatusCode())
	} else {
		c.Error(err.Error(), http.StatusInternalServerError)
	}
}

func (r *Router) add(method, path string, handlers []Handler) {
	store := r.stores[method]
	if store == nil {
		store = newStore()
		r.stores[method] = store
	}
	if n := store.Add(path, handlers); n > r.maxParams {
		r.maxParams = n
	}
}

func (r *Router) find(method, path string, pvalues []string) (handlers []Handler, pnames []string) {
	var hh interface{}
	if store := r.stores[method]; store != nil {
		hh, pnames = store.Get(path, pvalues)
	}
	if hh != nil {
		return hh.([]Handler), pnames
	}
	return r.notFoundHandlers, pnames
}

func (r *Router) findAllowedMethods(path string) map[string]bool {
	methods := make(map[string]bool)
	pvalues := make([]string, r.maxParams)
	for m, store := range r.stores {
		if handlers, _ := store.Get(path, pvalues); handlers != nil {
			methods[m] = true
		}
	}
	return methods
}

// NotFoundHandler returns a 404 HTTP error indicating a request has no matching route.
func NotFoundHandler(*Context) error {
	return NewHTTPError(http.StatusNotFound)
}

// MethodNotAllowedHandler handles the situation when a request has matching route without matching HTTP method.
// In this case, the handler will respond with an Allow HTTP header listing the allowed HTTP methods.
// Otherwise, the handler will do nothing and let the next handler (usually a NotFoundHandler) to handle the problem.
func MethodNotAllowedHandler(c *Context) error {
	methods := c.Router().findAllowedMethods(string(c.Path()))
	if len(methods) == 0 {
		return nil
	}
	methods["OPTIONS"] = true
	ms := make([]string, len(methods))
	i := 0
	for method := range methods {
		ms[i] = method
		i++
	}
	sort.Strings(ms)
	c.Response.Header.Set("Allow", strings.Join(ms, ", "))
	if string(c.Method()) != "OPTIONS" {
		c.Response.SetStatusCode(http.StatusMethodNotAllowed)
	}
	c.Abort()
	return nil
}
<|endoftext|>


<commit_before>package Components

import (
	"github.com/go-gl/gl"
	//"image"
	//"github.com/go-gl/glfw"
	//"gl/glu"
	//"log"

	//"bufio"
	//"image/png"
	//"os"
	//"strconv"
	//"github.com/go-gl/glfw"
	"github.com/vova616/GarageEngine/Engine"
	"github.com/vova616/GarageEngine/Engine/Input"
	"github.com/vova616/chipmunk/vect"
	//"runtime"
)

type UIText struct {
	Engine.BaseComponent
	Font           *Engine.Font
	text           string
	buffer         gl.Buffer
	vertexCount    int
	texcoordsIndex int

	tabSize int

	width  float32
	height float32
	align  Engine.AlignType

	focused    bool
	writeable  bool
	updateText bool

	autoFocus bool //This will go away

	Color Engine.Vector
}

func NewUIText(font *Engine.Font, text string) *UIText {
	if font == nil {
		return nil
	}

	uitext := &UIText{BaseComponent: Engine.NewComponent(),
		Font:      font,
		text:      text,
		buffer:    gl.GenBuffer(),
		align:     Engine.AlignCenter,
		writeable: false,
		tabSize:   4,
		Color:     Engine.Vector{1, 1, 1}}

	uitext.setString(text)
	Input.AddCharCallback(func(rn rune) { uitext.charCallback(rn) })
	return uitext
}

func (ui *UIText) OnComponentBind(binded *Engine.GameObject) {
	ph := binded.AddComponent(Engine.NewPhysics(false, 1, 1)).(*Engine.Physics)
	_ = ph
	ph.Body.IgnoreGravity = true
	ph.Shape.IsSensor = true
}

func (ui *UIText) Width() float32 {
	return ui.width
}

func (ui *UIText) Height() float32 {
	return ui.height
}

func (ui *UIText) SetString(text string) {
	ui.text = text
	ui.updateText = true
}

func (ui *UIText) setString(text string) {
	ui.text = text

	if text == "" {
		ui.buffer.Bind(gl.ARRAY_BUFFER)
		gl.BufferData(gl.ARRAY_BUFFER, 1, []byte{1}, gl.STATIC_DRAW)
		return
	}

	l := len(text)
	lt := l * 12
	_ = lt
	data := make([]float32, 20*l)

	vertexCount := 0
	texcoordsIndex := lt * 4

	space := float32(0)
	w, h := ui.GetPixelSize(text)

	index := 0
	for _, rune := range text {
		spaceMult := float32(1)
		if rune == '\t' {
			rune = ' '
			spaceMult = float32(index % ui.tabSize)
		}
		atlasImage := ui.Font.LetterInfo(rune)

		if atlasImage == nil {
			continue
		}

		yratio := atlasImage.RelativeHeight
		xratio := atlasImage.RelativeWidth

		//ygrid := -0.5 + (atlasImage.YGrid)
		//xgrid := (-0.5 + (atlasImage.XGrid)) + space
		ygrid := -(h / 2) + (atlasImage.YOffset)
		xgrid := -(w / 2) + (atlasImage.XOffset) + space
		space += atlasImage.XAdvance * spaceMult

		vertexCount += 4

		uv := Engine.IndexUV(ui.Font, rune)

		data[(index*12)+0] = xgrid
		data[(index*12)+1] = ygrid
		data[(index*12)+2] = 1
		data[(index*12)+3] = (xratio) + xgrid
		data[(index*12)+4] = ygrid
		data[(index*12)+5] = 1
		data[(index*12)+6] = (xratio) + xgrid
		data[(index*12)+7] = (yratio) + ygrid
		data[(index*12)+8] = 1
		data[(index*12)+9] = xgrid
		data[(index*12)+10] = (yratio) + ygrid
		data[(index*12)+11] = 1

		data[lt+(index*8)+0] = uv.U1
		data[lt+(index*8)+1] = uv.V2
		data[lt+(index*8)+2] = uv.U2
		data[lt+(index*8)+3] = uv.V2

		data[lt+(index*8)+4] = uv.U2
		data[lt+(index*8)+5] = uv.V1
		data[lt+(index*8)+6] = uv.U1
		data[lt+(index*8)+7] = uv.V1
		index++
	}

	ui.width = w
	ui.height = h

	ui.vertexCount = vertexCount
	ui.texcoordsIndex = texcoordsIndex
	ui.buffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, data, gl.STATIC_DRAW)
}

func (ui *UIText) GetPixelSize(text string) (width float32, height float32) {
	index := 0
	for _, rune := range text {
		spaceMult := float32(1)
		if rune == '\t' {
			rune = ' '
			spaceMult = float32(index % ui.tabSize)
		}
		atlasImage := ui.Font.LetterInfo(rune)

		if atlasImage == nil {
			continue
		}
		width += atlasImage.RelativeWidth * spaceMult
		/*
			yratio := atlasImage.PlaneHeight
			ygrid := atlasImage.YGrid
			if yratio < 0 {
				yratio = -yratio
			}
			if ygrid < 0 {
				ygrid = -ygrid
			}

			if yratio+ygrid > height {
				height = yratio + ygrid
			}
		*/
		height = 1
	}
	return
}

func (ui *UIText) String() string {
	return ui.text
}

func (ui *UIText) Start() {

}

func (ui *UIText) SetFocus(b bool) {
	ui.focused = b
}
func (ui *UIText) SetWritable(b bool) {
	ui.writeable = b
}

func (ui *UIText) charCallback(rn rune) {
	if ui.focused && ui.writeable {
		ui.text += string(rn)
		ui.updateText = true
	}
}

//var speed = float32(30)

func (ui *UIText) Update() {
	ui.UpdateCollider()

	/*
		s := ui.Transform().Scale()

		if s.X < 20 && speed < 0 {
			speed = -speed
		} else if s.X > 200 && speed > 0 {
			speed = -speed
		}

		s.X += speed * Engine.DeltaTime()
		s.Y += speed * Engine.DeltaTime()

		ui.Transform().SetScale(s)
	*/

	//Handle Tab & Backspace
	if ui.focused && ui.writeable {
		if len(ui.text) > 0 && Input.KeyPress(Input.KeyBackspace) {
			ui.updateText = true
			ui.text = ui.text[:len(ui.text)-1]
		}
		if Input.KeyPress(Input.KeyTab) {
			ui.updateText = true
			ui.text += "\t"
		}
	}
}

func (ui *UIText) LateUpdate() {
	if ui.updateText {
		ui.updateText = false
		ui.setString(ui.text)
	}
}

func (ui *UIText) UpdateCollider() {
	//if ui.GameObject().Physics.Body.Enabled {
	if ui.GameObject().Physics == nil {
		return
	}
	b := ui.GameObject().Physics.Box
	if b != nil {
		h := vect.Float(float64(ui.height) * float64(ui.GameObject().Transform().WorldScale().Y))
		w := vect.Float(float64(ui.width) * float64(ui.GameObject().Transform().WorldScale().X))
		update := false
		if h != b.Height || w != b.Width {
			b.Width = w
			b.Height = h
			update = true
		}

		c := Engine.Align(ui.align)
		center := vect.Vect{vect.Float(c.X), vect.Float(c.Y)}
		center.X = (center.X * w)
		center.Y = (center.Y * h)

		if b.Position.X != center.X || b.Position.Y != center.Y {
			update = true
			b.Position.X, b.Position.Y = center.X, center.Y
		}

		if update {
			b.UpdatePoly()
		}
	}
	//log.Println(b.Height, b.Width, ui.GameObject().Transform().Scale().X, ui.GameObject().Name())
	//}
}

func (ui *UIText) Align() Engine.AlignType {
	return ui.align
}

func (ui *UIText) SetAlign(align Engine.AlignType) {
	ui.align = align
}

func (ui *UIText) Draw() {
	if ui.text == "" {
		return
	}

	v := Engine.Align(ui.align)
	v.X = (v.X * ui.width)
	v.Y = (v.Y * ui.height)

	mat := Engine.TextureMaterial
	if ui.Font.IsSDF() {
		mat = Engine.SDFMaterial
	}
	mat.Begin(ui.GameObject())

	vert := mat.Verts
	uv := mat.UV
	mp := mat.ProjMatrix
	mv := mat.ViewMatrix
	mm := mat.ModelMatrix
	tx := mat.Texture
	color := mat.AddColor
	_ = color

	vert.EnableArray()
	uv.EnableArray()

	ui.buffer.Bind(gl.ARRAY_BUFFER)

	vert.AttribPointer(3, gl.FLOAT, false, 0, uintptr(0))
	uv.AttribPointer(2, gl.FLOAT, false, 0, uintptr(ui.texcoordsIndex))

	camera := Engine.GetScene().SceneBase().Camera

	view := camera.Transform().Matrix()
	view = view.Invert()
	model := Engine.NewIdentity()
	model.Translate(v.X, v.Y, 0)
	model.Mul(ui.GameObject().Transform().Matrix())

	/*
		view := camera.Transform().Matrix()
		view = view.Invert()
		model := ui.GameObject().Transform().Matrix()
	*/

	mv.UniformMatrix4fv(false, view)
	mp.UniformMatrix4fv(false, *camera.Projection)
	mm.UniformMatrix4fv(false, *model)

	ui.Font.Bind()
	gl.ActiveTexture(gl.TEXTURE0)
	tx.Uniform1i(0)

	color.Uniform4f(ui.Color.X, ui.Color.Y, ui.Color.Z, 1)

	gl.DrawArrays(gl.QUADS, 0, ui.vertexCount)

	ui.Font.Unbind()
	vert.DisableArray()
	uv.DisableArray()

}
<commit_msg>Fixed GetPixelSize.<commit_after>package Components

import (
	"github.com/go-gl/gl"
	//"image"
	//"github.com/go-gl/glfw"
	//"gl/glu"
	//"log"

	//"bufio"
	//"image/png"
	//"os"
	//"strconv"
	//"github.com/go-gl/glfw"
	"github.com/vova616/GarageEngine/Engine"
	"github.com/vova616/GarageEngine/Engine/Input"
	"github.com/vova616/chipmunk/vect"
	//"runtime"
)

type UIText struct {
	Engine.BaseComponent
	Font           *Engine.Font
	text           string
	buffer         gl.Buffer
	vertexCount    int
	texcoordsIndex int

	tabSize int

	width  float32
	height float32
	align  Engine.AlignType

	focused    bool
	writeable  bool
	updateText bool

	autoFocus bool //This will go away

	Color Engine.Vector
}

func NewUIText(font *Engine.Font, text string) *UIText {
	if font == nil {
		return nil
	}

	uitext := &UIText{BaseComponent: Engine.NewComponent(),
		Font:      font,
		text:      text,
		buffer:    gl.GenBuffer(),
		align:     Engine.AlignCenter,
		writeable: false,
		tabSize:   4,
		Color:     Engine.Vector{1, 1, 1}}

	uitext.setString(text)
	Input.AddCharCallback(func(rn rune) { uitext.charCallback(rn) })
	return uitext
}

func (ui *UIText) OnComponentBind(binded *Engine.GameObject) {
	ph := binded.AddComponent(Engine.NewPhysics(false, 1, 1)).(*Engine.Physics)
	_ = ph
	ph.Body.IgnoreGravity = true
	ph.Shape.IsSensor = true
}

func (ui *UIText) Width() float32 {
	return ui.width
}

func (ui *UIText) Height() float32 {
	return ui.height
}

func (ui *UIText) SetString(text string) {
	ui.text = text
	ui.updateText = true
}

func (ui *UIText) setString(text string) {
	ui.text = text

	if text == "" {
		ui.buffer.Bind(gl.ARRAY_BUFFER)
		gl.BufferData(gl.ARRAY_BUFFER, 1, []byte{1}, gl.STATIC_DRAW)
		return
	}

	l := len(text)
	lt := l * 12
	_ = lt
	data := make([]float32, 20*l)

	vertexCount := 0
	texcoordsIndex := lt * 4

	space := float32(0)
	w, h := ui.GetPixelSize(text)

	index := 0
	for _, rune := range text {
		spaceMult := float32(1)
		if rune == '\t' {
			rune = ' '
			spaceMult = float32(index % ui.tabSize)
		}
		atlasImage := ui.Font.LetterInfo(rune)

		if atlasImage == nil {
			continue
		}

		yratio := atlasImage.RelativeHeight
		xratio := atlasImage.RelativeWidth

		//ygrid := -0.5 + (atlasImage.YGrid)
		//xgrid := (-0.5 + (atlasImage.XGrid)) + space
		ygrid := -(h / 2) + (atlasImage.YOffset)
		xgrid := -(w / 2) + (atlasImage.XOffset) + space
		space += atlasImage.XAdvance * spaceMult

		vertexCount += 4

		uv := Engine.IndexUV(ui.Font, rune)

		data[(index*12)+0] = xgrid
		data[(index*12)+1] = ygrid
		data[(index*12)+2] = 1
		data[(index*12)+3] = (xratio) + xgrid
		data[(index*12)+4] = ygrid
		data[(index*12)+5] = 1
		data[(index*12)+6] = (xratio) + xgrid
		data[(index*12)+7] = (yratio) + ygrid
		data[(index*12)+8] = 1
		data[(index*12)+9] = xgrid
		data[(index*12)+10] = (yratio) + ygrid
		data[(index*12)+11] = 1

		data[lt+(index*8)+0] = uv.U1
		data[lt+(index*8)+1] = uv.V2
		data[lt+(index*8)+2] = uv.U2
		data[lt+(index*8)+3] = uv.V2

		data[lt+(index*8)+4] = uv.U2
		data[lt+(index*8)+5] = uv.V1
		data[lt+(index*8)+6] = uv.U1
		data[lt+(index*8)+7] = uv.V1
		index++
	}

	ui.width = w
	ui.height = h

	ui.vertexCount = vertexCount
	ui.texcoordsIndex = texcoordsIndex
	ui.buffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, data, gl.STATIC_DRAW)
}

func (ui *UIText) GetPixelSize(text string) (width float32, height float32) {
	index := 0
	for _, rune := range text {
		spaceMult := float32(1)
		if rune == '\t' {
			rune = ' '
			spaceMult = float32(index % ui.tabSize)
		}
		atlasImage := ui.Font.LetterInfo(rune)

		if atlasImage == nil {
			continue
		}
		width += atlasImage.XAdvance * spaceMult
		/*
			yratio := atlasImage.PlaneHeight
			ygrid := atlasImage.YGrid
			if yratio < 0 {
				yratio = -yratio
			}
			if ygrid < 0 {
				ygrid = -ygrid
			}

			if yratio+ygrid > height {
				height = yratio + ygrid
			}
		*/
		height = 1
	}
	return
}

func (ui *UIText) String() string {
	return ui.text
}

func (ui *UIText) Start() {

}

func (ui *UIText) SetFocus(b bool) {
	ui.focused = b
}
func (ui *UIText) SetWritable(b bool) {
	ui.writeable = b
}

func (ui *UIText) charCallback(rn rune) {
	if ui.focused && ui.writeable {
		ui.text += string(rn)
		ui.updateText = true
	}
}

//var speed = float32(30)

func (ui *UIText) Update() {
	ui.UpdateCollider()

	/*
		s := ui.Transform().Scale()

		if s.X < 20 && speed < 0 {
			speed = -speed
		} else if s.X > 200 && speed > 0 {
			speed = -speed
		}

		s.X += speed * Engine.DeltaTime()
		s.Y += speed * Engine.DeltaTime()

		ui.Transform().SetScale(s)
	*/

	//Handle Tab & Backspace
	if ui.focused && ui.writeable {
		if len(ui.text) > 0 && Input.KeyPress(Input.KeyBackspace) {
			ui.updateText = true
			ui.text = ui.text[:len(ui.text)-1]
		}
		if Input.KeyPress(Input.KeyTab) {
			ui.updateText = true
			ui.text += "\t"
		}
	}
}

func (ui *UIText) LateUpdate() {
	if ui.updateText {
		ui.updateText = false
		ui.setString(ui.text)
	}
}

func (ui *UIText) UpdateCollider() {
	//if ui.GameObject().Physics.Body.Enabled {
	if ui.GameObject().Physics == nil {
		return
	}
	b := ui.GameObject().Physics.Box
	if b != nil {
		h := vect.Float(float64(ui.height) * float64(ui.GameObject().Transform().WorldScale().Y))
		w := vect.Float(float64(ui.width) * float64(ui.GameObject().Transform().WorldScale().X))
		update := false
		if h != b.Height || w != b.Width {
			b.Width = w
			b.Height = h
			update = true
		}

		c := Engine.Align(ui.align)
		center := vect.Vect{vect.Float(c.X), vect.Float(c.Y)}
		center.X = (center.X * w)
		center.Y = (center.Y * h)

		if b.Position.X != center.X || b.Position.Y != center.Y {
			update = true
			b.Position.X, b.Position.Y = center.X, center.Y
		}

		if update {
			b.UpdatePoly()
		}
	}
	//log.Println(b.Height, b.Width, ui.GameObject().Transform().Scale().X, ui.GameObject().Name())
	//}
}

func (ui *UIText) Align() Engine.AlignType {
	return ui.align
}

func (ui *UIText) SetAlign(align Engine.AlignType) {
	ui.align = align
}

func (ui *UIText) Draw() {
	if ui.text == "" {
		return
	}

	v := Engine.Align(ui.align)
	v.X = (v.X * ui.width)
	v.Y = (v.Y * ui.height)

	mat := Engine.TextureMaterial
	if ui.Font.IsSDF() {
		mat = Engine.SDFMaterial
	}
	mat.Begin(ui.GameObject())

	vert := mat.Verts
	uv := mat.UV
	mp := mat.ProjMatrix
	mv := mat.ViewMatrix
	mm := mat.ModelMatrix
	tx := mat.Texture
	color := mat.AddColor
	_ = color

	vert.EnableArray()
	uv.EnableArray()

	ui.buffer.Bind(gl.ARRAY_BUFFER)

	vert.AttribPointer(3, gl.FLOAT, false, 0, uintptr(0))
	uv.AttribPointer(2, gl.FLOAT, false, 0, uintptr(ui.texcoordsIndex))

	camera := Engine.GetScene().SceneBase().Camera

	view := camera.Transform().Matrix()
	view = view.Invert()
	model := Engine.NewIdentity()
	model.Translate(v.X, v.Y, 0)
	model.Mul(ui.GameObject().Transform().Matrix())

	/*
		view := camera.Transform().Matrix()
		view = view.Invert()
		model := ui.GameObject().Transform().Matrix()
	*/

	mv.UniformMatrix4fv(false, view)
	mp.UniformMatrix4fv(false, *camera.Projection)
	mm.UniformMatrix4fv(false, *model)

	ui.Font.Bind()
	gl.ActiveTexture(gl.TEXTURE0)
	tx.Uniform1i(0)

	color.Uniform4f(ui.Color.X, ui.Color.Y, ui.Color.Z, 1)

	gl.DrawArrays(gl.QUADS, 0, ui.vertexCount)

	ui.Font.Unbind()
	vert.DisableArray()
	uv.DisableArray()

}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oglematchers_test

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

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

type IdenticalToTest struct {
}

func init() { RegisterTestSuite(&IdenticalToTest{}) }

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func (t *IdenticalToTest) TypesNotIdentical() {
	var m Matcher
	var res bool
	var err error

	type intAlias int

	// Type alias expected value
	m = IdenticalTo(intAlias(17))
	res, err = m.Matches(int(17))

	ExpectFalse(res)
	ExpectThat(err, Error(Equals("which is of type int")))

	// Type alias candidate
	m = IdenticalTo(int(17))
	res, err = m.Matches(intAlias(17))

	ExpectFalse(res)
	ExpectThat(err, Error(Equals("which is of type intAlias")))

	// int and uint
	m = IdenticalTo(int(17))
	res, err = m.Matches(uint(17))

	ExpectFalse(res)
	ExpectThat(err, Error(Equals("which is of type uint")))
}

func (t *IdenticalToTest) NilExpectedValue() {
}

func (t *IdenticalToTest) NilCandidate() {
}

func (t *IdenticalToTest) Slices() {
}

func (t *IdenticalToTest) Maps() {
}

func (t *IdenticalToTest) Functions() {
}

func (t *IdenticalToTest) Channels() {
}

func (t *IdenticalToTest) Bools() {
}

func (t *IdenticalToTest) Ints() {
}

func (t *IdenticalToTest) Int8s() {
}

func (t *IdenticalToTest) Int16s() {
}

func (t *IdenticalToTest) Int32s() {
}

func (t *IdenticalToTest) Int64s() {
}

func (t *IdenticalToTest) Uints() {
}

func (t *IdenticalToTest) Uint8s() {
}

func (t *IdenticalToTest) Uint16s() {
}

func (t *IdenticalToTest) Uint32s() {
}

func (t *IdenticalToTest) Uint64s() {
}

func (t *IdenticalToTest) Float32s() {
}

func (t *IdenticalToTest) Float64s() {
}

func (t *IdenticalToTest) Complex64s() {
}

func (t *IdenticalToTest) Complex128s() {
}

func (t *IdenticalToTest) ComparableArrays() {
}

func (t *IdenticalToTest) NonComparableArrays() {
}

func (t *IdenticalToTest) ComparableInterfaces() {
}

func (t *IdenticalToTest) NonComparableInterfaces() {
}

func (t *IdenticalToTest) Pointers() {
}

func (t *IdenticalToTest) Strings() {
}

func (t *IdenticalToTest) ComparableStructs() {
}

func (t *IdenticalToTest) NonComparableStructs() {
}

func (t *IdenticalToTest) UnsafePointers() {
}

func (t *IdenticalToTest) IntAlias() {
}
<commit_msg>Fixed some errors.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oglematchers_test

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

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

type IdenticalToTest struct {
}

func init() { RegisterTestSuite(&IdenticalToTest{}) }

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func (t *IdenticalToTest) TypesNotIdentical() {
	var m Matcher
	var err error

	type intAlias int

	// Type alias expected value
	m = IdenticalTo(intAlias(17))
	err = m.Matches(int(17))
	ExpectThat(err, Error(Equals("which is of type int")))

	// Type alias candidate
	m = IdenticalTo(int(17))
	err = m.Matches(intAlias(17))
	ExpectThat(err, Error(Equals("which is of type intAlias")))

	// int and uint
	m = IdenticalTo(int(17))
	err = m.Matches(uint(17))
	ExpectThat(err, Error(Equals("which is of type uint")))
}

func (t *IdenticalToTest) NilExpectedValue() {
}

func (t *IdenticalToTest) NilCandidate() {
}

func (t *IdenticalToTest) Slices() {
}

func (t *IdenticalToTest) Maps() {
}

func (t *IdenticalToTest) Functions() {
}

func (t *IdenticalToTest) Channels() {
}

func (t *IdenticalToTest) Bools() {
}

func (t *IdenticalToTest) Ints() {
}

func (t *IdenticalToTest) Int8s() {
}

func (t *IdenticalToTest) Int16s() {
}

func (t *IdenticalToTest) Int32s() {
}

func (t *IdenticalToTest) Int64s() {
}

func (t *IdenticalToTest) Uints() {
}

func (t *IdenticalToTest) Uint8s() {
}

func (t *IdenticalToTest) Uint16s() {
}

func (t *IdenticalToTest) Uint32s() {
}

func (t *IdenticalToTest) Uint64s() {
}

func (t *IdenticalToTest) Float32s() {
}

func (t *IdenticalToTest) Float64s() {
}

func (t *IdenticalToTest) Complex64s() {
}

func (t *IdenticalToTest) Complex128s() {
}

func (t *IdenticalToTest) ComparableArrays() {
}

func (t *IdenticalToTest) NonComparableArrays() {
}

func (t *IdenticalToTest) ComparableInterfaces() {
}

func (t *IdenticalToTest) NonComparableInterfaces() {
}

func (t *IdenticalToTest) Pointers() {
}

func (t *IdenticalToTest) Strings() {
}

func (t *IdenticalToTest) ComparableStructs() {
}

func (t *IdenticalToTest) NonComparableStructs() {
}

func (t *IdenticalToTest) UnsafePointers() {
}

func (t *IdenticalToTest) IntAlias() {
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"sort"
	"strconv"
)

func (app *application) index(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	page, _ := strconv.Atoi(query.Get("page"))
	if page == 0 {
		page = 1
	}
	movies, count, err := app.getMovies(page)
	if err != nil {
		log.Println("getAllMovies ", err)
		return
	}
	log.Println(movies, count)
	log.Println(len(movies))
	genres := []string{}
	years := []string{}
	for _, movie := range movies {
		year := strconv.Itoa(movie.Year)
		if stringInSlice(years, year) == false {
			years = append(years, year)
		}
		filmGenres := movie.Genre
		for _, genre := range filmGenres {
			if stringInSlice(genres, genre) == false {
				genres = append(genres, genre)
			}
		}
	}
	sort.Strings(genres)
	sort.Strings(years)
	cont := context{Title: "NNM-club RSS", Movies: movies, Genres: genres, Years: years, Count: count}
	render(w, cont, "index")
}

// func (app *application) getOneMovieJSON(w http.ResponseWriter, r *http.Request) {
// 	t := time.Now()
// 	movies := app.getMovies(1, 0)
// 	data, err := json.Marshal(movies)
// 	if err != nil {
// 		http.Error(w, err.Error(), http.StatusInternalServerError)
// 		return
// 	}
// 	w.Header().Set("Content-Type", "application/json")
// 	w.Write(data)
// 	app.printLog(t, r)
// }

// func (app *application) getMoviesJSON(w http.ResponseWriter, r *http.Request) {
// 	t := time.Now()
// 	query := r.URL.Query()
// 	limitStr := query.Get("limit")
// 	offsetStr := query.Get("offset")
// 	limit, _ := strconv.Atoi(limitStr)
// 	offset, _ := strconv.Atoi(offsetStr)
// 	movies := app.getMovies(limit, offset)
// 	data, err := json.Marshal(movies)
// 	if err != nil {
// 		http.Error(w, err.Error(), http.StatusInternalServerError)
// 		return
// 	}
// 	w.Header().Set("Content-Type", "application/json")
// 	w.Write(data)
// 	app.printLog(t, r)
// }
<commit_msg>remove debug log<commit_after>package main

import (
	"log"
	"net/http"
	"sort"
	"strconv"
)

func (app *application) index(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	page, _ := strconv.Atoi(query.Get("page"))
	if page == 0 {
		page = 1
	}
	movies, count, err := app.getMovies(page)
	if err != nil {
		log.Println("getAllMovies ", err)
		return
	}
	genres := []string{}
	years := []string{}
	for _, movie := range movies {
		year := strconv.Itoa(movie.Year)
		if stringInSlice(years, year) == false {
			years = append(years, year)
		}
		filmGenres := movie.Genre
		for _, genre := range filmGenres {
			if stringInSlice(genres, genre) == false {
				genres = append(genres, genre)
			}
		}
	}
	sort.Strings(genres)
	sort.Strings(years)
	cont := context{Title: "NNM-club RSS", Movies: movies, Genres: genres, Years: years, Count: count}
	render(w, cont, "index")
}

// func (app *application) getOneMovieJSON(w http.ResponseWriter, r *http.Request) {
// 	t := time.Now()
// 	movies := app.getMovies(1, 0)
// 	data, err := json.Marshal(movies)
// 	if err != nil {
// 		http.Error(w, err.Error(), http.StatusInternalServerError)
// 		return
// 	}
// 	w.Header().Set("Content-Type", "application/json")
// 	w.Write(data)
// 	app.printLog(t, r)
// }

// func (app *application) getMoviesJSON(w http.ResponseWriter, r *http.Request) {
// 	t := time.Now()
// 	query := r.URL.Query()
// 	limitStr := query.Get("limit")
// 	offsetStr := query.Get("offset")
// 	limit, _ := strconv.Atoi(limitStr)
// 	offset, _ := strconv.Atoi(offsetStr)
// 	movies := app.getMovies(limit, offset)
// 	data, err := json.Marshal(movies)
// 	if err != nil {
// 		http.Error(w, err.Error(), http.StatusInternalServerError)
// 		return
// 	}
// 	w.Header().Set("Content-Type", "application/json")
// 	w.Write(data)
// 	app.printLog(t, r)
// }
<|endoftext|>


<commit_before>// Package identify handles how peers identify with eachother upon
// connection to the network
package identify

import (
	"bytes"
	"errors"
	"strings"

	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"hash"

	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	ci "github.com/jbenet/go-ipfs/crypto"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

// List of supported protocols--each section in order of preference.
// Takes the form:  ECDH curves : Ciphers : Hashes
var SupportedExchanges = "P-256,P-224,P-384,P-521"
var SupportedCiphers = "AES-256,AES-128"
var SupportedHashes = "SHA256,SHA512,SHA1"

// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
var ErrUnsupportedKeyType = errors.New("unsupported key type")

// Performs initial communication with this peer to share node ID's and
// initiate communication.  (secureIn, secureOut, error)
func Handshake(self, remote *peer.Peer, in <-chan []byte, out chan<- []byte) (<-chan []byte, chan<- []byte, error) {
	h, err := genRandHello(self)
	if err != nil {
		return nil, nil, err
	}

	encoded, err := proto.Marshal(h)
	if err != nil {
		return nil, nil, err
	}

	out <- encoded

	// Parse their Hello packet and generate an Exchange packet.
	// Exchange = (EphemeralPubKey, Signature)
	resp := <-in

	helloResp := new(Hello)
	err = proto.Unmarshal(resp, helloResp)
	if err != nil {
		return nil, nil, err
	}

	remote.PubKey, err = ci.UnmarshalPublicKey(helloResp.GetPubkey())
	if err != nil {
		return nil, nil, err
	}

	remote.ID, err = IDFromPubKey(remote.PubKey)
	if err != nil {
		return nil, nil, err
	}

	exchange, err := selectBest(SupportedExchanges, helloResp.GetExchanges())
	if err != nil {
		return nil, nil, err
	}

	cipherType, err := selectBest(SupportedCiphers, helloResp.GetCiphers())
	if err != nil {
		return nil, nil, err
	}

	hashType, err := selectBest(SupportedHashes, helloResp.GetHashes())
	if err != nil {
		return nil, nil, err
	}

	epubkey, done, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey
	if err != nil {
		return nil, nil, err
	}

	var handshake bytes.Buffer // Gather corpus to sign.
	handshake.Write(encoded)
	handshake.Write(resp)
	handshake.Write(epubkey)

	exPacket := new(Exchange)

	exPacket.Epubkey = epubkey
	exPacket.Signature, err = self.PrivKey.Sign(handshake.Bytes())
	if err != nil {
		return nil, nil, err
	}

	exEncoded, err := proto.Marshal(exPacket)
	if err != nil {
		return nil, nil, err
	}

	out <- exEncoded

	// Parse their Exchange packet and generate a Finish packet.
	// Finish = E('Finish')
	resp1 := <-in

	exchangeResp := new(Exchange)
	err = proto.Unmarshal(resp1, exchangeResp)
	if err != nil {
		return nil, nil, err
	}

	var theirHandshake bytes.Buffer
	_, err = theirHandshake.Write(resp)
	if err != nil {
		return nil, nil, err
	}
	_, err = theirHandshake.Write(encoded)
	if err != nil {
		return nil, nil, err
	}
	_, err = theirHandshake.Write(exchangeResp.GetEpubkey())
	if err != nil {
		return nil, nil, err
	}

	ok, err := remote.PubKey.Verify(theirHandshake.Bytes(), exchangeResp.GetSignature())
	if err != nil {
		return nil, nil, err
	}

	if !ok {
		return nil, nil, errors.New("Bad signature!")
	}

	secret, err := done(exchangeResp.GetEpubkey())
	if err != nil {
		return nil, nil, err
	}

	myPubKey, err := self.PubKey.Bytes()
	if err != nil {
		return nil, nil, err
	}

	cmp := bytes.Compare(myPubKey, helloResp.GetPubkey())
	mIV, tIV, mCKey, tCKey, mMKey, tMKey := ci.KeyStretcher(cmp, cipherType, hashType, secret)

	secureIn := make(chan []byte)
	secureOut := make(chan []byte)

	go secureInProxy(in, secureIn, hashType, tIV, tCKey, tMKey)
	go secureOutProxy(out, secureOut, hashType, mIV, mCKey, mMKey)

	finished := []byte("Finished")

	secureOut <- finished
	resp2 := <-secureIn

	if bytes.Compare(resp2, finished) != 0 {
		return nil, nil, errors.New("Negotiation failed.")
	}

	u.DOut("[%s] identify: Got node id: %s\n", self.ID.Pretty(), remote.ID.Pretty())

	return secureIn, secureOut, nil
}

func makeMac(hashType string, key []byte) (hash.Hash, int) {
	switch hashType {
	case "SHA1":
		return hmac.New(sha1.New, key), sha1.Size
	case "SHA512":
		return hmac.New(sha512.New, key), sha512.Size
	default:
		return hmac.New(sha256.New, key), sha256.Size
	}
}

func secureInProxy(in <-chan []byte, secureIn chan<- []byte, hashType string, tIV, tCKey, tMKey []byte) {
	theirBlock, _ := aes.NewCipher(tCKey)
	theirCipher := cipher.NewCTR(theirBlock, tIV)

	theirMac, macSize := makeMac(hashType, tMKey)

	for {
		data, ok := <-in
		if !ok {
			close(secureIn)
			return
		}

		if len(data) <= macSize {
			continue
		}

		mark := len(data) - macSize
		buff := make([]byte, mark)

		theirCipher.XORKeyStream(buff, data[0:mark])

		theirMac.Write(data[0:mark])
		expected := theirMac.Sum(nil)
		theirMac.Reset()

		hmacOk := hmac.Equal(data[mark:], expected)

		if hmacOk {
			secureIn <- buff
		} else {
			secureIn <- nil
		}
	}
}

func secureOutProxy(out chan<- []byte, secureOut <-chan []byte, hashType string, mIV, mCKey, mMKey []byte) {
	myBlock, _ := aes.NewCipher(mCKey)
	myCipher := cipher.NewCTR(myBlock, mIV)

	myMac, macSize := makeMac(hashType, mMKey)

	for {
		data, ok := <-secureOut
		if !ok {
			close(out)
			return
		}

		if len(data) == 0 {
			continue
		}

		buff := make([]byte, len(data)+macSize)

		myCipher.XORKeyStream(buff, data)

		myMac.Write(buff[0:len(data)])
		copy(buff[len(data):], myMac.Sum(nil))
		myMac.Reset()

		out <- buff
	}
}

// IDFromPubKey returns Nodes ID given its public key
func IDFromPubKey(pk ci.PubKey) (peer.ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return nil, err
	}
	hash, err := u.Hash(b)
	if err != nil {
		return nil, err
	}
	return peer.ID(hash), nil
}

// Determines which algorithm to use.  Note:  f(a, b) = f(b, a)
func selectBest(myPrefs, theirPrefs string) (string, error) {
	// Person with greatest hash gets first choice.
	myHash, err := u.Hash([]byte(myPrefs))
	if err != nil {
		return "", err
	}

	theirHash, err := u.Hash([]byte(theirPrefs))
	if err != nil {
		return "", err
	}

	cmp := bytes.Compare(myHash, theirHash)
	var firstChoiceArr, secChoiceArr []string

	if cmp == -1 {
		firstChoiceArr = strings.Split(theirPrefs, ",")
		secChoiceArr = strings.Split(myPrefs, ",")
	} else if cmp == 1 {
		firstChoiceArr = strings.Split(myPrefs, ",")
		secChoiceArr = strings.Split(theirPrefs, ",")
	} else { // Exact same preferences.
		myPrefsArr := strings.Split(myPrefs, ",")
		return myPrefsArr[0], nil
	}

	for _, secChoice := range secChoiceArr {
		for _, firstChoice := range firstChoiceArr {
			if firstChoice == secChoice {
				return firstChoice, nil
			}
		}
	}

	return "", errors.New("No algorithms in common!")
}

func genRandHello(self *peer.Peer) (*Hello, error) {
	hello := new(Hello)

	// Generate and send Hello packet.
	// Hello = (rand, PublicKey, Supported)
	nonce := make([]byte, 16)
	_, err := rand.Read(nonce)
	if err != nil {
		return nil, err
	}

	myPubKey, err := self.PubKey.Bytes()
	if err != nil {
		return nil, err
	}

	hello.Rand = nonce
	hello.Pubkey = myPubKey
	hello.Exchanges = &SupportedExchanges
	hello.Ciphers = &SupportedCiphers
	hello.Hashes = &SupportedHashes
	return hello, nil
}
<commit_msg>refactor(identify) extract proto encoding<commit_after>// Package identify handles how peers identify with eachother upon
// connection to the network
package identify

import (
	"bytes"
	"errors"
	"strings"

	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"hash"

	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	ci "github.com/jbenet/go-ipfs/crypto"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

// List of supported protocols--each section in order of preference.
// Takes the form:  ECDH curves : Ciphers : Hashes
var SupportedExchanges = "P-256,P-224,P-384,P-521"
var SupportedCiphers = "AES-256,AES-128"
var SupportedHashes = "SHA256,SHA512,SHA1"

// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
var ErrUnsupportedKeyType = errors.New("unsupported key type")

// Performs initial communication with this peer to share node ID's and
// initiate communication.  (secureIn, secureOut, error)
func Handshake(self, remote *peer.Peer, in <-chan []byte, out chan<- []byte) (<-chan []byte, chan<- []byte, error) {

	encodedHello, err := encodedProtoHello(self)
	if err != nil {
		return nil, nil, err
	}

	// TODO(brian): select on |ctx|
	out <- encodedHello

	// Parse their Hello packet and generate an Exchange packet.
	// Exchange = (EphemeralPubKey, Signature)
	resp := <-in

	helloResp := new(Hello)
	err = proto.Unmarshal(resp, helloResp)
	if err != nil {
		return nil, nil, err
	}

	remote.PubKey, err = ci.UnmarshalPublicKey(helloResp.GetPubkey())
	if err != nil {
		return nil, nil, err
	}

	remote.ID, err = IDFromPubKey(remote.PubKey)
	if err != nil {
		return nil, nil, err
	}

	exchange, err := selectBest(SupportedExchanges, helloResp.GetExchanges())
	if err != nil {
		return nil, nil, err
	}

	cipherType, err := selectBest(SupportedCiphers, helloResp.GetCiphers())
	if err != nil {
		return nil, nil, err
	}

	hashType, err := selectBest(SupportedHashes, helloResp.GetHashes())
	if err != nil {
		return nil, nil, err
	}

	epubkey, done, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey
	if err != nil {
		return nil, nil, err
	}

	var handshake bytes.Buffer // Gather corpus to sign.
	handshake.Write(encoded)
	handshake.Write(resp)
	handshake.Write(epubkey)

	exPacket := new(Exchange)

	exPacket.Epubkey = epubkey
	exPacket.Signature, err = self.PrivKey.Sign(handshake.Bytes())
	if err != nil {
		return nil, nil, err
	}

	exEncoded, err := proto.Marshal(exPacket)
	if err != nil {
		return nil, nil, err
	}

	out <- exEncoded

	// Parse their Exchange packet and generate a Finish packet.
	// Finish = E('Finish')
	resp1 := <-in

	exchangeResp := new(Exchange)
	err = proto.Unmarshal(resp1, exchangeResp)
	if err != nil {
		return nil, nil, err
	}

	var theirHandshake bytes.Buffer
	_, err = theirHandshake.Write(resp)
	if err != nil {
		return nil, nil, err
	}
	_, err = theirHandshake.Write(encoded)
	if err != nil {
		return nil, nil, err
	}
	_, err = theirHandshake.Write(exchangeResp.GetEpubkey())
	if err != nil {
		return nil, nil, err
	}

	ok, err := remote.PubKey.Verify(theirHandshake.Bytes(), exchangeResp.GetSignature())
	if err != nil {
		return nil, nil, err
	}

	if !ok {
		return nil, nil, errors.New("Bad signature!")
	}

	secret, err := done(exchangeResp.GetEpubkey())
	if err != nil {
		return nil, nil, err
	}

	myPubKey, err := self.PubKey.Bytes()
	if err != nil {
		return nil, nil, err
	}

	cmp := bytes.Compare(myPubKey, helloResp.GetPubkey())
	mIV, tIV, mCKey, tCKey, mMKey, tMKey := ci.KeyStretcher(cmp, cipherType, hashType, secret)

	secureIn := make(chan []byte)
	secureOut := make(chan []byte)

	go secureInProxy(in, secureIn, hashType, tIV, tCKey, tMKey)
	go secureOutProxy(out, secureOut, hashType, mIV, mCKey, mMKey)

	finished := []byte("Finished")

	secureOut <- finished
	resp2 := <-secureIn

	if bytes.Compare(resp2, finished) != 0 {
		return nil, nil, errors.New("Negotiation failed.")
	}

	u.DOut("[%s] identify: Got node id: %s\n", self.ID.Pretty(), remote.ID.Pretty())

	return secureIn, secureOut, nil
}

func makeMac(hashType string, key []byte) (hash.Hash, int) {
	switch hashType {
	case "SHA1":
		return hmac.New(sha1.New, key), sha1.Size
	case "SHA512":
		return hmac.New(sha512.New, key), sha512.Size
	default:
		return hmac.New(sha256.New, key), sha256.Size
	}
}

func secureInProxy(in <-chan []byte, secureIn chan<- []byte, hashType string, tIV, tCKey, tMKey []byte) {
	theirBlock, _ := aes.NewCipher(tCKey)
	theirCipher := cipher.NewCTR(theirBlock, tIV)

	theirMac, macSize := makeMac(hashType, tMKey)

	for {
		data, ok := <-in
		if !ok {
			close(secureIn)
			return
		}

		if len(data) <= macSize {
			continue
		}

		mark := len(data) - macSize
		buff := make([]byte, mark)

		theirCipher.XORKeyStream(buff, data[0:mark])

		theirMac.Write(data[0:mark])
		expected := theirMac.Sum(nil)
		theirMac.Reset()

		hmacOk := hmac.Equal(data[mark:], expected)

		if hmacOk {
			secureIn <- buff
		} else {
			secureIn <- nil
		}
	}
}

func secureOutProxy(out chan<- []byte, secureOut <-chan []byte, hashType string, mIV, mCKey, mMKey []byte) {
	myBlock, _ := aes.NewCipher(mCKey)
	myCipher := cipher.NewCTR(myBlock, mIV)

	myMac, macSize := makeMac(hashType, mMKey)

	for {
		data, ok := <-secureOut
		if !ok {
			close(out)
			return
		}

		if len(data) == 0 {
			continue
		}

		buff := make([]byte, len(data)+macSize)

		myCipher.XORKeyStream(buff, data)

		myMac.Write(buff[0:len(data)])
		copy(buff[len(data):], myMac.Sum(nil))
		myMac.Reset()

		out <- buff
	}
}

// IDFromPubKey returns Nodes ID given its public key
func IDFromPubKey(pk ci.PubKey) (peer.ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return nil, err
	}
	hash, err := u.Hash(b)
	if err != nil {
		return nil, err
	}
	return peer.ID(hash), nil
}

// Determines which algorithm to use.  Note:  f(a, b) = f(b, a)
func selectBest(myPrefs, theirPrefs string) (string, error) {
	// Person with greatest hash gets first choice.
	myHash, err := u.Hash([]byte(myPrefs))
	if err != nil {
		return "", err
	}

	theirHash, err := u.Hash([]byte(theirPrefs))
	if err != nil {
		return "", err
	}

	cmp := bytes.Compare(myHash, theirHash)
	var firstChoiceArr, secChoiceArr []string

	if cmp == -1 {
		firstChoiceArr = strings.Split(theirPrefs, ",")
		secChoiceArr = strings.Split(myPrefs, ",")
	} else if cmp == 1 {
		firstChoiceArr = strings.Split(myPrefs, ",")
		secChoiceArr = strings.Split(theirPrefs, ",")
	} else { // Exact same preferences.
		myPrefsArr := strings.Split(myPrefs, ",")
		return myPrefsArr[0], nil
	}

	for _, secChoice := range secChoiceArr {
		for _, firstChoice := range firstChoiceArr {
			if firstChoice == secChoice {
				return firstChoice, nil
			}
		}
	}

	return "", errors.New("No algorithms in common!")
}

func genRandHello(self *peer.Peer) (*Hello, error) {
	hello := new(Hello)

	// Generate and send Hello packet.
	// Hello = (rand, PublicKey, Supported)
	nonce := make([]byte, 16)
	_, err := rand.Read(nonce)
	if err != nil {
		return nil, err
	}

	myPubKey, err := self.PubKey.Bytes()
	if err != nil {
		return nil, err
	}

	hello.Rand = nonce
	hello.Pubkey = myPubKey
	hello.Exchanges = &SupportedExchanges
	hello.Ciphers = &SupportedCiphers
	hello.Hashes = &SupportedHashes
	return hello, nil
}

func encodedProtoHello(self *peer.Peer) ([]byte, error) {
	h, err := genRandHello(self)
	if err != nil {
		return nil, err
	}

	return proto.Marshal(h)
}
<|endoftext|>


<commit_before>package sudoku

import (
	"testing"
)

func TestHumanSolveSearcher(t *testing.T) {

	grid := NewGrid()
	grid.LoadSDK(TEST_GRID)

	searcher := newHumanSolveSearcher(grid, nil, DefaultHumanSolveOptions())

	if searcher.itemsToExplore.Len() != 1 {
		t.Error("Expected new frontier to have exactly one item in it, but got", searcher.itemsToExplore.Len())
	}

	if searcher.grid == nil {
		t.Error("No grid in frontier")
	}

	basePotentialNextStep := searcher.NextPossibleStep()

	if basePotentialNextStep == nil {
		t.Error("Didn'get base potential next step")
	}

	baseGrid := basePotentialNextStep.Grid()

	if baseGrid.DataString() != grid.DataString() {
		t.Error("the grid in the base item in the frontier was not right. Got", baseGrid.DataString(), "wanted", grid.DataString())
	}

	if searcher.itemsToExplore.Len() != 0 {
		t.Error("Getting the base potential next step should have emptied it, but len is", searcher.itemsToExplore.Len())
	}

	nInRowTechnique := techniquesByName["Necessary In Row"]

	simpleFillStep := &SolveStep{
		Technique: nInRowTechnique,
		TargetCells: CellSlice{
			grid.Cell(0, 0),
		},
		TargetNums: IntSlice{1},
	}

	if simpleFillStep.Technique == nil {
		t.Fatal("couldn't find necessary in row technique")
	}

	simpleFillStepItem := basePotentialNextStep.AddStep(simpleFillStep)

	if simpleFillStepItem == nil {
		t.Fatal("Adding fill step didn't return anything")
	}

	if simpleFillStepItem.heapIndex != -1 {
		t.Fatal("Adding completed item to frontier didn't have -1 index")
	}

	if len(searcher.completedItems) != 1 {
		t.Error("Expected the completed item to go into CompletedItems,but it's empty")
	}

	if len(searcher.itemsToExplore) != 0 {
		t.Error("Expected the completed item to go into COmpletedItems, but it apparently went into items.")
	}

	//This is a fragile way to test this; it will need to be updated every
	//time we change the twiddlers. :-( Currently 5 for common numbers, 22.5
	//for Human Likelihood, and 1 for chained steps.
	expectedGoodness := 112.5

	if simpleFillStepItem.Goodness() != expectedGoodness {
		t.Error("Goodness of simple fill step was wrong. Execpted", expectedGoodness, "got", simpleFillStepItem.Goodness(), simpleFillStepItem.explainGoodness())
	}

	cell := simpleFillStepItem.Grid().Cell(0, 0)

	if cell.Number() != 1 {
		t.Error("Cell in grid was not set correctly. Got", cell.Number(), "wanted 1")
	}

	nonFillStep := &SolveStep{
		Technique: techniquesByName["Pointing Pair Row"],
		TargetCells: CellSlice{
			grid.Cell(0, 1),
		},
		TargetNums: IntSlice{2},
	}

	if nonFillStep.Technique == nil {
		t.Fatal("Couldn't find pointing pair row techhnique")
	}

	nonFillStepItem := basePotentialNextStep.AddStep(nonFillStep)

	if nonFillStepItem == nil {
		t.Fatal("Adding non fill step didn't return a frontier object")
	}

	if searcher.itemsToExplore.Len() != 1 {
		t.Error("Frontier had wrong length after adding one complete and one incomplete items. Got", searcher.itemsToExplore.Len(), "expected 1")
	}

	if searcher.itemsToExplore[0] != nonFillStepItem {
		t.Error("We though that simpleFillStep should be at the end of the queue but it wasn't.")
	}

	expensiveStep := &SolveStep{
		Technique: techniquesByName["Hidden Quad Block"],
		TargetCells: CellSlice{
			grid.Cell(0, 2),
		},
		TargetNums: IntSlice{3},
	}

	expensiveStepItem := basePotentialNextStep.AddStep(expensiveStep)

	if searcher.itemsToExplore.Len() != 2 {
		t.Error("Wrong length after adding two items to frontier. Got", searcher.itemsToExplore.Len(), "expected 2")
	}

	if searcher.itemsToExplore[0] != nonFillStepItem {
		t.Error("We expected the expensive step to be worse", searcher.String())
	}

	expensiveStepItem.Twiddle(0.00000000000000001, "Very small amount to make this #1")

	if searcher.itemsToExplore[0] != expensiveStepItem {
		t.Error("Even after twiddling up guess step by a lot it still wasn't in the top position in frontier", searcher.itemsToExplore[0], searcher.itemsToExplore[1])
	}

	poppedItem := searcher.NextPossibleStep()

	if poppedItem != expensiveStepItem {
		t.Error("Expected popped item to be the non-fill step now that its goodness is higher, but got", poppedItem)
	}

	if searcher.itemsToExplore.Len() != 1 {
		t.Error("Wrong frontier length after popping item. Got", searcher.itemsToExplore.Len(), "expected 1")
	}

	poppedItem = searcher.NextPossibleStep()
	//Should be nonFillStepItem

	currentGoodness := nonFillStepItem.Goodness()

	completedNonFillStemItem := nonFillStepItem.AddStep(simpleFillStep)

	if completedNonFillStemItem.Goodness() == currentGoodness {
		t.Error("Adding a step to end of nonfill step didn't change goodness.")
	}

	if searcher.itemsToExplore.Len() != 0 {
		t.Error("Adding an item gave wrong len. Got", searcher.itemsToExplore.Len(), "wanted 0")
	}

	if len(searcher.completedItems) != 2 {
		t.Error("Got wrong number of completed items. Got", len(searcher.completedItems), "expected 2")
	}

	steps := completedNonFillStemItem.Steps()

	if len(steps) != 2 {
		t.Error("Expected two steps back, got", len(steps))
	}

	if steps[0] != nonFillStepItem.step {
		t.Error("Expected first step to be the step of nonFillStepItem. Got", steps[0])
	}

}
<commit_msg>Fixed a failing test introduced in d667be337<commit_after>package sudoku

import (
	"testing"
)

func TestHumanSolveSearcher(t *testing.T) {

	grid := NewGrid()
	grid.LoadSDK(TEST_GRID)

	searcher := newHumanSolveSearcher(grid, nil, DefaultHumanSolveOptions())

	if searcher.itemsToExplore.Len() != 1 {
		t.Error("Expected new frontier to have exactly one item in it, but got", searcher.itemsToExplore.Len())
	}

	if searcher.grid == nil {
		t.Error("No grid in frontier")
	}

	basePotentialNextStep := searcher.NextPossibleStep()

	if basePotentialNextStep == nil {
		t.Error("Didn'get base potential next step")
	}

	baseGrid := basePotentialNextStep.Grid()

	if baseGrid.DataString() != grid.DataString() {
		t.Error("the grid in the base item in the frontier was not right. Got", baseGrid.DataString(), "wanted", grid.DataString())
	}

	if searcher.itemsToExplore.Len() != 0 {
		t.Error("Getting the base potential next step should have emptied it, but len is", searcher.itemsToExplore.Len())
	}

	nInRowTechnique := techniquesByName["Necessary In Row"]

	simpleFillStep := &SolveStep{
		Technique: nInRowTechnique,
		TargetCells: CellSlice{
			grid.Cell(0, 0),
		},
		TargetNums: IntSlice{1},
	}

	if simpleFillStep.Technique == nil {
		t.Fatal("couldn't find necessary in row technique")
	}

	simpleFillStepItem := basePotentialNextStep.AddStep(simpleFillStep)

	if simpleFillStepItem == nil {
		t.Fatal("Adding fill step didn't return anything")
	}

	if simpleFillStepItem.heapIndex != -1 {
		t.Fatal("Adding completed item to frontier didn't have -1 index")
	}

	if len(searcher.completedItems) != 1 {
		t.Error("Expected the completed item to go into CompletedItems,but it's empty")
	}

	if len(searcher.itemsToExplore) != 0 {
		t.Error("Expected the completed item to go into COmpletedItems, but it apparently went into items.")
	}

	//This is a fragile way to test this; it will need to be updated every
	//time we change the twiddlers. :-( Currently 5 for common numbers, 22.5
	//for Human Likelihood, and 1 for chained steps.
	expectedGoodness := 112.5

	if simpleFillStepItem.Goodness() != expectedGoodness {
		t.Error("Goodness of simple fill step was wrong. Execpted", expectedGoodness, "got", simpleFillStepItem.Goodness(), simpleFillStepItem.explainGoodness())
	}

	cell := simpleFillStepItem.Grid().Cell(0, 0)

	if cell.Number() != 1 {
		t.Error("Cell in grid was not set correctly. Got", cell.Number(), "wanted 1")
	}

	nonFillStep := &SolveStep{
		Technique: techniquesByName["Pointing Pair Row"],
		TargetCells: CellSlice{
			grid.Cell(0, 1),
		},
		TargetNums: IntSlice{2},
	}

	if nonFillStep.Technique == nil {
		t.Fatal("Couldn't find pointing pair row techhnique")
	}

	nonFillStepItem := basePotentialNextStep.AddStep(nonFillStep)

	if nonFillStepItem == nil {
		t.Fatal("Adding non fill step didn't return a frontier object")
	}

	if searcher.itemsToExplore.Len() != 1 {
		t.Error("Frontier had wrong length after adding one complete and one incomplete items. Got", searcher.itemsToExplore.Len(), "expected 1")
	}

	if searcher.itemsToExplore[0] != nonFillStepItem {
		t.Error("We though that simpleFillStep should be at the end of the queue but it wasn't.")
	}

	expensiveStep := &SolveStep{
		Technique: techniquesByName["Hidden Quad Block"],
		TargetCells: CellSlice{
			grid.Cell(0, 2),
		},
		TargetNums: IntSlice{3},
	}

	expensiveStepItem := basePotentialNextStep.AddStep(expensiveStep)

	if searcher.itemsToExplore.Len() != 2 {
		t.Error("Wrong length after adding two items to frontier. Got", searcher.itemsToExplore.Len(), "expected 2")
	}

	if searcher.itemsToExplore[0] != nonFillStepItem {
		t.Error("We expected the expensive step to be worse", searcher.String())
	}

	//Horrendous hack to allow us to twiddle again
	expensiveStepItem.doneTwiddling = false
	expensiveStepItem.cachedGoodness = 0.0

	expensiveStepItem.Twiddle(0.00000000000000001, "Very small amount to make this #1")

	if searcher.itemsToExplore[0] != expensiveStepItem {
		t.Error("Even after twiddling up guess step by a lot it still wasn't in the top position in frontier", searcher.itemsToExplore[0], searcher.itemsToExplore[1])
	}

	poppedItem := searcher.NextPossibleStep()

	if poppedItem != expensiveStepItem {
		t.Error("Expected popped item to be the non-fill step now that its goodness is higher, but got", poppedItem)
	}

	if searcher.itemsToExplore.Len() != 1 {
		t.Error("Wrong frontier length after popping item. Got", searcher.itemsToExplore.Len(), "expected 1")
	}

	poppedItem = searcher.NextPossibleStep()
	//Should be nonFillStepItem

	currentGoodness := nonFillStepItem.Goodness()

	completedNonFillStemItem := nonFillStepItem.AddStep(simpleFillStep)

	if completedNonFillStemItem.Goodness() == currentGoodness {
		t.Error("Adding a step to end of nonfill step didn't change goodness.")
	}

	if searcher.itemsToExplore.Len() != 0 {
		t.Error("Adding an item gave wrong len. Got", searcher.itemsToExplore.Len(), "wanted 0")
	}

	if len(searcher.completedItems) != 2 {
		t.Error("Got wrong number of completed items. Got", len(searcher.completedItems), "expected 2")
	}

	steps := completedNonFillStemItem.Steps()

	if len(steps) != 2 {
		t.Error("Expected two steps back, got", len(steps))
	}

	if steps[0] != nonFillStepItem.step {
		t.Error("Expected first step to be the step of nonFillStepItem. Got", steps[0])
	}

}
<|endoftext|>