func (app *App) buildTree() *App {
	if !app.routesRefreshed {
		return app
	}
	for m := range intMethod {
		app.treeStack[m] = make(map[string][]*Route)
		for _, route := range app.stack[m] {
			treePath := ""
			if len(route.routeParser.segs) > 0 && len(route.routeParser.segs[0].Const) >= 3 {
				treePath = route.routeParser.segs[0].Const[:3]
			}
			app.treeStack[m][treePath] = append(app.treeStack[m][treePath], route)
		}
	}
	for m := range intMethod {
		for treePart := range app.treeStack[m] {
			if treePart != "" {
				app.treeStack[m][treePart] = uniqueRouteStack(append(app.treeStack[m][treePart], app.treeStack[m][""]...))
			}
			sort.Slice(app.treeStack[m][treePart], func(i, j int) bool {
				return app.treeStack[m][treePart][i].pos < app.treeStack[m][treePart][j].pos
			})
		}
	}
	app.routesRefreshed = false
	return app
}
buildTree build the prefix tree from the previously registered routes
package fiber
import (
	"fmt"
	"sort"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
	"github.com/gofiber/fiber/v2/utils"
	"github.com/valyala/fasthttp"
)
type Router interface {
	Use(args ...interface{}) Router
	Get(path string, handlers ...Handler) Router
	Head(path string, handlers ...Handler) Router
	Post(path string, handlers ...Handler) Router
	Put(path string, handlers ...Handler) Router
	Delete(path string, handlers ...Handler) Router
	Connect(path string, handlers ...Handler) Router
	Options(path string, handlers ...Handler) Router
	Trace(path string, handlers ...Handler) Router
	Patch(path string, handlers ...Handler) Router
	Add(method, path string, handlers ...Handler) Router
	Static(prefix, root string, config ...Static) Router
	All(path string, handlers ...Handler) Router
	Group(prefix string, handlers ...Handler) Router
	Mount(prefix string, fiber *App) Router
}
type Route struct {
	pos         uint32       
	use         bool         
	star        bool         
	root        bool         
	path        string       
	routeParser routeParser  
	Method   string    `json:"method"`  
	Path     string    `json:"path"`    
	Params   []string  `json:"params"`  
	Handlers []Handler `json:"-"`       
}
func (r *Route) match(detectionPath, path string, params *[maxParams]string) (match bool) {
	if r.root && detectionPath == "/" {
		return true
	} else if r.star {
		if len(path) > 1 {
			params[0] = path[1:]
		} else {
			params[0] = ""
		}
		return true
	}
	if len(r.Params) > 0 {
		if match := r.routeParser.getMatch(detectionPath, path, params, r.use); match {
			return match
		}
	}
	if r.use {
		if r.root || strings.HasPrefix(detectionPath, r.path) {
			return true
		}
	} else if len(r.path) == len(detectionPath) && r.path == detectionPath {
		return true
	}
	return false
}
func (app *App) next(c *Ctx) (match bool, err error) {
	tree, ok := app.treeStack[c.methodINT][c.treePath]
	if !ok {
		tree = app.treeStack[c.methodINT][""]
	}
	lenr := len(tree) - 1
	for c.indexRoute < lenr {
		c.indexRoute++
		route := tree[c.indexRoute]
		match = route.match(c.detectionPath, c.path, &c.values)
		if !match {
			continue
		}
		c.route = route
		if !c.matched && !route.use {
			c.matched = true
		}
		c.indexHandler = 0
		err = route.Handlers[0](c)
		return match, err  
	}
	_ = c.SendStatus(StatusNotFound)
	_ = c.SendString("Cannot " + c.method + " " + c.pathOriginal)
	if !c.matched && methodExist(c) {
		err = ErrMethodNotAllowed
	}
	return
}
func (app *App) handler(rctx *fasthttp.RequestCtx) {
	c := app.AcquireCtx(rctx)
	if c.methodINT == -1 {
		_ = c.Status(StatusBadRequest).SendString("Invalid http method")
		app.ReleaseCtx(c)
		return
	}
	match, err := app.next(c)
	if err != nil {
		if catch := c.app.ErrorHandler(c, err); catch != nil {
			_ = c.SendStatus(StatusInternalServerError)
		}
	}
	if match && app.config.ETag {
		setETag(c, false)
	}
	app.ReleaseCtx(c)
}
func (app *App) addPrefixToRoute(prefix string, route *Route) *Route {
	prefixedPath := getGroupPath(prefix, route.Path)
	prettyPath := prefixedPath
	if !app.config.CaseSensitive {
		prettyPath = utils.ToLower(prettyPath)
	}
	if !app.config.StrictRouting && len(prettyPath) > 1 {
		prettyPath = utils.TrimRight(prettyPath, '/')
	}
	route.Path = prefixedPath
	route.path = RemoveEscapeChar(prettyPath)
	route.routeParser = parseRoute(prettyPath)
	route.root = false
	route.star = false
	return route
}
func (app *App) copyRoute(route *Route) *Route {
	return &Route{
		use:  route.use,
		star: route.star,
		root: route.root,
		path:        route.path,
		routeParser: route.routeParser,
		Params:      route.Params,
		Path:     route.Path,
		Method:   route.Method,
		Handlers: route.Handlers,
	}
}
func (app *App) register(method, pathRaw string, handlers ...Handler) Router {
	method = utils.ToUpper(method)
	if method != methodUse && methodInt(method) == -1 {
		panic(fmt.Sprintf("add: invalid http method %s\n", method))
	}
	if len(handlers) == 0 {
		panic(fmt.Sprintf("missing handler in route: %s\n", pathRaw))
	}
	if pathRaw == "" {
		pathRaw = "/"
	}
	if pathRaw[0] != '/' {
		pathRaw = "/" + pathRaw
	}
	pathPretty := pathRaw
	if !app.config.CaseSensitive {
		pathPretty = utils.ToLower(pathPretty)
	}
	if !app.config.StrictRouting && len(pathPretty) > 1 {
		pathPretty = utils.TrimRight(pathPretty, '/')
	}
	var isUse = method == methodUse
	var isStar = pathPretty == "/*"
	var isRoot = pathPretty == "/"
	var parsedRaw = parseRoute(pathRaw)
	var parsedPretty = parseRoute(pathPretty)
	route := Route{
		use:  isUse,
		star: isStar,
		root: isRoot,
		path:        RemoveEscapeChar(pathPretty),
		routeParser: parsedPretty,
		Params:      parsedRaw.params,
		Path:     pathRaw,
		Method:   method,
		Handlers: handlers,
	}
	atomic.AddUint32(&app.handlerCount, uint32(len(handlers)))
	if isUse {
		for _, m := range intMethod {
			r := route
			app.addRoute(m, &r)
		}
	} else {
		app.addRoute(method, &route)
	}
	return app
}
func (app *App) registerStatic(prefix, root string, config ...Static) Router {
	if root == "" {
		root = "."
	}
	if prefix == "" {
		prefix = "/"
	}
	if prefix[0] != '/' {
		prefix = "/" + prefix
	}
	if !app.config.CaseSensitive {
		prefix = utils.ToLower(prefix)
	}
	if len(root) > 0 && root[len(root)-1] == '/' {
		root = root[:len(root)-1]
	}
	var isStar = prefix == "/*"
	var isRoot = prefix == "/"
	if strings.Contains(prefix, "*") {
		isStar = true
		prefix = strings.Split(prefix, "*")[0]
	}
	prefixLen := len(prefix)
	if prefixLen > 1 && prefix[prefixLen-1:] == "/" {
		prefixLen--
		prefix = prefix[:prefixLen]
	}
	fs := &fasthttp.FS{
		Root:                 root,
		GenerateIndexPages:   false,
		AcceptByteRange:      false,
		Compress:             false,
		CompressedFileSuffix: app.config.CompressedFileSuffix,
		CacheDuration:        10 * time.Second,
		IndexNames:           []string{"index.html"},
		PathRewrite: func(fctx *fasthttp.RequestCtx) []byte {
			path := fctx.Path()
			if len(path) >= prefixLen {
				if isStar && app.getString(path[0:prefixLen]) == prefix {
					path = append(path[0:0], '/')
				} else {
					path = path[prefixLen:]
					if len(path) == 0 || path[len(path)-1] != '/' {
						path = append(path, '/')
					}
				}
			}
			if len(path) > 0 && path[0] != '/' {
				path = append([]byte("/"), path...)
			}
			return path
		},
		PathNotFound: func(fctx *fasthttp.RequestCtx) {
			fctx.Response.SetStatusCode(StatusNotFound)
		},
	}
	var cacheControlValue string
	if len(config) > 0 {
		maxAge := config[0].MaxAge
		if maxAge > 0 {
			cacheControlValue = "public, max-age=" + strconv.Itoa(maxAge)
		}
		fs.CacheDuration = config[0].CacheDuration
		fs.Compress = config[0].Compress
		fs.AcceptByteRange = config[0].ByteRange
		fs.GenerateIndexPages = config[0].Browse
		if config[0].Index != "" {
			fs.IndexNames = []string{config[0].Index}
		}
	}
	fileHandler := fs.NewRequestHandler()
	handler := func(c *Ctx) error {
		if len(config) != 0 && config[0].Next != nil && config[0].Next(c) {
			return c.Next()
		}
		fileHandler(c.fasthttp)
		status := c.fasthttp.Response.StatusCode()
		if status != StatusNotFound && status != StatusForbidden {
			if len(cacheControlValue) > 0 {
				c.fasthttp.Response.Header.Set(HeaderCacheControl, cacheControlValue)
			}
			return nil
		}
		c.fasthttp.SetContentType("")  
		c.fasthttp.Response.SetStatusCode(StatusOK)
		c.fasthttp.Response.SetBodyString("")
		return c.Next()
	}
	route := Route{
		use:  true,
		root: isRoot,
		path: prefix,
		Method:   MethodGet,
		Path:     prefix,
		Handlers: []Handler{handler},
	}
	atomic.AddUint32(&app.handlerCount, 1)
	app.addRoute(MethodGet, &route)
	app.addRoute(MethodHead, &route)
	return app
}
func (app *App) addRoute(method string, route *Route) {
	m := methodInt(method)
	l := len(app.stack[m])
	if l > 0 && app.stack[m][l-1].Path == route.Path && route.use == app.stack[m][l-1].use {
		preRoute := app.stack[m][l-1]
		preRoute.Handlers = append(preRoute.Handlers, route.Handlers...)
	} else {
		route.pos = atomic.AddUint32(&app.routesCount, 1)
		route.Method = method
		app.stack[m] = append(app.stack[m], route)
		app.routesRefreshed = true
	}
}