func (r *Router) retrieveMethods(path string) (methods []string) {
	for method, reg := range r.combinedRegexps {
		if reg.MatchString(path) {
			methods = append(methods, method)
		}
	}
	return
}
retrieveMethods returns all allowed methods of the request
path. And the result is random, since it uses map.
package fastrouter
import (
	"context"
	"fmt"
	"net/http"
	"regexp"
	"strings"
)
const (
	IgnoreTrailingSlashes = iota
	AppendTrailingSlashes
	RemoveTrailingSlashes
	StrictTrailingSlashes
)
type ParamsKey struct{}
var contextParamsKey ParamsKey
func New() *Router {
	return NewWithParser(NewParser())
}
func NewWithParser(parser ParserInterface) *Router {
	return &Router{
		combinedRegexps:       make(map[string]*regexp.Regexp),
		groups:                make(map[string]*Router),
		parser:                parser,
		routes:                make(map[string][]*route),
		TrailingSlashesPolicy: IgnoreTrailingSlashes,
	}
}
type Router struct {
	parent *Router
	Middleware []Middleware
	combinedRegexps map[string]*regexp.Regexp
	groups map[string]*Router
	routes map[string][]*route
	parser ParserInterface
	PanicHandler func(w http.ResponseWriter, req *http.Request, rcv interface{})
	OptionsHandler func(w http.ResponseWriter, req *http.Request, methods []string)
	MethodNotAllowedHandler func(w http.ResponseWriter, req *http.Request, methods []string)
	NotFoundHandler http.Handler
	TrailingSlashesPolicy int8
}
func (r *Router) Prepare() {
	r.prepare()
}
func (r *Router) prepare() {
	middleware := r.middleware()
	for method := range r.routes {
		routes := r.routes[method]
		regs := []string{}
		for i := 0; i < len(routes); i++ {
			if routes[i] != nil {
				regs = append(regs, "("+routes[i].reg+")")
				handler := routes[i].handler
				for j := len(routes[i].middleware) - 1; j >= 0; j-- {
					handler = routes[i].middleware[j](handler)
				}
				for j := len(middleware) - 1; j >= 0; j-- {
					handler = middleware[j](handler)
				}
				routes[i].finalHandler = handler
				routes[i].finalHandler = handler
			}
		}
		reg := strings.Join(regs, "|")
		r.combinedRegexps[method] = regexp.MustCompile("^(?:" + reg + ")$")
	}
	for _, group := range r.groups {
		group.prepare()
	}
}
func (r *Router) Group(prefix string) *Router {
	if prefix == "" {
		panic(`the group prefix MUST NOT be empty`)
	}
	if strings.Contains(prefix, "/") {
		panic(`the group prefix MUST NOT contains '/'`)
	}
	if _, ok := r.groups[prefix]; ok {
		panic(fmt.Errorf("the group which prefix equal to %q already exists", prefix))
	}
	group := New()
	group.parent = r
	group.parser = r.parser
	r.groups[prefix] = group
	return group
}
func (r *Router) Handle(method, pattern string, handler http.HandlerFunc, middleware ...Middleware) {
	if _, ok := r.routes[method]; !ok {
		r.routes[method] = []*route{nil}
	}
	route := &route{handler: handler, middleware: middleware}
	var err error
	route.reg, route.params, route.hasTrailingSlashes, err = r.parser.Parse(pattern)
	if err != nil {
		panic(err)
	}
	r.routes[method] = append(r.routes[method], route)
	for i := 0; i < len(route.params); i++ {
		r.routes[method] = append(r.routes[method], nil)
	}
}
func (r *Router) Delete(pattern string, handler http.HandlerFunc, middleware ...Middleware) {
	r.Handle(http.MethodDelete, pattern, handler, middleware...)
}
func (r *Router) Get(pattern string, handler http.HandlerFunc, middleware ...Middleware) {
	r.Handle(http.MethodGet, pattern, handler, middleware...)
}
func (r *Router) Post(pattern string, handler http.HandlerFunc, middleware ...Middleware) {
	r.Handle(http.MethodPost, pattern, handler, middleware...)
}
func (r *Router) Put(pattern string, handler http.HandlerFunc, middleware ...Middleware) {
	r.Handle(http.MethodPut, pattern, handler, middleware...)
}
func (r *Router) ServeFiles(pattern, root string, middleware ...Middleware) {
	if !strings.Contains(pattern, "filepath") {
		panic(`the pattern MUST contains parameter placeholder named "filepath"`)
	}
	fs := http.FileServer(http.Dir(root))
	handler := func(w http.ResponseWriter, req *http.Request) {
		if params, ok := req.Context().Value(contextParamsKey).(map[string]string); ok {
			req.URL.Path = params["filepath"]
			fs.ServeHTTP(w, req)
			return
		}
	}
	r.Handle(http.MethodGet, pattern, http.HandlerFunc(handler), middleware...)
}