func (self *Trie) AddRoute(path string, route interface{}) error {
	return self.root.addRoute(path, route)
}
Insert the route in the Trie following or creating the nodes corresponding to the path.
package trie
import (
	"errors"
	"fmt"
)
func splitParam(remaining string) (string, string) {
	i := 0
	for len(remaining) > i && remaining[i] != '/' && remaining[i] != '.' {
		i++
	}
	return remaining[:i], remaining[i:]
}
type node struct {
	Route          interface{}
	Children       map[string]*node
	ChildrenKeyLen int
	ParamChild     *node
	ParamName      string
	SplatChild     *node
	SplatName      string
}
func (self *node) addRoute(path string, route interface{}) error {
	if len(path) == 0 {
		if self.Route != nil {
			return errors.New("node.Route already set, duplicated path")
		}
		self.Route = route
		return nil
	}
	token := path[0:1]
	remaining := path[1:]
	var nextNode *node
	if token[0] == ':' {
		var name string
		name, remaining = splitParam(remaining)
		if self.ParamChild == nil {
			self.ParamChild = &node{}
			self.ParamName = name
		}
		nextNode = self.ParamChild
	} else if token[0] == '*' {
		name := remaining
		remaining = ""
		if self.SplatChild == nil {
			self.SplatChild = &node{}
			self.SplatName = name
		}
		nextNode = self.SplatChild
	} else {
		if self.Children == nil {
			self.Children = map[string]*node{}
			self.ChildrenKeyLen = 1
		}
		if self.Children[token] == nil {
			self.Children[token] = &node{}
		}
		nextNode = self.Children[token]
	}
	return nextNode.addRoute(remaining, route)
}
type pstack struct {
	params []map[string]string
}
func (self *pstack) add(name, value string) {
	self.params = append(
		self.params,
		map[string]string{name: value},
	)
}
func (self *pstack) pop() {
	self.params = self.params[:len(self.params)-1]
}
func (self *pstack) asMap() map[string]string {
	r := map[string]string{}
	for _, param := range self.params {
		for key, value := range param {
			if r[key] != "" {
				panic(fmt.Sprintf(
					"placeholder %s already found, placeholder names should be unique per route",
					key,
				))
			}
			r[key] = value
		}
	}
	return r
}
type Match struct {
	Route interface{}
	Params map[string]string
}
func (self *node) findRoutes(path string, stack *pstack) []*Match {
	matches := []*Match{}
	if self.Route != nil && path == "" {
		matches = append(
			matches,
			&Match{
				Route:  self.Route,
				Params: stack.asMap(),
			},
		)
	}
	if len(path) == 0 {
		return matches
	}
	if self.SplatChild != nil {
		stack.add(self.SplatName, path)
		matches = append(
			matches,
			self.SplatChild.findRoutes("", stack)...,
		)
		stack.pop()
	}
	if self.ParamChild != nil {
		value, remaining := splitParam(path)
		stack.add(self.ParamName, value)
		matches = append(
			matches,
			self.ParamChild.findRoutes(remaining, stack)...,
		)
		stack.pop()
	}
	length := self.ChildrenKeyLen
	if len(path) < length {
		return matches
	}
	token := path[0:length]
	remaining := path[length:]
	if self.Children[token] != nil {
		matches = append(
			matches,
			self.Children[token].findRoutes(remaining, stack)...,
		)
	}
	return matches
}
func (self *node) compress() {
	if self.SplatChild != nil {
		self.SplatChild.compress()
	}
	if self.ParamChild != nil {
		self.ParamChild.compress()
	}
	if len(self.Children) == 0 {
		return
	}
	canCompress := true
	for _, node := range self.Children {
		if node.Route != nil || node.SplatChild != nil || node.ParamChild != nil {
			canCompress = false
		}
	}
	if canCompress {
		merged := map[string]*node{}
		for key, node := range self.Children {
			for gdKey, gdNode := range node.Children {
				mergedKey := key + gdKey
				merged[mergedKey] = gdNode
			}
		}
		self.Children = merged
		self.ChildrenKeyLen++
		self.compress()
	} else {
		for _, node := range self.Children {
			node.compress()
		}
	}
}
type Trie struct {
	root *node
}
func New() *Trie {
	return &Trie{
		root: &node{},
	}
}