<commit_before>// +build ignore
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

var registries = []string{"afrinic", "apnic", "arin", "iana", "lacnic", "ripe-ncc"}
var mirror = "https://ftp.apnic.net/stats"

func filename(reg string) string {
	ffmt := "delegated-%s-extended-latest"
	if reg == "iana" {
		ffmt = "delegated-%s-latest"
	}
	return fmt.Sprintf(ffmt, strings.Replace(reg, "-", "", -1))
}

func fetch() error {
	for _, reg := range registries {
		fname := filename(reg)

		_, err := os.Stat(fname)
		if err == nil {
			fmt.Printf("%s: cached\n", reg)
			continue
		}
		if !os.IsNotExist(err) {
			return err
		}

		url := mirror + "/" + reg + "/" + fname
		fmt.Printf("%s: get %s\n", fname, url)
		rsp, err := http.Get(url)
		if err != nil {
			return err
		}
		defer rsp.Body.Close()

		if rsp.StatusCode != http.StatusOK {
			return fmt.Errorf("gen: http error: %d %s", rsp.StatusCode, rsp.Status)
		}

		out, err := os.Create(fname)
		if err != nil {
			return err
		}
		defer out.Close()

		n, err := io.Copy(out, rsp.Body)
		if err != nil {
			return err
		}
		fmt.Printf("%s: %d bytes\n", fname, n)
	}
	return nil
}

func main() {
	if err := fetch(); err != nil {
		fmt.Fprintf(os.Stderr, "gen: fetchh error: %s", err)
		os.Exit(1)
	}
}
<commit_msg>parse all files<commit_after>// +build ignore
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"

	"github.com/ebfe/ipcc/rirstat"
)

var registries = []string{"afrinic", "apnic", "arin", "iana", "lacnic", "ripe-ncc"}
var mirror = "https://ftp.apnic.net/stats"

func filename(reg string) string {
	ffmt := "delegated-%s-extended-latest"
	if reg == "iana" {
		ffmt = "delegated-%s-latest"
	}
	return fmt.Sprintf(ffmt, strings.Replace(reg, "-", "", -1))
}

func fetch() error {
	for _, reg := range registries {
		fname := filename(reg)

		_, err := os.Stat(fname)
		if err == nil {
			fmt.Printf("%s: cached\n", reg)
			continue
		}
		if !os.IsNotExist(err) {
			return err
		}

		url := mirror + "/" + reg + "/" + fname
		fmt.Printf("%s: get %s\n", fname, url)
		rsp, err := http.Get(url)
		if err != nil {
			return err
		}
		defer rsp.Body.Close()

		if rsp.StatusCode != http.StatusOK {
			return fmt.Errorf("gen: http error: %d %s", rsp.StatusCode, rsp.Status)
		}

		out, err := os.Create(fname)
		if err != nil {
			return err
		}
		defer out.Close()

		n, err := io.Copy(out, rsp.Body)
		if err != nil {
			return err
		}
		fmt.Printf("%s: %d bytes\n", fname, n)
	}
	return nil
}

func main() {
	if err := fetch(); err != nil {
		fmt.Fprintf(os.Stderr, "gen: fetch error: %s", err)
		os.Exit(1)
	}

	for _, reg := range registries {
		fname := filename(reg)
		f, err := os.Open(fname)
		if err != nil {
			fmt.Fprintf(os.Stderr, "gen: open %s: %s\n", fname, err)
			os.Exit(1)
		}
		defer f.Close()

		hdr, recs, err := rirstat.Parse(f)
		if err != nil {
			fmt.Fprintf(os.Stderr, "gen: parse %s: %s\n", fname, err)
			os.Exit(1)
		}
		fmt.Println(hdr.Registry, hdr.EndDate.Format("20060-01-02"), hdr.Records, len(recs), "records")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/evoL/gif/config"
	"github.com/evoL/gif/store"
	"github.com/evoL/gif/version"
	"net/url"
	"os"
	"regexp"
	"strings"
)

func main() {
	typeFlags := []cli.Flag{
		cli.BoolFlag{
			Name:  "tag, t",
			Usage: "Enforces searching by tag.",
		},
		cli.BoolFlag{
			Name:  "untagged",
			Usage: "Lists only images that have no tag.",
		},
		cli.BoolFlag{
			Name:  "local",
			Usage: "Lists only images that are local, that is not avaliable remotely.",
		},
	}
	getFlags := append(
		typeFlags,
		cli.BoolFlag{
			Name:  "all, a",
			Usage: "Gets all matching images.",
		},
		cli.StringFlag{
			Name:  "order, sort, s",
			Usage: "Specifies the order of images. Must be one of: random, newest, oldest.",
			Value: "random",
		},
	)
	removeFlags := append(
		typeFlags,
		cli.BoolFlag{
			Name:  "all, a",
			Usage: "Removes all matching images.",
		},
		cli.BoolFlag{
			Name:  "really",
			Usage: "Doesn't ask for confirmation.",
		},
	)
	exportFlags := []cli.Flag{
		cli.StringFlag{
			Name:  "output, o",
			Usage: "Target output file. Set to '-' for stdout.",
			Value: "-",
		},
		cli.BoolFlag{
			Name:  "bundle",
			Usage: "Export a bundle containing all images and metadata.",
		},
	}
	importFlags := []cli.Flag{
		cli.BoolFlag{
			Name:  "recursive, r",
			Usage: "When importing directories, do it recursively.",
		},
	}
	uploadFlags := append(
		typeFlags,
		cli.BoolFlag{
			Name:  "really",
			Usage: "Doesn't ask for confirmation.",
		},
	)

	app := cli.NewApp()
	app.Name = "gif"
	app.Usage = "a stupid gif manager"
	app.Author = "Rafał Hirsz"
	app.Email = "rafal@hirsz.co"
	app.Version = version.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Value: "default",
			Usage: "Path to the configuration file",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:   "add",
			Usage:  "Adds an image",
			Action: AddCommand,
		},
		{
			Name:   "config",
			Usage:  "Prints the current configuration",
			Action: ConfigCommand,
		},
		{
			Name:   "tag",
			Usage:  "Enables to change tags for images",
			Action: TagCommand,
			Flags:  typeFlags,
		},
		{
			Name:   "list",
			Usage:  "Lists stored images",
			Action: ListCommand,
			Flags:  typeFlags,
		},
		{
			Name:   "url",
			Usage:  "Lists URLs of images",
			Action: UrlCommand,
			Flags:  getFlags,
		},
		{
			Name:   "path",
			Usage:  "Lists paths to images",
			Action: PathCommand,
			Flags:  getFlags,
		},
		{
			Name:    "remove",
			Aliases: []string{"rm"},
			Usage:   "Removes images",
			Action:  RemoveCommand,
			Flags:   removeFlags,
		},
		{
			Name:   "export",
			Usage:  "Exports the database",
			Action: ExportCommand,
			Flags:  exportFlags,
		},
		{
			Name:   "import",
			Usage:  "Imports multiple images into the database",
			Action: ImportCommand,
			Flags:  importFlags,
		},
		{
			Name:   "upload",
			Usage:  "Uploads images to a server and saves the URLs for later use",
			Action: UploadCommand,
			Flags:  uploadFlags,
		},
		{
			Name:   "tags",
			Usage:  "Lists tags available in the database along with their image count",
			Action: TagsCommand,
		},
	}
	app.Before = func(c *cli.Context) (err error) {
		err = loadConfig(c.String("config"))
		return
	}

	app.Run(os.Args)
}

func ConfigCommand(c *cli.Context) {
	config.Global.Print()
}

///////////////////////////////////////////////////////////////////////////////

type locationType int

const (
	invalidLocation locationType = iota
	fileLocation
	directoryLocation
	urlLocation
)

func loadConfig(arg string) (err error) {
	if arg == "default" {
		err = config.Default()
	} else {
		err = config.Load(arg)
	}

	if err != nil {
		fmt.Println("Error while loading the configuration file: " + err.Error())
	}
	return
}

func getStore() *store.Store {
	s, err := store.Default()
	if err != nil {
		fmt.Println("Cannot create store: " + err.Error())
		os.Exit(1)
	}
	return s
}

func typeFilter(c *cli.Context) (filter store.Filter) {
	if c.Args().Present() {
		arg := strings.Join(c.Args(), " ")

		if !c.Bool("tag") && regexp.MustCompile("^[0-9a-f]+$").MatchString(arg) {
			filter = store.IdOrTagFilter{Id: arg}
		} else {
			filter = store.TagFilter{Tag: arg}
		}
	} else if c.Bool("untagged") {
		filter = store.UntaggedFilter{}
	} else {
		filter = store.NullFilter{}
	}

	if c.Bool("local") {
		filter = store.LocalFilter{Filter: filter}
	}

	return
}

func listFilter(c *cli.Context) store.Filter {
	return store.DateOrderer{
		Filter:    typeFilter(c),
		Direction: store.Descending,
	}
}

func orderAndLimit(input store.Filter, c *cli.Context) (filter store.Filter) {
	switch c.String("order") {
	case "random":
		filter = store.RandomOrderer{Filter: input}
	case "newest":
		filter = store.DateOrderer{Filter: input, Direction: store.Descending}
	case "oldest":
		filter = store.DateOrderer{Filter: input, Direction: store.Ascending}
	default:
		fmt.Println("Invalid order.")
		os.Exit(1)
	}

	if !c.Bool("all") {
		filter = store.Limiter{Filter: filter, Limit: 1}
	}

	return
}

func parseLocation(location string) (locationType, error) {
	if location == "" {
		return invalidLocation, errors.New("No location specified")
	}

	// Check for URL
	u, err := url.Parse(location)
	if err == nil {
		if u.Scheme == "http" || u.Scheme == "https" {
			return urlLocation, nil
		} else if u.Scheme != "" {
			return urlLocation, errors.New("Only HTTP and HTTPS URLs are supported")
		}
	}

	// Check for path
	fileInfo, err := os.Stat(location)
	if err == nil {
		if fileInfo.IsDir() {
			return directoryLocation, nil
		}
		return fileLocation, nil
	}

	return invalidLocation, errors.New("Invalid location")
}
<commit_msg>Reordered the commands alphabetically in the help screen.<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/evoL/gif/config"
	"github.com/evoL/gif/store"
	"github.com/evoL/gif/version"
	"net/url"
	"os"
	"regexp"
	"strings"
)

