func (t *Trie) Match(path string) *Matched {
	if path == "" || path[0] != '/' {
		panic(fmt.Errorf(`path is not start with "/": "%s"`, path))
	}
	fixedLen := len(path)
	if t.fpr {
		path = fixPath(path)
		fixedLen -= len(path)
	}
	start := 1
	end := len(path)
	matched := new(Matched)
	parent := t.root
	for i := 1; i <= end; i++ {
		if i < end && path[i] != '/' {
			continue
		}
		segment := path[start:i]
		_segment := segment
		if t.ignoreCase {
			_segment = strings.ToLower(segment)
		}
		node := matchNode(parent, _segment)
		if node == nil {
			if t.tsr && parent.endpoint && i == end && segment == "" {
				matched.TSR = path[:end-1]
				if t.fpr && fixedLen > 0 {
					matched.FPR = matched.TSR
					matched.TSR = ""
				}
			}
			return matched
		}
		parent = node
		if parent.name != "" {
			if matched.Params == nil {
				matched.Params = make(map[string]string)
			}
			if parent.wildcard {
				matched.Params[parent.name] = path[start:end]
				break
			} else {
				if parent.suffix != "" {
					segment = segment[0 : len(segment)-len(parent.suffix)]
				}
				matched.Params[parent.name] = segment
			}
		}
		start = i + 1
	}
	switch {
	case parent.endpoint:
		matched.Node = parent
		if t.fpr && fixedLen > 0 {
			matched.FPR = path
			matched.Node = nil
		}
	case t.tsr && parent.getChild("") != nil:
		matched.TSR = path + "/"
		if t.fpr && fixedLen > 0 {
			matched.FPR = matched.TSR
			matched.TSR = ""
		}
	}
	return matched
}
Match try to match path. It will returns a Matched instance that
includes	*Node, Params and Tsr flag when matching success, otherwise a nil.

matched := trie.Match("/a/b")
package trie
import (
	"fmt"
	"regexp"
	"sort"
	"strings"
)
const Version = "1.5.2"
type Options struct {
	IgnoreCase bool
	FixedPathRedirect bool
	TrailingSlashRedirect bool
}
var (
	multiSlashReg  = regexp.MustCompile(`/{2,}`)
	wordReg        = regexp.MustCompile(`^\w+$`)
	suffixReg      = regexp.MustCompile(`\+[A-Za-z0-9!$%&'*+,-.:;=@_~]*$`)
	doubleColonReg = regexp.MustCompile(`^::[A-Za-z0-9!$%&'*+,-.:;=@_~]*$`)
	defaultOptions = Options{
		IgnoreCase:            true,
		TrailingSlashRedirect: true,
		FixedPathRedirect:     true,
	}
)
func New(args ...Options) *Trie {
	opts := defaultOptions
	if len(args) > 0 {
		opts = args[0]
	}
	return &Trie{
		ignoreCase: opts.IgnoreCase,
		fpr:        opts.FixedPathRedirect,
		tsr:        opts.TrailingSlashRedirect,
		root: &Node{
			parent:   nil,
			children: make(map[string]*Node),
			handlers: make(map[string]interface{}),
		},
	}
}
type Trie struct {
	ignoreCase bool
	fpr        bool
	tsr        bool
	root       *Node
}
func (t *Trie) GetEndpoints() []*Node {
	endpoints := make([]*Node, 0)
	if t.root.endpoint {
		endpoints = append(endpoints, t.root)
	}
	for _, n := range t.root.GetDescendants() {
		if n.endpoint {
			endpoints = append(endpoints, n)
		}
	}
	return endpoints
}
func (t *Trie) Define(pattern string) *Node {
	if strings.Contains(pattern, "//") {
		panic(fmt.Errorf(`multi-slash exist: "%s"`, pattern))
	}
	_pattern := strings.TrimPrefix(pattern, "/")
	if i := strings.IndexRune(_pattern, '?'); i > -1 {
		_pattern = _pattern[:i]
	}
	node := defineNode(t.root, strings.Split(_pattern, "/"), t.ignoreCase)
	if node.pattern == "" {
		node.pattern = pattern
	}
	return node
}