diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bbc9898
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,56 @@
+### https://raw.github.com/github/gitignore/fdb7293c82a5554ceb748db99e01672c17808292/Global/OSX.gitignore
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon

+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### https://raw.github.com/github/gitignore/fdb7293c82a5554ceb748db99e01672c17808292/Go.gitignore
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9af5b54
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: go
+go:
+  - 1.2
+  - 1.3
+  - 1.4
+  - 1.5
+  - 1.6
+  - tip
+install:
+  - go get -t -v ./...
+script:
+  - go test -v ./...
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..574a288
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Salim Alami
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Status API Training Shop Blog About
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0839bc3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,461 @@
+# Lion [![Build Status](https://img.shields.io/travis/celrenheit/lion.svg?style=flat-square)](https://travis-ci.org/celrenheit/lion) [![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/celrenheit/lion) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)
+
+Lion is a fast http(2) router for Go with support for middlewares for building modern scalable modular REST APIs.
+
+## Features
+
+* **Zero allocations**: Lion generates zero garbage.
+* **Context-Aware**: Lion uses [net/Context](https://golang.org/x/net/context) for storing route params and sharing variables between middlewares and HTTP handlers. Which [_could_](https://github.com/golang/go/issues/14660) be integrated in the [standard library](https://github.com/golang/go/issues/13021) for Go 1.7 in 2016.
+* **Modular**: You can define your own modules to easily build a scalable architecture
+* **REST friendly**: You can define
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+## Table of contents
+
+  - [Install/Update](#installupdate)
+  - [Hello World](#hello-world)
+  - [Getting started with modules and resources](#getting-started-with-modules-and-resources)
+  - [Handlers](#handlers)
+    - [Using HandlerFuncs](#using-handlerfuncs)
+    - [Using native http.Handler using *lion.Wrap()*](#using-native-httphandler-using-lionwrap)
+    - [Using native http.Handler using *lion.WrapFunc()*](#using-native-httphandler-using-lionwrapfunc)
+  - [Middlewares](#middlewares)
+  - [Resources](#resources)
+  - [Examples](#examples)
+    - [Using GET, POST, PUT, DELETE http methods](#using-get-post-put-delete-http-methods)
+    - [Using middlewares](#using-middlewares)
+    - [Group routes by a base path](#group-routes-by-a-base-path)
+    - [Mouting a router into a base path](#mouting-a-router-into-a-base-path)
+    - [Default middlewares](#default-middlewares)
+- [Custom Middlewares](#custom-middlewares)
+    - [Custom Logger example](#custom-logger-example)
+- [Todo](#todo)
+- [Credits](#credits)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+
+## Install/Update
+
+```shell
+$ go get -u github.com/celrenheit/lion
+```
+
+
+## Hello World
+
+```go
+package main
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+func Home(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Home\n")
+}
+
+func Hello(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Hello "+c.Value("name").(string))
+}
+
+func main() {
+	l := lion.Classic()
+	l.GetFunc("/", Home)
+	l.GetFunc("/hello/:name", Hello)
+	l.Run()
+}
+```
+
+Try it your self by running the following command from the current directory:
+
+```shell
+$ go run examples/hello/hello.go
+```
+
+## Getting started with modules and resources
+
+We are going to build a sample products listing REST api (without database handling to keep it simple):
+
+```go
+
+func main() {
+	l := lion.Classic()
+	api := l.Group("/api")
+	api.Module(Products{})
+	l.Run()
+}
+
+// Products module is accessible at url: /api/products
+// It handles getting a list of products or creating a new product
+type Products struct{}
+
+func (p Products) Base() string {
+	return "/products"
+}
+
+func (p Products) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Fetching all products")
+}
+
+func (p Products) Post(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Creating a new product")
+}
+
+func (p Products) Routes(r *lion.Router) {
+	// Defining a resource for getting, editing and deleting a single product
+	r.Resource("/:id", OneProduct{})
+}
+
+// OneProduct resource is accessible at url: /api/products/:id
+// It handles getting, editing and deleting a single product
+type OneProduct struct{}
+
+func (p OneProduct) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	id := lion.Param(c, "id")
+	fmt.Fprintf(w, "Getting product: %s", id)
+}
+
+func (p OneProduct) Put(c context.Context, w http.ResponseWriter, r *http.Request) {
+	id := lion.Param(c, "id")
+	fmt.Fprintf(w, "Updating article: %s", id)
+}
+
+func (p OneProduct) Delete(c context.Context, w http.ResponseWriter, r *http.Request) {
+	id := lion.Param(c, "id")
+	fmt.Fprintf(w, "Deleting article: %s", id)
+}
+```
+
+Try it. Run:
+```shell
+$ go run examples/modular-hello/modular-hello.go
+```
+
+Open your web browser to [http://localhost:3000/api/products](http://localhost:3000/api/products) or [http://localhost:3000/api/products/123](http://localhost:3000/api/products/123). You should see "_Fetching all products_" or "_Getting product: 123_".
+
+## Handlers
+
+Handlers should implement the Handler interface:
+### Handler interface
+```go
+type Handler interface {
+	ServeHTTPC(context.Context, http.ResponseWriter, *http.Request)
+}
+```
+
+### Using HandlerFuncs
+
+HandlerFuncs shoud have this function signature:
+
+```go
+func Get(c context.Context, w http.ResponseWriter, r *http.Request)  {
+
+}
+
+l.GetFunc("/somepath", Get)
+```
+
+### Using native http.Handler using *lion.Wrap()*
+
+*Note*: using native http handler you cannot access url params.
+
+```go
+type nativehandler struct {}
+
+func (_ nativehandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+
+}
+
+func main() {
+	l := lion.New()
+	l.Get("/somepath", lion.Wrap(nativehandler{}))
+}
+```
+
+### Using native http.Handler using *lion.WrapFunc()*
+
+
+```go
+func getHandlerFunc(w http.ResponseWriter, r *http.Request) {
+
+}
+
+func main() {
+	l := lion.New()
+	l.Get("/somepath", lion.WrapFunc(getHandlerFunc))
+}
+```
+
+## Middlewares
+
+Middlewares should implement the Middleware interface:
+
+```go
+type Middleware interface {
+	ServeNext(Handler) Handler
+}
+```
+
+The ServeNext function accepts a Handler and returns a Handler.
+
+You can also use MiddlewareFuncs. For example:
+
+```go
+func middlewareFunc(next Handler) Handler  {
+	return next
+}
+```
+
+You can also use Negroni middlewares by registering them using:
+
+```go
+l := lion.New()
+l.UseNegroni(negroni.NewRecovery())
+l.Run()
+```
+
+## Resources
+
+You can define a resource to represent a REST, CRUD api resource.
+You define global middlewares using Uses() method. For defining custom middlewares for each http method, you have to create a function which name is composed of the http method suffixed by "Middlewares". For example, if you want to define middlewares for the Get method you will have to create a method called: **GetMiddlewares()**.
+
+A resource is defined by the following methods. **Everything is optional**:
+```go
+
+// Global middlewares for the resource (Optional)
+Uses() Middlewares
+
+// Middlewares for the http methods (Optional)
+GetMiddlewares() Middlewares
+PostMiddlewares() Middlewares
+PutMiddlewares() Middlewares
+DeleteMiddlewares() Middlewares
+
+
+// HandlerFuncs for each HTTP Methods (Optional)
+Get(c context.Context, w http.ResponseWriter, r *http.Request)
+Post(c context.Context, w http.ResponseWriter, r *http.Request)
+Put(c context.Context, w http.ResponseWriter, r *http.Request)
+Delete(c context.Context, w http.ResponseWriter, r *http.Request)
+```
+
+**_Example_**:
+
+```go
+package main
+
+type todolist struct{}
+
+func (t todolist) Uses() lion.Middlewares {
+	return lion.Middlewares{lion.NewLogger()}
+}
+
+func (t todolist) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "getting todos")
+}
+
+func main() {
+	l := lion.New()
+	l.Resource("/todos", todolist{})
+	l.Run()
+}
+```
+
+
+## Modules
+
+Modules are a way to modularize an api which can then define submodules, subresources and custom routes.
+A module is defined by the following methods:
+
+```go
+// Required: Base url pattern of the module
+Base() string
+
+// Routes accepts a Router instance. This method is used to define the routes of this module.
+// Each routes defined are relative to the Base() url pattern
+Routes(*Router)
+
+// Optional: Requires named middlewares. Refer to Named Middlewares section
+Requires() []string
+```
+
+```go
+package main
+
+type api struct{}
+
+// Required: Base url
+func (t api) Base() string { return "/api" }
+
+// Required: Here you can declare sub-resources, submodules and custom routes.
+func (t api) Routes(r *lion.Router) {
+	r.Module(v1{})
+	r.Get("/custom", t.CustomRoute)
+}
+
+// Optional: Attach Get method to this Module.
+// ====> A Module is also a Resource.
+func (t api) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "This also a resource accessible at http://localhost:3000/api")
+}
+
+// Optional: Defining custom routes
+func (t api) CustomRoute(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "This a custom route for this module http://localhost:3000/api/")
+}
+
+func main() {
+	l := lion.New()
+	// Registering the module
+	l.Module(api{})
+	l.Run()
+}
+```
+
+## Examples
+
+### Using GET, POST, PUT, DELETE http methods
+
+```go
+l := lion.Classic()
+
+// Using Handlers
+l.Get("/get", get)
+l.Post("/post", post)
+l.Put("/put", put)
+l.Delete("/delete", delete)
+
+// Using functions
+l.GetFunc("/get", getFunc)
+l.PostFunc("/post", postFunc)
+l.PutFunc("/put", putFunc)
+l.DeleteFunc("/delete", deleteFunc)
+
+l.Run()
+```
+
+### Using middlewares
+
+```go
+func main() {
+	l := lion.Classic()
+
+	// Using middleware
+	l.Use(lion.NewLogger())
+
+	// Using middleware functions
+	l.UseFunc(someMiddlewareFunc)
+
+	l.GetFunc("/hello/:name", Hello)
+
+	l.Run()
+}
+```
+
+
+### Group routes by a base path
+
+```go
+l := lion.Classic()
+api := l.Group("/api")
+
+v1 := l.Group("/v1")
+v1.GetFunc("/somepath", gettingFromV1)
+
+v2 := l.Group("/v2")
+v2.GetFunc("/somepath", gettingFromV2)
+
+l.Run()
+```
+
+### Mouting a router into a base path
+
+
+```go
+l := lion.Classic()
+
+sub := lion.New()
+sub.GetFunc("/somepath", getting)
+
+
+l.Mount("/api", sub)
+```
+
+### Default middlewares
+
+`lion.Classic()` creates a router with default middlewares (Recovery, RealIP, Logger, Static).
+If you wish to create a blank router without any middlewares you can use `lion.New()`.
+
+```go
+func main()  {
+	// This a no middlewares registered
+	l := lion.New()
+	l.Use(lion.NewLogger())
+
+	l.GetFunc("/hello/:name", Hello)
+
+	l.Run()
+}
+```
+
+# Custom Middlewares
+
+Custom middlewares should implement the Middleware interface:
+
+```go
+type Middleware interface {
+	ServeNext(Handler) Handler
+}
+```
+
+You can also make MiddlewareFuncs to use using `.UseFunc()` method.
+It has to accept a Handler and return a Handler:
+```go
+func(next Handler) Handler
+```
+
+
+### Custom Logger example
+
+```go
+type logger struct{}
+
+func (*logger) ServeNext(next lion.Handler) lion.Handler {
+	return lion.HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		start := time.Now()
+
+		next.ServeHTTPC(c, w, r)
+
+		fmt.Printf("Served %s in %s\n", r.URL.Path, time.Since(start))
+	})
+}
+```
+
+Then in the main function you can use the middleware using:
+
+```go
+l := lion.New()
+
+l.Use(&logger{})
+l.GetFunc("/hello/:name", Hello)
+l.Run()
+```
+
+# Todo
+
+[ ] Better static file handling
+[ ] Better docs
+
+# Credits
+
+* @codegangsta for https://github.com/codegangsta/negroni
+	* Static and Recovery middlewares are taken from Negroni
+* @zenazn for https://github.com/zenazn/goji/
+	* RealIP middleware is taken from goji
+* @armon for https://github.com/armon/go-radix
diff --git a/bench_test.go b/bench_test.go
new file mode 100644
index 0000000..cc65dec
--- /dev/null
+++ b/bench_test.go
@@ -0,0 +1,364 @@
+package lion
+
+import (
+	"net/http"
+	"testing"
+)
+
+var githubLion http.Handler
+
+func init() {
+	githubLion = loadLion(githubAPI)
+}
+
+func BenchmarkGithubAPI(b *testing.B) {
+	benchRoutes(b, githubLion, githubAPI)
+}
+
+func BenchmarkLion_GithubParam(b *testing.B) {
+	req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil)
+	benchRequest(b, githubLion, req)
+}
+
+func benchRequest(b *testing.B, router http.Handler, r *http.Request) {
+	w := new(mockResponseWriter)
+	u := r.URL
+	rq := u.RawQuery
+	r.RequestURI = u.RequestURI()
+
+	b.ReportAllocs()
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		u.RawQuery = rq
+		router.ServeHTTP(w, r)
+	}
+}
+
+func benchRoutes(b *testing.B, router http.Handler, routes []route) {
+	w := new(mockResponseWriter)
+	r, _ := http.NewRequest("GET", "/", nil)
+	u := r.URL
+	rq := u.RawQuery
+
+	b.ReportAllocs()
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		for _, route := range routes {
+			r.Method = route.method
+			r.RequestURI = route.path
+			u.Path = route.path
+			u.RawQuery = rq
+			router.ServeHTTP(w, r)
+		}
+	}
+}
+
+type route struct {
+	method string
+	path   string
+}
+type mockResponseWriter struct{}
+
+func (m *mockResponseWriter) Header() (h http.Header) {
+	return http.Header{}
+}
+
+func (m *mockResponseWriter) Write(p []byte) (n int, err error) {
+	return len(p), nil
+}
+
+func (m *mockResponseWriter) WriteString(s string) (n int, err error) {
+	return len(s), nil
+}
+
+func (m *mockResponseWriter) WriteHeader(int) {}
+
+func loadLion(routes []route) http.Handler {
+	hn := httpHandlerFunc
+	h := Wrap(http.HandlerFunc(hn))
+	mux := New()
+	for _, route := range routes {
+		switch route.method {
+		case "GET":
+			mux.Get(route.path, h)
+		case "POST":
+			mux.Post(route.path, h)
+		case "PUT":
+			mux.Put(route.path, h)
+		case "PATCH":
+			mux.Patch(route.path, h)
+		case "DELETE":
+			mux.Delete(route.path, h)
+		default:
+			panic("Unknown HTTP method: " + route.method)
+		}
+	}
+	// mux.Matcher.DisplayTree(0)
+	return mux
+}
+func httpHandlerFunc(w http.ResponseWriter, r *http.Request) {}
+
+var githubAPI = []route{
+	// OAuth Authorizations
+	{"GET", "/authorizations"},
+	{"GET", "/authorizations/:id"},
+	{"POST", "/authorizations"},
+	//{"PUT", "/authorizations/clients/:client_id"},
+	//{"PATCH", "/authorizations/:id"},
+	{"DELETE", "/authorizations/:id"},
+	{"GET", "/applications/:client_id/tokens/:access_token"},
+	{"DELETE", "/applications/:client_id/tokens"},
+	{"DELETE", "/applications/:client_id/tokens/:access_token"},
+
+	// Activity
+	{"GET", "/events"},
+	{"GET", "/repos/:owner/:repo/events"},
+	{"GET", "/networks/:owner/:repo/events"},
+	{"GET", "/orgs/:org/events"},
+	{"GET", "/users/:user/received_events"},
+	{"GET", "/users/:user/received_events/public"},
+	{"GET", "/users/:user/events"},
+	{"GET", "/users/:user/events/public"},
+	{"GET", "/users/:user/events/orgs/:org"},
+	{"GET", "/feeds"},
+	{"GET", "/notifications"},
+	{"GET", "/repos/:owner/:repo/notifications"},
+	{"PUT", "/notifications"},
+	{"PUT", "/repos/:owner/:repo/notifications"},
+	{"GET", "/notifications/threads/:id"},
+	//{"PATCH", "/notifications/threads/:id"},
+	{"GET", "/notifications/threads/:id/subscription"},
+	{"PUT", "/notifications/threads/:id/subscription"},
+	{"DELETE", "/notifications/threads/:id/subscription"},
+	{"GET", "/repos/:owner/:repo/stargazers"},
+	{"GET", "/users/:user/starred"},
+	{"GET", "/user/starred"},
+	{"GET", "/user/starred/:owner/:repo"},
+	{"PUT", "/user/starred/:owner/:repo"},
+	{"DELETE", "/user/starred/:owner/:repo"},
+	{"GET", "/repos/:owner/:repo/subscribers"},
+	{"GET", "/users/:user/subscriptions"},
+	{"GET", "/user/subscriptions"},
+	{"GET", "/repos/:owner/:repo/subscription"},
+	{"PUT", "/repos/:owner/:repo/subscription"},
+	{"DELETE", "/repos/:owner/:repo/subscription"},
+	{"GET", "/user/subscriptions/:owner/:repo"},
+	{"PUT", "/user/subscriptions/:owner/:repo"},
+	{"DELETE", "/user/subscriptions/:owner/:repo"},
+
+	// Gists
+	{"GET", "/users/:user/gists"},
+	{"GET", "/gists"},
+	//{"GET", "/gists/public"},
+	//{"GET", "/gists/starred"},
+	{"GET", "/gists/:id"},
+	{"POST", "/gists"},
+	//{"PATCH", "/gists/:id"},
+	{"PUT", "/gists/:id/star"},
+	{"DELETE", "/gists/:id/star"},
+	{"GET", "/gists/:id/star"},
+	{"POST", "/gists/:id/forks"},
+	{"DELETE", "/gists/:id"},
+
+	// Git Data
+	{"GET", "/repos/:owner/:repo/git/blobs/:sha"},
+	{"POST", "/repos/:owner/:repo/git/blobs"},
+	{"GET", "/repos/:owner/:repo/git/commits/:sha"},
+	{"POST", "/repos/:owner/:repo/git/commits"},
+	//{"GET", "/repos/:owner/:repo/git/refs/*ref"},
+	{"GET", "/repos/:owner/:repo/git/refs"},
+	{"POST", "/repos/:owner/:repo/git/refs"},
+	//{"PATCH", "/repos/:owner/:repo/git/refs/*ref"},
+	//{"DELETE", "/repos/:owner/:repo/git/refs/*ref"},
+	{"GET", "/repos/:owner/:repo/git/tags/:sha"},
+	{"POST", "/repos/:owner/:repo/git/tags"},
+	{"GET", "/repos/:owner/:repo/git/trees/:sha"},
+	{"POST", "/repos/:owner/:repo/git/trees"},
+
+	// Issues
+	{"GET", "/issues"},
+	{"GET", "/user/issues"},
+	{"GET", "/orgs/:org/issues"},
+	{"GET", "/repos/:owner/:repo/issues"},
+	{"GET", "/repos/:owner/:repo/issues/:number"},
+	{"POST", "/repos/:owner/:repo/issues"},
+	//{"PATCH", "/repos/:owner/:repo/issues/:number"},
+	{"GET", "/repos/:owner/:repo/assignees"},
+	{"GET", "/repos/:owner/:repo/assignees/:assignee"},
+	{"GET", "/repos/:owner/:repo/issues/:number/comments"},
+	//{"GET", "/repos/:owner/:repo/issues/comments"},
+	//{"GET", "/repos/:owner/:repo/issues/comments/:id"},
+	{"POST", "/repos/:owner/:repo/issues/:number/comments"},
+	//{"PATCH", "/repos/:owner/:repo/issues/comments/:id"},
+	//{"DELETE", "/repos/:owner/:repo/issues/comments/:id"},
+	{"GET", "/repos/:owner/:repo/issues/:number/events"},
+	//{"GET", "/repos/:owner/:repo/issues/events"},
+	//{"GET", "/repos/:owner/:repo/issues/events/:id"},
+	{"GET", "/repos/:owner/:repo/labels"},
+	{"GET", "/repos/:owner/:repo/labels/:name"},
+	{"POST", "/repos/:owner/:repo/labels"},
+	//{"PATCH", "/repos/:owner/:repo/labels/:name"},
+	{"DELETE", "/repos/:owner/:repo/labels/:name"},
+	{"GET", "/repos/:owner/:repo/issues/:number/labels"},
+	{"POST", "/repos/:owner/:repo/issues/:number/labels"},
+	{"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"},
+	{"PUT", "/repos/:owner/:repo/issues/:number/labels"},
+	{"DELETE", "/repos/:owner/:repo/issues/:number/labels"},
+	{"GET", "/repos/:owner/:repo/milestones/:number/labels"},
+	{"GET", "/repos/:owner/:repo/milestones"},
+	{"GET", "/repos/:owner/:repo/milestones/:number"},
+	{"POST", "/repos/:owner/:repo/milestones"},
+	//{"PATCH", "/repos/:owner/:repo/milestones/:number"},
+	{"DELETE", "/repos/:owner/:repo/milestones/:number"},
+
+	// Miscellaneous
+	{"GET", "/emojis"},
+	{"GET", "/gitignore/templates"},
+	{"GET", "/gitignore/templates/:name"},
+	{"POST", "/markdown"},
+	{"POST", "/markdown/raw"},
+	{"GET", "/meta"},
+	{"GET", "/rate_limit"},
+
+	// Organizations
+	{"GET", "/users/:user/orgs"},
+	{"GET", "/user/orgs"},
+	{"GET", "/orgs/:org"},
+	//{"PATCH", "/orgs/:org"},
+	{"GET", "/orgs/:org/members"},
+	{"GET", "/orgs/:org/members/:user"},
+	{"DELETE", "/orgs/:org/members/:user"},
+	{"GET", "/orgs/:org/public_members"},
+	{"GET", "/orgs/:org/public_members/:user"},
+	{"PUT", "/orgs/:org/public_members/:user"},
+	{"DELETE", "/orgs/:org/public_members/:user"},
+	{"GET", "/orgs/:org/teams"},
+	{"GET", "/teams/:id"},
+	{"POST", "/orgs/:org/teams"},
+	//{"PATCH", "/teams/:id"},
+	{"DELETE", "/teams/:id"},
+	{"GET", "/teams/:id/members"},
+	{"GET", "/teams/:id/members/:user"},
+	{"PUT", "/teams/:id/members/:user"},
+	{"DELETE", "/teams/:id/members/:user"},
+	{"GET", "/teams/:id/repos"},
+	{"GET", "/teams/:id/repos/:owner/:repo"},
+	{"PUT", "/teams/:id/repos/:owner/:repo"},
+	{"DELETE", "/teams/:id/repos/:owner/:repo"},
+	{"GET", "/user/teams"},
+
+	// Pull Requests
+	{"GET", "/repos/:owner/:repo/pulls"},
+	{"GET", "/repos/:owner/:repo/pulls/:number"},
+	{"POST", "/repos/:owner/:repo/pulls"},
+	//{"PATCH", "/repos/:owner/:repo/pulls/:number"},
+	{"GET", "/repos/:owner/:repo/pulls/:number/commits"},
+	{"GET", "/repos/:owner/:repo/pulls/:number/files"},
+	{"GET", "/repos/:owner/:repo/pulls/:number/merge"},
+	{"PUT", "/repos/:owner/:repo/pulls/:number/merge"},
+	{"GET", "/repos/:owner/:repo/pulls/:number/comments"},
+	//{"GET", "/repos/:owner/:repo/pulls/comments"},
+	//{"GET", "/repos/:owner/:repo/pulls/comments/:number"},
+	{"PUT", "/repos/:owner/:repo/pulls/:number/comments"},
+	//{"PATCH", "/repos/:owner/:repo/pulls/comments/:number"},
+	//{"DELETE", "/repos/:owner/:repo/pulls/comments/:number"},
+
+	// Repositories
+	{"GET", "/user/repos"},
+	{"GET", "/users/:user/repos"},
+	{"GET", "/orgs/:org/repos"},
+	{"GET", "/repositories"},
+	{"POST", "/user/repos"},
+	{"POST", "/orgs/:org/repos"},
+	{"GET", "/repos/:owner/:repo"},
+	//{"PATCH", "/repos/:owner/:repo"},
+	{"GET", "/repos/:owner/:repo/contributors"},
+	{"GET", "/repos/:owner/:repo/languages"},
+	{"GET", "/repos/:owner/:repo/teams"},
+	{"GET", "/repos/:owner/:repo/tags"},
+	{"GET", "/repos/:owner/:repo/branches"},
+	{"GET", "/repos/:owner/:repo/branches/:branch"},
+	{"DELETE", "/repos/:owner/:repo"},
+	{"GET", "/repos/:owner/:repo/collaborators"},
+	{"GET", "/repos/:owner/:repo/collaborators/:user"},
+	{"PUT", "/repos/:owner/:repo/collaborators/:user"},
+	{"DELETE", "/repos/:owner/:repo/collaborators/:user"},
+	{"GET", "/repos/:owner/:repo/comments"},
+	{"GET", "/repos/:owner/:repo/commits/:sha/comments"},
+	{"POST", "/repos/:owner/:repo/commits/:sha/comments"},
+	{"GET", "/repos/:owner/:repo/comments/:id"},
+	//{"PATCH", "/repos/:owner/:repo/comments/:id"},
+	{"DELETE", "/repos/:owner/:repo/comments/:id"},
+	{"GET", "/repos/:owner/:repo/commits"},
+	{"GET", "/repos/:owner/:repo/commits/:sha"},
+	{"GET", "/repos/:owner/:repo/readme"},
+	//{"GET", "/repos/:owner/:repo/contents/*path"},
+	//{"PUT", "/repos/:owner/:repo/contents/*path"},
+	//{"DELETE", "/repos/:owner/:repo/contents/*path"},
+	//{"GET", "/repos/:owner/:repo/:archive_format/:ref"},
+	{"GET", "/repos/:owner/:repo/keys"},
+	{"GET", "/repos/:owner/:repo/keys/:id"},
+	{"POST", "/repos/:owner/:repo/keys"},
+	//{"PATCH", "/repos/:owner/:repo/keys/:id"},
+	{"DELETE", "/repos/:owner/:repo/keys/:id"},
+	{"GET", "/repos/:owner/:repo/downloads"},
+	{"GET", "/repos/:owner/:repo/downloads/:id"},
+	{"DELETE", "/repos/:owner/:repo/downloads/:id"},
+	{"GET", "/repos/:owner/:repo/forks"},
+	{"POST", "/repos/:owner/:repo/forks"},
+	{"GET", "/repos/:owner/:repo/hooks"},
+	{"GET", "/repos/:owner/:repo/hooks/:id"},
+	{"POST", "/repos/:owner/:repo/hooks"},
+	//{"PATCH", "/repos/:owner/:repo/hooks/:id"},
+	{"POST", "/repos/:owner/:repo/hooks/:id/tests"},
+	{"DELETE", "/repos/:owner/:repo/hooks/:id"},
+	{"POST", "/repos/:owner/:repo/merges"},
+	{"GET", "/repos/:owner/:repo/releases"},
+	{"GET", "/repos/:owner/:repo/releases/:id"},
+	{"POST", "/repos/:owner/:repo/releases"},
+	//{"PATCH", "/repos/:owner/:repo/releases/:id"},
+	{"DELETE", "/repos/:owner/:repo/releases/:id"},
+	{"GET", "/repos/:owner/:repo/releases/:id/assets"},
+	{"GET", "/repos/:owner/:repo/stats/contributors"},
+	{"GET", "/repos/:owner/:repo/stats/commit_activity"},
+	{"GET", "/repos/:owner/:repo/stats/code_frequency"},
+	{"GET", "/repos/:owner/:repo/stats/participation"},
+	{"GET", "/repos/:owner/:repo/stats/punch_card"},
+	{"GET", "/repos/:owner/:repo/statuses/:ref"},
+	{"POST", "/repos/:owner/:repo/statuses/:ref"},
+
+	// Search
+	{"GET", "/search/repositories"},
+	{"GET", "/search/code"},
+	{"GET", "/search/issues"},
+	{"GET", "/search/users"},
+	{"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"},
+	{"GET", "/legacy/repos/search/:keyword"},
+	{"GET", "/legacy/user/search/:keyword"},
+	{"GET", "/legacy/user/email/:email"},
+
+	// Users
+	{"GET", "/users/:user"},
+	{"GET", "/user"},
+	//{"PATCH", "/user"},
+	{"GET", "/users"},
+	{"GET", "/user/emails"},
+	{"POST", "/user/emails"},
+	{"DELETE", "/user/emails"},
+	{"GET", "/users/:user/followers"},
+	{"GET", "/user/followers"},
+	{"GET", "/users/:user/following"},
+	{"GET", "/user/following"},
+	{"GET", "/user/following/:user"},
+	{"GET", "/users/:user/following/:target_user"},
+	{"PUT", "/user/following/:user"},
+	{"DELETE", "/user/following/:user"},
+	{"GET", "/users/:user/keys"},
+	{"GET", "/user/keys"},
+	{"GET", "/user/keys/:id"},
+	{"POST", "/user/keys"},
+	//{"PATCH", "/user/keys/:id"},
+	{"DELETE", "/user/keys/:id"},
+}
diff --git a/context.go b/context.go
new file mode 100644
index 0000000..ab10794
--- /dev/null
+++ b/context.go
@@ -0,0 +1,75 @@
+package lion
+
+import "golang.org/x/net/context"
+
+// Check Context implements net.Context
+var _ context.Context = (*Context)(nil)
+
+// type ContextI interface {
+// 	context.Context
+// 	Param(string) string
+// }
+
+// Context implements golang.org/x/net/context.Context and stores values of url parameters
+type Context struct {
+	context.Context
+	parent context.Context
+
+	keys   []string
+	values []string
+}
+
+// NewContext creates a new context instance
+func NewContext() *Context {
+	return NewContextWithParent(context.Background())
+}
+
+// NewContextWithParent creates a new context with a parent context specified
+func NewContextWithParent(c context.Context) *Context {
+	return &Context{
+		parent: c,
+	}
+}
+
+// Value returns the value for the passed key. If it is not found in the url params it returns parent's context Value
+func (p *Context) Value(key interface{}) interface{} {
+	if k, ok := key.(string); ok {
+		return p.Param(k)
+	}
+
+	return p.parent.Value(key)
+}
+
+func (p *Context) addParam(key, val string) {
+	p.keys = append(p.keys, key)
+	p.values = append(p.values, val)
+}
+
+// Param returns the value of a param
+func (p *Context) Param(key string) string {
+	for i, name := range p.keys {
+		if name == key {
+			return p.values[i]
+		}
+	}
+	return ""
+}
+
+func (p *Context) reset() {
+	p.keys = p.keys[:0]
+	p.values = p.values[:0]
+	p.parent = nil
+}
+
+// C returns a Context based on a context.Context passed. If it does not convert to Context, it creates a new one with the context passed as argument.
+func C(c context.Context) *Context {
+	if ctx, ok := c.(*Context); ok {
+		return ctx
+	}
+	return NewContextWithParent(c)
+}
+
+// Param returns the value of a url param base on the passed context
+func Param(c context.Context, key string) string {
+	return C(c).Param(key)
+}
diff --git a/examples/basic-auth/basic-auth.go b/examples/basic-auth/basic-auth.go
new file mode 100644
index 0000000..34fe871
--- /dev/null
+++ b/examples/basic-auth/basic-auth.go
@@ -0,0 +1,62 @@
+package main
+
+import (
+	"bytes"
+	"encoding/base64"
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+const basicAuthPrefix = "Basic "
+
+var user = []byte("lion")
+var pass = []byte("argh")
+
+func Home(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Home")
+}
+
+func BasicAuthMiddleware(next lion.Handler) lion.Handler {
+	return lion.HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		auth := r.Header.Get("Authorization")
+
+		if strings.HasPrefix(auth, basicAuthPrefix) {
+			// Check credentials
+			payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
+			if err == nil {
+				pair := bytes.SplitN(payload, []byte(":"), 2)
+				if len(pair) == 2 &&
+					bytes.Equal(pair[0], user) &&
+					bytes.Equal(pair[1], pass) {
+
+					// Delegate request to the given handle
+					next.ServeHTTPC(c, w, r)
+					return
+				}
+			}
+		}
+
+		// Request Basic Authentication otherwise
+		w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
+		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
+	})
+}
+
+func ProtectedHome(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Connected to the protected home")
+}
+
+func main() {
+	l := lion.Classic()
+	l.GetFunc("/", Home)
+
+	g := l.Group("/protected")
+	g.UseFunc(BasicAuthMiddleware)
+	g.GetFunc("/", ProtectedHome)
+
+	l.Run(":3000")
+}
diff --git a/examples/custom-logger/custom-logger.go b/examples/custom-logger/custom-logger.go
new file mode 100644
index 0000000..306e47f
--- /dev/null
+++ b/examples/custom-logger/custom-logger.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+	"time"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+func Home(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Home")
+}
+
+func Hello(c context.Context, w http.ResponseWriter, r *http.Request) {
+	ctx := lion.C(c)
+	fmt.Fprintf(w, "Hello "+ctx.Param("name"))
+}
+
+type logger struct{}
+
+func (*logger) ServeNext(next lion.Handler) lion.Handler {
+	return lion.HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		start := time.Now()
+
+		next.ServeHTTPC(c, w, r)
+
+		fmt.Printf("Served %s in %s\n", r.URL.Path, time.Since(start))
+	})
+}
+
+func main() {
+	l := lion.New()
+	l.Use(&logger{})
+	l.GetFunc("/", Home)
+	l.GetFunc("/hello/:name", Hello)
+	l.Run(":3000")
+}
diff --git a/examples/hello/hello.go b/examples/hello/hello.go
new file mode 100644
index 0000000..4f8fdad
--- /dev/null
+++ b/examples/hello/hello.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+func Home(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Home\n")
+}
+
+func Hello(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Hello "+c.Value("name").(string))
+}
+
+func main() {
+	l := lion.Classic()
+	l.GetFunc("/", Home)
+	l.GetFunc("/hello/:name", Hello)
+	l.Run()
+}
diff --git a/examples/modular-hello/modular-hello.go b/examples/modular-hello/modular-hello.go
new file mode 100644
index 0000000..43fbe26
--- /dev/null
+++ b/examples/modular-hello/modular-hello.go
@@ -0,0 +1,56 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+func main() {
+	l := lion.Classic()
+	api := l.Group("/api")
+	api.Module(Products{})
+	l.Run()
+}
+
+// Products module is accessible at url: /api/products
+// It handles getting a list of products or creating a new product
+type Products struct{}
+
+func (p Products) Base() string {
+	return "/products"
+}
+
+func (p Products) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Fetching all products")
+}
+
+func (p Products) Post(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Creating a new product")
+}
+
+func (p Products) Routes(r *lion.Router) {
+	// Defining a resource for getting, editing and deleting a single product
+	r.Resource("/:id", OneProduct{})
+}
+
+// OneProduct resource is accessible at url: /api/products/:id
+// It handles getting, editing and deleting a single product
+type OneProduct struct{}
+
+func (p OneProduct) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	id := lion.Param(c, "id")
+	fmt.Fprintf(w, "Getting product: %s", id)
+}
+
+func (p OneProduct) Put(c context.Context, w http.ResponseWriter, r *http.Request) {
+	id := lion.Param(c, "id")
+	fmt.Fprintf(w, "Updating article: %s", id)
+}
+
+func (p OneProduct) Delete(c context.Context, w http.ResponseWriter, r *http.Request) {
+	id := lion.Param(c, "id")
+	fmt.Fprintf(w, "Deleting article: %s", id)
+}
diff --git a/examples/module/module.go b/examples/module/module.go
new file mode 100644
index 0000000..142ae66
--- /dev/null
+++ b/examples/module/module.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+// Open your web browser at http://localhost:3000/api/v1/todos
+
+type api struct{}
+
+func (t api) Base() string { return "/api" }
+
+func (t api) Routes(r *lion.Router) {
+	r.Module(v1{})
+}
+
+// Attach Get methods to a Module.
+// ====> A Module is also a Resource.
+func (t api) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, `
+    Description of available apis
+    Go to: http://localhost:3000/api/v1/todos
+    `)
+}
+
+type v1 struct{}
+
+func (t v1) Base() string { return "/v1" }
+
+func (t v1) Routes(r *lion.Router) {
+	r.Resource("/todos", todoList{})
+}
+
+type todoList struct{}
+
+func (t todoList) Uses() lion.Middlewares {
+	return lion.Middlewares{lion.NewLogger()}
+}
+
+func (t todoList) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "TODO")
+}
+
+func main() {
+	l := lion.New()
+	l.Module(api{})
+	l.Run()
+}
diff --git a/examples/resource/resource.go b/examples/resource/resource.go
new file mode 100644
index 0000000..f1b4b17
--- /dev/null
+++ b/examples/resource/resource.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/celrenheit/lion"
+	"golang.org/x/net/context"
+)
+
+type TodoList struct{}
+
+func (t TodoList) Uses() lion.Middlewares {
+	return lion.Middlewares{lion.NewLogger()}
+}
+
+func (t TodoList) GetMiddlewares() lion.Middlewares {
+	return lion.Middlewares{lion.NewRecovery()}
+}
+
+func (t TodoList) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "TODO")
+	// Should be catched by GetMiddlewares()'s Recovery middleware
+	panic("test")
+}
+
+func main() {
+	l := lion.New()
+	l.Resource("/todos", TodoList{})
+	l.Run()
+}
diff --git a/lion.go b/lion.go
new file mode 100644
index 0000000..0bcbe52
--- /dev/null
+++ b/lion.go
@@ -0,0 +1,48 @@
+package lion
+
+import (
+	"net/http"
+
+	"golang.org/x/net/context"
+)
+
+// Handler responds to an HTTP request
+type Handler interface {
+	ServeHTTPC(context.Context, http.ResponseWriter, *http.Request)
+}
+
+// HandlerFunc is a wrapper for a function to implement the Handler interface
+type HandlerFunc func(context.Context, http.ResponseWriter, *http.Request)
+
+// ServeHTTP makes HandlerFunc implement net/http.Handler interface
+func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	h(context.TODO(), w, r)
+}
+
+// ServeHTTPC makes HandlerFunc implement Handler interface
+func (h HandlerFunc) ServeHTTPC(c context.Context, w http.ResponseWriter, r *http.Request) {
+	h(c, w, r)
+}
+
+// Middleware interface that takes as input a Handler and returns a Handler
+type Middleware interface {
+	ServeNext(Handler) Handler
+}
+
+// MiddlewareFunc wraps a function that takes as input a Handler and returns a Handler. So that it implements the Middlewares interface
+type MiddlewareFunc func(Handler) Handler
+
+// ServeNext makes MiddlewareFunc implement Middleware
+func (m MiddlewareFunc) ServeNext(next Handler) Handler {
+	return m(next)
+}
+
+// Middlewares is an array of Middleware
+type Middlewares []Middleware
+
+func (middlewares Middlewares) BuildHandler(handler Handler) Handler {
+	for i := len(middlewares) - 1; i >= 0; i-- {
+		handler = middlewares[i].ServeNext(handler)
+	}
+	return handler
+}
diff --git a/matcher.go b/matcher.go
new file mode 100644
index 0000000..b58b087
--- /dev/null
+++ b/matcher.go
@@ -0,0 +1,56 @@
+package lion
+
+import (
+	"net/http"
+)
+
+// RegisterMatcher registers and matches routes to Handlers
+type RegisterMatcher interface {
+	Register(method, pattern string, handler Handler)
+	Match(*Context, *http.Request) (*Context, Handler)
+}
+
+////////////////////////////////////////////////////////////////////////////
+///												RADIX 																				 ///
+////////////////////////////////////////////////////////////////////////////
+
+var _ RegisterMatcher = (*radixMatcher)(nil)
+
+type radixMatcher struct {
+	trees map[string]*node
+}
+
+func newRadixMatcher() *radixMatcher {
+	r := &radixMatcher{
+		trees: make(map[string]*node),
+	}
+	return r
+}
+
+func (d *radixMatcher) Register(method, pattern string, handler Handler) {
+	if len(pattern) == 0 || pattern[0] != '/' {
+		panic("path must begin with '/' in path '" + pattern + "'")
+	}
+
+	if d.trees == nil {
+		d.trees = make(map[string]*node)
+	}
+
+	root := d.trees[method]
+	if root == nil {
+		root = &node{}
+		d.trees[method] = root
+	}
+	root.addRoute(pattern, handler)
+}
+
+func (d *radixMatcher) Match(c *Context, r *http.Request) (*Context, Handler) {
+	if root, ok := d.trees[r.Method]; ok {
+		n, c := root.findNode(c, cleanPath(r.URL.Path))
+		if n == nil {
+			return c, nil
+		}
+		return c, n.handler
+	}
+	return c, nil
+}
diff --git a/middlewares.go b/middlewares.go
new file mode 100644
index 0000000..a03ac2f
--- /dev/null
+++ b/middlewares.go
@@ -0,0 +1,331 @@
+package lion
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"path"
+	"runtime"
+	"strings"
+	"time"
+
+	"github.com/fatih/color"
+
+	"golang.org/x/net/context"
+)
+
+var red = color.New(color.FgRed).SprintFunc()
+var yellow = color.New(color.FgYellow).SprintFunc()
+var magenta = color.New(color.FgHiMagenta).SprintFunc()
+var blue = color.New(color.FgBlue).SprintFunc()
+var green = color.New(color.FgGreen).SprintFunc()
+var cyan = color.New(color.FgCyan).SprintFunc()
+var hiBlue = color.New(color.FgHiBlue).SprintFunc()
+var lionColor = color.New(color.Italic, color.FgHiGreen).SprintFunc()
+
+// Classic creates a new router with some handy middlewares.
+func Classic() *Router {
+	return New(NewRecovery(), RealIP(), NewLogger(), NewStatic(http.Dir("public")))
+}
+
+var lionLogger = log.New(os.Stdout, lionColor("[lion]")+" ", log.Ldate|log.Ltime)
+
+// Logger is a middlewares that logs incomming http requests
+type Logger struct {
+	*log.Logger
+}
+
+// NewLogger creates a new Logger
+func NewLogger() *Logger {
+	return &Logger{
+		Logger: lionLogger,
+	}
+}
+
+// ServeNext implements the Middleware interface for Logger.
+// It wraps the corresponding http.ResponseWriter and saves statistics about the status code returned, the number of bytes written and the time that requests took.
+func (l *Logger) ServeNext(next Handler) Handler {
+
+	return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+
+		res := WrapResponseWriter(w)
+		start := time.Now()
+
+		next.ServeHTTPC(c, res, r)
+
+		l.Printf("%s %s | %s | %dB in %v from %s", magenta(r.Method), hiBlue(r.URL.Path), statusColor(res.Status()), res.BytesWritten(), timeColor(time.Since(start)), r.RemoteAddr)
+	})
+}
+
+func statusColor(status int) string {
+	msg := fmt.Sprintf("%d %s", status, http.StatusText(status))
+	switch {
+	case status < 200:
+		return blue(msg)
+	case status < 300:
+		return green(msg)
+	case status < 400:
+		return cyan(msg)
+	case status < 500:
+		return yellow(msg)
+	default:
+		return red(msg)
+	}
+}
+
+func timeColor(dur time.Duration) string {
+	switch {
+	case dur < 500*time.Millisecond:
+		return green(dur)
+	case dur < 5*time.Second:
+		return yellow(dur)
+	default:
+		return red(dur)
+	}
+}
+
+// Recovery is a middleware that recovers from panics
+// Taken from https://github.com/codegangsta/negroni/blob/master/recovery.go
+type Recovery struct {
+	Logger     *log.Logger
+	PrintStack bool
+	StackAll   bool
+	StackSize  int
+}
+
+// NewRecovery creates a new Recovery instance
+func NewRecovery() *Recovery {
+	return &Recovery{
+		Logger:     lionLogger,
+		PrintStack: false,
+		StackAll:   false,
+		StackSize:  1024 * 8,
+	}
+}
+
+// ServeNext is the method responsible for recovering from a panic
+func (rec *Recovery) ServeNext(next Handler) Handler {
+	return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		defer func() {
+			if err := recover(); err != nil {
+				w.WriteHeader(http.StatusInternalServerError)
+				stack := make([]byte, rec.StackSize)
+				stack = stack[:runtime.Stack(stack, rec.StackAll)]
+
+				f := "PANIC: %s\n%s"
+				rec.Logger.Printf(f, err, stack)
+
+				if rec.PrintStack {
+					fmt.Fprintf(w, f, err, stack)
+				}
+
+			}
+		}()
+
+		next.ServeHTTPC(c, w, r)
+	})
+}
+
+func defaultPanicHandler() Handler {
+	return HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
+		log.Println(fmt.Sprintf("%v", ctx.Value("panic")))
+		http.Error(w, fmt.Sprintf("%v", ctx.Value("panic")), http.StatusInternalServerError)
+	})
+}
+
+// Static is a middleware handler that serves static files in the given directory/filesystem.
+// Taken from https://github.com/codegangsta/negroni/blob/master/static.go
+type Static struct {
+	// Dir is the directory to serve static files from
+	Dir http.FileSystem
+	// Prefix is the optional prefix used to serve the static directory content
+	Prefix string
+	// IndexFile defines which file to serve as index if it exists.
+	IndexFile string
+}
+
+// NewStatic returns a new instance of Static
+func NewStatic(directory http.FileSystem) *Static {
+	return &Static{
+		Dir:       directory,
+		Prefix:    "",
+		IndexFile: "index.html",
+	}
+}
+
+// ServeNext tries to find a file in the directory
+func (s *Static) ServeNext(next Handler) Handler {
+	return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+
+		if r.Method != "GET" && r.Method != "HEAD" {
+			next.ServeHTTPC(c, w, r)
+			return
+		}
+
+		file := r.URL.Path
+		// if we have a prefix, filter requests by stripping the prefix
+		if s.Prefix != "" {
+			if !strings.HasPrefix(file, s.Prefix) {
+				next.ServeHTTPC(c, w, r)
+				return
+			}
+			file = file[len(s.Prefix):]
+			if file != "" && file[0] != '/' {
+				next.ServeHTTPC(c, w, r)
+				return
+			}
+		}
+		f, err := s.Dir.Open(file)
+		if err != nil {
+			// discard the error?
+			next.ServeHTTPC(c, w, r)
+			return
+		}
+		defer f.Close()
+
+		fi, err := f.Stat()
+		if err != nil {
+			next.ServeHTTPC(c, w, r)
+			return
+		}
+
+		// try to serve index file
+		if fi.IsDir() {
+			// redirect if missing trailing slash
+			if !strings.HasSuffix(r.URL.Path, "/") {
+				http.Redirect(w, r, r.URL.Path+"/", http.StatusFound)
+				return
+			}
+
+			file = path.Join(file, s.IndexFile)
+			f, err = s.Dir.Open(file)
+			if err != nil {
+				next.ServeHTTPC(c, w, r)
+				return
+			}
+			defer f.Close()
+
+			fi, err = f.Stat()
+			if err != nil || fi.IsDir() {
+				next.ServeHTTPC(c, w, r)
+				return
+			}
+		}
+
+		http.ServeContent(w, r, file, fi.ModTime(), f)
+	})
+}
+
+// MaxAge is a middleware that defines the max duration headers
+func MaxAge(dur time.Duration) Middleware {
+	return MaxAgeWithFilter(dur, func(c context.Context, w http.ResponseWriter, r *http.Request) bool { return true })
+}
+
+// MaxAgeWithFilter is a middleware that defines the max duration headers with a filter function.
+// If the filter returns true then the headers will be set. Otherwise, if it returns false the headers will not be set.
+func MaxAgeWithFilter(dur time.Duration, filter func(c context.Context, w http.ResponseWriter, r *http.Request) bool) Middleware {
+	if filter == nil {
+		filter = func(c context.Context, w http.ResponseWriter, r *http.Request) bool { return false }
+	}
+	return MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			if !filter(c, w, r) {
+				return
+			}
+			w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d, public, must-revalidate, proxy-revalidate", int(dur.Seconds())))
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+}
+
+// NoCache middleware sets headers to disable browser caching.
+// Inspired by https://github.com/mytrile/nocache
+func NoCache() Middleware {
+	var epoch = time.Unix(0, 0).Format(time.RFC1123)
+
+	return noCache{
+		responseHeaders: map[string]string{
+			"Expires":         epoch,
+			"Cache-Control":   "no-cache, private, must-revalidate, max-age=0",
+			"Pragma":          "no-cache",
+			"X-Accel-Expires": "0",
+		},
+		etagHeaders: []string{
+			"ETag",
+			"If-Modified-Since",
+			"If-Match",
+			"If-Note-Match",
+			"If-Range",
+			"If-Unmodified-Since",
+		},
+	}
+}
+
+type noCache struct {
+	responseHeaders map[string]string
+	etagHeaders     []string
+}
+
+func (n noCache) ServeNext(next Handler) Handler {
+	return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		// Delete ETag headers
+		for _, v := range n.etagHeaders {
+			if r.Header.Get(v) != "" {
+				r.Header.Del(v)
+			}
+		}
+
+		// Add nocache headers
+		for k, v := range n.responseHeaders {
+			w.Header().Set(k, v)
+		}
+
+	})
+}
+
+var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
+var xRealIP = http.CanonicalHeaderKey("X-Real-IP")
+
+// RealIP is a middleware that sets a http.Request's RemoteAddr to the results
+// of parsing either the X-Forwarded-For header or the X-Real-IP header (in that
+// order).
+//
+// This middleware should be inserted fairly early in the middleware stack to
+// ensure that subsequent layers (e.g., request loggers) which examine the
+// RemoteAddr will see the intended value.
+//
+// You should only use this middleware if you can trust the headers passed to
+// you (in particular, the two headers this middleware uses), for example
+// because you have placed a reverse proxy like HAProxy or nginx in front of
+// Goji. If your reverse proxies are configured to pass along arbitrary header
+// values from the client, or if you use this middleware without a reverse
+// proxy, malicious clients will be able to make you very sad (or, depending on
+// how you're using RemoteAddr, vulnerable to an attack of some sort).
+// Taken from https://github.com/zenazn/goji/blob/master/web/middleware/realip.go
+func RealIP() Middleware {
+	return MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			if rip := realIP(r); rip != "" {
+				r.RemoteAddr = rip
+			}
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+}
+
+func realIP(r *http.Request) string {
+	var ip string
+
+	if xff := r.Header.Get(xForwardedFor); xff != "" {
+		i := strings.Index(xff, ", ")
+		if i == -1 {
+			i = len(xff)
+		}
+		ip = xff[:i]
+	} else if xrip := r.Header.Get(xRealIP); xrip != "" {
+		ip = xrip
+	}
+
+	return ip
+}
diff --git a/module.go b/module.go
new file mode 100644
index 0000000..65c44a1
--- /dev/null
+++ b/module.go
@@ -0,0 +1,33 @@
+package lion
+
+type Module interface {
+	Resource
+	Base() string
+	Routes(*Router)
+}
+
+type ModuleRequirements interface {
+	Requires() []string
+}
+
+func (r *Router) Module(modules ...Module) {
+	for _, m := range modules {
+		r.registerModule(m)
+	}
+}
+
+func (r *Router) registerModule(m Module) {
+	g := r.Group(m.Base())
+	if req, ok := m.(ModuleRequirements); ok {
+		for _, dep := range req.Requires() {
+			if !r.hasNamed(dep) {
+				panic("Unmet middleware requirement for " + dep)
+			}
+			g.UseNamed(dep)
+		}
+	}
+
+	g.Resource("/", m)
+
+	m.Routes(g)
+}
diff --git a/module_test.go b/module_test.go
new file mode 100644
index 0000000..b2fdc2b
--- /dev/null
+++ b/module_test.go
@@ -0,0 +1,55 @@
+package lion
+
+import (
+	"net/http"
+	"testing"
+
+	"golang.org/x/net/context"
+)
+
+type testmodule struct {
+	base string
+}
+
+func (m testmodule) Routes(r *Router) {
+
+}
+
+func (m testmodule) Base() string {
+	return m.base
+}
+
+func (m testmodule) Requires() []string {
+	return []string{"auth", "jwt"}
+}
+
+func (m testmodule) Uses() (mws Middlewares) {
+	return mws
+}
+
+func (m testmodule) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte("getmodule"))
+}
+
+func TestModule(t *testing.T) {
+	l := New()
+	l.DefineFunc("auth", func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("auth", "authmw")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+
+	l.DefineFunc("jwt", func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("token", "jwtmw")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+
+	l.Module(testmodule{"/admin"})
+
+	expectHeader(t, l, "GET", "/admin", "auth", "authmw")
+	expectHeader(t, l, "GET", "/admin", "token", "jwtmw")
+	expectBody(t, l, "GET", "/admin", "getmodule")
+}
diff --git a/resource.go b/resource.go
new file mode 100644
index 0000000..bc9e686
--- /dev/null
+++ b/resource.go
@@ -0,0 +1,97 @@
+package lion
+
+import (
+	"net/http"
+
+	"golang.org/x/net/context"
+)
+
+// Resource defines the minimum required methods
+type Resource interface{}
+
+type ResourceUses interface {
+	Uses() Middlewares
+}
+
+// GetResourceMiddlewares is an interface for defining middlewares used in Resource method
+type GetResourceMiddlewares interface {
+	GetMiddlewares() Middlewares
+}
+
+// PostResourceMiddlewares is an interface for defining middlewares used in Resource method
+type PostResourceMiddlewares interface {
+	PostMiddlewares() Middlewares
+}
+
+// PutResourceMiddlewares is an interface for defining middlewares used in Resource method
+type PutResourceMiddlewares interface {
+	PutMiddlewares() Middlewares
+}
+
+// DeleteResourceMiddlewares is an interface for defining middlewares used in Resource method
+type DeleteResourceMiddlewares interface {
+	DeleteMiddlewares() Middlewares
+}
+
+// GetResource is an interface for defining a HandlerFunc used in Resource method
+type GetResource interface {
+	Get(c context.Context, w http.ResponseWriter, r *http.Request)
+}
+
+// PostResource is an interface for defining a HandlerFunc used in Resource method
+type PostResource interface {
+	Post(c context.Context, w http.ResponseWriter, r *http.Request)
+}
+
+// PutResource is an interface for defining a HandlerFunc used in Resource method
+type PutResource interface {
+	Put(c context.Context, w http.ResponseWriter, r *http.Request)
+}
+
+// DeleteResource is an interface for defining a HandlerFunc used in Resource method
+type DeleteResource interface {
+	Delete(c context.Context, w http.ResponseWriter, r *http.Request)
+}
+
+// Resource registers a Resource with the corresponding pattern
+func (r *Router) Resource(pattern string, resource Resource) {
+	sub := r.Group(pattern)
+
+	if usesRes, ok := resource.(ResourceUses); ok {
+		if len(usesRes.Uses()) > 0 {
+			sub.Use(usesRes.Uses()...)
+		}
+	}
+
+	if res, ok := resource.(GetResource); ok {
+		s := sub.Group("/")
+		if mw, ok := resource.(GetResourceMiddlewares); ok {
+			s.Use(mw.GetMiddlewares()...)
+		}
+		s.GetFunc("/", res.Get)
+	}
+
+	if res, ok := resource.(PostResource); ok {
+		s := sub.Group("/")
+		if mw, ok := resource.(PostResourceMiddlewares); ok {
+			s.Use(mw.PostMiddlewares()...)
+		}
+		s.PostFunc("/", res.Post)
+	}
+
+	if res, ok := resource.(PutResource); ok {
+		s := sub.Group("/")
+		if mw, ok := resource.(PutResourceMiddlewares); ok {
+			s.Use(mw.PutMiddlewares()...)
+		}
+		s.PutFunc("/", res.Put)
+	}
+
+	if res, ok := resource.(DeleteResource); ok {
+		s := sub.Group("/")
+		if mw, ok := resource.(DeleteResourceMiddlewares); ok {
+			s.Use(mw.DeleteMiddlewares()...)
+		}
+		s.DeleteFunc("/", res.Delete)
+	}
+}
diff --git a/resource_test.go b/resource_test.go
new file mode 100644
index 0000000..b6a84ed
--- /dev/null
+++ b/resource_test.go
@@ -0,0 +1,85 @@
+package lion
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"golang.org/x/net/context"
+)
+
+type testResource struct{}
+
+func (tr testResource) Uses() Middlewares { return Middlewares{} }
+
+func (tr testResource) GetMiddlewares() Middlewares {
+	return Middlewares{MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("foo", "Get")
+			next.ServeHTTPC(c, w, r)
+		})
+	})}
+}
+
+func (tr testResource) PostMiddlewares() Middlewares {
+	return Middlewares{MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("foo", "Post")
+			next.ServeHTTPC(c, w, r)
+		})
+	})}
+}
+func (tr testResource) PutMiddlewares() Middlewares {
+	return Middlewares{MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("foo", "Put")
+			next.ServeHTTPC(c, w, r)
+		})
+	})}
+}
+func (tr testResource) DeleteMiddlewares() Middlewares {
+	return Middlewares{MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("foo", "Delete")
+			next.ServeHTTPC(c, w, r)
+		})
+	})}
+}
+
+func (tr testResource) Get(c context.Context, w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte("Get"))
+}
+func (tr testResource) Post(c context.Context, w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte("Post"))
+}
+func (tr testResource) Put(c context.Context, w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte("Put"))
+}
+func (tr testResource) Delete(c context.Context, w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte("Delete"))
+}
+
+func TestResources(t *testing.T) {
+	methods := []string{"GET", "POST", "PUT", "DELETE"}
+	expected := []string{"Get", "Post", "Put", "Delete"}
+	tr := testResource{}
+	// hfuncs := []HandlerFunc{tr.Get, tr.Post, tr.Put, tr.Delete}
+
+	r := New()
+	r.Resource("/testpath", tr)
+
+	for i := 0; i < len(methods); i++ {
+		w := httptest.NewRecorder()
+		req, _ := http.NewRequest(methods[i], "/testpath", nil)
+
+		r.ServeHTTP(w, req)
+
+		if w.Body.String() != expected[i] {
+			t.Errorf("[Resource] Expected body %s but got %s for http method %s", expected[i], w.Body.String(), methods[i])
+		}
+
+		if w.Header().Get("foo") != expected[i] {
+			t.Errorf("[Resource] Expected header %s but got %s for http method %s", expected[i], w.Header().Get("foo"), methods[i])
+		}
+	}
+}
diff --git a/response_writer.go b/response_writer.go
new file mode 100644
index 0000000..8c62423
--- /dev/null
+++ b/response_writer.go
@@ -0,0 +1,105 @@
+package lion
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+)
+
+// ResponseWriter is the proxy responseWriter
+type ResponseWriter interface {
+	http.ResponseWriter
+	http.Flusher
+	http.Hijacker
+	Status() int
+	BytesWritten() int
+	Tee(io.Writer)
+	Unwrap() http.ResponseWriter
+}
+
+// WrapResponseWriter wraps an http.ResponseWriter and returns a ResponseWriter
+func WrapResponseWriter(w http.ResponseWriter) ResponseWriter {
+	return &basicWriter{ResponseWriter: w}
+}
+
+var _ ResponseWriter = (*basicWriter)(nil)
+var _ http.ResponseWriter = (*basicWriter)(nil)
+
+type basicWriter struct {
+	http.ResponseWriter
+	code  int
+	bytes int
+	tee   io.Writer
+}
+
+func (b *basicWriter) Header() http.Header {
+	return b.ResponseWriter.Header()
+}
+
+func (b *basicWriter) WriteHeader(code int) {
+	if !b.Written() {
+		b.ResponseWriter.WriteHeader(code)
+		b.code = code
+	}
+}
+
+func (b *basicWriter) Write(data []byte) (int, error) {
+	if !b.Written() {
+		b.WriteHeader(http.StatusOK)
+	}
+	size, err := b.ResponseWriter.Write(data)
+	b.bytes += size
+	return size, err
+}
+
+func (b *basicWriter) Written() bool {
+	return b.Status() != 0
+}
+
+func (b *basicWriter) BytesWritten() int {
+	return b.bytes
+}
+
+func (b *basicWriter) Status() int {
+	return b.code
+}
+
+func (b *basicWriter) Tee(w io.Writer) {
+	b.tee = w
+}
+
+func (b *basicWriter) Unwrap() http.ResponseWriter {
+	return b.ResponseWriter
+}
+
+func (b *basicWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	hijacker, ok := b.ResponseWriter.(http.Hijacker)
+	if !ok {
+		return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
+	}
+	return hijacker.Hijack()
+}
+
+func (b *basicWriter) CloseNotify() <-chan bool {
+	return b.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
+
+func (b *basicWriter) Flush() {
+	fl, ok := b.ResponseWriter.(http.Flusher)
+	if ok {
+		fl.Flush()
+	}
+}
+
+func (b *basicWriter) ReadFrom(r io.Reader) (int64, error) {
+	if b.tee != nil {
+		return io.Copy(b, r)
+	}
+	rf := b.ResponseWriter.(io.ReaderFrom)
+	if !b.Written() {
+		b.ResponseWriter.WriteHeader(http.StatusOK)
+	}
+	return rf.ReadFrom(r)
+}
diff --git a/router.go b/router.go
new file mode 100644
index 0000000..c01424d
--- /dev/null
+++ b/router.go
@@ -0,0 +1,343 @@
+package lion
+
+import (
+	"fmt"
+	"net/http"
+	"os"
+	"sync"
+
+	"golang.org/x/net/context"
+)
+
+// Router is responsible for registering handlers and middlewares
+type Router struct {
+	tree *tree
+	rm   RegisterMatcher
+
+	router *Router
+
+	middlewares Middlewares
+
+	handler Handler // TODO: create a handler
+
+	pattern string
+
+	notFoundHandler Handler
+
+	registeredHandlers []registeredHandler // Used for Mount()
+
+	pool sync.Pool
+
+	namedMiddlewares map[string]Middlewares
+}
+
+// New creates a new router instance
+func New(mws ...Middleware) *Router {
+	r := &Router{
+		middlewares:      Middlewares{},
+		rm:               newRadixMatcher(),
+		namedMiddlewares: make(map[string]Middlewares),
+	}
+	r.pool.New = func() interface{} {
+		return NewContext()
+	}
+	r.router = r
+	r.Use(mws...)
+	return r
+}
+
+// Group creates a subrouter with parent pattern provided.
+func (r *Router) Group(pattern string, mws ...Middleware) *Router {
+	p := r.pattern + pattern
+	if pattern == "/" && r.pattern != "/" {
+		p = r.pattern
+	}
+	validatePattern(p)
+
+	nr := &Router{
+		router:           r,
+		rm:               r.rm,
+		pattern:          p,
+		middlewares:      Middlewares{},
+		namedMiddlewares: make(map[string]Middlewares),
+	}
+	nr.Use(mws...)
+	return nr
+}
+
+// Get registers an http GET method receiver with the provided Handler
+func (r *Router) Get(pattern string, handler Handler) {
+	r.Handle("GET", pattern, handler)
+}
+
+// Post registers an http POST method receiver with the provided Handler
+func (r *Router) Post(pattern string, handler Handler) {
+	r.Handle("POST", pattern, handler)
+}
+
+// Put registers an http PUT method receiver with the provided Handler
+func (r *Router) Put(pattern string, handler Handler) {
+	r.Handle("PUT", pattern, handler)
+}
+
+// Patch registers an http PATCH method receiver with the provided Handler
+func (r *Router) Patch(pattern string, handler Handler) {
+	r.Handle("PATCH", pattern, handler)
+}
+
+// Delete registers an http DELETE method receiver with the provided Handler
+func (r *Router) Delete(pattern string, handler Handler) {
+	r.Handle("DELETE", pattern, handler)
+}
+
+// GetFunc wraps a HandlerFunc as a Handler and registers it to the router
+func (r *Router) GetFunc(pattern string, fn HandlerFunc) {
+	r.Get(pattern, HandlerFunc(fn))
+}
+
+// PostFunc wraps a HandlerFunc as a Handler and registers it to the router
+func (r *Router) PostFunc(pattern string, fn HandlerFunc) {
+	r.Post(pattern, HandlerFunc(fn))
+}
+
+// PutFunc wraps a HandlerFunc as a Handler and registers it to the router
+func (r *Router) PutFunc(pattern string, fn HandlerFunc) {
+	r.Put(pattern, HandlerFunc(fn))
+}
+
+// PatchFunc wraps a HandlerFunc as a Handler and registers it to the router
+func (r *Router) PatchFunc(pattern string, fn HandlerFunc) {
+	r.Patch(pattern, HandlerFunc(fn))
+}
+
+// DeleteFunc wraps a HandlerFunc as a Handler and registers it to the router
+func (r *Router) DeleteFunc(pattern string, fn HandlerFunc) {
+	r.Delete(pattern, HandlerFunc(fn))
+}
+
+// Use registers middlewares to be used
+func (r *Router) Use(middlewares ...Middleware) {
+	r.middlewares = append(r.middlewares, middlewares...)
+}
+
+// UseFunc wraps a MiddlewareFunc as a Middleware and registers it middlewares to be used
+func (r *Router) UseFunc(middlewareFuncs ...MiddlewareFunc) {
+	for _, fn := range middlewareFuncs {
+		r.Use(MiddlewareFunc(fn))
+	}
+}
+
+type negroniHandler interface {
+	ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
+}
+
+type negroniHandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
+
+func (h negroniHandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+	h(rw, r, next)
+}
+
+func (r *Router) UseNegroni(n negroniHandler) {
+	r.Use(MiddlewareFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			n.ServeHTTP(w, r, HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) {
+				next.ServeHTTPC(c, w, r)
+			}).ServeHTTP)
+		})
+	}))
+}
+
+func (r *Router) UseNegroniFunc(n func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
+	r.UseNegroni(negroniHandlerFunc(n))
+}
+
+// UseHandler uses
+func (r *Router) UseHandler(handler Handler) {
+	r.UseFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			handler.ServeHTTPC(c, w, r)
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+}
+
+// UseHandlerFunc uses
+func (r *Router) UseHandlerFunc(fn HandlerFunc) {
+	r.UseHandler(HandlerFunc(fn))
+}
+
+// Handle is the underling method responsible for registering a handler for a specific method and pattern.
+func (r *Router) Handle(method, pattern string, handler Handler) {
+	validatePattern(pattern)
+
+	var p string
+	if !r.isRoot() && pattern == "/" {
+		p = r.pattern
+	} else {
+		p = r.pattern + pattern
+	}
+
+	built := r.buildMiddlewares(handler)
+	r.registeredHandlers = append(r.registeredHandlers, registeredHandler{method, pattern, built})
+	r.router.rm.Register(method, p, built)
+}
+
+type registeredHandler struct {
+	method, pattern string
+	handler         Handler
+}
+
+// Mount mounts a subrouter at the provided pattern
+func (r *Router) Mount(pattern string, router *Router, mws ...Middleware) {
+	sub := r.Group(pattern, mws...)
+	for _, rh := range router.registeredHandlers {
+		sub.Handle(rh.method, rh.pattern, rh.handler)
+	}
+}
+
+func (r *Router) buildMiddlewares(handler Handler) Handler {
+	handler = r.middlewares.BuildHandler(handler)
+	if !r.isRoot() {
+		handler = r.router.buildMiddlewares(handler)
+	}
+	return handler
+}
+
+func (r *Router) isRoot() bool {
+	return r.router == r
+}
+
+// HandleFunc wraps a HandlerFunc and pass it to Handle method
+func (r *Router) HandleFunc(method, pattern string, fn HandlerFunc) {
+	r.Handle(method, pattern, HandlerFunc(fn))
+}
+
+// ServeHTTP calls ServeHTTPC with a context.Background()
+func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	r.ServeHTTPC(context.TODO(), w, req)
+}
+
+// ServeHTTPC finds the handler associated with the request's path.
+// If it is not found it calls the NotFound handler
+func (r *Router) ServeHTTPC(c context.Context, w http.ResponseWriter, req *http.Request) {
+	ctx := r.pool.Get().(*Context)
+	ctx.parent = c
+
+	if ctx, h := r.router.rm.Match(ctx, req); h != nil {
+		h.ServeHTTPC(ctx, w, req)
+	} else {
+		r.notFound(ctx, w, req) // r.middlewares.BuildHandler(HandlerFunc(r.NotFound)).ServeHTTPC
+	}
+
+	ctx.reset()
+	r.pool.Put(ctx)
+}
+
+// NotFound calls NotFoundHandler() if it is set. Otherwise, it calls net/http.NotFound
+func (r *Router) notFound(c context.Context, w http.ResponseWriter, req *http.Request) {
+	if r.router.notFoundHandler != nil {
+		r.router.notFoundHandler.ServeHTTPC(c, w, req)
+	} else {
+		http.NotFound(w, req)
+	}
+}
+
+func (r *Router) NotFoundHandler(handler Handler) {
+	r.notFoundHandler = handler
+}
+
+// ServeFiles serves files located in root http.FileSystem
+//
+// This can be used as shown below:
+// 	r := New()
+// 	r.ServeFiles("/static", http.Dir("static")) // This will serve files in the directory static with /static prefix
+func (r *Router) ServeFiles(path string, root http.FileSystem) {
+	fileServer := http.FileServer(root)
+	r.Get(path, HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		fmt.Println("rurl", r.URL.Path)
+		fileServer.ServeHTTP(w, r)
+	}))
+}
+
+// GetH wraps a http.Handler
+func (r *Router) GetH(pattern string, handler http.Handler) {
+	r.Get(pattern, Wrap(handler))
+}
+
+// PostH wraps a http.Handler
+func (r *Router) PostH(pattern string, handler http.Handler) {
+	r.Post(pattern, Wrap(handler))
+}
+
+// PutH wraps a http.Handler
+func (r *Router) PutH(pattern string, handler http.Handler) {
+	r.Put(pattern, Wrap(handler))
+}
+
+// DeleteH wraps a http.Handler
+func (r *Router) DeleteH(pattern string, handler http.Handler) {
+	r.Delete(pattern, Wrap(handler))
+}
+
+// Run calls http.ListenAndServe for the current router.
+// If no addresses are specified as arguments, it will use the PORT environnement variable if it is defined. Otherwise, it will listen on port 3000 of the localmachine
+//
+// 	r := New()
+// 	r.Run() // will call
+// 	r.Run(":8080")
+func (r *Router) Run(addr ...string) {
+	var a string
+
+	if len(addr) == 0 {
+		if p := os.Getenv("PORT"); p != "" {
+			a = p
+		} else {
+			a = ":3000"
+		}
+	} else {
+		a = addr[0]
+	}
+
+	lionLogger.Printf("listening on %s", a)
+	lionLogger.Fatal(http.ListenAndServe(a, r))
+}
+
+// RunTLS calls http.ListenAndServeTLS for the current router
+//
+// 	r := New()
+// 	r.RunTLS(":3443", "cert.pem", "key.pem")
+func (r *Router) RunTLS(addr, certFile, keyFile string) {
+	lionLogger.Printf("listening on %s", addr)
+	lionLogger.Fatal(http.ListenAndServeTLS(addr, certFile, keyFile, r))
+}
+
+func (r *Router) Define(name string, mws ...Middleware) {
+	r.namedMiddlewares[name] = append(r.namedMiddlewares[name], mws...)
+}
+
+func (r *Router) DefineFunc(name string, mws ...MiddlewareFunc) {
+	for _, mw := range mws {
+		r.Define(name, mw)
+	}
+}
+
+func (r *Router) UseNamed(name string) {
+	if r.hasNamed(name) { // Find if it this is registered in the current router
+		r.Use(r.namedMiddlewares[name]...)
+	} else if !r.isRoot() { // Otherwise, look for it in parent router.
+		r.router.UseNamed(name)
+	} else { // not found
+		panic("Unknow named middlewares: " + name)
+	}
+}
+
+func (r *Router) hasNamed(name string) bool {
+	_, exist := r.namedMiddlewares[name]
+	return exist
+}
+
+func validatePattern(pattern string) {
+	if len(pattern) > 0 && pattern[0] != '/' {
+		panic("path must start with '/' in path '" + pattern + "'")
+	}
+}
diff --git a/router_test.go b/router_test.go
new file mode 100644
index 0000000..57ceb5a
--- /dev/null
+++ b/router_test.go
@@ -0,0 +1,347 @@
+package lion
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"golang.org/x/net/context"
+)
+
+var (
+	emptyParams = map[string]string{}
+)
+
+func TestRouteMatching(t *testing.T) {
+	helloHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	helloNameHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	helloNameTweetsHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	helloNameGetTweetHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	cartsHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	getCartHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	helloContactHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	helloContactByPersonHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	extensionHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	usernameHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+	wildcardHandler := HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {})
+
+	routes := []struct {
+		Method  string
+		Pattern string
+		Handler Handler
+	}{
+		{
+			Method:  "GET",
+			Pattern: "/hello",
+			Handler: helloHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/hello/contact",
+			Handler: helloContactHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/hello/:name",
+			Handler: helloNameHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/hello/:name/tweets",
+			Handler: helloNameTweetsHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/hello/:name/tweets/:id",
+			Handler: helloNameGetTweetHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/carts",
+			Handler: cartsHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/carts/:cartid",
+			Handler: getCartHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/hello/contact/:dest",
+			Handler: helloContactByPersonHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/extension/:file.:ext",
+			Handler: extensionHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/@:username",
+			Handler: usernameHandler,
+		},
+		{
+			Method:  "GET",
+			Pattern: "/*",
+			Handler: wildcardHandler,
+		},
+	}
+
+	tests := []struct {
+		Input           string
+		ExpectedHandler Handler
+		ExpectedParams  map[string]string
+	}{
+		{
+			Input:           "/hello",
+			ExpectedHandler: helloHandler,
+			ExpectedParams:  emptyParams,
+		},
+		{
+			Input:           "/hello/batman",
+			ExpectedHandler: helloNameHandler,
+			ExpectedParams:  map[string]string{"name": "batman"},
+		},
+		{
+			Input:           "/hello/dot.inthemiddle",
+			ExpectedHandler: helloNameHandler,
+			ExpectedParams:  map[string]string{"name": "dot.inthemiddle"},
+		},
+		{
+			Input:           "/hello/batman/tweets",
+			ExpectedHandler: helloNameTweetsHandler,
+			ExpectedParams:  map[string]string{"name": "batman"},
+		},
+		{
+			Input:           "/hello/batman/tweets/123",
+			ExpectedHandler: helloNameGetTweetHandler,
+			ExpectedParams:  map[string]string{"name": "batman", "id": "123"},
+		},
+		{
+			Input:           "/carts",
+			ExpectedHandler: cartsHandler,
+			ExpectedParams:  emptyParams,
+		},
+		{
+			Input:           "/carts/123456",
+			ExpectedHandler: getCartHandler,
+			ExpectedParams:  map[string]string{"cartid": "123456"},
+		},
+		{
+			Input:           "/hello/contact",
+			ExpectedHandler: helloContactHandler,
+			ExpectedParams:  emptyParams,
+		},
+		{
+			Input:           "/hello/contact/batman",
+			ExpectedHandler: helloContactByPersonHandler,
+			ExpectedParams:  map[string]string{"dest": "batman"},
+		},
+		{
+			Input:           "/extension/batman.jpg",
+			ExpectedHandler: extensionHandler,
+			ExpectedParams:  map[string]string{"file": "batman", "ext": "jpg"},
+		},
+		{
+			Input:           "/@celrenheit",
+			ExpectedHandler: usernameHandler,
+			ExpectedParams:  map[string]string{"username": "celrenheit"},
+		},
+		{
+			Input:           "/unkownpath/subfolder",
+			ExpectedHandler: wildcardHandler,
+			ExpectedParams:  map[string]string{"*": "unkownpath/subfolder"},
+		},
+	}
+
+	mux := New()
+	for _, r := range routes {
+		mux.Handle(r.Method, r.Pattern, r.Handler)
+	}
+
+	for _, test := range tests {
+		req, _ := http.NewRequest("GET", test.Input, nil)
+
+		c, h := mux.rm.Match(&Context{
+			parent: context.TODO(),
+		}, req)
+
+		// Compare params
+		for k, v := range test.ExpectedParams {
+			assert.NotNil(t, c.Value(k))
+			actual := c.Value(k).(string)
+			if actual != v {
+				t.Errorf("Expected %s but got %s for url: %s", green(v), red(actual), test.Input)
+			}
+		}
+
+		// Compare handlers
+		if fmt.Sprintf("%v", h) != fmt.Sprintf("%v", test.ExpectedHandler) {
+			t.Errorf("Handler not match for %s", test.Input)
+		}
+
+		w := httptest.NewRecorder()
+
+		mux.ServeHTTP(w, req)
+
+		// Compare response code
+		if w.Code != http.StatusOK {
+			t.Errorf("Response should be 200 OK for %s", test.Input)
+		}
+	}
+}
+
+type testmw struct{}
+
+func (m testmw) ServeNext(next Handler) Handler {
+	return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Test-Key", "Test-Value")
+		next.ServeHTTPC(c, w, r)
+	})
+}
+
+func TestMiddleware(t *testing.T) {
+	mux := New()
+	mux.Use(testmw{})
+	mux.Get("/hi", HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("Hi!"))
+	}))
+
+	expectHeader(t, mux, "GET", "/hi", "Test-Key", "Test-Value")
+}
+
+func TestMiddlewareFunc(t *testing.T) {
+	mux := New()
+	mux.UseFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Test-Key", "Test-Value")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+	mux.Get("/hi", HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("Hi!"))
+	}))
+
+	expectHeader(t, mux, "GET", "/hi", "Test-Key", "Test-Value")
+}
+
+func TestMiddlewareChain(t *testing.T) {
+	mux := New()
+	mux.UseFunc(func(next Handler) Handler {
+		return nil
+	})
+}
+
+func TestMountingSubrouter(t *testing.T) {
+	mux := New()
+
+	adminrouter := New()
+	adminrouter.GetFunc("/:id", func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("admin", "id")
+	})
+
+	mux.Mount("/admin", adminrouter)
+
+	expectHeader(t, mux, "GET", "/admin/123", "admin", "id")
+}
+
+func TestGroupSubGroup(t *testing.T) {
+	s := New()
+
+	admin := s.Group("/admin")
+	sub := admin.Group("/")
+	sub.UseFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Test-Key", "Get")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+
+	sub.GetFunc("/", func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("Get"))
+	})
+
+	sub2 := admin.Group("/")
+	sub2.UseFunc(func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Test-Key", "Put")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+
+	sub2.PutFunc("/", func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("Put"))
+	})
+
+	expectHeader(t, s, "GET", "/admin", "Test-Key", "Get")
+	expectHeader(t, s, "PUT", "/admin", "Test-Key", "Put")
+}
+
+func TestNamedMiddlewares(t *testing.T) {
+	l := New()
+	l.DefineFunc("admin", func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Test-Key", "admin")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+
+	l.DefineFunc("public", func(next Handler) Handler {
+		return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Test-Key", "public")
+			next.ServeHTTPC(c, w, r)
+		})
+	})
+
+	g := l.Group("/admin")
+	g.UseNamed("admin")
+	g.GetFunc("/test", func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("admintest"))
+	})
+
+	p := l.Group("/public")
+	p.UseNamed("public")
+	p.GetFunc("/test", func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("publictest"))
+	})
+
+	expectHeader(t, l, "GET", "/admin/test", "Test-Key", "admin")
+	expectHeader(t, l, "GET", "/public/test", "Test-Key", "public")
+	expectBody(t, l, "GET", "/admin/test", "admintest")
+	expectBody(t, l, "GET", "/public/test", "publictest")
+}
+
+func TestEmptyRouter(t *testing.T) {
+	l := New()
+	expectStatus(t, l, "GET", "/", http.StatusNotFound)
+}
+
+func expectStatus(t *testing.T, mux http.Handler, method, path string, status int) {
+	req, _ := http.NewRequest(method, path, nil)
+	w := httptest.NewRecorder()
+	mux.ServeHTTP(w, req)
+	if w.Code != status {
+		t.Errorf("Expected status code to be %d but got %d for request: %s %s", status, w.Code, method, path)
+	}
+}
+
+func expectHeader(t *testing.T, mux http.Handler, method, path, k, v string) {
+	req, _ := http.NewRequest(method, path, nil)
+	w := httptest.NewRecorder()
+	mux.ServeHTTP(w, req)
+	if w.Header().Get(k) != v {
+		t.Errorf("Expected header to be %s but got %s for request: %s %s", v, w.Header().Get(k), method, path)
+	}
+}
+
+func expectBody(t *testing.T, mux http.Handler, method, path, v string) {
+	req, _ := http.NewRequest(method, path, nil)
+	w := httptest.NewRecorder()
+	mux.ServeHTTP(w, req)
+	if w.Body.String() != v {
+		t.Errorf("Expected body to be %s but got %s for request: %s %s", v, w.Body.String(), method, path)
+	}
+}
diff --git a/tree.go b/tree.go
new file mode 100644
index 0000000..c538e51
--- /dev/null
+++ b/tree.go
@@ -0,0 +1,324 @@
+package lion
+
+import (
+	"sort"
+	"strings"
+)
+
+type nodeType uint8
+
+const (
+	static   nodeType = iota // /hello
+	regexp                   // TODO: /:id(regex)
+	param                    // /:id
+	wildcard                 // *
+)
+
+type tree struct {
+	subtrees map[string]*node
+}
+
+func newTree() *tree {
+	return &tree{
+		subtrees: make(map[string]*node),
+	}
+}
+
+func (t *tree) addRoute(method, pattern string, handler Handler) {
+	root := t.subtrees[method]
+	if root == nil {
+		root = &node{}
+		t.subtrees[method] = root
+	}
+	root.addRoute(pattern, handler)
+}
+
+type node struct {
+	nodeType    nodeType
+	pattern     string
+	handler     Handler
+	children    typesToNodes
+	label       byte
+	endinglabel byte
+}
+
+func (n *node) isLeaf() bool {
+	return n.handler != nil
+}
+
+func (n *node) addRoute(pattern string, handler Handler) {
+	search := pattern
+
+	if len(search) == 0 {
+		n.handler = handler
+		return
+	}
+	child := n.getEdge(search[0])
+	if child == nil {
+		child = &node{
+			label:   search[0],
+			pattern: search,
+			handler: handler,
+		}
+		n.addChild(child)
+		return
+	}
+
+	if child.nodeType > static {
+		pos := stringsIndex(search, '/')
+		if pos < 0 {
+			pos = len(search)
+		}
+
+		search = search[pos:]
+
+		child.addRoute(search, handler)
+		return
+	}
+
+	commonPrefix := child.longestPrefix(search)
+	if commonPrefix == len(child.pattern) {
+
+		search = search[commonPrefix:]
+
+		child.addRoute(search, handler)
+		return
+	}
+
+	subchild := &node{
+		nodeType: static,
+		pattern:  search[:commonPrefix],
+	}
+
+	n.replaceChild(search[0], subchild)
+	c2 := child
+	c2.label = child.pattern[commonPrefix]
+	subchild.addChild(c2)
+	child.pattern = child.pattern[commonPrefix:]
+
+	search = search[commonPrefix:]
+	if len(search) == 0 {
+		subchild.handler = handler
+		return
+	}
+
+	subchild.addChild(&node{
+		label:    search[0],
+		nodeType: static,
+		pattern:  search,
+		handler:  handler,
+	})
+	return
+}
+
+func (n *node) getEdge(label byte) *node {
+	for _, nds := range n.children {
+		for _, n := range nds {
+			if n.label == label {
+				return n
+			}
+		}
+	}
+
+	return nil
+}
+
+func (n *node) replaceChild(label byte, child *node) {
+	for i := 0; i < len(n.children[child.nodeType]); i++ {
+		if n.children[child.nodeType][i].label == label {
+			n.children[child.nodeType][i] = child
+			n.children[child.nodeType][i].label = label
+			return
+		}
+	}
+
+	panic("cannot replace child")
+}
+
+func (n *node) findNode(c *Context, path string) (*node, *Context) {
+	root := n
+	search := path
+
+LOOP:
+	for {
+
+		if len(search) == 0 {
+			break
+		}
+
+		l := len(root.children)
+		for i := 0; i < l; i++ {
+			t := nodeType(i)
+
+			if len(root.children[i]) == 0 {
+				continue
+			}
+
+			var label byte
+			if len(search) > 0 {
+				label = search[0]
+			}
+
+			xn := root.findEdge(nodeType(t), label)
+			if xn == nil {
+				continue
+			}
+
+			xsearch := search
+			if xn.nodeType > static {
+				p := -1
+				if xn.nodeType < wildcard {
+					// To match or not match . in path
+					chars := "/"
+					if xn.endinglabel == '.' {
+						chars += "."
+					}
+					p = stringsIndexAny(xsearch, chars)
+				}
+
+				if p < 0 {
+					p = len(xsearch)
+				}
+
+				if xn.nodeType == wildcard {
+					c.addParam("*", xsearch)
+				} else {
+					c.addParam(xn.pattern[1:], xsearch[:p])
+				}
+
+				xsearch = xsearch[p:]
+			} else if strings.HasPrefix(xsearch, xn.pattern) {
+				xsearch = xsearch[len(xn.pattern):]
+			} else {
+				continue
+			}
+
+			if len(xsearch) == 0 && xn.isLeaf() {
+				return xn, c
+			}
+
+			root = xn
+			search = xsearch
+			continue LOOP // Search for next node (xn)
+		}
+
+		break
+	}
+
+	return nil, c
+}
+
+func (n *node) findEdge(ndtype nodeType, label byte) *node {
+	nds := n.children[ndtype]
+	l := len(nds)
+	idx := 0
+
+LOOP:
+	for ; idx < l; idx++ {
+		switch ndtype {
+		case static:
+			if nds[idx].label >= label {
+				break LOOP
+			}
+		default:
+			break LOOP
+		}
+	}
+
+	if idx >= l {
+		return nil
+	}
+	node := nds[idx]
+	if node.nodeType == static && node.label == label {
+		return node
+	} else if node.nodeType > static {
+		return node
+	}
+	return nil
+}
+
+func (n *node) isEdge() bool {
+	return n.label != 0
+}
+
+func (n *node) longestPrefix(pattern string) int {
+	return longestPrefix(n.pattern, pattern)
+}
+
+func (n *node) addChild(child *node) {
+	search := child.pattern
+
+	pos := stringsIndexAny(search, ":*")
+
+	ndtype := static
+	if pos >= 0 {
+		switch search[pos] {
+		case ':':
+			ndtype = param
+		case '*':
+			ndtype = wildcard
+		}
+	}
+
+	switch {
+	case pos == 0: // Pattern starts with wildcard
+		l := len(search)
+		handler := child.handler
+		child.nodeType = ndtype
+		if ndtype == wildcard {
+			pos = -1
+		} else {
+			pos = stringsIndexAny(search, "./")
+		}
+		if pos < 0 {
+			pos = l
+		} else {
+			child.endinglabel = search[pos]
+		}
+
+		child.pattern = search[:pos]
+
+		if pos != l {
+			child.handler = nil
+
+			search = search[pos:]
+			subchild := &node{
+				label:    search[0],
+				pattern:  search,
+				nodeType: static,
+				handler:  handler,
+			}
+			child.addChild(subchild)
+		}
+
+	case pos > 0: // Pattern has a wildcard parameter
+		handler := child.handler
+
+		child.nodeType = static
+		child.pattern = search[:pos]
+		child.handler = nil
+
+		search = search[pos:]
+		subchild := &node{
+			label:    search[0],
+			nodeType: ndtype,
+			pattern:  search,
+			handler:  handler,
+		}
+		child.addChild(subchild)
+	default: // all static
+		child.nodeType = ndtype
+	}
+
+	n.children[child.nodeType] = append(n.children[child.nodeType], child)
+	n.children[child.nodeType].Sort()
+}
+
+type nodes []*node
+
+func (ns nodes) Len() int           { return len(ns) }
+func (ns nodes) Less(i, j int) bool { return ns[i].label < ns[j].label }
+func (ns nodes) Swap(i, j int)      { ns[i], ns[j] = ns[j], ns[i] }
+func (ns nodes) Sort()              { sort.Sort(ns) }
+
+type typesToNodes [wildcard + 1]nodes
diff --git a/utils.go b/utils.go
new file mode 100644
index 0000000..14cedf3
--- /dev/null
+++ b/utils.go
@@ -0,0 +1,100 @@
+package lion
+
+import (
+	"net/http"
+	"path"
+
+	"golang.org/x/net/context"
+)
+
+func min(a, b int) int {
+	if a <= b {
+		return a
+	}
+	return b
+}
+
+func longestPrefix(s1, s2 string) int {
+	max := min(len(s1), len(s2))
+	i := 0
+	for i < max && s1[i] == s2[i] {
+		i++
+	}
+	return i
+}
+
+// Wrap converts an http.Handler to returns a Handler
+func Wrap(h http.Handler) Handler {
+	return HandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
+		h.ServeHTTP(w, r)
+	})
+}
+
+// WrapFunc converts an http.HandlerFunc to return a Handler
+func WrapFunc(fn http.HandlerFunc) Handler {
+	return Wrap(http.HandlerFunc(fn))
+}
+
+// UnWrap converts a Handler to an http.Handler
+func UnWrap(h Handler) http.Handler {
+	return HandlerFunc(h.ServeHTTPC)
+}
+
+func stringsIndexAny(str, chars string) int {
+	ls := len(str)
+	lc := len(chars)
+
+	for i := 0; i < ls; i++ {
+		s := str[i]
+		for j := 0; j < lc; j++ {
+			if s == chars[j] {
+				return i
+			}
+		}
+	}
+	return -1
+}
+
+func stringsIndex(str string, char byte) int {
+	ls := len(str)
+
+	for i := 0; i < ls; i++ {
+		if str[i] == char {
+			return i
+		}
+	}
+	return -1
+}
+
+func stringsHasPrefix(str, prefix string) bool {
+	// ls := len(str)
+	sl := len(str)
+	pl := len(prefix)
+	if sl < pl {
+		return false
+	}
+	i := 0
+	for ; i < pl; i++ {
+		if str[i] != prefix[i] {
+			break
+		}
+	}
+	if i == pl {
+		return true
+	}
+	return false
+}
+
+func cleanPath(p string) string {
+	if p == "" {
+		return "/"
+	}
+	if p[0] != '/' {
+		p = "/" + p
+	}
+	newpath := path.Clean(p)
+	if newpath != "/" && p[len(p)-1] == '/' {
+		return newpath + "/"
+	}
+	return newpath
+}