func main() {
	typeFlags := []cli.Flag{
		cli.BoolFlag{
			Name:  "tag, t",
			Usage: "Enforces searching by tag.",
		},
		cli.BoolFlag{
			Name:  "untagged",
			Usage: "Lists only images that have no tag.",
		},
		cli.BoolFlag{
			Name:  "local",
			Usage: "Lists only images that are local, that is not avaliable remotely.",
		},
	}
	getFlags := append(
		typeFlags,
		cli.BoolFlag{
			Name:  "all, a",
			Usage: "Gets all matching images.",
		},
		cli.StringFlag{
			Name:  "order, sort, s",
			Usage: "Specifies the order of images. Must be one of: random, newest, oldest.",
			Value: "random",
		},
	)
	removeFlags := append(
		typeFlags,
		cli.BoolFlag{
			Name:  "all, a",
			Usage: "Removes all matching images.",
		},
		cli.BoolFlag{
			Name:  "really",
			Usage: "Doesn't ask for confirmation.",
		},
	)
	exportFlags := []cli.Flag{
		cli.StringFlag{
			Name:  "output, o",
			Usage: "Target output file. Set to '-' for stdout.",
			Value: "-",
		},
		cli.BoolFlag{
			Name:  "bundle",
			Usage: "Export a bundle containing all images and metadata.",
		},
	}
	importFlags := []cli.Flag{
		cli.BoolFlag{
			Name:  "recursive, r",
			Usage: "When importing directories, do it recursively.",
		},
	}
	uploadFlags := append(
		typeFlags,
		cli.BoolFlag{
			Name:  "really",
			Usage: "Doesn't ask for confirmation.",
		},
	)

	app := cli.NewApp()
	app.Name = "gif"
	app.Usage = "a stupid gif manager"
	app.Author = "Rafał Hirsz"
	app.Email = "rafal@hirsz.co"
	app.Version = version.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Value: "default",
			Usage: "Path to the configuration file",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:   "add",
			Usage:  "Adds an image",
			Action: AddCommand,
		},
		{
			Name:   "config",
			Usage:  "Prints the current configuration",
			Action: ConfigCommand,
		},
		{
			Name:   "export",
			Usage:  "Exports the database",
			Action: ExportCommand,
			Flags:  exportFlags,
		},
		{
			Name:   "import",
			Usage:  "Imports multiple images into the database",
			Action: ImportCommand,
			Flags:  importFlags,
		},
		{
			Name:   "list",
			Usage:  "Lists stored images",
			Action: ListCommand,
			Flags:  typeFlags,
		},
		{
			Name:   "path",
			Usage:  "Lists paths to images",
			Action: PathCommand,
			Flags:  getFlags,
		},
		{
			Name:    "remove",
			Aliases: []string{"rm"},
			Usage:   "Removes images",
			Action:  RemoveCommand,
			Flags:   removeFlags,
		},
		{
			Name:   "tag",
			Usage:  "Enables to change tags for images",
			Action: TagCommand,
			Flags:  typeFlags,
		},
		{
			Name:   "tags",
			Usage:  "Lists tags available in the database along with their image count",
			Action: TagsCommand,
		},
		{
			Name:   "url",
			Usage:  "Lists URLs of images",
			Action: UrlCommand,
			Flags:  getFlags,
		},
		{
			Name:   "upload",
			Usage:  "Uploads images to a server and saves the URLs for later use",
			Action: UploadCommand,
			Flags:  uploadFlags,
		},
		{
			Name:   "path",
			Usage:  "Lists paths to images",
			Action: PathCommand,
			Flags:  getFlags,
		},
	}
	app.Before = func(c *cli.Context) (err error) {
		err = loadConfig(c.String("config"))
		return
	}

	app.Run(os.Args)
}

func ConfigCommand(c *cli.Context) {
	config.Global.Print()
}

///////////////////////////////////////////////////////////////////////////////

type locationType int

const (
	invalidLocation locationType = iota
	fileLocation
	directoryLocation
	urlLocation
)

func loadConfig(arg string) (err error) {
	if arg == "default" {
		err = config.Default()
	} else {
		err = config.Load(arg)
	}

	if err != nil {
		fmt.Println("Error while loading the configuration file: " + err.Error())
	}
	return
}

func getStore() *store.Store {
	s, err := store.Default()
	if err != nil {
		fmt.Println("Cannot create store: " + err.Error())
		os.Exit(1)
	}
	return s
}

func typeFilter(c *cli.Context) (filter store.Filter) {
	if c.Args().Present() {
		arg := strings.Join(c.Args(), " ")

		if !c.Bool("tag") && regexp.MustCompile("^[0-9a-f]+$").MatchString(arg) {
			filter = store.IdOrTagFilter{Id: arg}
		} else {
			filter = store.TagFilter{Tag: arg}
		}
	} else if c.Bool("untagged") {
		filter = store.UntaggedFilter{}
	} else {
		filter = store.NullFilter{}
	}

	if c.Bool("local") {
		filter = store.LocalFilter{Filter: filter}
	}

	return
}

func listFilter(c *cli.Context) store.Filter {
	return store.DateOrderer{
		Filter:    typeFilter(c),
		Direction: store.Descending,
	}
}

func orderAndLimit(input store.Filter, c *cli.Context) (filter store.Filter) {
	switch c.String("order") {
	case "random":
		filter = store.RandomOrderer{Filter: input}
	case "newest":
		filter = store.DateOrderer{Filter: input, Direction: store.Descending}
	case "oldest":
		filter = store.DateOrderer{Filter: input, Direction: store.Ascending}
	default:
		fmt.Println("Invalid order.")
		os.Exit(1)
	}

	if !c.Bool("all") {
		filter = store.Limiter{Filter: filter, Limit: 1}
	}

	return
}

func parseLocation(location string) (locationType, error) {
	if location == "" {
		return invalidLocation, errors.New("No location specified")
	}

	// Check for URL
	u, err := url.Parse(location)
	if err == nil {
		if u.Scheme == "http" || u.Scheme == "https" {
			return urlLocation, nil
		} else if u.Scheme != "" {
			return urlLocation, errors.New("Only HTTP and HTTPS URLs are supported")
		}
	}

	// Check for path
	fileInfo, err := os.Stat(location)
	if err == nil {
		if fileInfo.IsDir() {
			return directoryLocation, nil
		}
		return fileLocation, nil
	}

	return invalidLocation, errors.New("Invalid location")
}
<|endoftext|>


<commit_before>package gin

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"html/template"
	"log"
	"math"
	"net/http"
	"path"
)

const (
	AbortIndex = math.MaxInt8 / 2
)

type (
	HandlerFunc func(*Context)

	H map[string]interface{}

	// Used internally to collect a error ocurred during a http request.
	ErrorMsg struct {
		Err  string      `json:"error"`
		Meta interface{} `json:"meta"`
	}

	ErrorMsgs []ErrorMsg

	Config struct {
		CacheSize    int
		Preallocated int
	}

	// Context is the most important part of gin. It allows us to pass variables between middleware,
	// manage the flow, validate the JSON of a request and render a JSON response for example.
	Context struct {
		Req      *http.Request
		Writer   http.ResponseWriter
		Keys     map[string]interface{}
		Errors   ErrorMsgs
		Params   httprouter.Params
		Engine   *Engine
		handlers []HandlerFunc
		index    int8
	}

	// Used internally to configure router, a RouterGroup is associated with a prefix
	// and an array of handlers (middlewares)
	RouterGroup struct {
		Handlers []HandlerFunc
		prefix   string
		parent   *RouterGroup
		engine   *Engine
	}

	// Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares.
	Engine struct {
		*RouterGroup
		HTMLTemplates *template.Template
		cache         chan *Context
		handlers404   []HandlerFunc
		router        *httprouter.Router
	}
)

func (a ErrorMsgs) String() string {
	var buffer bytes.Buffer
	for i, msg := range a {
		text := fmt.Sprintf("Error #%02d: %s \n     Meta: %v\n\n", (i + 1), msg.Err, msg.Meta)
		buffer.WriteString(text)
	}
	return buffer.String()
}

func NewWithConfig(config Config) *Engine {
	if config.CacheSize < 2 {
		panic("CacheSize must be at least 2")
	}
	if config.Preallocated > config.CacheSize {
		panic("Preallocated must be less or equal to CacheSize")
	}
	engine := &Engine{}
	engine.RouterGroup = &RouterGroup{nil, "/", nil, engine}
	engine.router = httprouter.New()
	engine.router.NotFound = engine.handle404
	engine.cache = make(chan *Context, config.CacheSize)

	// Fill it with empty contexts
	for i := 0; i < config.Preallocated; i++ {
		engine.cache <- &Context{Engine: engine}
	}
	return engine
}

// Returns a new blank Engine instance without any middleware attached.
// The most basic configuration
func New() *Engine {
	return NewWithConfig(Config{
		CacheSize:    1024,
		Preallocated: 512,
	})
}

// Returns a Engine instance with the Logger and Recovery already attached.
func Default() *Engine {
	engine := New()
	engine.Use(Recovery(), Logger())
	return engine
}

func (engine *Engine) LoadHTMLTemplates(pattern string) {
	engine.HTMLTemplates = template.Must(template.ParseGlob(pattern))
}

// Adds handlers for NotFound. It return a 404 code by default.
func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
	engine.handlers404 = handlers
}

func (engine *Engine) CacheStress() float32 {
	return 1.0 - float32(len(engine.cache))/float32(cap(engine.cache))
}

func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
	handlers := engine.combineHandlers(engine.handlers404)
	c := engine.createContext(w, req, nil, handlers)
	if engine.handlers404 == nil {
		http.NotFound(c.Writer, c.Req)
	} else {
		c.Writer.WriteHeader(404)
	}

	c.Next()
	engine.reuseContext(c)
}

// 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 (engine *Engine) ServeFiles(path string, root http.FileSystem) {
	engine.router.ServeFiles(path, root)
}

// ServeHTTP makes the router implement the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	engine.router.ServeHTTP(w, req)
}

func (engine *Engine) Run(addr string) {
	if err := http.ListenAndServe(addr, engine); err != nil {
		panic(err)
	}
}

/************************************/
/********** ROUTES GROUPING *********/
/************************************/

func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
	select {
	case c := <-engine.cache:
		c.Writer = w
		c.Req = req
		c.Params = params
		c.handlers = handlers
		c.Keys = nil
		c.index = -1
		return c
	default:
		return &Context{
			Writer:   w,
			Req:      req,
			Params:   params,
			handlers: handlers,
			index:    -1,
			Engine:   engine,
		}
	}
}

func (engine *Engine) reuseContext(c *Context) {
	select {
	case engine.cache <- c:
	default:
	}
}

// Adds middlewares to the group, see example code in github.
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
	group.Handlers = append(group.Handlers, middlewares...)
}

// Greates a new router group. You should create add all the routes that share that have common middlwares or same path prefix.
// For example, all the routes that use a common middlware for authorization could be grouped.
func (group *RouterGroup) Group(component string, handlers ...HandlerFunc) *RouterGroup {
	prefix := path.Join(group.prefix, component)
	return &RouterGroup{
		Handlers: group.combineHandlers(handlers),
		parent:   group,
		prefix:   prefix,
		engine:   group.engine,
	}
}

// Handle registers a new request handle and middlewares with the given path and method.
// The last handler should be the real handler, the other ones should be middlewares that can and should be shared among different routes.
// See the example code in github.
//
// 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 (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
	p = path.Join(group.prefix, p)
	handlers = group.combineHandlers(handlers)
	group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		c := group.engine.createContext(w, req, params, handlers)
		c.Next()
		group.engine.reuseContext(c)
	})
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (group *RouterGroup) POST(path string, handlers ...HandlerFunc) {
	group.Handle("POST", path, handlers)
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (group *RouterGroup) GET(path string, handlers ...HandlerFunc) {
	group.Handle("GET", path, handlers)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (group *RouterGroup) DELETE(path string, handlers ...HandlerFunc) {
	group.Handle("DELETE", path, handlers)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (group *RouterGroup) PATCH(path string, handlers ...HandlerFunc) {
	group.Handle("PATCH", path, handlers)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (group *RouterGroup) PUT(path string, handlers ...HandlerFunc) {
	group.Handle("PUT", path, handlers)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (group *RouterGroup) OPTIONS(path string, handlers ...HandlerFunc) {
	group.Handle("OPTIONS", path, handlers)
}

func (group *RouterGroup) combineHandlers(handlers []HandlerFunc) []HandlerFunc {
	s := len(group.Handlers) + len(handlers)
	h := make([]HandlerFunc, 0, s)
	h = append(h, group.Handlers...)
	h = append(h, handlers...)
	return h
}

/************************************/
/****** FLOW AND ERROR MANAGEMENT****/
/************************************/

func (c *Context) Copy() *Context {
	var cp Context = *c
	cp.index = AbortIndex
	cp.handlers = nil
	return &cp
}

// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
// See example in github.
func (c *Context) Next() {
	c.index++
	s := int8(len(c.handlers))
	for ; c.index < s; c.index++ {
		c.handlers[c.index](c)
	}
}

// Forces the system to do not continue calling the pending handlers.
// For example, the first handler checks if the request is authorized. If it's not, context.Abort(401) should be called.
// The rest of pending handlers would never be called for that request.
func (c *Context) Abort(code int) {
	c.Writer.WriteHeader(code)
	c.index = AbortIndex
}

// Fail is the same than Abort plus an error message.
// Calling `context.Fail(500, err)` is equivalent to:
// ```
// context.Error("Operation aborted", err)
// context.Abort(500)
// ```
func (c *Context) Fail(code int, err error) {
	c.Error(err, "Operation aborted")
	c.Abort(code)
}

// Attachs an error to the current context. The error is pushed to a list of errors.
// It's a gooc idea to call Error for each error ocurred during the resolution of a request.
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
func (c *Context) Error(err error, meta interface{}) {
	c.Errors = append(c.Errors, ErrorMsg{
		Err:  err.Error(),
		Meta: meta,
	})
}

func (c *Context) LastError() error {
	s := len(c.Errors)
	if s > 0 {
		return errors.New(c.Errors[s-1].Err)
	} else {
		return nil
	}
}

/************************************/
/******** METADATA MANAGEMENT********/
/************************************/

// Sets a new pair key/value just for the specefied context.
// It also lazy initializes the hashmap
func (c *Context) Set(key string, item interface{}) {
	if c.Keys == nil {
		c.Keys = make(map[string]interface{})
	}
	c.Keys[key] = item
}

// Returns the value for the given key.
// It panics if the value doesn't exist.
func (c *Context) Get(key string) interface{} {
	var ok bool
	var item interface{}
	if c.Keys != nil {
		item, ok = c.Keys[key]
	} else {
		item, ok = nil, false
	}
	if !ok || item == nil {
		log.Panicf("Key %s doesn't exist", key)
	}
	return item
}

/************************************/
/******** ENCOGING MANAGEMENT********/
/************************************/

// Like ParseBody() but this method also writes a 400 error if the json is not valid.
func (c *Context) EnsureBody(item interface{}) bool {
	if err := c.ParseBody(item); err != nil {
		c.Fail(400, err)
		return false
	}
	return true
}

// Parses the body content as a JSON input. It decodes the json payload into the struct specified as a pointer.
func (c *Context) ParseBody(item interface{}) error {
	decoder := json.NewDecoder(c.Req.Body)
	if err := decoder.Decode(&item); err == nil {
		return Validate(c, item)
	} else {
		return err
	}
}

// Serializes the given struct as a JSON into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/json"
func (c *Context) JSON(code int, obj interface{}) {
	c.Writer.Header().Set("Content-Type", "application/json")
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	encoder := json.NewEncoder(c.Writer)
	if err := encoder.Encode(obj); err != nil {
		c.Error(err, obj)
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Serializes the given struct as a XML into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/xml"
func (c *Context) XML(code int, obj interface{}) {
	c.Writer.Header().Set("Content-Type", "application/xml")
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	encoder := xml.NewEncoder(c.Writer)
	if err := encoder.Encode(obj); err != nil {
		c.Error(err, obj)
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Renders the HTTP template specified by his file name.
// It also update the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, name string, data interface{}) {
	c.Writer.Header().Set("Content-Type", "text/html")
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	if err := c.Engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
		c.Error(err, map[string]interface{}{
			"name": name,
			"data": data,
		})
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Writes the given string into the response body and sets the Content-Type to "text/plain"
func (c *Context) String(code int, msg string) {
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	c.Writer.Header().Set("Content-Type", "text/plain")
	c.Writer.Write([]byte(msg))
}

// Writes some data into the body stream and updates the HTTP code
func (c *Context) Data(code int, data []byte) {
	c.Writer.WriteHeader(code)
	c.Writer.Write(data)
}
<commit_msg>Adds HEAD<commit_after>package gin

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"html/template"
	"log"
	"math"
	"net/http"
	"path"
)

const (
	AbortIndex = math.MaxInt8 / 2
)

type (
	HandlerFunc func(*Context)

	H map[string]interface{}

	// Used internally to collect a error ocurred during a http request.
	ErrorMsg struct {
		Err  string      `json:"error"`
		Meta interface{} `json:"meta"`
	}

	ErrorMsgs []ErrorMsg

	Config struct {
		CacheSize    int
		Preallocated int
	}

	// Context is the most important part of gin. It allows us to pass variables between middleware,
	// manage the flow, validate the JSON of a request and render a JSON response for example.
	Context struct {
		Req      *http.Request
		Writer   http.ResponseWriter
		Keys     map[string]interface{}
		Errors   ErrorMsgs
		Params   httprouter.Params
		Engine   *Engine
		handlers []HandlerFunc
		index    int8
	}

	// Used internally to configure router, a RouterGroup is associated with a prefix
	// and an array of handlers (middlewares)
	RouterGroup struct {
		Handlers []HandlerFunc
		prefix   string
		parent   *RouterGroup
		engine   *Engine
	}

	// Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares.
	Engine struct {
		*RouterGroup
		HTMLTemplates *template.Template
		cache         chan *Context
		handlers404   []HandlerFunc
		router        *httprouter.Router
	}
)

func (a ErrorMsgs) String() string {
	var buffer bytes.Buffer
	for i, msg := range a {
		text := fmt.Sprintf("Error #%02d: %s \n     Meta: %v\n\n", (i + 1), msg.Err, msg.Meta)
		buffer.WriteString(text)
	}
	return buffer.String()
}

func NewWithConfig(config Config) *Engine {
	if config.CacheSize < 2 {
		panic("CacheSize must be at least 2")
	}
	if config.Preallocated > config.CacheSize {
		panic("Preallocated must be less or equal to CacheSize")
	}
	engine := &Engine{}
	engine.RouterGroup = &RouterGroup{nil, "/", nil, engine}
	engine.router = httprouter.New()
	engine.router.NotFound = engine.handle404
	engine.cache = make(chan *Context, config.CacheSize)

	// Fill it with empty contexts
	for i := 0; i < config.Preallocated; i++ {
		engine.cache <- &Context{Engine: engine}
	}
	return engine
}

// Returns a new blank Engine instance without any middleware attached.
// The most basic configuration
func New() *Engine {
	return NewWithConfig(Config{
		CacheSize:    1024,
		Preallocated: 512,
	})
}

// Returns a Engine instance with the Logger and Recovery already attached.
func Default() *Engine {
	engine := New()
	engine.Use(Recovery(), Logger())
	return engine
}

func (engine *Engine) LoadHTMLTemplates(pattern string) {
	engine.HTMLTemplates = template.Must(template.ParseGlob(pattern))
}

// Adds handlers for NotFound. It return a 404 code by default.
func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
	engine.handlers404 = handlers
}

func (engine *Engine) CacheStress() float32 {
	return 1.0 - float32(len(engine.cache))/float32(cap(engine.cache))
}

func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
	handlers := engine.combineHandlers(engine.handlers404)
	c := engine.createContext(w, req, nil, handlers)
	if engine.handlers404 == nil {
		http.NotFound(c.Writer, c.Req)
	} else {
		c.Writer.WriteHeader(404)
	}

	c.Next()
	engine.reuseContext(c)
}

// 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 (engine *Engine) ServeFiles(path string, root http.FileSystem) {
	engine.router.ServeFiles(path, root)
}

// ServeHTTP makes the router implement the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	engine.router.ServeHTTP(w, req)
}

func (engine *Engine) Run(addr string) {
	if err := http.ListenAndServe(addr, engine); err != nil {
		panic(err)
	}
}

/************************************/
/********** ROUTES GROUPING *********/
/************************************/

func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
	select {
	case c := <-engine.cache:
		c.Writer = w
		c.Req = req
		c.Params = params
		c.handlers = handlers
		c.Keys = nil
		c.index = -1
		return c
	default:
		return &Context{
			Writer:   w,
			Req:      req,
			Params:   params,
			handlers: handlers,
			index:    -1,
			Engine:   engine,
		}
	}
}

func (engine *Engine) reuseContext(c *Context) {
	select {
	case engine.cache <- c:
	default:
	}
}

// Adds middlewares to the group, see example code in github.
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
	group.Handlers = append(group.Handlers, middlewares...)
}

// Greates a new router group. You should create add all the routes that share that have common middlwares or same path prefix.
// For example, all the routes that use a common middlware for authorization could be grouped.
func (group *RouterGroup) Group(component string, handlers ...HandlerFunc) *RouterGroup {
	prefix := path.Join(group.prefix, component)
	return &RouterGroup{
		Handlers: group.combineHandlers(handlers),
		parent:   group,
		prefix:   prefix,
		engine:   group.engine,
	}
}

// Handle registers a new request handle and middlewares with the given path and method.
// The last handler should be the real handler, the other ones should be middlewares that can and should be shared among different routes.
// See the example code in github.
//
// 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 (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
	p = path.Join(group.prefix, p)
	handlers = group.combineHandlers(handlers)
	group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		c := group.engine.createContext(w, req, params, handlers)
		c.Next()
		group.engine.reuseContext(c)
	})
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (group *RouterGroup) POST(path string, handlers ...HandlerFunc) {
	group.Handle("POST", path, handlers)
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (group *RouterGroup) GET(path string, handlers ...HandlerFunc) {
	group.Handle("GET", path, handlers)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (group *RouterGroup) DELETE(path string, handlers ...HandlerFunc) {
	group.Handle("DELETE", path, handlers)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (group *RouterGroup) PATCH(path string, handlers ...HandlerFunc) {
	group.Handle("PATCH", path, handlers)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (group *RouterGroup) PUT(path string, handlers ...HandlerFunc) {
	group.Handle("PUT", path, handlers)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (group *RouterGroup) OPTIONS(path string, handlers ...HandlerFunc) {
	group.Handle("OPTIONS", path, handlers)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (group *RouterGroup) HEAD(path string, handlers ...HandlerFunc) {
	group.Handle("HEAD", path, handlers)
}

func (group *RouterGroup) combineHandlers(handlers []HandlerFunc) []HandlerFunc {
	s := len(group.Handlers) + len(handlers)
	h := make([]HandlerFunc, 0, s)
	h = append(h, group.Handlers...)
	h = append(h, handlers...)
	return h
}

/************************************/
/****** FLOW AND ERROR MANAGEMENT****/
/************************************/

func (c *Context) Copy() *Context {
	var cp Context = *c
	cp.index = AbortIndex
	cp.handlers = nil
	return &cp
}

// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
// See example in github.
func (c *Context) Next() {
	c.index++
	s := int8(len(c.handlers))
	for ; c.index < s; c.index++ {
		c.handlers[c.index](c)
	}
}

// Forces the system to do not continue calling the pending handlers.
// For example, the first handler checks if the request is authorized. If it's not, context.Abort(401) should be called.
// The rest of pending handlers would never be called for that request.
func (c *Context) Abort(code int) {
	c.Writer.WriteHeader(code)
	c.index = AbortIndex
}

// Fail is the same than Abort plus an error message.
// Calling `context.Fail(500, err)` is equivalent to:
// ```
// context.Error("Operation aborted", err)
// context.Abort(500)
// ```
func (c *Context) Fail(code int, err error) {
	c.Error(err, "Operation aborted")
	c.Abort(code)
}

// Attachs an error to the current context. The error is pushed to a list of errors.
// It's a gooc idea to call Error for each error ocurred during the resolution of a request.
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
func (c *Context) Error(err error, meta interface{}) {
	c.Errors = append(c.Errors, ErrorMsg{
		Err:  err.Error(),
		Meta: meta,
	})
}

func (c *Context) LastError() error {
	s := len(c.Errors)
	if s > 0 {
		return errors.New(c.Errors[s-1].Err)
	} else {
		return nil
	}
}

/************************************/
/******** METADATA MANAGEMENT********/
/************************************/

// Sets a new pair key/value just for the specefied context.
// It also lazy initializes the hashmap
func (c *Context) Set(key string, item interface{}) {
	if c.Keys == nil {
		c.Keys = make(map[string]interface{})
	}
	c.Keys[key] = item
}

// Returns the value for the given key.
// It panics if the value doesn't exist.
func (c *Context) Get(key string) interface{} {
	var ok bool
	var item interface{}
	if c.Keys != nil {
		item, ok = c.Keys[key]
	} else {
		item, ok = nil, false
	}
	if !ok || item == nil {
		log.Panicf("Key %s doesn't exist", key)
	}
	return item
}

/************************************/
/******** ENCOGING MANAGEMENT********/
/************************************/

// Like ParseBody() but this method also writes a 400 error if the json is not valid.
func (c *Context) EnsureBody(item interface{}) bool {
	if err := c.ParseBody(item); err != nil {
		c.Fail(400, err)
		return false
	}
	return true
}

// Parses the body content as a JSON input. It decodes the json payload into the struct specified as a pointer.
func (c *Context) ParseBody(item interface{}) error {
	decoder := json.NewDecoder(c.Req.Body)
	if err := decoder.Decode(&item); err == nil {
		return Validate(c, item)
	} else {
		return err
	}
}

// Serializes the given struct as a JSON into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/json"
func (c *Context) JSON(code int, obj interface{}) {
	c.Writer.Header().Set("Content-Type", "application/json")
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	encoder := json.NewEncoder(c.Writer)
	if err := encoder.Encode(obj); err != nil {
		c.Error(err, obj)
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Serializes the given struct as a XML into the response body in a fast and efficient way.
// It also sets the Content-Type as "application/xml"
func (c *Context) XML(code int, obj interface{}) {
	c.Writer.Header().Set("Content-Type", "application/xml")
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	encoder := xml.NewEncoder(c.Writer)
	if err := encoder.Encode(obj); err != nil {
		c.Error(err, obj)
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Renders the HTTP template specified by his file name.
// It also update the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, name string, data interface{}) {
	c.Writer.Header().Set("Content-Type", "text/html")
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	if err := c.Engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
		c.Error(err, map[string]interface{}{
			"name": name,
			"data": data,
		})
		http.Error(c.Writer, err.Error(), 500)
	}
}

// Writes the given string into the response body and sets the Content-Type to "text/plain"
func (c *Context) String(code int, msg string) {
	if code >= 0 {
		c.Writer.WriteHeader(code)
	}
	c.Writer.Header().Set("Content-Type", "text/plain")
	c.Writer.Write([]byte(msg))
}

// Writes some data into the body stream and updates the HTTP code
func (c *Context) Data(code int, data []byte) {
	c.Writer.WriteHeader(code)
	c.Writer.Write(data)
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd Authors.

   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 nvidia

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

const nvidiaCLI = "nvidia-container-cli"

// Capability specifies capabilities for the gpu inside the container
// Detailed explanation of options can be found:
// https://github.com/nvidia/nvidia-container-runtime#supported-driver-capabilities
type Capability string

const (
	// Compute capability
	Compute Capability = "compute"
	// Compat32 capability
	Compat32 Capability = "compat32"
	// Graphics capability
	Graphics Capability = "graphics"
	// Utility capability
	Utility Capability = "utility"
	// Video capability
	Video Capability = "video"
	// Display capability
	Display Capability = "display"
)

var allCaps = []Capability{
	Compute,
	Compat32,
	Graphics,
	Utility,
	Video,
	Display,
}

// WithGPUs adds NVIDIA gpu support to a container
func WithGPUs(opts ...Opts) oci.SpecOpts {
	return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
		c := &config{}
		for _, o := range opts {
			if err := o(c); err != nil {
				return err
			}
		}
		if c.OCIHookPath == "" {
			path, err := exec.LookPath("containerd")
			if err != nil {
				return err
			}
			c.OCIHookPath = path
		}
		nvidiaPath, err := exec.LookPath(nvidiaCLI)
		if err != nil {
			return err
		}
		if s.Hooks == nil {
			s.Hooks = &specs.Hooks{}
		}
		s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
			Path: c.OCIHookPath,
			Args: append([]string{
				"containerd",
				"oci-hook",
				"--",
				nvidiaPath,
				// ensures the required kernel modules are properly loaded
				"--load-kmods",
			}, c.args()...),
			Env: os.Environ(),
		})
		return nil
	}
}

type config struct {
	Devices      []string
	Capabilities []Capability
	LoadKmods    bool
	LDCache      string
	LDConfig     string
	Requirements []string
	OCIHookPath  string
}

func (c *config) args() []string {
	var args []string

	if c.LoadKmods {
		args = append(args, "--load-kmods")
	}
	if c.LDCache != "" {
		args = append(args, fmt.Sprintf("--ldcache=%s", c.LDCache))
	}
	args = append(args,
		"configure",
	)
	if len(c.Devices) > 0 {
		args = append(args, fmt.Sprintf("--device=%s", strings.Join(c.Devices, ",")))
	}
	for _, c := range c.Capabilities {
		args = append(args, fmt.Sprintf("--%s", c))
	}
	if c.LDConfig != "" {
		args = append(args, fmt.Sprintf("--ldconfig=%s", c.LDConfig))
	}
	for _, r := range c.Requirements {
		args = append(args, fmt.Sprintf("--require=%s", r))
	}
	args = append(args, "--pid={{pid}}", "{{rootfs}}")
	return args
}

// Opts are options for configuring gpu support
type Opts func(*config) error

// WithDevices adds the provided device indexes to the container
func WithDevices(ids ...int) Opts {
	return func(c *config) error {
		for _, i := range ids {
			c.Devices = append(c.Devices, strconv.Itoa(i))
		}
		return nil
	}
}

// WithDeviceUUIDs adds the specific device UUID to the container
func WithDeviceUUIDs(uuids ...string) Opts {
	return func(c *config) error {
		c.Devices = append(c.Devices, uuids...)
		return nil
	}
}

// WithAllDevices adds all gpus to the container
func WithAllDevices(c *config) error {
	c.Devices = []string{"all"}
	return nil
}

// WithAllCapabilities adds all capabilities to the container for the gpus
func WithAllCapabilities(c *config) error {
	c.Capabilities = allCaps
	return nil
}

// WithCapabilities adds the specified capabilities to the container for the gpus
func WithCapabilities(caps ...Capability) Opts {
	return func(c *config) error {
		c.Capabilities = append(c.Capabilities, caps...)
		return nil
	}
}

// WithRequiredCUDAVersion sets the required cuda version
func WithRequiredCUDAVersion(major, minor int) Opts {
	return func(c *config) error {
		c.Requirements = append(c.Requirements, fmt.Sprintf("cuda>=%d.%d", major, minor))
		return nil
	}
}

// WithOCIHookPath sets the hook path for the binary
func WithOCIHookPath(path string) Opts {
	return func(c *config) error {
		c.OCIHookPath = path
		return nil
	}
}

// WithLookupOCIHookPath sets the hook path for the binary via a binary name
func WithLookupOCIHookPath(name string) Opts {
	return func(c *config) error {
		path, err := exec.LookPath(name)
		if err != nil {
			return err
		}
		c.OCIHookPath = path
		return nil
	}
}
<commit_msg>contrib/nvidia: export helper binary path and list of Nvidia capabilities<commit_after>/*
   Copyright The containerd Authors.

   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 nvidia

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

// NvidiaCLI is the path to the Nvidia helper binary
const NvidiaCLI = "nvidia-container-cli"

// Capability specifies capabilities for the gpu inside the container
// Detailed explanation of options can be found:
// https://github.com/nvidia/nvidia-container-runtime#supported-driver-capabilities
type Capability string

const (
	// Compute capability
	Compute Capability = "compute"
	// Compat32 capability
	Compat32 Capability = "compat32"
	// Graphics capability
	Graphics Capability = "graphics"
	// Utility capability
	Utility Capability = "utility"
	// Video capability
	Video Capability = "video"
	// Display capability
	Display Capability = "display"
)

// AllCaps returns the complete list of supported Nvidia capabilties.
func AllCaps() []Capability {
	return []Capability{
		Compute,
		Compat32,
		Graphics,
		Utility,
		Video,
		Display,
	}
}

// WithGPUs adds NVIDIA gpu support to a container
func WithGPUs(opts ...Opts) oci.SpecOpts {
	return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
		c := &config{}
		for _, o := range opts {
			if err := o(c); err != nil {
				return err
			}
		}
		if c.OCIHookPath == "" {
			path, err := exec.LookPath("containerd")
			if err != nil {
				return err
			}
			c.OCIHookPath = path
		}
		nvidiaPath, err := exec.LookPath(NvidiaCLI)
		if err != nil {
			return err
		}
		if s.Hooks == nil {
			s.Hooks = &specs.Hooks{}
		}
		s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
			Path: c.OCIHookPath,
			Args: append([]string{
				"containerd",
				"oci-hook",
				"--",
				nvidiaPath,
				// ensures the required kernel modules are properly loaded
				"--load-kmods",
			}, c.args()...),
			Env: os.Environ(),
		})
		return nil
	}
}

type config struct {
	Devices      []string
	Capabilities []Capability
	LoadKmods    bool
	LDCache      string
	LDConfig     string
	Requirements []string
	OCIHookPath  string
}

func (c *config) args() []string {
	var args []string

	if c.LoadKmods {
		args = append(args, "--load-kmods")
	}
	if c.LDCache != "" {
		args = append(args, fmt.Sprintf("--ldcache=%s", c.LDCache))
	}
	args = append(args,
		"configure",
	)
	if len(c.Devices) > 0 {
		args = append(args, fmt.Sprintf("--device=%s", strings.Join(c.Devices, ",")))
	}
	for _, c := range c.Capabilities {
		args = append(args, fmt.Sprintf("--%s", c))
	}
	if c.LDConfig != "" {
		args = append(args, fmt.Sprintf("--ldconfig=%s", c.LDConfig))
	}
	for _, r := range c.Requirements {
		args = append(args, fmt.Sprintf("--require=%s", r))
	}
	args = append(args, "--pid={{pid}}", "{{rootfs}}")
	return args
}

// Opts are options for configuring gpu support
type Opts func(*config) error

// WithDevices adds the provided device indexes to the container
func WithDevices(ids ...int) Opts {
	return func(c *config) error {
		for _, i := range ids {
			c.Devices = append(c.Devices, strconv.Itoa(i))
		}
		return nil
	}
}

// WithDeviceUUIDs adds the specific device UUID to the container
func WithDeviceUUIDs(uuids ...string) Opts {
	return func(c *config) error {
		c.Devices = append(c.Devices, uuids...)
		return nil
	}
}

// WithAllDevices adds all gpus to the container
func WithAllDevices(c *config) error {
	c.Devices = []string{"all"}
	return nil
}

// WithAllCapabilities adds all capabilities to the container for the gpus
func WithAllCapabilities(c *config) error {
	c.Capabilities = AllCaps()
	return nil
}

// WithCapabilities adds the specified capabilities to the container for the gpus
func WithCapabilities(caps ...Capability) Opts {
	return func(c *config) error {
		c.Capabilities = append(c.Capabilities, caps...)
		return nil
	}
}

// WithRequiredCUDAVersion sets the required cuda version
func WithRequiredCUDAVersion(major, minor int) Opts {
	return func(c *config) error {
		c.Requirements = append(c.Requirements, fmt.Sprintf("cuda>=%d.%d", major, minor))
		return nil
	}
}

// WithOCIHookPath sets the hook path for the binary
func WithOCIHookPath(path string) Opts {
	return func(c *config) error {
		c.OCIHookPath = path
		return nil
	}
}

// WithLookupOCIHookPath sets the hook path for the binary via a binary name
func WithLookupOCIHookPath(name string) Opts {
	return func(c *config) error {
		path, err := exec.LookPath(name)
		if err != nil {
			return err
		}
		c.OCIHookPath = path
		return nil
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 controller

import (
	"time"

	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"

	"github.com/kubernetes-incubator/external-dns/plan"
	"github.com/kubernetes-incubator/external-dns/registry"
	"github.com/kubernetes-incubator/external-dns/source"
)

var (
	registryErrors = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "registry_errors_total",
			Help: "Number of Registry errors.",
		},
	)
	sourceErrors = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "source_errors_total",
			Help: "Number of Source errors.",
		},
	)
)

func init() {
	prometheus.MustRegister(registryErrors)
	prometheus.MustRegister(sourceErrors)
}

// Controller is responsible for orchestrating the different components.
// It works in the following way:
// * Ask the DNS provider for current list of endpoints.
// * Ask the Source for the desired list of endpoints.
// * Take both lists and calculate a Plan to move current towards desired state.
// * Tell the DNS provider to apply the changes calucated by the Plan.
type Controller struct {
	Source   source.Source
	Registry registry.Registry
	// The policy that defines which changes to DNS records are allowed
	Policy plan.Policy
	// The interval between individual synchronizations
	Interval time.Duration
}

// RunOnce runs a single iteration of a reconciliation loop.
func (c *Controller) RunOnce() error {
	records, err := c.Registry.Records()
	if err != nil {
		registryErrors.Inc()
		return err
	}

	endpoints, err := c.Source.Endpoints()
	if err != nil {
		sourceErrors.Inc()
		return err
	}

	plan := &plan.Plan{
		Policies: []plan.Policy{c.Policy},
		Current:  records,
		Desired:  endpoints,
	}

	plan = plan.Calculate()

	err = c.Registry.ApplyChanges(plan.Changes)
	if err != nil {
		registryErrors.Inc()
		return err
	}
	return nil
}

// Run runs RunOnce in a loop with a delay until stopChan receives a value.
func (c *Controller) Run(stopChan <-chan struct{}) {
	ticker := time.NewTicker(c.Interval)
	defer ticker.Stop()
	for {
		err := c.RunOnce()
		if err != nil {
			log.Error(err)
		}
		select {
		case <-ticker.C:
		case <-stopChan:
			log.Info("Terminating main controller loop")
			return
		}
	}
}
<commit_msg>feat(controller): expose managed resources and records as metrics<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 controller

import (
	"time"

	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"

	"github.com/kubernetes-incubator/external-dns/plan"
	"github.com/kubernetes-incubator/external-dns/registry"
	"github.com/kubernetes-incubator/external-dns/source"
)

var (
	registryErrors = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "registry_errors_total",
			Help: "Number of Registry errors.",
		},
	)
	sourceErrors = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "source_errors_total",
			Help: "Number of Source errors.",
		},
	)
	sourceEndpointsTotal = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: "external_dns",
			Subsystem: "source",
			Name:      "endpoints_total",
			Help:      "Number of Endpoints in all sources",
		},
	)
	registryEndpointsTotal = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Namespace: "external_dns",
			Subsystem: "registry",
			Name:      "endpoints_total",
			Help:      "Number of Endpoints in the registry",
		},
	)
)

func init() {
	prometheus.MustRegister(registryErrors)
	prometheus.MustRegister(sourceErrors)
	prometheus.MustRegister(sourceEndpointsTotal)
	prometheus.MustRegister(registryEndpointsTotal)
}

// Controller is responsible for orchestrating the different components.
// It works in the following way:
// * Ask the DNS provider for current list of endpoints.
// * Ask the Source for the desired list of endpoints.
// * Take both lists and calculate a Plan to move current towards desired state.
// * Tell the DNS provider to apply the changes calucated by the Plan.
type Controller struct {
	Source   source.Source
	Registry registry.Registry
	// The policy that defines which changes to DNS records are allowed
	Policy plan.Policy
	// The interval between individual synchronizations
	Interval time.Duration
}

// RunOnce runs a single iteration of a reconciliation loop.
func (c *Controller) RunOnce() error {
	records, err := c.Registry.Records()
	if err != nil {
		registryErrors.Inc()
		return err
	}
	registryEndpointsTotal.Set(float64(len(records)))

	endpoints, err := c.Source.Endpoints()
	if err != nil {
		sourceErrors.Inc()
		return err
	}
	sourceEndpointsTotal.Set(float64(len(endpoints)))

	plan := &plan.Plan{
		Policies: []plan.Policy{c.Policy},
		Current:  records,
		Desired:  endpoints,
	}

	plan = plan.Calculate()

	err = c.Registry.ApplyChanges(plan.Changes)
	if err != nil {
		registryErrors.Inc()
		return err
	}
	return nil
}

// Run runs RunOnce in a loop with a delay until stopChan receives a value.
func (c *Controller) Run(stopChan <-chan struct{}) {
	ticker := time.NewTicker(c.Interval)
	defer ticker.Stop()
	for {
		err := c.RunOnce()
		if err != nil {
			log.Error(err)
		}
		select {
		case <-ticker.C:
		case <-stopChan:
			log.Info("Terminating main controller loop")
			return
		}
	}
}
<|endoftext|>


<commit_before>package gpx

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"strconv"
	"time"
)

const nsGPX11 = "http://www.topografix.com/GPX/1/1"

// Decoder decodes a GPX document from an input stream.
type Decoder struct {
	Strict bool
	r      io.Reader
	xd     *xml.Decoder
	err    error
}

// NewDecoder creates a new decoder reading from r. The decoder
// operates in strict mode.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{
		Strict: true,
		r:      r,
	}
}

// Decode decodes a document.
func (d *Decoder) Decode() (doc Document, err error) {
	d.xd = xml.NewDecoder(d.r)

	se, err := d.findGPX()
	if err != nil {
		return doc, err
	}

	return d.consumeGPX(se), d.err
}

func (d *Decoder) findGPX() (se xml.StartElement, err error) {
	for {
		tok, err := d.xd.Token()
		if err != nil {
			return se, err
		}
		if se, ok := tok.(xml.StartElement); ok {
			if se.Name.Local != "gpx" {
				return se, errors.New("gpx: root element must be <gpx>")
			}
			if se.Name.Space != nsGPX11 {
				return se, errors.New("gpx: can only parse GPX 1.1 documents")
			}
			return se, nil
		}
	}

	return se, errors.New("gpx: no start <gpx> found")
}

func (d *Decoder) consumeGPX(se xml.StartElement) (doc Document) {
	for _, a := range se.Attr {
		switch a.Name.Local {
		case "version":
			doc.Version = a.Value
		}
	}

	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "trk" {
				track := d.consumeTrack(se)
				if d.err != nil {
					return
				}
				doc.Tracks = append(doc.Tracks, track)
			} else if lvl == 0 && se.Name.Local == "metadata" {
				metadata := d.consumeMetadata(se)
				if d.err != nil {
					return
				}
				doc.Metadata = metadata
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "gpx" {
				return
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeMetadata(se xml.StartElement) (metadata Metadata) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "time" {
				t := d.consumeTime(se)
				if d.err != nil {
					return
				}
				metadata.Time = t
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "metadata" {
				return
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeTrack(se xml.StartElement) (track Track) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "trkseg" {
				seg := d.consumeSegment(se)
				if d.err != nil {
					return
				}
				track.Segments = append(track.Segments, seg)
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "trk" {
				return
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeSegment(se xml.StartElement) (seg Segment) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "trkpt" {
				point := d.consumePoint(se)
				if d.err != nil {
					return
				}
				seg.Points = append(seg.Points, point)
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "trkseg" {
				return
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumePoint(se xml.StartElement) (point Point) {
	for _, a := range se.Attr {
		switch a.Name.Local {
		case "lat":
			lat, err := strconv.ParseFloat(a.Value, 64)
			if err == nil {
				point.Latitude = lat
			} else if d.Strict {
				d.err = fmt.Errorf("gpx: invalid <trkpt> lat: %s", err)
				return
			}
		case "lon":
			lon, err := strconv.ParseFloat(a.Value, 64)
			if err == nil {
				point.Longitude = lon
			} else if d.Strict {
				d.err = fmt.Errorf("gpx: invalid <trkpt> lon: %s", err)
				return
			}
		}
	}

	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "ele" {
				ele := d.consumeEle(se)
				if d.err != nil {
					return
				}
				point.Elevation = ele
			} else if lvl == 0 && se.Name.Local == "time" {
				t := d.consumeTime(se)
				if d.err != nil {
					return
				}
				point.Time = t
			} else if lvl == 0 && se.Name.Local == "extensions" {
				exts := d.consumeExtensions(se)
				if d.err != nil {
					return
				}
				point.Extensions = exts
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "trkpt" {
				return
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeEle(se xml.StartElement) (ele float64) {
	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.CharData:
			cd := tok.(xml.CharData)
			ele, err = strconv.ParseFloat(string(cd), 64)
			if err != nil && d.Strict {
				d.err = fmt.Errorf("gpx: invalid <ele>: %s", err)
				return
			}
		case xml.StartElement:
			d.err = errors.New("gpx: invalid <ele>")
			return
		case xml.EndElement:
			return
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeTime(se xml.StartElement) (t time.Time) {
	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.CharData:
			cd := tok.(xml.CharData)
			t, err = time.Parse(time.RFC3339Nano, string(cd))
			if err != nil && d.Strict {
				d.err = fmt.Errorf("gpx: invalid <time>: %s", err)
				return
			}
		case xml.StartElement:
			d.err = errors.New("gpx: invalid <time>")
			return
		case xml.EndElement:
			return
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeExtensions(se xml.StartElement) (tokens []xml.Token) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			d.err = err
			return
		}
		switch tok.(type) {
		case xml.StartElement:
			lvl++
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "extensions" {
				return
			}
			lvl--
		}
		tokens = append(tokens, xml.CopyToken(tok))
	}

	panic("gpx: internal error")
}
<commit_msg>Make every consume function return an error<commit_after>package gpx

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"strconv"
	"time"
)

const nsGPX11 = "http://www.topografix.com/GPX/1/1"

// Decoder decodes a GPX document from an input stream.
type Decoder struct {
	Strict bool
	r      io.Reader
	xd     *xml.Decoder
}

// NewDecoder creates a new decoder reading from r. The decoder
// operates in strict mode.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{
		Strict: true,
		r:      r,
	}
}

// Decode decodes a document.
func (d *Decoder) Decode() (doc Document, err error) {
	d.xd = xml.NewDecoder(d.r)

	se, err := d.findGPX()
	if err != nil {
		return doc, err
	}

	return d.consumeGPX(se)
}

func (d *Decoder) findGPX() (se xml.StartElement, err error) {
	for {
		tok, err := d.xd.Token()
		if err != nil {
			return se, err
		}
		if se, ok := tok.(xml.StartElement); ok {
			if se.Name.Local != "gpx" {
				return se, errors.New("gpx: root element must be <gpx>")
			}
			if se.Name.Space != nsGPX11 {
				return se, errors.New("gpx: can only parse GPX 1.1 documents")
			}
			return se, nil
		}
	}

	return se, errors.New("gpx: no start <gpx> found")
}

func (d *Decoder) consumeGPX(se xml.StartElement) (doc Document, err error) {
	for _, a := range se.Attr {
		switch a.Name.Local {
		case "version":
			doc.Version = a.Value
		}
	}

	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			return doc, err
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "trk" {
				track, err := d.consumeTrack(se)
				if err != nil {
					return doc, err
				}
				doc.Tracks = append(doc.Tracks, track)
			} else if lvl == 0 && se.Name.Local == "metadata" {
				metadata, err := d.consumeMetadata(se)
				if err != nil {
					return doc, err
				}
				doc.Metadata = metadata
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "gpx" {
				return doc, nil
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeMetadata(se xml.StartElement) (metadata Metadata, err error) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			return metadata, err
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "time" {
				t, err := d.consumeTime(se)
				if err != nil {
					return metadata, err
				}
				metadata.Time = t
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "metadata" {
				return metadata, nil
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeTrack(se xml.StartElement) (track Track, err error) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			return track, err
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "trkseg" {
				seg, err := d.consumeSegment(se)
				if err != nil {
					return track, err
				}
				track.Segments = append(track.Segments, seg)
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "trk" {
				return track, nil
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeSegment(se xml.StartElement) (seg Segment, err error) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			return seg, err
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "trkpt" {
				point, err := d.consumePoint(se)
				if err != nil {
					return seg, err
				}
				seg.Points = append(seg.Points, point)
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "trkseg" {
				return seg, nil
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumePoint(se xml.StartElement) (point Point, err error) {
	for _, a := range se.Attr {
		switch a.Name.Local {
		case "lat":
			lat, err := strconv.ParseFloat(a.Value, 64)
			if err == nil {
				point.Latitude = lat
			} else if d.Strict {
				return point, fmt.Errorf("gpx: invalid <trkpt> lat: %s", err)
			}
		case "lon":
			lon, err := strconv.ParseFloat(a.Value, 64)
			if err == nil {
				point.Longitude = lon
			} else if d.Strict {
				return point, fmt.Errorf("gpx: invalid <trkpt> lon: %s", err)
			}
		}
	}

	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			return point, err
		}
		switch tok.(type) {
		case xml.StartElement:
			se := tok.(xml.StartElement)
			if lvl == 0 && se.Name.Local == "ele" {
				ele, err := d.consumeEle(se)
				if err != nil {
					return point, err
				}
				point.Elevation = ele
			} else if lvl == 0 && se.Name.Local == "time" {
				t, err := d.consumeTime(se)
				if err != nil {
					return point, err
				}
				point.Time = t
			} else if lvl == 0 && se.Name.Local == "extensions" {
				exts, err := d.consumeExtensions(se)
				if err != nil {
					return point, err
				}
				point.Extensions = exts
			} else {
				lvl++
			}
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "trkpt" {
				return point, nil
			}
			lvl--
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeEle(se xml.StartElement) (ele float64, err error) {
	for {
		tok, err := d.xd.Token()
		if err != nil {
			return ele, err
		}
		switch tok.(type) {
		case xml.CharData:
			cd := tok.(xml.CharData)
			ele, err = strconv.ParseFloat(string(cd), 64)
			if err != nil && d.Strict {
				return ele, fmt.Errorf("gpx: invalid <ele>: %s", err)
			}
		case xml.StartElement:
			return ele, errors.New("gpx: invalid <ele>")
		case xml.EndElement:
			return ele, nil
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeTime(se xml.StartElement) (t time.Time, err error) {
	for {
		tok, err := d.xd.Token()
		if err != nil {
			return t, err
		}
		switch tok.(type) {
		case xml.CharData:
			cd := tok.(xml.CharData)
			t, err = time.Parse(time.RFC3339Nano, string(cd))
			if err != nil && d.Strict {
				return t, fmt.Errorf("gpx: invalid <time>: %s", err)
			}
		case xml.StartElement:
			return t, errors.New("gpx: invalid <time>")
		case xml.EndElement:
			return t, nil
		}
	}

	panic("gpx: internal error")
}

func (d *Decoder) consumeExtensions(se xml.StartElement) (tokens []xml.Token, err error) {
	lvl := 0

	for {
		tok, err := d.xd.Token()
		if err != nil {
			return tokens, err
		}
		switch tok.(type) {
		case xml.StartElement:
			lvl++
		case xml.EndElement:
			ee := tok.(xml.EndElement)
			if lvl == 0 && ee.Name.Local == "extensions" {
				return tokens, nil
			}
			lvl--
		}
		tokens = append(tokens, xml.CopyToken(tok))
	}

	panic("gpx: internal error")
}
<|endoftext|>


<commit_before>// Package gpx provides convenience types for reading and writing GPX
// documents.
// See http://www.topografix.com/gpx.asp.
package gpx

// TODO DGPSID
// TODO Extensions

import (
	"encoding/xml"
	"strconv"
	"time"
)

const timeLayout = "2006-01-02T15:04:05.999999999Z"

type BoundsType struct {
	MinLat float64 `xml:"minlat,attr"`
	MinLon float64 `xml:"minlon,attr"`
	MaxLat float64 `xml:"maxlat,attr"`
	MaxLon float64 `xml:"maxlon,attr"`
}

type CopyrightType struct {
	Author  string `xml:"author,attr"`
	Year    int    `xml:"year,omitempty"`
	License string `xml:"license,omitempty"`
}

type ExtensionsType []byte

type GPXType struct {
	Version  string        `xml:"version,attr"`
	Creator  string        `xml:"creator,attr"`
	Metadata *MetadataType `xml:"metadata,omitempty"`
	Wpt      []*WptType    `xml:"wpt,omitempty"`
	Rte      []*RteType    `xml:"rte,omitempty"`
	Trk      []*TrkType    `xml:"trk,omitempty"`
	// Extensions
}

type LinkType struct {
	HREF string `xml:"href,attr"`
	Text string `xml:"text,omitempty"`
	Type string `xml:"type,omitempty"`
}

type PersonType struct {
	Name  string    `xml:"name,omitempty"`
	Email string    `xml:"email,omitempty"`
	Link  *LinkType `xml:"link,omitempty"`
}

type MetadataType struct {
	Name      string         `xml:"name,omitempty"`
	Desc      string         `xml:"desc,omitempty"`
	Author    *PersonType    `xml:"author,omitempty"`
	Copyright *CopyrightType `xml:"copyright,omitempty"`
	Link      []*LinkType    `xml:"link,omitempty"`
	Time      time.Time      `xml:"time,omitempty"`
	Keywords  string         `xml:"keywords,omitempty"`
	Bounds    *BoundsType    `xml:"bounds,omitempty"`
	// Extensions
}

type RteType struct {
	Name   string      `xml:"name,omitempty"`
	Cmt    string      `xml:"cmt,omitempty"`
	Desc   string      `xml:"desc,omitempty"`
	Src    string      `xml:"src,omitempty"`
	Link   []*LinkType `xml:"link,omitempty"`
	Number int         `xml:"number,omitempty"`
	Type   string      `xml:"type,omitempty"`
	// Extensions
	RtePt []*WptType `xml:"rtept,omitempty"`
}

type TrkSegType struct {
	TrkPt []*WptType `xml:"trkpt,omitempty"`
	// Extensions
}

type TrkType struct {
	Name   string      `xml:"name,omitempty"`
	Cmt    string      `xml:"cmt,omitempty"`
	Desc   string      `xml:"desc,omitempty"`
	Src    string      `xml:"src,omitempty"`
	Link   []*LinkType `xml:"link,omitempty"`
	Number int         `xml:"number,omitempty"`
	Type   string      `xml:"type,omitempty"`
	// Extensions
	TrkSeg []*TrkSegType `xml:"trkseg,omitempty"`
}

type WptType struct {
	Lat          float64
	Lon          float64
	Ele          float64
	Time         time.Time
	MagVar       float64
	GeoidHeight  float64
	Name         string
	Cmt          string
	Desc         string
	Src          string
	Link         []*LinkType
	Sym          string
	Type         string
	Fix          string
	Sat          int
	HDOP         float64
	VDOP         float64
	PDOP         float64
	AgeOfGPSData float64
	// DGPSID
	// Extensions
}

func emitIntElement(e *xml.Encoder, localName string, value int) error {
	return emitStringElement(e, localName, strconv.FormatInt(int64(value), 10))
}

func emitStringElement(e *xml.Encoder, localName, value string) error {
	return e.EncodeElement(value, xml.StartElement{Name: xml.Name{Local: localName}})
}

func maybeEmitFloatElement(e *xml.Encoder, localName string, value float64) error {
	if value == 0.0 {
		return nil
	}
	return emitStringElement(e, localName, strconv.FormatFloat(value, 'f', -1, 64))
}

func maybeEmitIntElement(e *xml.Encoder, localName string, value int) error {
	if value == 0 {
		return nil
	}
	return emitIntElement(e, localName, value)
}

func maybeEmitStringElement(e *xml.Encoder, localName, value string) error {
	if value == "" {
		return nil
	}
	return emitStringElement(e, localName, value)
}

func (w *WptType) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	latAttr := xml.Attr{
		Name:  xml.Name{Local: "lat"},
		Value: strconv.FormatFloat(w.Lat, 'f', -1, 64),
	}
	lonAttr := xml.Attr{
		Name:  xml.Name{Local: "lon"},
		Value: strconv.FormatFloat(w.Lon, 'f', -1, 64),
	}
	start.Attr = append(start.Attr, latAttr, lonAttr)
	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ele", w.Ele); err != nil {
		return err
	}
	if !w.Time.IsZero() {
		if err := maybeEmitStringElement(e, "time", w.Time.UTC().Format(timeLayout)); err != nil {
			return err
		}
	}
	if err := maybeEmitFloatElement(e, "magvar", w.MagVar); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "geoidheight", w.GeoidHeight); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "name", w.Name); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "cmt", w.Cmt); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "desc", w.Desc); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "src", w.Src); err != nil {
		return err
	}
	if w.Link != nil {
		if err := e.EncodeElement(w.Link, xml.StartElement{Name: xml.Name{Local: "link"}}); err != nil {
			return err
		}
	}
	if err := maybeEmitStringElement(e, "sym", w.Sym); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "type", w.Type); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "fix", w.Fix); err != nil {
		return err
	}
	if err := maybeEmitIntElement(e, "sat", w.Sat); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "hdop", w.HDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "vdop", w.VDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "pdop", w.PDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ageofgpsdata", w.AgeOfGPSData); err != nil {
		return err
	}
	// DGPSID
	// Extensions
	return e.EncodeToken(start.End())
}

func (w *WptType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var e struct {
		Lat          float64     `xml:"lat,attr"`
		Lon          float64     `xml:"lon,attr"`
		Ele          float64     `xml:"ele"`
		Time         string      `xml:"time"`
		MagVar       float64     `xml:"magvar"`
		GeoidHeight  float64     `xml:"geoidheight"`
		Name         string      `xml:"name"`
		Cmt          string      `xml:"cmt"`
		Desc         string      `xml:"desc"`
		Src          string      `xml:"src"`
		Link         []*LinkType `xml:"link"`
		Sym          string      `xml:"sym"`
		Type         string      `xml:"type"`
		Fix          string      `xml:"fix"`
		Sat          int         `xml:"sat"`
		HDOP         float64     `xml:"hdop"`
		VDOP         float64     `xml:"vdop"`
		PDOP         float64     `xml:"pdop"`
		AgeOfGPSData float64     `xml:"ageofgpsdata"`
		// DGPSID
		// Extensions
	}
	if err := d.DecodeElement(&e, &start); err != nil {
		return err
	}
	*w = WptType{
		Lat:          e.Lat,
		Lon:          e.Lon,
		Ele:          e.Ele,
		MagVar:       e.MagVar,
		GeoidHeight:  e.GeoidHeight,
		Name:         e.Name,
		Cmt:          e.Cmt,
		Desc:         e.Desc,
		Src:          e.Src,
		Link:         e.Link,
		Sym:          e.Sym,
		Type:         e.Type,
		Fix:          e.Fix,
		Sat:          e.Sat,
		HDOP:         e.HDOP,
		VDOP:         e.VDOP,
		PDOP:         e.PDOP,
		AgeOfGPSData: e.AgeOfGPSData,
		// DGPSID
		// Extensions
	}
	if e.Time != "" {
		t, err := time.ParseInLocation(timeLayout, e.Time, time.UTC)
		if err != nil {
			return err
		}
		w.Time = t
	}
	return nil
}

var (
	_ xml.Marshaler   = &WptType{}
	_ xml.Unmarshaler = &WptType{}
)
<commit_msg>Add GPXType XMLName<commit_after>// Package gpx provides convenience types for reading and writing GPX
// documents.
// See http://www.topografix.com/gpx.asp.
package gpx

// TODO DGPSID
// TODO Extensions

import (
	"encoding/xml"
	"strconv"
	"time"
)

const timeLayout = "2006-01-02T15:04:05.999999999Z"

type BoundsType struct {
	MinLat float64 `xml:"minlat,attr"`
	MinLon float64 `xml:"minlon,attr"`
	MaxLat float64 `xml:"maxlat,attr"`
	MaxLon float64 `xml:"maxlon,attr"`
}

type CopyrightType struct {
	Author  string `xml:"author,attr"`
	Year    int    `xml:"year,omitempty"`
	License string `xml:"license,omitempty"`
}

type ExtensionsType []byte

type GPXType struct {
	XMLName  string        `xml:"gpx"`
	Version  string        `xml:"version,attr"`
	Creator  string        `xml:"creator,attr"`
	Metadata *MetadataType `xml:"metadata,omitempty"`
	Wpt      []*WptType    `xml:"wpt,omitempty"`
	Rte      []*RteType    `xml:"rte,omitempty"`
	Trk      []*TrkType    `xml:"trk,omitempty"`
	// Extensions
}

type LinkType struct {
	HREF string `xml:"href,attr"`
	Text string `xml:"text,omitempty"`
	Type string `xml:"type,omitempty"`
}

type PersonType struct {
	Name  string    `xml:"name,omitempty"`
	Email string    `xml:"email,omitempty"`
	Link  *LinkType `xml:"link,omitempty"`
}

type MetadataType struct {
	Name      string         `xml:"name,omitempty"`
	Desc      string         `xml:"desc,omitempty"`
	Author    *PersonType    `xml:"author,omitempty"`
	Copyright *CopyrightType `xml:"copyright,omitempty"`
	Link      []*LinkType    `xml:"link,omitempty"`
	Time      time.Time      `xml:"time,omitempty"`
	Keywords  string         `xml:"keywords,omitempty"`
	Bounds    *BoundsType    `xml:"bounds,omitempty"`
	// Extensions
}

type RteType struct {
	Name   string      `xml:"name,omitempty"`
	Cmt    string      `xml:"cmt,omitempty"`
	Desc   string      `xml:"desc,omitempty"`
	Src    string      `xml:"src,omitempty"`
	Link   []*LinkType `xml:"link,omitempty"`
	Number int         `xml:"number,omitempty"`
	Type   string      `xml:"type,omitempty"`
	// Extensions
	RtePt []*WptType `xml:"rtept,omitempty"`
}

type TrkSegType struct {
	TrkPt []*WptType `xml:"trkpt,omitempty"`
	// Extensions
}

type TrkType struct {
	Name   string      `xml:"name,omitempty"`
	Cmt    string      `xml:"cmt,omitempty"`
	Desc   string      `xml:"desc,omitempty"`
	Src    string      `xml:"src,omitempty"`
	Link   []*LinkType `xml:"link,omitempty"`
	Number int         `xml:"number,omitempty"`
	Type   string      `xml:"type,omitempty"`
	// Extensions
	TrkSeg []*TrkSegType `xml:"trkseg,omitempty"`
}

type WptType struct {
	Lat          float64
	Lon          float64
	Ele          float64
	Time         time.Time
	MagVar       float64
	GeoidHeight  float64
	Name         string
	Cmt          string
	Desc         string
	Src          string
	Link         []*LinkType
	Sym          string
	Type         string
	Fix          string
	Sat          int
	HDOP         float64
	VDOP         float64
	PDOP         float64
	AgeOfGPSData float64
	// DGPSID
	// Extensions
}

func emitIntElement(e *xml.Encoder, localName string, value int) error {
	return emitStringElement(e, localName, strconv.FormatInt(int64(value), 10))
}

func emitStringElement(e *xml.Encoder, localName, value string) error {
	return e.EncodeElement(value, xml.StartElement{Name: xml.Name{Local: localName}})
}

func maybeEmitFloatElement(e *xml.Encoder, localName string, value float64) error {
	if value == 0.0 {
		return nil
	}
	return emitStringElement(e, localName, strconv.FormatFloat(value, 'f', -1, 64))
}

func maybeEmitIntElement(e *xml.Encoder, localName string, value int) error {
	if value == 0 {
		return nil
	}
	return emitIntElement(e, localName, value)
}

func maybeEmitStringElement(e *xml.Encoder, localName, value string) error {
	if value == "" {
		return nil
	}
	return emitStringElement(e, localName, value)
}

func (w *WptType) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	latAttr := xml.Attr{
		Name:  xml.Name{Local: "lat"},
		Value: strconv.FormatFloat(w.Lat, 'f', -1, 64),
	}
	lonAttr := xml.Attr{
		Name:  xml.Name{Local: "lon"},
		Value: strconv.FormatFloat(w.Lon, 'f', -1, 64),
	}
	start.Attr = append(start.Attr, latAttr, lonAttr)
	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ele", w.Ele); err != nil {
		return err
	}
	if !w.Time.IsZero() {
		if err := maybeEmitStringElement(e, "time", w.Time.UTC().Format(timeLayout)); err != nil {
			return err
		}
	}
	if err := maybeEmitFloatElement(e, "magvar", w.MagVar); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "geoidheight", w.GeoidHeight); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "name", w.Name); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "cmt", w.Cmt); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "desc", w.Desc); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "src", w.Src); err != nil {
		return err
	}
	if w.Link != nil {
		if err := e.EncodeElement(w.Link, xml.StartElement{Name: xml.Name{Local: "link"}}); err != nil {
			return err
		}
	}
	if err := maybeEmitStringElement(e, "sym", w.Sym); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "type", w.Type); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "fix", w.Fix); err != nil {
		return err
	}
	if err := maybeEmitIntElement(e, "sat", w.Sat); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "hdop", w.HDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "vdop", w.VDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "pdop", w.PDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ageofgpsdata", w.AgeOfGPSData); err != nil {
		return err
	}
	// DGPSID
	// Extensions
	return e.EncodeToken(start.End())
}

func (w *WptType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var e struct {
		Lat          float64     `xml:"lat,attr"`
		Lon          float64     `xml:"lon,attr"`
		Ele          float64     `xml:"ele"`
		Time         string      `xml:"time"`
		MagVar       float64     `xml:"magvar"`
		GeoidHeight  float64     `xml:"geoidheight"`
		Name         string      `xml:"name"`
		Cmt          string      `xml:"cmt"`
		Desc         string      `xml:"desc"`
		Src          string      `xml:"src"`
		Link         []*LinkType `xml:"link"`
		Sym          string      `xml:"sym"`
		Type         string      `xml:"type"`
		Fix          string      `xml:"fix"`
		Sat          int         `xml:"sat"`
		HDOP         float64     `xml:"hdop"`
		VDOP         float64     `xml:"vdop"`
		PDOP         float64     `xml:"pdop"`
		AgeOfGPSData float64     `xml:"ageofgpsdata"`
		// DGPSID
		// Extensions
	}
	if err := d.DecodeElement(&e, &start); err != nil {
		return err
	}
	*w = WptType{
		Lat:          e.Lat,
		Lon:          e.Lon,
		Ele:          e.Ele,
		MagVar:       e.MagVar,
		GeoidHeight:  e.GeoidHeight,
		Name:         e.Name,
		Cmt:          e.Cmt,
		Desc:         e.Desc,
		Src:          e.Src,
		Link:         e.Link,
		Sym:          e.Sym,
		Type:         e.Type,
		Fix:          e.Fix,
		Sat:          e.Sat,
		HDOP:         e.HDOP,
		VDOP:         e.VDOP,
		PDOP:         e.PDOP,
		AgeOfGPSData: e.AgeOfGPSData,
		// DGPSID
		// Extensions
	}
	if e.Time != "" {
		t, err := time.ParseInLocation(timeLayout, e.Time, time.UTC)
		if err != nil {
			return err
		}
		w.Time = t
	}
	return nil
}

var (
	_ xml.Marshaler   = &WptType{}
	_ xml.Unmarshaler = &WptType{}
)
<|endoftext|>


<commit_before>package form

import (
	"math"
	"reflect"
	"testing"
)

func TestCreateTypeMap(t *testing.T) {
	for n, test := range [...]struct {
		Input  reflect.Type
		Output typeMap
	}{
		{ // 1
			Input: reflect.TypeOf(struct {
				A int
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 2
			Input: reflect.TypeOf(struct {
				A int `form:"B"`
			}{}),
			Output: typeMap{
				"B": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 3
			Input: reflect.TypeOf(struct {
				A int `form:",required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 4
			Input: reflect.TypeOf(struct {
				A int `form:",post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:  true,
					Index: []int{0},
				},
			},
		},
		{ // 5
			Input: reflect.TypeOf(struct {
				A int `form:",post,required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 6
			Input: reflect.TypeOf(struct {
				A int `form:",required,post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 7
			Input: reflect.TypeOf(struct {
				A int `min:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  -20,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 8
			Input: reflect.TypeOf(struct {
				A int `max:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  -20,
					},
					Index: []int{0},
				},
			},
		},
		{ // 9
			Input: reflect.TypeOf(struct {
				A int8
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 8,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 10
			Input: reflect.TypeOf(struct {
				A int16
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 16,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 11
			Input: reflect.TypeOf(struct {
				A int32
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 32,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 12
			Input: reflect.TypeOf(struct {
				A int64
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 13
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 14
			Input: reflect.TypeOf(struct {
				A uint `min:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						min:  10,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 15
			Input: reflect.TypeOf(struct {
				A uint `min:"-1"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 16
			Input: reflect.TypeOf(struct {
				A uint `max:"100"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  100,
					},
					Index: []int{0},
				},
			},
		},
	} {
		output := createTypeMap(test.Input)
		if !reflect.DeepEqual(output, test.Output) {
			t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
		}
	}
}
<commit_msg>added uint bitsize tests<commit_after>package form

import (
	"math"
	"reflect"
	"testing"
)

func TestCreateTypeMap(t *testing.T) {
	for n, test := range [...]struct {
		Input  reflect.Type
		Output typeMap
	}{
		{ // 1
			Input: reflect.TypeOf(struct {
				A int
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 2
			Input: reflect.TypeOf(struct {
				A int `form:"B"`
			}{}),
			Output: typeMap{
				"B": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 3
			Input: reflect.TypeOf(struct {
				A int `form:",required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 4
			Input: reflect.TypeOf(struct {
				A int `form:",post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:  true,
					Index: []int{0},
				},
			},
		},
		{ // 5
			Input: reflect.TypeOf(struct {
				A int `form:",post,required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 6
			Input: reflect.TypeOf(struct {
				A int `form:",required,post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 7
			Input: reflect.TypeOf(struct {
				A int `min:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  -20,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 8
			Input: reflect.TypeOf(struct {
				A int `max:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  -20,
					},
					Index: []int{0},
				},
			},
		},
		{ // 9
			Input: reflect.TypeOf(struct {
				A int8
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 8,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 10
			Input: reflect.TypeOf(struct {
				A int16
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 16,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 11
			Input: reflect.TypeOf(struct {
				A int32
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 32,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 12
			Input: reflect.TypeOf(struct {
				A int64
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 13
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 14
			Input: reflect.TypeOf(struct {
				A uint `min:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						min:  10,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 15
			Input: reflect.TypeOf(struct {
				A uint `min:"-1"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 16
			Input: reflect.TypeOf(struct {
				A uint `max:"100"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  100,
					},
					Index: []int{0},
				},
			},
		},
		{ // 17
			Input: reflect.TypeOf(struct {
				A uint8
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 8,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 18
			Input: reflect.TypeOf(struct {
				A uint16
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 16,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 19
			Input: reflect.TypeOf(struct {
				A uint32
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 32,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 20
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
	} {
		output := createTypeMap(test.Input)
		if !reflect.DeepEqual(output, test.Output) {
			t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
		}
	}
}
<|endoftext|>