From d837381b167e94e0d84bb184770ad3fac01f477c Mon Sep 17 00:00:00 2001
From: Makis Maropoulos <makis@ideopod.com>
Date: Tue, 14 Jun 2016 08:45:40 +0300
Subject: [PATCH] Update to 3.0.0-rc.1 - Read the HISTORY.md. Relative: #183
 #184 #166 #176 #181

Read https://github.com/kataras/iris/tree/master/HISTORY.md
---
 HISTORY.md                              |  153 +++
 README.md                               |   13 +-
 bindings/errors.go                      |   14 -
 bindings/form.go                        |  420 -------
 bindings/json.go                        |   25 -
 bindings/xml.go                         |   23 -
 branch.go                               |  457 --------
 config/iris.go                          |   81 +-
 config/server.go                        |    4 +-
 config/websocket.go                     |   12 +-
 context.go                              |  676 ++++++++++-
 context/context.go                      |   19 +-
 context_renderer.go                     |  203 ----
 context_request.go                      |  139 ---
 context_response.go                     |   55 -
 context_storage.go                      |  157 ---
 errors.go                               |   44 -
 errors/error.go                         |    4 +-
 graceful/graceful.go                    |   30 +-
 handler.go                              |  119 --
 http.go                                 | 1303 +++++++++++++++++++++
 httperror.go                            |  228 ----
 initiatory.go                           |  193 ++++
 iris.go                                 | 1379 +++++++++++++++++++----
 iris_singleton.go                       |  412 -------
 logger/logger.go                        |   12 +-
 mail/service.go                         |   56 +-
 middleware/basicauth/basicauth.go       |    2 +-
 middleware/logger/logger.go             |   36 +-
 npm/npm.go                              |  123 --
 party.go                                |  642 -----------
 plugin.go                               |  376 +++---
 plugin/editor/README.md                 |    2 +-
 plugin/editor/editor.go                 |   14 +-
 plugin/iriscontrol/README.md            |    3 +-
 plugin/iriscontrol/control_panel.go     |   26 +-
 plugin/iriscontrol/index.go             |    6 +-
 plugin/iriscontrol/iriscontrol.go       |   35 +-
 plugin/iriscontrol/main_controls.go     |   10 +-
 plugin/routesinfo/README.md             |   61 -
 plugin/routesinfo/routesinfo.go         |  151 ---
 plugin/typescript/README.md             |    2 +-
 plugin/typescript/typescript.go         |   10 +-
 render/template/engine/pongo/pongo.go   |    6 +-
 render/template/template.go             |   14 +-
 route.go                                |  280 -----
 router.go                               |  308 -----
 server/README.md                        |    6 -
 server/errors.go                        |   26 -
 server/server.go                        |  248 ----
 sessions/providers/memory/register.go   |    1 -
 sessions/sessions.go                    |    7 +-
 tests/httperror_test.go                 |   17 +-
 tests/party_test.go                     |   53 +
 tests/{router_test.go => route_test.go} |   10 +-
 tree.go                                 |  145 ---
 utils/README.md                         |    2 +-
 websocket/server.go                     |   12 +-
 websocket/websocket.go                  |   34 +-
 59 files changed, 3972 insertions(+), 4927 deletions(-)
 delete mode 100644 bindings/errors.go
 delete mode 100644 bindings/form.go
 delete mode 100644 bindings/json.go
 delete mode 100644 bindings/xml.go
 delete mode 100644 branch.go
 delete mode 100644 context_renderer.go
 delete mode 100644 context_request.go
 delete mode 100644 context_response.go
 delete mode 100644 context_storage.go
 delete mode 100644 errors.go
 delete mode 100644 handler.go
 create mode 100644 http.go
 delete mode 100644 httperror.go
 create mode 100644 initiatory.go
 delete mode 100644 iris_singleton.go
 delete mode 100644 npm/npm.go
 delete mode 100644 party.go
 delete mode 100644 plugin/routesinfo/README.md
 delete mode 100644 plugin/routesinfo/routesinfo.go
 delete mode 100644 route.go
 delete mode 100644 router.go
 delete mode 100644 server/README.md
 delete mode 100644 server/errors.go
 delete mode 100644 server/server.go
 create mode 100644 tests/party_test.go
 rename tests/{router_test.go => route_test.go} (94%)
 delete mode 100644 tree.go

diff --git a/HISTORY.md b/HISTORY.md
index c655ef17..1606a4ce 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,158 @@
 # History
 
+## 3.0.0-beta.3, 3.0.0-beta.4 -> 3.0.0-rc.1
+
+This version took me many days because the whole framework's underline code is rewritten after many many many 'yoga'. Iris is not so small anymore, so I (tried) to organized it a little better. Note that, today, you can just go to [iris.go](https://github.com/kataras/iris/tree/master/iris.go) and [context.go](https://github.com/kataras/iris/tree/master/context/context.go) and look what functions you can use. You had some 'bugs' to subdomains, mail service, basic authentication and logger, these are fixed also, see below...
+
+All [examples](https://github.com/iris-contrib/examples) are updated, and I tested them one by one.
+
+
+Many underline changes but the public API didn't changed much, of course this is relative to the way you use this framework, because that:
+
+- Configuration changes: **0**
+
+- iris.Iris pointer -> **iris.Framework** pointer
+
+- iris.DefaultIris -> **iris.Default**
+- iris.Config() -> **iris.Config** is field now
+- iris.Websocket() -> **iris.Websocket** is field now
+- iris.Logger() -> **iris.Logger** is field now
+- iris.Plugins() -> **iris.Plugins** is field now
+- iris.Server() -> **iris.HTTPServer** is field now
+- iris.Rest() -> **REMOVED**
+
+- iris.Mail() -> **REMOVED**
+- iris.Mail().Send() -> **iris.SendMail()**
+- iris.Templates() -> **REMOVED**
+- iris.Templates().RenderString() -> **iris.TemplateString()**
+
+- iris.StaticHandlerFunc -> **iris.StaticHandler**
+- iris.URIOf() -> **iris.URL()**
+- iris.PathOf() -> **iris.Path()**
+
+- context.RenderString() returned string,error -> **context.TemplateString() returns only string, which is empty on any parse error**
+- context.WriteHTML() -> **context.HTML()**
+- context.HTML() -> **context.RenderWithStatus()**
+
+Entirely new
+
+-  -> **iris.ListenUNIX(addr string, socket os.Mode)**
+-  -> **context.MustRender, same as Render but send response 500 and logs the error on parse error**
+-  -> **context.Log(format string, a...interface{})**
+-  -> **context.PostFormMulti(name string) []string**
+-  -> **iris.Lookups() []Route**
+-  -> **iris.Lookup(routeName string) Route**
+-  -> **iris.Plugins.On(eventName string, ...func())** and fire all by **iris.Plugins.Call(eventName)**
+
+- iris.Wildcard() **REMOVED**, subdomains and dynamic(wildcard) subdomains can only be registered with **iris.Party("mysubdomain.") && iris.Party("*.")**
+
+
+Semantic change for static subdomains
+
+**1**
+
+**BEFORE** :
+```go
+apiSubdomain := iris.Party("api.mydomain.com")
+{
+//....
+}
+iris.Listen("mydomain.com:80")
+```
+
+
+**NOW** just subdomain part, no need to duplicate ourselves:
+```go
+apiSubdomain := iris.Party("api.")
+{
+//....
+}
+iris.Listen("mydomain.com:80")
+```
+**2**
+
+Before you couldn't set dynamic subdomains and normal subdomains at the same iris station, now you can.
+**NOW, this is possible**
+
+```go
+/* admin.mydomain.com,  and for other subdomains the Party(*.) */
+
+admin := iris.Party("admin.")
+{
+	// admin.mydomain.com
+	admin.Get("/", func(c *iris.Context) {
+		c.Write("INDEX FROM admin.mydomain.com")
+	})
+	// admin.mydomain.com/hey
+	admin.Get("/hey", func(c *iris.Context) {
+		c.Write("HEY FROM admin.mydomain.com/hey")
+	})
+	// admin.mydomain.com/hey2
+	admin.Get("/hey2", func(c *iris.Context) {
+		c.Write("HEY SECOND FROM admin.mydomain.com/hey")
+	})
+}
+
+// other.mydomain.com, otadsadsadsa.mydomain.com  and so on....
+dynamicSubdomains := iris.Party("*.")
+{
+	dynamicSubdomains.Get("/", dynamicSubdomainHandler)
+
+	dynamicSubdomains.Get("/something", dynamicSubdomainHandler)
+
+	dynamicSubdomains.Get("/something/:param1", dynamicSubdomainHandlerWithParam)
+}
+```
+
+Minor change for listen
+
+
+**BEFORE you could just listen to a port**
+```go
+iris.Listen("8080")
+```
+**NOW you have set a HOSTNAME:PORT**
+```go
+iris.Listen(":8080")
+```
+
+Relative issues/features:  https://github.com/kataras/iris/issues/166 , https://github.com/kataras/iris/issues/176, https://github.com/kataras/iris/issues/183,  https://github.com/kataras/iris/issues/184
+
+
+**Plugins**
+
+PreHandle and PostHandle are removed, no need to use them anymore you can take routes by **iris.Lookups()**, but add support for custom event listeners by **iris.Plugins.On("event",func(){})** and fire all callbacks by **iris.Plugins.Call("event")** .
+
+**FOR TESTERS**
+
+**BEFORE** :
+```go
+api := iris.New()
+//...
+
+api.PreListen(config.Server{ListeningAddr: ""})
+
+e := httpexpect.WithConfig(httpexpect.Config{
+	Reporter: httpexpect.NewAssertReporter(t),
+	Client:   fasthttpexpect.NewBinder(api.ServeRequest),
+})
+
+```
+
+**NOW**:
+
+```go
+api := iris.New()
+//...
+
+e := httpexpect.WithConfig(httpexpect.Config{
+	Reporter: httpexpect.NewAssertReporter(t),
+	Client:   fasthttpexpect.NewBinder(api.NoListen().Handler),
+})
+
+
+```
+
 ## 3.0.0-beta.2 -> 3.0.0-beta.3
 
 - Complete the Jade Template Engine support, {{ render }} and {{ url }} done also.
diff --git a/README.md b/README.md
index 38d2b960..9b3a112d 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
 [Travis]: http://travis-ci.org/kataras/iris
 [License Widget]: https://img.shields.io/badge/license-Apache%20License%202.0-E91E63.svg?style=flat-square
 [License]: https://github.com/kataras/iris/blob/master/LICENSE
-[Release Widget]: https://img.shields.io/badge/release-v3.0.0--beta.4-blue.svg?style=flat-square
+[Release Widget]: https://img.shields.io/badge/release-v3.0.0--rc.1-blue.svg?style=flat-square
 [Release]: https://github.com/kataras/iris/releases
 [Gitter Widget]: https://img.shields.io/badge/chat-on%20gitter-00BCD4.svg?style=flat-square
 [Gitter]: https://gitter.im/kataras/iris
@@ -18,12 +18,7 @@
 [Language]: http://golang.org
 [Platform Widget]: https://img.shields.io/badge/platform-Any--OS-gray.svg?style=flat-square
 
-The fastest backend web framework for Go, provides robust set of features.
-
-```sh
-$ which -a motivation-counter
-Stars | https://github.com/kataras/iris/stargazers
-```
+the fastest backend web framework for Go, provides robust set of features.
 
 [![Benchmark Wizzard Processing Time Horizontal Graph](https://raw.githubusercontent.com/iris-contrib/website/cf71811e6acb2f9bf1e715e25660392bf090b923/assets/benchmark_horizontal_transparent.png)](#benchmarks)
 
@@ -83,7 +78,7 @@ Docs & Community
 
 - Take a look at the [examples](https://github.com/iris-contrib/examples)
 
-
+- If for some reason your old code doesn't runs, view the [HISTORY](https://github.com//kataras/iris/tree/master/HISTORY.md)
 
 
 If you'd like to discuss this package, or ask questions about it, feel free to
@@ -123,7 +118,7 @@ Iris suggests you to use [this](https://github.com/gavv/httpexpect) new  suite t
 Versioning
 ------------
 
-Current: **v3.0.0-beta.4**
+Current: **v3.0.0-rc.1**
 >  Iris is an active project
 
 
diff --git a/bindings/errors.go b/bindings/errors.go
deleted file mode 100644
index 380fbf3e..00000000
--- a/bindings/errors.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package bindings
-
-import "github.com/kataras/iris/errors"
-
-var (
-	// ErrNoForm returns an error with message: 'Request has no any valid form'
-	ErrNoForm = errors.New("Request has no any valid form")
-	// ErrWriteJSON returns an error with message: 'Before JSON be written to the body, JSON Encoder returned an error. Trace: +specific error'
-	ErrWriteJSON = errors.New("Before JSON be written to the body, JSON Encoder returned an error. Trace: %s")
-	// ErrRenderMarshalled returns an error with message: 'Before +type Rendering, MarshalIndent retured an error. Trace: +specific error'
-	ErrRenderMarshalled = errors.New("Before +type Rendering, MarshalIndent returned an error. Trace: %s")
-	// ErrReadBody returns an error with message: 'While trying to read +type from the request body. Trace +specific error'
-	ErrReadBody = errors.New("While trying to read %s from the request body. Trace %s")
-)
diff --git a/bindings/form.go b/bindings/form.go
deleted file mode 100644
index ddbcb837..00000000
--- a/bindings/form.go
+++ /dev/null
@@ -1,420 +0,0 @@
-// Package bindings source code from https://github.com/monoculum/formame.
-package bindings
-
-import (
-	"encoding"
-	"errors"
-	"fmt"
-	"net/url"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
-
-	"github.com/kataras/iris/context"
-)
-
-const tagName = "form"
-
-// A pathMap holds the values of a map with its key and values correspondent
-type pathMap struct {
-	m reflect.Value
-
-	key   string
-	value reflect.Value
-
-	path string
-}
-
-// a pathMaps holds the values for each key
-type pathMaps []*pathMap
-
-// find find and get the value by the given key
-func (ma pathMaps) find(id reflect.Value, key string) *pathMap {
-	for _, v := range ma {
-		if v.m == id && v.key == key {
-			return v
-		}
-	}
-	return nil
-}
-
-// A decoder holds the values from form, the 'reflect' value of main struct
-// and the 'reflect' value of current path
-type decoder struct {
-	main reflect.Value
-
-	curr   reflect.Value
-	value  string
-	values []string
-
-	path  string
-	field string
-	index int
-
-	maps pathMaps
-}
-
-// Decode decodes the url.Values into a element that must be a pointer to a type provided by argument
-func Decode(vs url.Values, dst interface{}) error {
-	main := reflect.ValueOf(dst)
-	if main.Kind() != reflect.Ptr {
-		return fmt.Errorf(tagName+": the value passed for decode is not a pointer but a %v", main.Kind())
-	}
-
-	dec := &decoder{main: main.Elem()}
-
-	// iterate over the form's values and decode it
-	for k, v := range vs {
-		dec.path = k
-		dec.field = k
-		dec.values = v
-		dec.value = v[0]
-		if dec.value != "" {
-			if err := dec.begin(); err != nil {
-				return err
-			}
-		}
-	}
-	// set values of each maps
-	for _, v := range dec.maps {
-		key := v.m.Type().Key()
-		switch key.Kind() {
-		case reflect.String:
-			// the key is a string
-			v.m.SetMapIndex(reflect.ValueOf(v.key), v.value)
-		default:
-			// must to implement the TextUnmarshaler interface for to can to decode the map's key
-			var val reflect.Value
-
-			if key.Kind() == reflect.Ptr {
-				val = reflect.New(key.Elem())
-			} else {
-				val = reflect.New(key).Elem()
-			}
-
-			dec.value = v.key
-			if ok, err := dec.unmarshalText(val); !ok {
-				return fmt.Errorf(tagName+": the key with %s type (%v) in the path %v should implements the TextUnmarshaler interface for to can decode it", key, v.m.Type(), v.path)
-			} else if err != nil {
-				return fmt.Errorf(tagName+": an error has occured in the UnmarshalText method for type %s: %s", key, err)
-			}
-
-			v.m.SetMapIndex(val, v.value)
-		}
-	}
-
-	dec.maps = make(pathMaps, 0)
-	return nil
-}
-
-// begin prepare the current path to walk through it
-func (dec *decoder) begin() (err error) {
-	dec.curr = dec.main
-	fields := strings.Split(dec.field, ".")
-	for i, field := range fields {
-		b := strings.IndexAny(field, "[")
-		if b != -1 {
-			// is a array
-			e := strings.IndexAny(field, "]")
-			if e == -1 {
-				return errors.New(tagName + ": bad syntax array")
-			}
-			dec.field = field[:b]
-			if dec.index, err = strconv.Atoi(field[b+1 : e]); err != nil {
-				return errors.New(tagName + ": the index of array is not a number")
-			}
-			if len(fields) == i+1 {
-				return dec.end()
-			}
-			if err = dec.walk(); err != nil {
-				return
-			}
-		} else {
-			// not is a array
-			dec.field = field
-			dec.index = -1
-			if len(fields) == i+1 {
-				return dec.end()
-			}
-			if err = dec.walk(); err != nil {
-				return
-			}
-		}
-	}
-	return
-}
-
-// walk traverses the current path until to the last field
-func (dec *decoder) walk() error {
-	// check if is a struct or map
-	switch dec.curr.Kind() {
-	case reflect.Struct:
-		if err := dec.findStructField(); err != nil {
-			return err
-		}
-	case reflect.Map:
-		dec.currentMap()
-	}
-	// check if the struct or map is a interface
-	if dec.curr.Kind() == reflect.Interface {
-		dec.curr = dec.curr.Elem()
-	}
-	// check if the struct or map is a pointer
-	if dec.curr.Kind() == reflect.Ptr {
-		if dec.curr.IsNil() {
-			dec.curr.Set(reflect.New(dec.curr.Type().Elem()))
-		}
-		dec.curr = dec.curr.Elem()
-	}
-	// finally, check if there are access to slice/array or not...
-	if dec.index != -1 {
-		switch dec.curr.Kind() {
-		case reflect.Slice, reflect.Array:
-			if dec.curr.Len() <= dec.index {
-				dec.expandSlice(dec.index + 1)
-			}
-			dec.curr = dec.curr.Index(dec.index)
-		default:
-			return fmt.Errorf(tagName+": the field \"%v\" in path \"%v\" has a index for array but it is not", dec.field, dec.path)
-		}
-	}
-	return nil
-}
-
-// end finds the last field for decode its value correspondent
-func (dec *decoder) end() error {
-	if dec.curr.Kind() == reflect.Struct {
-		if err := dec.findStructField(); err != nil {
-			return err
-		}
-	}
-	if dec.value == "" {
-		return nil
-	}
-	return dec.decode()
-}
-
-// decode sets the value in the last field found by end function
-func (dec *decoder) decode() error {
-	if ok, err := dec.unmarshalText(dec.curr); ok || err != nil {
-		return err
-	}
-
-	switch dec.curr.Kind() {
-	case reflect.Map:
-		dec.currentMap()
-		return dec.decode()
-	case reflect.Slice, reflect.Array:
-		if dec.index == -1 {
-			// not has index, so to decode all values in the slice/array
-			dec.expandSlice(len(dec.values))
-			tmp := dec.curr
-			for i, v := range dec.values {
-				dec.curr = tmp.Index(i)
-				dec.value = v
-				if err := dec.decode(); err != nil {
-					return err
-				}
-			}
-		} else {
-			// has index, so to decode value by index indicated
-			if dec.curr.Len() <= dec.index {
-				dec.expandSlice(dec.index + 1)
-			}
-			dec.curr = dec.curr.Index(dec.index)
-			return dec.decode()
-		}
-	case reflect.String:
-		dec.curr.SetString(dec.value)
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		if num, err := strconv.ParseInt(dec.value, 10, 64); err != nil {
-			return fmt.Errorf(tagName+": the value of field \"%v\" in path \"%v\" should be a valid signed integer number", dec.field, dec.path)
-		} else {
-			dec.curr.SetInt(num)
-		}
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		if num, err := strconv.ParseUint(dec.value, 10, 64); err != nil {
-			return fmt.Errorf(tagName+": the value of field \"%v\" in path \"%v\" should be a valid unsigned integer number", dec.field, dec.path)
-		} else {
-			dec.curr.SetUint(num)
-		}
-	case reflect.Float32, reflect.Float64:
-		if num, err := strconv.ParseFloat(dec.value, dec.curr.Type().Bits()); err != nil {
-			return fmt.Errorf(tagName+": the value of field \"%v\" in path \"%v\" should be a valid float number", dec.field, dec.path)
-		} else {
-			dec.curr.SetFloat(num)
-		}
-	case reflect.Bool:
-		switch dec.value {
-		case "true", "on", "1":
-			dec.curr.SetBool(true)
-		case "false", "off", "0":
-			dec.curr.SetBool(false)
-		default:
-			return fmt.Errorf(tagName+": the value of field \"%v\" in path \"%v\" is not a valid boolean", dec.field, dec.path)
-		}
-	case reflect.Interface:
-		dec.curr.Set(reflect.ValueOf(dec.value))
-	case reflect.Ptr:
-		dec.curr.Set(reflect.New(dec.curr.Type().Elem()))
-		dec.curr = dec.curr.Elem()
-		return dec.decode()
-	case reflect.Struct:
-		switch dec.curr.Interface().(type) {
-		case time.Time:
-			t, err := time.Parse("2006-01-02", dec.value)
-			if err != nil {
-				return fmt.Errorf(tagName+": the value of field \"%v\" in path \"%v\" is not a valid datetime", dec.field, dec.path)
-			}
-			dec.curr.Set(reflect.ValueOf(t))
-		case url.URL:
-			u, err := url.Parse(dec.value)
-			if err != nil {
-				return fmt.Errorf(tagName+": the value of field \"%v\" in path \"%v\" is not a valid url", dec.field, dec.path)
-			}
-			dec.curr.Set(reflect.ValueOf(*u))
-		default:
-			return fmt.Errorf(tagName+": not supported type for field \"%v\" in path \"%v\"", dec.field, dec.path)
-		}
-	default:
-		return fmt.Errorf(tagName+": not supported type for field \"%v\" in path \"%v\"", dec.field, dec.path)
-	}
-
-	return nil
-}
-
-// findField finds a field by its name, if it is not found,
-// then retry the search examining the tag "form" of every field of struct
-func (dec *decoder) findStructField() error {
-	var anon reflect.Value
-
-	num := dec.curr.NumField()
-	for i := 0; i < num; i++ {
-		field := dec.curr.Type().Field(i)
-		if field.Name == dec.field {
-			// check if the field's name is equal
-			dec.curr = dec.curr.Field(i)
-			return nil
-		} else if field.Anonymous {
-			// if the field is a anonymous struct, then iterate over its fields
-			tmp := dec.curr
-			dec.curr = dec.curr.FieldByIndex(field.Index)
-			if err := dec.findStructField(); err != nil {
-				dec.curr = tmp
-				continue
-			}
-			// field in anonymous struct is found,
-			// but first it should found the field in the rest of struct
-			// (a field with same name in the current struct should have preference over anonymous struct)
-			anon = dec.curr
-			dec.curr = tmp
-		} else if dec.field == field.Tag.Get(tagName) {
-
-			dec.curr = dec.curr.Field(i)
-			return nil
-		}
-	}
-
-	if anon.IsValid() {
-		dec.curr = anon
-		return nil
-	}
-
-	return fmt.Errorf(tagName+": not found the field \"%v\" in the path \"%v\"", dec.field, dec.path)
-}
-
-// expandSlice expands the length and capacity of the current slice
-func (dec *decoder) expandSlice(length int) {
-	n := reflect.MakeSlice(dec.curr.Type(), length, length)
-	reflect.Copy(n, dec.curr)
-	dec.curr.Set(n)
-}
-
-// currentMap gets in d.curr the map concrete for decode the current value
-func (dec *decoder) currentMap() {
-	n := dec.curr.Type()
-	if dec.curr.IsNil() {
-		dec.curr.Set(reflect.MakeMap(n))
-		m := reflect.New(n.Elem()).Elem()
-		dec.maps = append(dec.maps, &pathMap{dec.curr, dec.field, m, dec.path})
-		dec.curr = m
-	} else if a := dec.maps.find(dec.curr, dec.field); a == nil {
-		m := reflect.New(n.Elem()).Elem()
-		dec.maps = append(dec.maps, &pathMap{dec.curr, dec.field, m, dec.path})
-		dec.curr = m
-	} else {
-		dec.curr = a.value
-	}
-}
-
-var (
-	timeType  = reflect.TypeOf(time.Time{})
-	timePType = reflect.TypeOf(&time.Time{})
-)
-
-// unmarshalText returns a boolean and error. The boolean is true if the
-// value implements TextUnmarshaler, and false if not.
-func (dec *decoder) unmarshalText(v reflect.Value) (bool, error) {
-	// skip if the type is time.Time
-	n := v.Type()
-	if n.ConvertibleTo(timeType) || n.ConvertibleTo(timePType) {
-		return false, nil
-	}
-	// check if implements the interface
-	m, ok := v.Interface().(encoding.TextUnmarshaler)
-	addr := v.CanAddr()
-	if !ok && !addr {
-		return false, nil
-	} else if addr {
-		return dec.unmarshalText(v.Addr())
-	}
-	// return result
-	err := m.UnmarshalText([]byte(dec.value))
-	return true, err
-}
-
-// BindForm binds the formObject  with the form data
-// it supports any kind of struct
-func BindForm(ctx context.IContext, formObject interface{}) error {
-	reqCtx := ctx.GetRequestCtx()
-	// first check if we have multipart form
-	multipartForm, err := reqCtx.MultipartForm()
-	if err == nil {
-		//we have multipart form
-		return ErrReadBody.With(Decode(multipartForm.Value, formObject))
-	}
-	// if no multipart and post arguments ( means normal form)
-
-	if reqCtx.PostArgs().Len() == 0 && reqCtx.QueryArgs().Len() == 0 {
-		return ErrReadBody.With(ErrNoForm.Return())
-	}
-
-	form := make(map[string][]string, reqCtx.PostArgs().Len()+reqCtx.QueryArgs().Len())
-
-	reqCtx.PostArgs().VisitAll(func(k []byte, v []byte) {
-		key := string(k)
-		value := string(v)
-		// for slices
-		if form[key] != nil {
-			form[key] = append(form[key], value)
-		} else {
-			form[key] = []string{value}
-		}
-
-	})
-
-	reqCtx.QueryArgs().VisitAll(func(k []byte, v []byte) {
-		key := string(k)
-		value := string(v)
-		// for slices
-		if form[key] != nil {
-			form[key] = append(form[key], value)
-		} else {
-			form[key] = []string{value}
-		}
-	})
-
-	return ErrReadBody.With(Decode(form, formObject))
-
-}
diff --git a/bindings/json.go b/bindings/json.go
deleted file mode 100644
index ec238253..00000000
--- a/bindings/json.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package bindings
-
-import (
-	"encoding/json"
-
-	"io"
-	"strings"
-
-	"github.com/kataras/iris/context"
-)
-
-// BindJSON reads JSON from request's body
-func BindJSON(ctx context.IContext, jsonObject interface{}) error {
-	data := ctx.GetRequestCtx().Request.Body()
-
-	decoder := json.NewDecoder(strings.NewReader(string(data)))
-	err := decoder.Decode(jsonObject)
-
-	//err != nil fix by @shiena
-	if err != nil && err != io.EOF {
-		return ErrReadBody.Format("JSON", err.Error())
-	}
-
-	return nil
-}
diff --git a/bindings/xml.go b/bindings/xml.go
deleted file mode 100644
index 29848f76..00000000
--- a/bindings/xml.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package bindings
-
-import (
-	"encoding/xml"
-	"io"
-	"strings"
-
-	"github.com/kataras/iris/context"
-)
-
-// BindXML reads XML from request's body
-func BindXML(ctx context.IContext, xmlObject interface{}) error {
-	data := ctx.GetRequestCtx().Request.Body()
-
-	decoder := xml.NewDecoder(strings.NewReader(string(data)))
-	err := decoder.Decode(xmlObject)
-	//err != nil fix by @shiena
-	if err != nil && err != io.EOF {
-		return ErrReadBody.Format("XML", err.Error())
-	}
-
-	return nil
-}
diff --git a/branch.go b/branch.go
deleted file mode 100644
index b7951c03..00000000
--- a/branch.go
+++ /dev/null
@@ -1,457 +0,0 @@
-// Copyright (c)  2013 Julien Schmidt, Copyright (c) 2016 Gerasimos Maropoulos,
-
-package iris
-
-import (
-	"bytes"
-	"strings"
-
-	"github.com/kataras/iris/utils"
-)
-
-const (
-	isStatic BranchCase = iota
-	isRoot
-	hasParams
-	matchEverything
-)
-
-type (
-	// PathParameter is a struct which contains Key and Value, used for named path parameters
-	PathParameter struct {
-		Key   string
-		Value string
-	}
-
-	// PathParameters type for a slice of PathParameter
-	// Tt's a slice of PathParameter type, because it's faster than map
-	PathParameters []PathParameter
-
-	// BranchCase is the type which the type of Branch using in order to determinate what type (parameterized, anything, static...) is the perticular node
-	BranchCase uint8
-
-	// IBranch is the interface which the type Branch must implement
-	IBranch interface {
-		AddBranch(string, Middleware)
-		AddNode(uint8, string, string, Middleware)
-		GetBranch(string, PathParameters) (Middleware, PathParameters, bool)
-		GivePrecedenceTo(index int) int
-	}
-
-	// Branch is the node of a tree of the routes,
-	// in order to learn how this is working, google 'trie' or watch this lecture: https://www.youtube.com/watch?v=uhAUk63tLRM
-	// this method is used by the BSD's kernel also
-	Branch struct {
-		part        string
-		BranchCase  BranchCase
-		hasWildNode bool
-		tokens      string
-		nodes       []*Branch
-		middleware  Middleware
-		precedence  uint64
-		paramsLen   uint8
-	}
-)
-
-var _ IBranch = &Branch{}
-
-// Get returns a value from a key inside this Parameters
-// If no parameter with this key given then it returns an empty string
-func (params PathParameters) Get(key string) string {
-	for _, p := range params {
-		if p.Key == key {
-			return p.Value
-		}
-	}
-	return ""
-}
-
-// String returns a string implementation of all parameters that this PathParameters object keeps
-// hasthe form of key1=value1,key2=value2...
-func (params PathParameters) String() string {
-	var buff bytes.Buffer
-	for i := range params {
-		buff.WriteString(params[i].Key)
-		buff.WriteString("=")
-		buff.WriteString(params[i].Value)
-		if i < len(params)-1 {
-			buff.WriteString(",")
-		}
-
-	}
-	return buff.String()
-}
-
-// ParseParams receives a string and returns PathParameters (slice of PathParameter)
-// received string must have this form:  key1=value1,key2=value2...
-func ParseParams(str string) PathParameters {
-	_paramsstr := strings.Split(str, ",")
-	if len(_paramsstr) == 0 {
-		return nil
-	}
-
-	params := make(PathParameters, 0) // PathParameters{}
-
-	//	for i := 0; i < len(_paramsstr); i++ {
-	for i := range _paramsstr {
-		idxOfEq := strings.IndexRune(_paramsstr[i], '=')
-		if idxOfEq == -1 {
-			//error
-			return nil
-		}
-
-		key := _paramsstr[i][:idxOfEq]
-		val := _paramsstr[i][idxOfEq+1:]
-		params = append(params, PathParameter{key, val})
-	}
-	return params
-}
-
-// GetParamsLen returns the parameters length from a given path
-func GetParamsLen(path string) uint8 {
-	var n uint
-	for i := 0; i < len(path); i++ {
-		if path[i] != ':' && path[i] != '*' { // ParameterStartByte & MatchEverythingByte
-			continue
-		}
-		n++
-	}
-	if n >= 255 {
-		return 255
-	}
-	return uint8(n)
-}
-
-// AddBranch adds a branch to the existing branch or to the tree if no branch has the prefix of
-func (b *Branch) AddBranch(path string, middleware Middleware) {
-	fullPath := path
-	b.precedence++
-	numParams := GetParamsLen(path)
-
-	if len(b.part) > 0 || len(b.nodes) > 0 {
-	loop:
-		for {
-			if numParams > b.paramsLen {
-				b.paramsLen = numParams
-			}
-
-			i := 0
-			max := utils.FindLower(len(path), len(b.part))
-			for i < max && path[i] == b.part[i] {
-				i++
-			}
-
-			if i < len(b.part) {
-				node := Branch{
-					part:        b.part[i:],
-					hasWildNode: b.hasWildNode,
-					tokens:      b.tokens,
-					nodes:       b.nodes,
-					middleware:  b.middleware,
-					precedence:  b.precedence - 1,
-				}
-
-				for i := range node.nodes {
-					if node.nodes[i].paramsLen > node.paramsLen {
-						node.paramsLen = node.nodes[i].paramsLen
-					}
-				}
-
-				b.nodes = []*Branch{&node}
-				b.tokens = string([]byte{b.part[i]})
-				b.part = path[:i]
-				b.middleware = nil
-				b.hasWildNode = false
-			}
-
-			if i < len(path) {
-				path = path[i:]
-
-				if b.hasWildNode {
-					b = b.nodes[0]
-					b.precedence++
-
-					if numParams > b.paramsLen {
-						b.paramsLen = numParams
-					}
-					numParams--
-
-					if len(path) >= len(b.part) && b.part == path[:len(b.part)] {
-
-						if len(b.part) >= len(path) || path[len(b.part)] == '/' {
-							continue loop
-						}
-					}
-
-					return
-				}
-
-				c := path[0]
-
-				if b.BranchCase == hasParams && c == '/' && len(b.nodes) == 1 {
-					b = b.nodes[0]
-					b.precedence++
-					continue loop
-				}
-				//we need the i here to be re-setting, so use the same i variable as we declare it on line 176
-				for i := range b.tokens {
-					if c == b.tokens[i] {
-						i = b.GivePrecedenceTo(i)
-						b = b.nodes[i]
-						continue loop
-					}
-				}
-
-				if c != ParameterStartByte && c != MatchEverythingByte {
-
-					b.tokens += string([]byte{c})
-					node := &Branch{
-						paramsLen: numParams,
-					}
-					b.nodes = append(b.nodes, node)
-					b.GivePrecedenceTo(len(b.tokens) - 1)
-					b = node
-				}
-				b.AddNode(numParams, path, fullPath, middleware)
-				return
-
-			} else if i == len(path) {
-				if b.middleware != nil {
-					return
-				}
-				b.middleware = middleware
-			}
-			return
-		}
-	} else {
-		b.AddNode(numParams, path, fullPath, middleware)
-		b.BranchCase = isRoot
-	}
-}
-
-// AddNode adds a branch as children to other Branch
-func (b *Branch) AddNode(numParams uint8, path string, fullPath string, middleware Middleware) {
-	var offset int
-
-	for i, max := 0, len(path); numParams > 0; i++ {
-		c := path[i]
-		if c != ParameterStartByte && c != MatchEverythingByte {
-			continue
-		}
-
-		end := i + 1
-		for end < max && path[end] != '/' {
-			switch path[end] {
-			case ParameterStartByte, MatchEverythingByte:
-
-			default:
-				end++
-			}
-		}
-
-		if len(b.nodes) > 0 {
-			return
-		}
-
-		if end-i < 2 {
-			return
-		}
-
-		if c == ParameterStartByte {
-
-			if i > 0 {
-				b.part = path[offset:i]
-				offset = i
-			}
-
-			child := &Branch{
-				BranchCase: hasParams,
-				paramsLen:  numParams,
-			}
-			b.nodes = []*Branch{child}
-			b.hasWildNode = true
-			b = child
-			b.precedence++
-			numParams--
-
-			if end < max {
-				b.part = path[offset:end]
-				offset = end
-
-				child := &Branch{
-					paramsLen:  numParams,
-					precedence: 1,
-				}
-				b.nodes = []*Branch{child}
-				b = child
-			}
-
-		} else {
-			if end != max || numParams > 1 {
-				return
-			}
-
-			if len(b.part) > 0 && b.part[len(b.part)-1] == '/' {
-				return
-			}
-
-			i--
-			if path[i] != '/' {
-				return
-			}
-
-			b.part = path[offset:i]
-
-			child := &Branch{
-				hasWildNode: true,
-				BranchCase:  matchEverything,
-				paramsLen:   1,
-			}
-			b.nodes = []*Branch{child}
-			b.tokens = string(path[i])
-			b = child
-			b.precedence++
-
-			child = &Branch{
-				part:       path[i:],
-				BranchCase: matchEverything,
-				paramsLen:  1,
-				middleware: middleware,
-				precedence: 1,
-			}
-			b.nodes = []*Branch{child}
-
-			return
-		}
-	}
-
-	b.part = path[offset:]
-	b.middleware = middleware
-}
-
-// GetBranch is used by the Router, it finds and returns the correct branch for a path
-func (b *Branch) GetBranch(path string, _params PathParameters) (middleware Middleware, params PathParameters, mustRedirect bool) {
-	params = _params
-loop:
-	for {
-		if len(path) > len(b.part) {
-			if path[:len(b.part)] == b.part {
-				path = path[len(b.part):]
-
-				if !b.hasWildNode {
-					c := path[0]
-					for i := range b.tokens {
-						if c == b.tokens[i] {
-							b = b.nodes[i]
-							continue loop
-						}
-					}
-
-					mustRedirect = (path == Slash && b.middleware != nil)
-					return
-				}
-
-				b = b.nodes[0]
-				switch b.BranchCase {
-				case hasParams:
-
-					end := 0
-					for end < len(path) && path[end] != '/' {
-						end++
-					}
-
-					if cap(params) < int(b.paramsLen) {
-						params = make(PathParameters, 0, b.paramsLen)
-					}
-					i := len(params)
-					params = params[:i+1]
-					params[i].Key = b.part[1:]
-					params[i].Value = path[:end]
-
-					if end < len(path) {
-						if len(b.nodes) > 0 {
-							path = path[end:]
-							b = b.nodes[0]
-							continue loop
-						}
-
-						mustRedirect = (len(path) == end+1)
-						return
-					}
-
-					if middleware = b.middleware; middleware != nil {
-						return
-					} else if len(b.nodes) == 1 {
-						b = b.nodes[0]
-						mustRedirect = (b.part == Slash && b.middleware != nil)
-					}
-
-					return
-
-				case matchEverything:
-					if cap(params) < int(b.paramsLen) {
-						params = make(PathParameters, 0, b.paramsLen)
-					}
-					i := len(params)
-					params = params[:i+1]
-					params[i].Key = b.part[2:]
-					params[i].Value = path
-
-					middleware = b.middleware
-					return
-
-				default:
-					return
-				}
-			}
-		} else if path == b.part {
-			if middleware = b.middleware; middleware != nil {
-				return
-			}
-
-			if path == Slash && b.hasWildNode && b.BranchCase != isRoot {
-				mustRedirect = true
-				return
-			}
-
-			for i := range b.tokens {
-				if b.tokens[i] == '/' {
-					b = b.nodes[i]
-					mustRedirect = (len(b.part) == 1 && b.middleware != nil) ||
-						(b.BranchCase == matchEverything && b.nodes[0].middleware != nil)
-					return
-				}
-			}
-
-			return
-		}
-
-		mustRedirect = (path == Slash) ||
-			(len(b.part) == len(path)+1 && b.part[len(path)] == '/' &&
-				path == b.part[:len(b.part)-1] && b.middleware != nil)
-		return
-	}
-}
-
-// GivePrecedenceTo just adds the priority of this branch by an index
-func (b *Branch) GivePrecedenceTo(index int) int {
-	b.nodes[index].precedence++
-	_precedence := b.nodes[index].precedence
-
-	newindex := index
-	for newindex > 0 && b.nodes[newindex-1].precedence < _precedence {
-		tmpN := b.nodes[newindex-1]
-		b.nodes[newindex-1] = b.nodes[newindex]
-		b.nodes[newindex] = tmpN
-
-		newindex--
-	}
-
-	if newindex != index {
-		b.tokens = b.tokens[:newindex] +
-			b.tokens[index:index+1] +
-			b.tokens[newindex:index] + b.tokens[index+1:]
-	}
-
-	return newindex
-}
diff --git a/config/iris.go b/config/iris.go
index 868f0783..a0d4370f 100644
--- a/config/iris.go
+++ b/config/iris.go
@@ -4,21 +4,24 @@ import (
 	"github.com/imdario/mergo"
 )
 
-// DefaultProfilePath is the default profile(http debug) path which is /debug/pprof
-const DefaultProfilePath = "/debug/pprof"
+// Default values for base Iris conf
+const (
+	DefaultDisablePathCorrection = false
+	DefaultDisablePathEscape     = false
+)
 
 type (
 	// Iris configs for the station
 	// All fields can be changed before server's listen except the DisablePathCorrection field
 	//
 	// MaxRequestBodySize is the only options that can be changed after server listen -
-	// using Config().MaxRequestBodySize = ...
+	// using Config.MaxRequestBodySize = ...
 	// Render's rest config can be changed after declaration but before server's listen -
-	// using Config().Render.Rest...
+	// using Config.Render.Rest...
 	// Render's Template config can be changed after declaration but before server's listen -
-	// using Config().Render.Template...
+	// using Config.Render.Template...
 	// Sessions config can be changed after declaration but before server's listen -
-	// using Config().Sessions...
+	// using Config.Sessions...
 	// and so on...
 	Iris struct {
 
@@ -56,40 +59,57 @@ type (
 		// By default request body size is -1, unlimited.
 		MaxRequestBodySize int64
 
-		// Profile set to true to enable web pprof (debug profiling)
-		// Default is false, enabling makes available these 7 routes:
-		// /debug/pprof/cmdline
-		// /debug/pprof/profile
-		// /debug/pprof/symbol
-		// /debug/pprof/goroutine
-		// /debug/pprof/heap
-		// /debug/pprof/threadcreate
-		// /debug/pprof/pprof/block
-		Profile bool
-
-		// ProfilePath change it if you want other url path than the default
-		// Default is /debug/pprof , which means yourhost.com/debug/pprof
+		// ProfilePath a the route path, set it to enable http pprof tool
+		// Default is empty, if you set it to a $path, these routes will handled:
+		// $path/cmdline
+		// $path/profile
+		// $path/symbol
+		// $path/goroutine
+		// $path/heap
+		// $path/threadcreate
+		// $path/pprof/block
+		// for example if '/debug/pprof'
+		// http://yourdomain:PORT/debug/pprof/
+		// http://yourdomain:PORT/debug/pprof/cmdline
+		// http://yourdomain:PORT/debug/pprof/profile
+		// http://yourdomain:PORT/debug/pprof/symbol
+		// http://yourdomain:PORT/debug/pprof/goroutine
+		// http://yourdomain:PORT/debug/pprof/heap
+		// http://yourdomain:PORT/debug/pprof/threadcreate
+		// http://yourdomain:PORT/debug/pprof/pprof/block
+		// it can be a subdomain also, for example, if 'debug.'
+		// http://debug.yourdomain:PORT/
+		// http://debug.yourdomain:PORT/cmdline
+		// http://debug.yourdomain:PORT/profile
+		// http://debug.yourdomain:PORT/symbol
+		// http://debug.yourdomain:PORT/goroutine
+		// http://debug.yourdomain:PORT/heap
+		// http://debug.yourdomain:PORT/threadcreate
+		// http://debug.yourdomain:PORT/pprof/block
 		ProfilePath string
 
 		// Logger the configuration for the logger
-		// Iris logs ONLY errors and the banner if enabled
+		// Iris logs ONLY SEMANTIC errors and the banner if enabled
 		Logger Logger
 
-		// Sessions the config for sessions
-		// contains 3(three) properties
-		// Provider: (look /sessions/providers)
-		// Secret: cookie's name (string)
-		// Life: cookie life (time.Duration)
+		// Sessions contains the configs for sessions
 		Sessions Sessions
 
 		// Render contains the configs for template and rest configuration
 		Render Render
 
 		// Websocket contains the configs for Websocket's server integration
-		Websocket Websocket
+		Websocket *Websocket
 
-		// Mail contains the config for the mail sender service
+		// Mail contains the configs for the mail sender service
 		Mail Mail
+
+		// Server contains the configs for the http server
+		// Server configs are the only one which are setted inside base Iris package (from Listen, ListenTLS, ListenUNIX) NO from users
+		//
+		// this field is useful only when you need to READ which is the server's address, certfile & keyfile or unix's mode.
+		//
+		Server Server
 	}
 
 	// Render struct keeps organise all configuration about rendering, templates and rest currently.
@@ -117,16 +137,17 @@ func DefaultRender() Render {
 // Default returns the default configuration for the Iris staton
 func Default() Iris {
 	return Iris{
-		DisablePathCorrection: false,
-		DisablePathEscape:     false,
+		DisablePathCorrection: DefaultDisablePathCorrection,
+		DisablePathEscape:     DefaultDisablePathEscape,
 		DisableBanner:         false,
 		MaxRequestBodySize:    -1,
-		ProfilePath:           DefaultProfilePath,
+		ProfilePath:           "",
 		Logger:                DefaultLogger(),
 		Sessions:              DefaultSessions(),
 		Render:                DefaultRender(),
 		Websocket:             DefaultWebsocket(),
 		Mail:                  DefaultMail(),
+		Server:                DefaultServer(),
 	}
 }
 
diff --git a/config/server.go b/config/server.go
index 2e1b22c7..52c5b345 100644
--- a/config/server.go
+++ b/config/server.go
@@ -7,8 +7,8 @@ import (
 )
 
 const (
-	// DefaultServerAddr the default server addr
-	DefaultServerAddr = ":8080"
+	// DefaultServerAddr the default server addr which is: 127.0.0.1:8080
+	DefaultServerAddr = "127.0.0.1:8080"
 )
 
 // ServerName the response header of the 'Server' value when writes to the client
diff --git a/config/websocket.go b/config/websocket.go
index be20ca3b..1ada5caa 100644
--- a/config/websocket.go
+++ b/config/websocket.go
@@ -43,8 +43,8 @@ type Websocket struct {
 }
 
 // DefaultWebsocket returns the default config for iris-ws websocket package
-func DefaultWebsocket() Websocket {
-	return Websocket{
+func DefaultWebsocket() *Websocket {
+	return &Websocket{
 		WriteTimeout:   DefaultWriteTimeout,
 		PongTimeout:    DefaultPongTimeout,
 		PingPeriod:     DefaultPingPeriod,
@@ -55,11 +55,11 @@ func DefaultWebsocket() Websocket {
 }
 
 // Merge merges the default with the given config and returns the result
-func (c Websocket) Merge(cfg []Websocket) (config Websocket) {
+func (c *Websocket) Merge(cfg []*Websocket) (config *Websocket) {
 
 	if len(cfg) > 0 {
 		config = cfg[0]
-		mergo.Merge(&config, c)
+		mergo.Merge(config, c)
 	} else {
 		_default := c
 		config = _default
@@ -69,10 +69,10 @@ func (c Websocket) Merge(cfg []Websocket) (config Websocket) {
 }
 
 // MergeSingle merges the default with the given config and returns the result
-func (c Websocket) MergeSingle(cfg Websocket) (config Websocket) {
+func (c *Websocket) MergeSingle(cfg *Websocket) (config *Websocket) {
 
 	config = cfg
-	mergo.Merge(&config, c)
+	mergo.Merge(config, c)
 
 	return
 }
diff --git a/context.go b/context.go
index 846ca775..f521bfd1 100644
--- a/context.go
+++ b/context.go
@@ -6,40 +6,72 @@ files: context_renderer.go, context_storage.go, context_request.go, context_resp
 package iris
 
 import (
+	"bufio"
+	"encoding/base64"
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"html/template"
+	"io"
+	"net"
+	"os"
+	"path"
 	"reflect"
 	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
 
+	"github.com/iris-contrib/formBinder"
+	"github.com/kataras/iris/config"
 	"github.com/kataras/iris/context"
+	"github.com/kataras/iris/errors"
 	"github.com/kataras/iris/sessions/store"
+	"github.com/kataras/iris/utils"
+	"github.com/klauspost/compress/gzip"
 	"github.com/valyala/fasthttp"
 )
 
 const (
 	// DefaultUserAgent default to 'iris' but it is not used anywhere yet
-	DefaultUserAgent = "iris"
+	defaultUserAgent = "iris"
 	// ContentType represents the header["Content-Type"]
-	ContentType = "Content-Type"
+	contentType = "Content-Type"
 	// ContentLength represents the header["Content-Length"]
-	ContentLength = "Content-Length"
+	contentLength = "Content-Length"
 	// ContentHTML is the  string of text/html response headers
-	ContentHTML = "text/html"
+	contentHTML = "text/html"
 	// ContentBINARY is the string of application/octet-stream response headers
-	ContentBINARY = "application/octet-stream"
+	contentBINARY = "application/octet-stream"
 
 	// LastModified "Last-Modified"
-	LastModified = "Last-Modified"
+	lastModified = "Last-Modified"
 	// IfModifiedSince "If-Modified-Since"
-	IfModifiedSince = "If-Modified-Since"
+	ifModifiedSince = "If-Modified-Since"
 	// ContentDisposition "Content-Disposition"
-	ContentDisposition = "Content-Disposition"
-
-	// TimeFormat default time format for any kind of datetime parsing
-	TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
+	contentDisposition = "Content-Disposition"
 
 	// stopExecutionPosition used inside the Context, is the number which shows us that the context's middleware manualy stop the execution
 	stopExecutionPosition = 255
 )
 
+// this pool is used everywhere needed in the iris for example inside party-> Static
+var gzipWriterPool = sync.Pool{New: func() interface{} { return &gzip.Writer{} }}
+
+// errors
+
+var (
+	errTemplateExecute  = errors.New("Unable to execute a template. Trace: %s")
+	errFlashNotFound    = errors.New("Unable to get flash message. Trace: Cookie does not exists")
+	errSessionNil       = errors.New("Unable to set session, Config().Session.Provider is nil, please refer to the docs!")
+	errNoForm           = errors.New("Request has no any valid form")
+	errWriteJSON        = errors.New("Before JSON be written to the body, JSON Encoder returned an error. Trace: %s")
+	errRenderMarshalled = errors.New("Before +type Rendering, MarshalIndent returned an error. Trace: %s")
+	errReadBody         = errors.New("While trying to read %s from the request body. Trace %s")
+	errServeContent     = errors.New("While trying to serve content to the client. Trace %s")
+)
+
 type (
 	// Map is just a conversion for a map[string]interface{}
 	Map map[string]interface{}
@@ -47,8 +79,8 @@ type (
 	// it is not good practice to use this object in goroutines, for these cases use the .Clone()
 	Context struct {
 		*fasthttp.RequestCtx
-		Params  PathParameters
-		station *Iris
+		Params    PathParameters
+		framework *Framework
 		//keep track all registed middleware (handlers)
 		middleware   Middleware
 		sessionStore store.IStore
@@ -128,3 +160,621 @@ func (ctx *Context) IsStopped() bool {
 func (ctx *Context) GetHandlerName() string {
 	return runtime.FuncForPC(reflect.ValueOf(ctx.middleware[len(ctx.middleware)-1]).Pointer()).Name()
 }
+
+/* Request */
+
+// Param returns the string representation of the key's path named parameter's value
+func (ctx *Context) Param(key string) string {
+	return ctx.Params.Get(key)
+}
+
+// ParamInt returns the int representation of the key's path named parameter's value
+func (ctx *Context) ParamInt(key string) (int, error) {
+	val, err := strconv.Atoi(ctx.Param(key))
+	return val, err
+}
+
+// URLParam returns the get parameter from a request , if any
+func (ctx *Context) URLParam(key string) string {
+	return string(ctx.RequestCtx.Request.URI().QueryArgs().Peek(key))
+}
+
+// URLParams returns a map of a list of each url(query) parameter
+func (ctx *Context) URLParams() map[string]string {
+	urlparams := make(map[string]string)
+	ctx.RequestCtx.Request.URI().QueryArgs().VisitAll(func(key, value []byte) {
+		urlparams[string(key)] = string(value)
+	})
+	return urlparams
+}
+
+// URLParamInt returns the get parameter int value from a request , if any
+func (ctx *Context) URLParamInt(key string) (int, error) {
+	return strconv.Atoi(ctx.URLParam(key))
+}
+
+// MethodString returns the HTTP Method
+func (ctx *Context) MethodString() string {
+	return utils.BytesToString(ctx.Method())
+}
+
+// HostString returns the Host of the request( the url as string )
+func (ctx *Context) HostString() string {
+	return utils.BytesToString(ctx.Host())
+}
+
+// VirtualHostname returns the hostname that user registers, host path maybe differs from the real which is HostString, which taken from a net.listener
+func (ctx *Context) VirtualHostname() string {
+	realhost := ctx.HostString()
+	virtualhost := ctx.framework.HTTPServer.VirtualHostname()
+	hostname := strings.Replace(realhost, "127.0.0.1", virtualhost, 1)
+	hostname = strings.Replace(realhost, "localhost", virtualhost, 1)
+	if portIdx := strings.IndexByte(hostname, ':'); portIdx > 0 {
+		hostname = hostname[0:portIdx]
+	}
+	return hostname
+}
+
+// PathString returns the full escaped path as string
+// for unescaped use: ctx.RequestCtx.RequestURI() or RequestPath(escape bool)
+func (ctx *Context) PathString() string {
+	return ctx.RequestPath(true)
+}
+
+// RequestPath returns the requested path
+func (ctx *Context) RequestPath(escape bool) string {
+	if escape {
+		return utils.BytesToString(ctx.RequestCtx.Path())
+	}
+	return utils.BytesToString(ctx.RequestCtx.RequestURI())
+}
+
+// RequestIP gets just the Remote Address from the client.
+func (ctx *Context) RequestIP() string {
+	if ip, _, err := net.SplitHostPort(strings.TrimSpace(ctx.RequestCtx.RemoteAddr().String())); err == nil {
+		return ip
+	}
+	return ""
+}
+
+// RemoteAddr is like RequestIP but it checks for proxy servers also, tries to get the real client's request IP
+func (ctx *Context) RemoteAddr() string {
+	header := string(ctx.RequestCtx.Request.Header.Peek("X-Real-Ip"))
+	realIP := strings.TrimSpace(header)
+	if realIP != "" {
+		return realIP
+	}
+	realIP = string(ctx.RequestCtx.Request.Header.Peek("X-Forwarded-For"))
+	idx := strings.IndexByte(realIP, ',')
+	if idx >= 0 {
+		realIP = realIP[0:idx]
+	}
+	realIP = strings.TrimSpace(realIP)
+	if realIP != "" {
+		return realIP
+	}
+	return ctx.RequestIP()
+
+}
+
+// RequestHeader returns the request header's value
+// accepts one parameter, the key of the header (string)
+// returns string
+func (ctx *Context) RequestHeader(k string) string {
+	return utils.BytesToString(ctx.RequestCtx.Request.Header.Peek(k))
+}
+
+// PostFormValue returns a single value from post request's data
+func (ctx *Context) PostFormValue(name string) string {
+	return string(ctx.RequestCtx.PostArgs().Peek(name))
+}
+
+// PostFormMulti returns a slice of string from post request's data
+func (ctx *Context) PostFormMulti(name string) []string {
+	arrBytes := ctx.PostArgs().PeekMulti(name)
+	arrStr := make([]string, len(arrBytes))
+	for i, v := range arrBytes {
+		arrStr[i] = string(v)
+	}
+	return arrStr
+}
+
+// Subdomain returns the subdomain (string) of this request, if any
+func (ctx *Context) Subdomain() (subdomain string) {
+	host := ctx.HostString()
+	if index := strings.IndexByte(host, '.'); index > 0 {
+		subdomain = host[0:index]
+	}
+
+	return
+}
+
+// URLEncode returns the path encoded as url
+// useful when you want to pass something to a database and be valid to retrieve it via context.Param
+// use it only for special cases, when the default behavior doesn't suits you.
+//
+// http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
+/* Credits to Manish Singh @kryptodev for URLEncode */
+func URLEncode(path string) string {
+	if path == "" {
+		return ""
+	}
+	u := fasthttp.AcquireURI()
+	u.SetPath(path)
+	encodedPath := u.String()[8:]
+	fasthttp.ReleaseURI(u)
+	return encodedPath
+}
+
+// ReadJSON reads JSON from request's body
+func (ctx *Context) ReadJSON(jsonObject interface{}) error {
+	data := ctx.RequestCtx.Request.Body()
+
+	decoder := json.NewDecoder(strings.NewReader(string(data)))
+	err := decoder.Decode(jsonObject)
+
+	//err != nil fix by @shiena
+	if err != nil && err != io.EOF {
+		return errReadBody.Format("JSON", err.Error())
+	}
+
+	return nil
+}
+
+// ReadXML reads XML from request's body
+func (ctx *Context) ReadXML(xmlObject interface{}) error {
+	data := ctx.RequestCtx.Request.Body()
+
+	decoder := xml.NewDecoder(strings.NewReader(string(data)))
+	err := decoder.Decode(xmlObject)
+	//err != nil fix by @shiena
+	if err != nil && err != io.EOF {
+		return errReadBody.Format("XML", err.Error())
+	}
+
+	return nil
+}
+
+// ReadForm binds the formObject  with the form data
+// it supports any kind of struct
+func (ctx *Context) ReadForm(formObject interface{}) error {
+	reqCtx := ctx.RequestCtx
+	// first check if we have multipart form
+	multipartForm, err := reqCtx.MultipartForm()
+	if err == nil {
+		//we have multipart form
+		return errReadBody.With(formBinder.Decode(multipartForm.Value, formObject))
+	}
+	// if no multipart and post arguments ( means normal form)
+
+	if reqCtx.PostArgs().Len() == 0 && reqCtx.QueryArgs().Len() == 0 {
+		return errReadBody.With(errNoForm.Return())
+	}
+
+	form := make(map[string][]string, reqCtx.PostArgs().Len()+reqCtx.QueryArgs().Len())
+
+	reqCtx.PostArgs().VisitAll(func(k []byte, v []byte) {
+		key := string(k)
+		value := string(v)
+		// for slices
+		if form[key] != nil {
+			form[key] = append(form[key], value)
+		} else {
+			form[key] = []string{value}
+		}
+
+	})
+
+	reqCtx.QueryArgs().VisitAll(func(k []byte, v []byte) {
+		key := string(k)
+		value := string(v)
+		// for slices
+		if form[key] != nil {
+			form[key] = append(form[key], value)
+		} else {
+			form[key] = []string{value}
+		}
+	})
+
+	return errReadBody.With(formBinder.Decode(form, formObject))
+}
+
+/* Response */
+
+// SetContentType sets the response writer's header key 'Content-Type' to a given value(s)
+func (ctx *Context) SetContentType(s string) {
+	ctx.RequestCtx.Response.Header.Set(contentType, s)
+}
+
+// SetHeader write to the response writer's header to a given key the given value(s)
+func (ctx *Context) SetHeader(k string, v string) {
+	ctx.RequestCtx.Response.Header.Set(k, v)
+}
+
+// Redirect redirect sends a redirect response the client
+// accepts 2 parameters string and an optional int
+// first parameter is the url to redirect
+// second parameter is the http status should send, default is 302 (StatusFound), you can set it to 301 (Permant redirect), if that's nessecery
+func (ctx *Context) Redirect(urlToRedirect string, statusHeader ...int) {
+	httpStatus := StatusFound // temporary redirect
+	if statusHeader != nil && len(statusHeader) > 0 && statusHeader[0] > 0 {
+		httpStatus = statusHeader[0]
+	}
+	ctx.RequestCtx.Redirect(urlToRedirect, httpStatus)
+	ctx.StopExecution()
+}
+
+// RedirectTo does the same thing as Redirect but instead of receiving a uri or path it receives a route name
+func (ctx *Context) RedirectTo(routeName string, args ...interface{}) {
+	s := ctx.framework.URL(routeName, args...)
+	if s != "" {
+		ctx.Redirect(s, StatusFound)
+	}
+}
+
+// NotFound emits an error 404 to the client, using the custom http errors
+// if no custom errors provided then it sends the default error message
+func (ctx *Context) NotFound() {
+	ctx.framework.EmitError(StatusNotFound, ctx)
+}
+
+// Panic emits an error 500 to the client, using the custom http errors
+// if no custom errors rpovided then it sends the default error message
+func (ctx *Context) Panic() {
+	ctx.framework.EmitError(StatusInternalServerError, ctx)
+}
+
+// EmitError executes the custom error by the http status code passed to the function
+func (ctx *Context) EmitError(statusCode int) {
+	ctx.framework.EmitError(statusCode, ctx)
+	ctx.StopExecution()
+}
+
+// Write writes a string to the client, something like fmt.Printf but for the web
+func (ctx *Context) Write(format string, a ...interface{}) {
+	//this doesn't work with gzip, so just write the []byte better |ctx.ResponseWriter.WriteString(fmt.Sprintf(format, a...))
+	ctx.RequestCtx.WriteString(fmt.Sprintf(format, a...))
+}
+
+// HTML writes html string with a http status
+func (ctx *Context) HTML(httpStatus int, htmlContents string) {
+	ctx.SetContentType(contentHTML + ctx.framework.rest.CompiledCharset)
+	ctx.RequestCtx.SetStatusCode(httpStatus)
+	ctx.RequestCtx.WriteString(htmlContents)
+}
+
+// Data writes out the raw bytes as binary data.
+func (ctx *Context) Data(status int, v []byte) error {
+	return ctx.framework.rest.Data(ctx.RequestCtx, status, v)
+}
+
+// RenderWithStatus builds up the response from the specified template and bindings.
+// Note: parameter layout has meaning only when using the iris.HTMLTemplate
+func (ctx *Context) RenderWithStatus(status int, name string, binding interface{}, layout ...string) error {
+	ctx.SetStatusCode(status)
+	return ctx.framework.templates.Render(ctx, name, binding, layout...)
+}
+
+// Render same as .RenderWithStatus but with status to iris.StatusOK (200)
+func (ctx *Context) Render(name string, binding interface{}, layout ...string) error {
+	return ctx.RenderWithStatus(StatusOK, name, binding, layout...)
+}
+
+// MustRender same as .Render but returns 500 internal server http status (error) if rendering fail
+func (ctx *Context) MustRender(name string, binding interface{}, layout ...string) {
+	if err := ctx.Render(name, binding, layout...); err != nil {
+		ctx.Panic()
+		ctx.framework.Logger.Dangerf("MustRender panics for client with IP: %s On template: %s", ctx.RemoteAddr(), name)
+	}
+}
+
+// TemplateString accepts a template filename, its context data and returns the result of the parsed template (string)
+// if any error returns empty string
+func (ctx *Context) TemplateString(name string, binding interface{}, layout ...string) string {
+	return ctx.framework.TemplateString(name, binding, layout...)
+}
+
+// JSON marshals the given interface object and writes the JSON response.
+func (ctx *Context) JSON(status int, v interface{}) error {
+	return ctx.framework.rest.JSON(ctx.RequestCtx, status, v)
+}
+
+// JSONP marshals the given interface object and writes the JSON response.
+func (ctx *Context) JSONP(status int, callback string, v interface{}) error {
+	return ctx.framework.rest.JSONP(ctx.RequestCtx, status, callback, v)
+}
+
+// Text writes out a string as plain text.
+func (ctx *Context) Text(status int, v string) error {
+	return ctx.framework.rest.Text(ctx.RequestCtx, status, v)
+}
+
+// XML marshals the given interface object and writes the XML response.
+func (ctx *Context) XML(status int, v interface{}) error {
+	return ctx.framework.rest.XML(ctx.RequestCtx, status, v)
+}
+
+// MarkdownString parses the (dynamic) markdown string and returns the converted html string
+func (ctx *Context) MarkdownString(markdownText string) string {
+	return ctx.framework.rest.Markdown([]byte(markdownText))
+}
+
+// Markdown parses and renders to the client a particular (dynamic) markdown string
+// accepts two parameters
+// first is the http status code
+// second is the markdown string
+func (ctx *Context) Markdown(status int, markdown string) {
+	ctx.HTML(status, ctx.MarkdownString(markdown))
+}
+
+// ExecuteTemplate executes a simple html template, you can use that if you already have the cached templates
+// the recommended way to render is to use iris.Templates("./templates/path/*.html") and ctx.RenderFile("filename.html",struct{})
+// accepts 2 parameters
+// the first parameter is the template (*template.Template)
+// the second parameter is the page context (interfac{})
+// returns an error if any errors occurs while executing this template
+func (ctx *Context) ExecuteTemplate(tmpl *template.Template, pageContext interface{}) error {
+	ctx.RequestCtx.SetContentType(contentHTML + ctx.framework.rest.CompiledCharset)
+	return errTemplateExecute.With(tmpl.Execute(ctx.RequestCtx.Response.BodyWriter(), pageContext))
+}
+
+// ServeContent serves content, headers are autoset
+// receives three parameters, it's low-level function, instead you can use .ServeFile(string)
+//
+// You can define your own "Content-Type" header also, after this function call
+func (ctx *Context) ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error {
+	if t, err := time.Parse(config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
+		ctx.RequestCtx.Response.Header.Del(contentType)
+		ctx.RequestCtx.Response.Header.Del(contentLength)
+		ctx.RequestCtx.SetStatusCode(StatusNotModified)
+		return nil
+	}
+
+	ctx.RequestCtx.Response.Header.Set(contentType, utils.TypeByExtension(filename))
+	ctx.RequestCtx.Response.Header.Set(lastModified, modtime.UTC().Format(config.TimeFormat))
+	ctx.RequestCtx.SetStatusCode(StatusOK)
+	var out io.Writer
+	if gzipCompression {
+		ctx.RequestCtx.Response.Header.Add("Content-Encoding", "gzip")
+		gzipWriter := gzipWriterPool.Get().(*gzip.Writer)
+		gzipWriter.Reset(ctx.RequestCtx.Response.BodyWriter())
+		defer gzipWriter.Close()
+		defer gzipWriterPool.Put(gzipWriter)
+		out = gzipWriter
+	} else {
+		out = ctx.RequestCtx.Response.BodyWriter()
+
+	}
+	_, err := io.Copy(out, content)
+	return errServeContent.With(err)
+}
+
+// ServeFile serves a view file, to send a file ( zip for example) to the client you should use the SendFile(serverfilename,clientfilename)
+// receives two parameters
+// filename/path (string)
+// gzipCompression (bool)
+//
+// You can define your own "Content-Type" header also, after this function call
+func (ctx *Context) ServeFile(filename string, gzipCompression bool) error {
+	f, err := os.Open(filename)
+	if err != nil {
+		return fmt.Errorf("%d", 404)
+	}
+	defer f.Close()
+	fi, _ := f.Stat()
+	if fi.IsDir() {
+		filename = path.Join(filename, "index.html")
+		f, err = os.Open(filename)
+		if err != nil {
+			return fmt.Errorf("%d", 404)
+		}
+		fi, _ = f.Stat()
+	}
+	return ctx.ServeContent(f, fi.Name(), fi.ModTime(), gzipCompression)
+}
+
+// SendFile sends file for force-download to the client
+//
+// You can define your own "Content-Type" header also, after this function call
+// for example: ctx.Response.Header.Set("Content-Type","thecontent/type")
+func (ctx *Context) SendFile(filename string, destinationName string) error {
+	err := ctx.ServeFile(filename, false)
+	if err != nil {
+		return err
+	}
+
+	ctx.RequestCtx.Response.Header.Set(contentDisposition, "attachment;filename="+destinationName)
+	return nil
+}
+
+// Stream same as StreamWriter
+func (ctx *Context) Stream(cb func(writer *bufio.Writer)) {
+	ctx.StreamWriter(cb)
+}
+
+// StreamWriter registers the given stream writer for populating
+// response body.
+//
+//
+// This function may be used in the following cases:
+//
+//     * if response body is too big (more than 10MB).
+//     * if response body is streamed from slow external sources.
+//     * if response body must be streamed to the client in chunks.
+//     (aka `http server push`).
+func (ctx *Context) StreamWriter(cb func(writer *bufio.Writer)) {
+	ctx.RequestCtx.SetBodyStreamWriter(cb)
+}
+
+// StreamReader sets response body stream and, optionally body size.
+//
+// If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
+// before returning io.EOF.
+//
+// If bodySize < 0, then bodyStream is read until io.EOF.
+//
+// bodyStream.Close() is called after finishing reading all body data
+// if it implements io.Closer.
+//
+// See also StreamReader.
+func (ctx *Context) StreamReader(bodyStream io.Reader, bodySize int) {
+	ctx.RequestCtx.Response.SetBodyStream(bodyStream, bodySize)
+}
+
+/* Storage */
+
+// Get returns the user's value from a key
+// if doesn't exists returns nil
+func (ctx *Context) Get(key string) interface{} {
+	return ctx.RequestCtx.UserValue(key)
+}
+
+// GetFmt returns a value which has this format: func(format string, args ...interface{}) string
+// if doesn't exists returns nil
+func (ctx *Context) GetFmt(key string) func(format string, args ...interface{}) string {
+	if v, ok := ctx.Get(key).(func(format string, args ...interface{}) string); ok {
+		return v
+	}
+	return func(format string, args ...interface{}) string { return "" }
+
+}
+
+// GetString same as Get but returns the value as string
+// if nothing founds returns empty string ""
+func (ctx *Context) GetString(key string) string {
+	if v, ok := ctx.Get(key).(string); ok {
+		return v
+	}
+
+	return ""
+}
+
+// GetInt same as Get but returns the value as int
+// if nothing founds returns -1
+func (ctx *Context) GetInt(key string) int {
+	if v, ok := ctx.Get(key).(int); ok {
+		return v
+	}
+
+	return -1
+}
+
+// Set sets a value to a key in the values map
+func (ctx *Context) Set(key string, value interface{}) {
+	ctx.RequestCtx.SetUserValue(key, value)
+}
+
+// GetCookie returns cookie's value by it's name
+// returns empty string if nothing was found
+func (ctx *Context) GetCookie(name string) (val string) {
+	bcookie := ctx.RequestCtx.Request.Header.Cookie(name)
+	if bcookie != nil {
+		val = string(bcookie)
+	}
+	return
+}
+
+// SetCookie adds a cookie
+func (ctx *Context) SetCookie(cookie *fasthttp.Cookie) {
+	ctx.RequestCtx.Response.Header.SetCookie(cookie)
+}
+
+// SetCookieKV adds a cookie, receives just a key(string) and a value(string)
+func (ctx *Context) SetCookieKV(key, value string) {
+	c := fasthttp.AcquireCookie() // &fasthttp.Cookie{}
+	c.SetKey(key)
+	c.SetValue(value)
+	c.SetHTTPOnly(true)
+	c.SetExpire(time.Now().Add(time.Duration(120) * time.Minute))
+	ctx.SetCookie(c)
+	fasthttp.ReleaseCookie(c)
+}
+
+// RemoveCookie deletes a cookie by it's name/key
+func (ctx *Context) RemoveCookie(name string) {
+	cookie := fasthttp.AcquireCookie()
+	cookie.SetKey(name)
+	cookie.SetValue("")
+	cookie.SetPath("/")
+	cookie.SetHTTPOnly(true)
+	exp := time.Now().Add(-time.Duration(1) * time.Minute) //RFC says 1 second, but make sure 1 minute because we are using fasthttp
+	cookie.SetExpire(exp)
+	ctx.Response.Header.SetCookie(cookie)
+	fasthttp.ReleaseCookie(cookie)
+}
+
+// GetFlash get a flash message by it's key
+// after this action the messages is removed
+// returns string, if the cookie doesn't exists the string is empty
+func (ctx *Context) GetFlash(key string) string {
+	val, err := ctx.GetFlashBytes(key)
+	if err != nil {
+		return ""
+	}
+	return string(val)
+}
+
+// GetFlashBytes get a flash message by it's key
+// after this action the messages is removed
+// returns []byte along with an error if the cookie doesn't exists or decode fails
+func (ctx *Context) GetFlashBytes(key string) (value []byte, err error) {
+	cookieValue := string(ctx.RequestCtx.Request.Header.Cookie(key))
+	if cookieValue == "" {
+		err = errFlashNotFound.Return()
+	} else {
+		value, err = base64.URLEncoding.DecodeString(cookieValue)
+		//remove the message
+		ctx.RemoveCookie(key)
+		//it should'b be removed until the next reload, so we don't do that: ctx.Request.Header.SetCookie(key, "")
+	}
+	return
+}
+
+// SetFlash sets a flash message, accepts 2 parameters the key(string) and the value(string)
+func (ctx *Context) SetFlash(key string, value string) {
+	ctx.SetFlashBytes(key, utils.StringToBytes(value))
+}
+
+// SetFlashBytes sets a flash message, accepts 2 parameters the key(string) and the value([]byte)
+func (ctx *Context) SetFlashBytes(key string, value []byte) {
+	c := fasthttp.AcquireCookie()
+	c.SetKey(key)
+	c.SetValue(base64.URLEncoding.EncodeToString(value))
+	c.SetPath("/")
+	c.SetHTTPOnly(true)
+	ctx.RequestCtx.Response.Header.SetCookie(c)
+	fasthttp.ReleaseCookie(c)
+}
+
+// Session returns the current session store, returns nil if provider is ""
+func (ctx *Context) Session() store.IStore {
+	if ctx.framework.sessions == nil || ctx.framework.Config.Sessions.Provider == "" { //the second check can be changed on runtime, users are able to  turn off the sessions by setting provider to  ""
+		return nil
+	}
+
+	if ctx.sessionStore == nil {
+		ctx.sessionStore = ctx.framework.sessions.Start(ctx)
+	}
+	return ctx.sessionStore
+}
+
+// SessionDestroy destroys the whole session, calls the provider's destroy and remove the cookie
+func (ctx *Context) SessionDestroy() {
+	if ctx.framework.sessions != nil {
+		if store := ctx.Session(); store != nil {
+			ctx.framework.sessions.Destroy(ctx)
+		}
+	}
+
+}
+
+// SendMail sends a mail to recipients
+// the body can be html also
+func (ctx *Context) SendMail(subject string, body string, to ...string) error {
+	return ctx.framework.SendMail(subject, body, to...)
+}
+
+// Log logs to the iris defined logger
+func (ctx *Context) Log(format string, a ...interface{}) {
+	ctx.framework.Logger.Printf(format, a...)
+}
diff --git a/context/context.go b/context/context.go
index eba14304..85670df4 100644
--- a/context/context.go
+++ b/context/context.go
@@ -18,7 +18,8 @@ type (
 		IContextBinder
 		IContextRequest
 		IContextResponse
-
+		SendMail(string, string, ...string) error
+		Log(string, ...interface{})
 		Reset(*fasthttp.RequestCtx)
 		GetRequestCtx() *fasthttp.RequestCtx
 		Clone() IContext
@@ -39,17 +40,18 @@ type (
 	// IContextRenderer is part of the IContext
 	IContextRenderer interface {
 		Write(string, ...interface{})
-		WriteHTML(int, string)
+		HTML(int, string)
 		// Data writes out the raw bytes as binary data.
 		Data(status int, v []byte) error
-		// HTML builds up the response from the specified template and bindings.
-		HTML(status int, name string, binding interface{}, layout ...string) error
-		// Render same as .HTML but with status to iris.StatusOK (200)
+		// RenderWithStatus builds up the response from the specified template and bindings.
+		RenderWithStatus(status int, name string, binding interface{}, layout ...string) error
+		// Render same as .RenderWithStatus but with status to iris.StatusOK (200)
 		Render(name string, binding interface{}, layout ...string) error
 		// MustRender same as .Render but returns 500 internal server http status (error) if rendering fail
 		MustRender(name string, binding interface{}, layout ...string)
-		// RenderString accepts a template filename, its context data and returns the result of the parsed template (string)
-		RenderString(name string, binding interface{}, layout ...string) (result string, err error)
+		// TemplateString accepts a template filename, its context data and returns the result of the parsed template (string)
+		// if any error returns empty string
+		TemplateString(name string, binding interface{}, layout ...string) string
 		// MarkdownString parses the (dynamic) markdown string and returns the converted html string
 		MarkdownString(markdown string) string
 		// Markdown parses and renders to the client a particular (dynamic) markdown string
@@ -86,10 +88,13 @@ type (
 		HostString() string
 		Subdomain() string
 		PathString() string
+		RequestPath(bool) string
 		RequestIP() string
 		RemoteAddr() string
 		RequestHeader(k string) string
 		PostFormValue(string) string
+		// PostFormMulti returns a slice of string from post request's data
+		PostFormMulti(string) []string
 	}
 
 	// IContextResponse is part of the IContext
diff --git a/context_renderer.go b/context_renderer.go
deleted file mode 100644
index 00e92086..00000000
--- a/context_renderer.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package iris
-
-import (
-	"bufio"
-	"fmt"
-	"html/template"
-	"io"
-	"os"
-	"path"
-	"time"
-
-	"github.com/kataras/iris/utils"
-	"github.com/klauspost/compress/gzip"
-)
-
-// Write writes a string via the context's ResponseWriter
-func (ctx *Context) Write(format string, a ...interface{}) {
-	//this doesn't work with gzip, so just write the []byte better |ctx.ResponseWriter.WriteString(fmt.Sprintf(format, a...))
-	ctx.RequestCtx.WriteString(fmt.Sprintf(format, a...))
-}
-
-// WriteHTML writes html string with a http status
-func (ctx *Context) WriteHTML(httpStatus int, htmlContents string) {
-	ctx.SetContentType(ContentHTML + ctx.station.rest.CompiledCharset)
-	ctx.RequestCtx.SetStatusCode(httpStatus)
-	ctx.RequestCtx.WriteString(htmlContents)
-}
-
-// Data writes out the raw bytes as binary data.
-func (ctx *Context) Data(status int, v []byte) error {
-	return ctx.station.rest.Data(ctx.RequestCtx, status, v)
-}
-
-// HTML builds up the response from the specified template and bindings.
-// Note: parameter layout has meaning only when using the iris.HTMLTemplate
-func (ctx *Context) HTML(status int, name string, binding interface{}, layout ...string) error {
-	ctx.SetStatusCode(status)
-	return ctx.station.templates.Render(ctx, name, binding, layout...)
-}
-
-// Render same as .HTML but with status to iris.StatusOK (200)
-func (ctx *Context) Render(name string, binding interface{}, layout ...string) error {
-	return ctx.HTML(StatusOK, name, binding, layout...)
-}
-
-// MustRender same as .Render but returns 500 internal server http status (error) if rendering fail
-func (ctx *Context) MustRender(name string, binding interface{}, layout ...string) {
-	if err := ctx.Render(name, binding, layout...); err != nil {
-		ctx.Panic()
-	}
-}
-
-// RenderString accepts a template filename, its context data and returns the result of the parsed template (string)
-func (ctx *Context) RenderString(name string, binding interface{}, layout ...string) (result string, err error) {
-	return ctx.station.templates.RenderString(name, binding, layout...)
-}
-
-// JSON marshals the given interface object and writes the JSON response.
-func (ctx *Context) JSON(status int, v interface{}) error {
-	return ctx.station.rest.JSON(ctx.RequestCtx, status, v)
-}
-
-// JSONP marshals the given interface object and writes the JSON response.
-func (ctx *Context) JSONP(status int, callback string, v interface{}) error {
-	return ctx.station.rest.JSONP(ctx.RequestCtx, status, callback, v)
-}
-
-// Text writes out a string as plain text.
-func (ctx *Context) Text(status int, v string) error {
-	return ctx.station.rest.Text(ctx.RequestCtx, status, v)
-}
-
-// XML marshals the given interface object and writes the XML response.
-func (ctx *Context) XML(status int, v interface{}) error {
-	return ctx.station.rest.XML(ctx.RequestCtx, status, v)
-}
-
-// MarkdownString parses the (dynamic) markdown string and returns the converted html string
-func (ctx *Context) MarkdownString(markdown string) string {
-	return ctx.station.rest.Markdown([]byte(markdown))
-}
-
-// Markdown parses and renders to the client a particular (dynamic) markdown string
-// accepts two parameters
-// first is the http status code
-// second is the markdown string
-func (ctx *Context) Markdown(status int, markdown string) {
-	ctx.WriteHTML(status, ctx.MarkdownString(markdown))
-}
-
-// ExecuteTemplate executes a simple html template, you can use that if you already have the cached templates
-// the recommended way to render is to use iris.Templates("./templates/path/*.html") and ctx.RenderFile("filename.html",struct{})
-// accepts 2 parameters
-// the first parameter is the template (*template.Template)
-// the second parameter is the page context (interfac{})
-// returns an error if any errors occurs while executing this template
-func (ctx *Context) ExecuteTemplate(tmpl *template.Template, pageContext interface{}) error {
-	ctx.RequestCtx.SetContentType(ContentHTML + ctx.station.rest.CompiledCharset)
-	return ErrTemplateExecute.With(tmpl.Execute(ctx.RequestCtx.Response.BodyWriter(), pageContext))
-}
-
-// ServeContent serves content, headers are autoset
-// receives three parameters, it's low-level function, instead you can use .ServeFile(string)
-//
-// You can define your own "Content-Type" header also, after this function call
-func (ctx *Context) ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error {
-	if t, err := time.Parse(TimeFormat, ctx.RequestHeader(IfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
-		ctx.RequestCtx.Response.Header.Del(ContentType)
-		ctx.RequestCtx.Response.Header.Del(ContentLength)
-		ctx.RequestCtx.SetStatusCode(StatusNotModified)
-		return nil
-	}
-
-	ctx.RequestCtx.Response.Header.Set(ContentType, utils.TypeByExtension(filename))
-	ctx.RequestCtx.Response.Header.Set(LastModified, modtime.UTC().Format(TimeFormat))
-	ctx.RequestCtx.SetStatusCode(StatusOK)
-	var out io.Writer
-	if gzipCompression {
-		ctx.RequestCtx.Response.Header.Add("Content-Encoding", "gzip")
-		gzipWriter := ctx.station.gzipWriterPool.Get().(*gzip.Writer)
-		gzipWriter.Reset(ctx.RequestCtx.Response.BodyWriter())
-		defer gzipWriter.Close()
-		defer ctx.station.gzipWriterPool.Put(gzipWriter)
-		out = gzipWriter
-	} else {
-		out = ctx.RequestCtx.Response.BodyWriter()
-
-	}
-	_, err := io.Copy(out, content)
-	return ErrServeContent.With(err)
-}
-
-// ServeFile serves a view file, to send a file ( zip for example) to the client you should use the SendFile(serverfilename,clientfilename)
-// receives two parameters
-// filename/path (string)
-// gzipCompression (bool)
-//
-// You can define your own "Content-Type" header also, after this function call
-func (ctx *Context) ServeFile(filename string, gzipCompression bool) error {
-	f, err := os.Open(filename)
-	if err != nil {
-		return fmt.Errorf("%d", 404)
-	}
-	defer f.Close()
-	fi, _ := f.Stat()
-	if fi.IsDir() {
-		filename = path.Join(filename, "index.html")
-		f, err = os.Open(filename)
-		if err != nil {
-			return fmt.Errorf("%d", 404)
-		}
-		fi, _ = f.Stat()
-	}
-	return ctx.ServeContent(f, fi.Name(), fi.ModTime(), gzipCompression)
-}
-
-// SendFile sends file for force-download to the client
-//
-// You can define your own "Content-Type" header also, after this function call
-// for example: ctx.Response.Header.Set("Content-Type","thecontent/type")
-func (ctx *Context) SendFile(filename string, destinationName string) error {
-	err := ctx.ServeFile(filename, false)
-	if err != nil {
-		return err
-	}
-
-	ctx.RequestCtx.Response.Header.Set(ContentDisposition, "attachment;filename="+destinationName)
-	return nil
-}
-
-// Stream same as StreamWriter
-func (ctx *Context) Stream(cb func(writer *bufio.Writer)) {
-	ctx.StreamWriter(cb)
-}
-
-// StreamWriter registers the given stream writer for populating
-// response body.
-//
-//
-// This function may be used in the following cases:
-//
-//     * if response body is too big (more than 10MB).
-//     * if response body is streamed from slow external sources.
-//     * if response body must be streamed to the client in chunks.
-//     (aka `http server push`).
-func (ctx *Context) StreamWriter(cb func(writer *bufio.Writer)) {
-	ctx.RequestCtx.SetBodyStreamWriter(cb)
-}
-
-// StreamReader sets response body stream and, optionally body size.
-//
-// If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
-// before returning io.EOF.
-//
-// If bodySize < 0, then bodyStream is read until io.EOF.
-//
-// bodyStream.Close() is called after finishing reading all body data
-// if it implements io.Closer.
-//
-// See also StreamReader.
-func (ctx *Context) StreamReader(bodyStream io.Reader, bodySize int) {
-	ctx.RequestCtx.Response.SetBodyStream(bodyStream, bodySize)
-}
diff --git a/context_request.go b/context_request.go
deleted file mode 100644
index 0aae9480..00000000
--- a/context_request.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package iris
-
-import (
-	"net"
-	"strconv"
-	"strings"
-
-	"github.com/kataras/iris/bindings"
-	"github.com/kataras/iris/utils"
-	"github.com/valyala/fasthttp"
-)
-
-// Param returns the string representation of the key's path named parameter's value
-func (ctx *Context) Param(key string) string {
-	return ctx.Params.Get(key)
-}
-
-// ParamInt returns the int representation of the key's path named parameter's value
-func (ctx *Context) ParamInt(key string) (int, error) {
-	val, err := strconv.Atoi(ctx.Param(key))
-	return val, err
-}
-
-// URLParam returns the get parameter from a request , if any
-func (ctx *Context) URLParam(key string) string {
-	return string(ctx.RequestCtx.Request.URI().QueryArgs().Peek(key))
-}
-
-// URLParams returns a map of a list of each url(query) parameter
-func (ctx *Context) URLParams() map[string]string {
-	urlparams := make(map[string]string)
-	ctx.RequestCtx.Request.URI().QueryArgs().VisitAll(func(key, value []byte) {
-		urlparams[string(key)] = string(value)
-	})
-	return urlparams
-}
-
-// URLParamInt returns the get parameter int value from a request , if any
-func (ctx *Context) URLParamInt(key string) (int, error) {
-	return strconv.Atoi(ctx.URLParam(key))
-}
-
-// MethodString returns the HTTP Method
-func (ctx *Context) MethodString() string {
-	return utils.BytesToString(ctx.Method())
-}
-
-// HostString returns the Host of the request( the url as string )
-func (ctx *Context) HostString() string {
-	return utils.BytesToString(ctx.Host())
-}
-
-// PathString returns the full path as string
-func (ctx *Context) PathString() string {
-	return utils.BytesToString(ctx.Path())
-}
-
-// RequestIP gets just the Remote Address from the client.
-func (ctx *Context) RequestIP() string {
-	if ip, _, err := net.SplitHostPort(strings.TrimSpace(ctx.RequestCtx.RemoteAddr().String())); err == nil {
-		return ip
-	}
-	return ""
-}
-
-// RemoteAddr is like RequestIP but it checks for proxy servers also, tries to get the real client's request IP
-func (ctx *Context) RemoteAddr() string {
-	header := string(ctx.RequestCtx.Request.Header.Peek("X-Real-Ip"))
-	realIP := strings.TrimSpace(header)
-	if realIP != "" {
-		return realIP
-	}
-	realIP = string(ctx.RequestCtx.Request.Header.Peek("X-Forwarded-For"))
-	idx := strings.IndexByte(realIP, ',')
-	if idx >= 0 {
-		realIP = realIP[0:idx]
-	}
-	realIP = strings.TrimSpace(realIP)
-	if realIP != "" {
-		return realIP
-	}
-	return ctx.RequestIP()
-
-}
-
-// RequestHeader returns the request header's value
-// accepts one parameter, the key of the header (string)
-// returns string
-func (ctx *Context) RequestHeader(k string) string {
-	return utils.BytesToString(ctx.RequestCtx.Request.Header.Peek(k))
-}
-
-// PostFormValue returns a single value from post request's data
-func (ctx *Context) PostFormValue(name string) string {
-	return string(ctx.RequestCtx.PostArgs().Peek(name))
-}
-
-// Subdomain returns the subdomain (string) of this request, if any
-func (ctx *Context) Subdomain() (subdomain string) {
-	host := ctx.HostString()
-	if index := strings.IndexByte(host, '.'); index > 0 {
-		subdomain = host[0:index]
-	}
-
-	return
-}
-
-// URLEncode returns the path encoded as url
-// useful when you want to pass something to a database and be valid to retrieve it via context.Param
-// use it only for special cases, when the default behavior doesn't suits you.
-//
-// http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
-/* Credits to Manish Singh @kryptodev for URLEncode */
-func URLEncode(path string) string {
-	if path == "" {
-		return ""
-	}
-	u := fasthttp.AcquireURI()
-	u.SetPath(path)
-	encodedPath := u.String()[8:]
-	fasthttp.ReleaseURI(u)
-	return encodedPath
-}
-
-// ReadJSON reads JSON from request's body
-func (ctx *Context) ReadJSON(jsonObject interface{}) error {
-	return bindings.BindJSON(ctx, jsonObject)
-}
-
-// ReadXML reads XML from request's body
-func (ctx *Context) ReadXML(xmlObject interface{}) error {
-	return bindings.BindXML(ctx, xmlObject)
-}
-
-// ReadForm binds the formObject  with the form data
-// it supports any kind of struct
-func (ctx *Context) ReadForm(formObject interface{}) error {
-	return bindings.BindForm(ctx, formObject)
-}
diff --git a/context_response.go b/context_response.go
deleted file mode 100644
index 54e70634..00000000
--- a/context_response.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package iris
-
-// SetContentType sets the response writer's header key 'Content-Type' to a given value(s)
-func (ctx *Context) SetContentType(s string) {
-	ctx.RequestCtx.Response.Header.Set(ContentType, s)
-}
-
-// SetHeader write to the response writer's header to a given key the given value(s)
-func (ctx *Context) SetHeader(k string, v string) {
-	ctx.RequestCtx.Response.Header.Set(k, v)
-}
-
-// Redirect redirect sends a redirect response the client
-// accepts 2 parameters string and an optional int
-// first parameter is the url to redirect
-// second parameter is the http status should send, default is 302 (StatusFound), you can set it to 301 (Permant redirect), if that's nessecery
-func (ctx *Context) Redirect(urlToRedirect string, statusHeader ...int) {
-	httpStatus := StatusFound // temporary redirect
-	if statusHeader != nil && len(statusHeader) > 0 && statusHeader[0] > 0 {
-		httpStatus = statusHeader[0]
-	}
-	ctx.RequestCtx.Redirect(urlToRedirect, httpStatus)
-	ctx.StopExecution()
-}
-
-// RedirectTo does the same thing as Redirect but instead of receiving a uri or path it receives a route name
-func (ctx *Context) RedirectTo(routeName string, args ...interface{}) {
-	s := ctx.station.RouteByName(routeName).ParseURI(args...)
-	if s != "" {
-		ctx.Redirect(s, StatusFound)
-	}
-}
-
-// Error handling
-
-// NotFound emits an error 404 to the client, using the custom http errors
-// if no custom errors provided then it sends the default http.NotFound
-func (ctx *Context) NotFound() {
-	ctx.StopExecution()
-	ctx.station.EmitError(404, ctx)
-}
-
-// Panic stops the executions of the context and returns the registed panic handler
-// or if not, the default which is  500 http status to the client
-//
-// This function is useful when you use the recovery middleware, which is auto-executing the (custom, registed) 500 internal server error.
-func (ctx *Context) Panic() {
-	ctx.StopExecution()
-	ctx.station.EmitError(500, ctx)
-}
-
-// EmitError executes the custom error by the http status code passed to the function
-func (ctx *Context) EmitError(statusCode int) {
-	ctx.station.EmitError(statusCode, ctx)
-}
diff --git a/context_storage.go b/context_storage.go
deleted file mode 100644
index 4cf394a2..00000000
--- a/context_storage.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package iris
-
-import (
-	"encoding/base64"
-	"time"
-
-	"github.com/kataras/iris/sessions/store"
-	"github.com/kataras/iris/utils"
-	"github.com/valyala/fasthttp"
-)
-
-// After v2.2.3 Get/GetFmt/GetString/GetInt/Set are all return values from the RequestCtx.userValues they are reseting on each connection.
-
-// Get returns the user's value from a key
-// if doesn't exists returns nil
-func (ctx *Context) Get(key string) interface{} {
-	return ctx.RequestCtx.UserValue(key)
-}
-
-// GetFmt returns a value which has this format: func(format string, args ...interface{}) string
-// if doesn't exists returns nil
-func (ctx *Context) GetFmt(key string) func(format string, args ...interface{}) string {
-	if v, ok := ctx.Get(key).(func(format string, args ...interface{}) string); ok {
-		return v
-	}
-	return func(format string, args ...interface{}) string { return "" }
-
-}
-
-// GetString same as Get but returns the value as string
-// if nothing founds returns empty string ""
-func (ctx *Context) GetString(key string) string {
-	if v, ok := ctx.Get(key).(string); ok {
-		return v
-	}
-
-	return ""
-}
-
-// GetInt same as Get but returns the value as int
-// if nothing founds returns -1
-func (ctx *Context) GetInt(key string) int {
-	if v, ok := ctx.Get(key).(int); ok {
-		return v
-	}
-
-	return -1
-}
-
-// Set sets a value to a key in the values map
-func (ctx *Context) Set(key string, value interface{}) {
-	ctx.RequestCtx.SetUserValue(key, value)
-}
-
-// GetCookie returns cookie's value by it's name
-// returns empty string if nothing was found
-func (ctx *Context) GetCookie(name string) (val string) {
-	bcookie := ctx.RequestCtx.Request.Header.Cookie(name)
-	if bcookie != nil {
-		val = string(bcookie)
-	}
-	return
-}
-
-// SetCookie adds a cookie
-func (ctx *Context) SetCookie(cookie *fasthttp.Cookie) {
-	ctx.RequestCtx.Response.Header.SetCookie(cookie)
-}
-
-// SetCookieKV adds a cookie, receives just a key(string) and a value(string)
-func (ctx *Context) SetCookieKV(key, value string) {
-	c := fasthttp.AcquireCookie() // &fasthttp.Cookie{}
-	c.SetKey(key)
-	c.SetValue(value)
-	c.SetHTTPOnly(true)
-	c.SetExpire(time.Now().Add(time.Duration(120) * time.Minute))
-	ctx.SetCookie(c)
-	fasthttp.ReleaseCookie(c)
-}
-
-// RemoveCookie deletes a cookie by it's name/key
-func (ctx *Context) RemoveCookie(name string) {
-	cookie := fasthttp.AcquireCookie()
-	cookie.SetKey(name)
-	cookie.SetValue("")
-	cookie.SetPath("/")
-	cookie.SetHTTPOnly(true)
-	exp := time.Now().Add(-time.Duration(1) * time.Minute) //RFC says 1 second, but make sure 1 minute because we are using fasthttp
-	cookie.SetExpire(exp)
-	ctx.Response.Header.SetCookie(cookie)
-	fasthttp.ReleaseCookie(cookie)
-}
-
-// GetFlash get a flash message by it's key
-// after this action the messages is removed
-// returns string, if the cookie doesn't exists the string is empty
-func (ctx *Context) GetFlash(key string) string {
-	val, err := ctx.GetFlashBytes(key)
-	if err != nil {
-		return ""
-	}
-	return string(val)
-}
-
-// GetFlashBytes get a flash message by it's key
-// after this action the messages is removed
-// returns []byte along with an error if the cookie doesn't exists or decode fails
-func (ctx *Context) GetFlashBytes(key string) (value []byte, err error) {
-	cookieValue := string(ctx.RequestCtx.Request.Header.Cookie(key))
-	if cookieValue == "" {
-		err = ErrFlashNotFound.Return()
-	} else {
-		value, err = base64.URLEncoding.DecodeString(cookieValue)
-		//remove the message
-		ctx.RemoveCookie(key)
-		//it should'b be removed until the next reload, so we don't do that: ctx.Request.Header.SetCookie(key, "")
-	}
-	return
-}
-
-// SetFlash sets a flash message, accepts 2 parameters the key(string) and the value(string)
-func (ctx *Context) SetFlash(key string, value string) {
-	ctx.SetFlashBytes(key, utils.StringToBytes(value))
-}
-
-// SetFlashBytes sets a flash message, accepts 2 parameters the key(string) and the value([]byte)
-func (ctx *Context) SetFlashBytes(key string, value []byte) {
-	c := fasthttp.AcquireCookie()
-	c.SetKey(key)
-	c.SetValue(base64.URLEncoding.EncodeToString(value))
-	c.SetPath("/")
-	c.SetHTTPOnly(true)
-	ctx.RequestCtx.Response.Header.SetCookie(c)
-	fasthttp.ReleaseCookie(c)
-}
-
-// Session returns the current session store, returns nil if provider is ""
-func (ctx *Context) Session() store.IStore {
-	if ctx.station.sessionManager == nil || ctx.station.config.Sessions.Provider == "" { //the second check can be changed on runtime, users are able to  turn off the sessions by setting provider to  ""
-		return nil
-	}
-
-	if ctx.sessionStore == nil {
-		ctx.sessionStore = ctx.station.sessionManager.Start(ctx)
-	}
-	return ctx.sessionStore
-}
-
-// SessionDestroy destroys the whole session, calls the provider's destroy and remove the cookie
-func (ctx *Context) SessionDestroy() {
-	if ctx.station.sessionManager != nil {
-		if store := ctx.Session(); store != nil {
-			ctx.station.sessionManager.Destroy(ctx)
-		}
-	}
-
-}
diff --git a/errors.go b/errors.go
deleted file mode 100644
index 31c9779c..00000000
--- a/errors.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package iris
-
-import "github.com/kataras/iris/errors"
-
-var (
-	// Router, Party & Handler
-
-	// ErrHandler returns na error with message: 'Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)
-	// It seems to be a  +type Points to: +pointer.'
-	ErrHandler = errors.New("Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)\n It seems to be a  %T Points to: %v.")
-	// ErrHandleAnnotated returns an error with message: 'HandleAnnotated parse: +specific error(s)'
-	ErrHandleAnnotated = errors.New("HandleAnnotated parse: %s")
-	// ErrControllerContextNotFound returns an error with message: 'Context *iris.Context could not be found, the Controller won't be registed.'
-	ErrControllerContextNotFound = errors.New("Context *iris.Context could not be found, the Controller won't be registed.")
-	// ErrDirectoryFileNotFound returns an error with message: 'Directory or file %s couldn't found. Trace: +error trace'
-	ErrDirectoryFileNotFound = errors.New("Directory or file %s couldn't found. Trace: %s")
-	// ErrRenderRouteNotFound returns an error with message 'Route with name +route_name not found', used inside 'url' template func
-	ErrRenderRouteNotFound = errors.New("Route with name %s not found")
-
-	// Plugin
-
-	// ErrPluginAlreadyExists returns an error with message: 'Cannot activate the same plugin again, plugin '+plugin name[+plugin description]' is already exists'
-	ErrPluginAlreadyExists = errors.New("Cannot use the same plugin again, '%s[%s]' is already exists")
-	// ErrPluginActivate returns an error with message: 'While trying to activate plugin '+plugin name'. Trace: +specific error'
-	ErrPluginActivate = errors.New("While trying to activate plugin '%s'. Trace: %s")
-	// ErrPluginRemoveNoPlugins returns an error with message: 'No plugins are registed yet, you cannot remove a plugin from an empty list!'
-	ErrPluginRemoveNoPlugins = errors.New("No plugins are registed yet, you cannot remove a plugin from an empty list!")
-	// ErrPluginRemoveEmptyName returns an error with message: 'Plugin with an empty name cannot be removed'
-	ErrPluginRemoveEmptyName = errors.New("Plugin with an empty name cannot be removed")
-	// ErrPluginRemoveNotFound returns an error with message: 'Cannot remove a plugin which doesn't exists'
-	ErrPluginRemoveNotFound = errors.New("Cannot remove a plugin which doesn't exists")
-	// Context other
-
-	// ErrServeContent returns an error with message: 'While trying to serve content to the client. Trace +specific error'
-	ErrServeContent = errors.New("While trying to serve content to the client. Trace %s")
-
-	// ErrTemplateExecute returns an error with message:'Unable to execute a template. Trace: +specific error'
-	ErrTemplateExecute = errors.New("Unable to execute a template. Trace: %s")
-
-	// ErrFlashNotFound returns an error with message: 'Unable to get flash message. Trace: Cookie does not exists'
-	ErrFlashNotFound = errors.New("Unable to get flash message. Trace: Cookie does not exists")
-	// ErrSessionNil returns an error with message: 'Unable to set session, Config().Session.Provider is nil, please refer to the docs!'
-	ErrSessionNil = errors.New("Unable to set session, Config().Session.Provider is nil, please refer to the docs!")
-)
diff --git a/errors/error.go b/errors/error.go
index c170ccac..5c3fef66 100644
--- a/errors/error.go
+++ b/errors/error.go
@@ -19,7 +19,7 @@ func (e *Error) Error() string {
 
 // Format returns a formatted new error based on the arguments
 func (e *Error) Format(args ...interface{}) error {
-	return fmt.Errorf(e.message, args)
+	return fmt.Errorf(e.message, args...)
 }
 
 // With does the same thing as Format but it receives an error type which if it's nil it returns a nil error
@@ -33,7 +33,7 @@ func (e *Error) With(err error) error {
 
 // Return returns the actual error as it is
 func (e *Error) Return() error {
-	return fmt.Errorf(e.message)
+	return e.Format()
 }
 
 // Panic output the message and after panics
diff --git a/graceful/graceful.go b/graceful/graceful.go
index 60ca19a5..1c60ecce 100644
--- a/graceful/graceful.go
+++ b/graceful/graceful.go
@@ -11,7 +11,6 @@ import (
 	"github.com/kataras/iris"
 	"github.com/kataras/iris/config"
 	"github.com/kataras/iris/logger"
-	"github.com/kataras/iris/server"
 	"golang.org/x/net/netutil"
 )
 
@@ -19,8 +18,8 @@ import (
 // It may be used directly in the same way as iris.Server, or may
 // be constructed with the global functions in this package.
 type Server struct {
-	*server.Server
-	station *iris.Iris
+	*iris.Server
+	station *iris.Framework
 	// Timeout is the duration to allow outstanding requests to survive
 	// before forcefully terminating them.
 	Timeout time.Duration
@@ -67,18 +66,18 @@ type Server struct {
 	connections map[net.Conn]struct{}
 }
 
-// Run serves the http.Handler with graceful shutdown enabled.
+// Run serves the iris.Handler with graceful shutdown enabled.
 //
 // timeout is the duration to wait until killing active requests and stopping the server.
 // If timeout is 0, the server never times out. It waits for all active requests to finish.
 // we don't pass an iris.RequestHandler , because we need iris.station.server to be setted in order the station.Close() to work
-func Run(addr string, timeout time.Duration, n *iris.Iris) {
+func Run(addr string, timeout time.Duration, s *iris.Framework) {
 	srv := &Server{
 		Timeout: timeout,
-		Logger:  DefaultLogger(),
+		Logger:  s.Logger,
+		station: s,
+		Server:  s.NoListen(),
 	}
-	srv.station = n
-	srv.Server = srv.station.PreListen(config.Server{ListeningAddr: addr})
 
 	if err := srv.listenAndServe(); err != nil {
 		if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
@@ -92,13 +91,14 @@ func Run(addr string, timeout time.Duration, n *iris.Iris) {
 //
 // Unlike Run this version will not exit the program if an error is encountered but will
 // return it instead.
-func RunWithErr(addr string, timeout time.Duration, n *iris.Iris) error {
+func RunWithErr(addr string, timeout time.Duration, s *iris.Framework) error {
 	srv := &Server{
 		Timeout: timeout,
-		Logger:  DefaultLogger(),
+		Logger:  s.Logger,
+		station: s,
+		Server:  s.NoListen(),
 	}
-	srv.station = n
-	srv.Server = srv.station.PreListen(config.Server{ListeningAddr: addr})
+
 	return srv.listenAndServe()
 }
 
@@ -143,7 +143,7 @@ func (srv *Server) serve(listener net.Listener) error {
 
 	// Serve with graceful listener.
 	// Execution blocks here until listener.Close() is called, above.
-	srv.station.PostListen()
+	srv.station.NoListen()
 	err := srv.Server.Serve(listener)
 	if err != nil {
 		// If the underlying listening is closed, Serve returns an error
@@ -218,7 +218,7 @@ func (srv *Server) manageConnections(add, remove chan net.Conn, shutdown chan ch
 		case <-kill:
 			for k := range srv.connections {
 				if err := k.Close(); err != nil {
-					srv.log("[IRIS GRACEFUL ERROR] %s", err.Error())
+					srv.log("[IRIS GRACEFUL ERROR]" + err.Error())
 				}
 			}
 			return
@@ -252,7 +252,7 @@ func (srv *Server) handleInterrupt(interrupt chan os.Signal, quitting chan struc
 		close(quitting)
 		srv.Server.DisableKeepalive = true
 		if err := listener.Close(); err != nil {
-			srv.log("[IRIS GRACEFUL ERROR] %s", err.Error())
+			srv.log("[IRIS GRACEFUL ERROR]" + err.Error())
 		}
 
 		if srv.ShutdownInitiated != nil {
diff --git a/handler.go b/handler.go
deleted file mode 100644
index 0ea29fe8..00000000
--- a/handler.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package iris
-
-import (
-	"net/http"
-
-	"github.com/valyala/fasthttp"
-	"github.com/valyala/fasthttp/fasthttpadaptor"
-)
-
-type (
-
-	// Handler the main Iris Handler interface.
-	Handler interface {
-		Serve(ctx *Context)
-	}
-
-	// HandlerFunc type is an adapter to allow the use of
-	// ordinary functions as HTTP handlers.  If f is a function
-	// with the appropriate signature, HandlerFunc(f) is a
-	// Handler that calls f.
-	HandlerFunc func(*Context)
-
-	// HandlerAPI allow the use of a custom struct as API handler(s) for a particular request path
-	// It's just an interface {}, we keep it here to make things more readable.
-	HandlerAPI interface {
-		// we don't use context.IContext because of some methods as Get() is already inside the IContext interface and conficts with the Get()
-		// we want to use for API.
-		// a valid controller has this form:
-		/*
-				type index struct {
-					*iris.Context
-			    }
-
-				// OR
-				type index struct {
-					Context *iris.Context
-			    }
-
-				func (i index) Get() {
-				    i.Write("Hello from /")
-				}
-
-				func (i index) GetBy(id string) {} // /:namedParameter
-				//POST,PUT,DELETE...
-
-		*/
-	}
-
-	//IMiddlewareSupporter is an interface which all routers must implement
-	IMiddlewareSupporter interface {
-		Use(handlers ...Handler)
-		UseFunc(handlersFn ...HandlerFunc)
-	}
-
-	// Middleware is just a slice of Handler []func(c *Context)
-	Middleware []Handler
-)
-
-// Serve serves the handler, is like ServeHTTP for Iris
-func (h HandlerFunc) Serve(ctx *Context) {
-	h(ctx)
-}
-
-// ToHandler converts an http.Handler or http.HandlerFunc to an iris.Handler
-func ToHandler(handler interface{}) Handler {
-	//this is not the best way to do it, but I dont have any options right now.
-	switch handler.(type) {
-	case Handler:
-		//it's already an iris handler
-		return handler.(Handler)
-	case http.Handler:
-		//it's http.Handler
-		h := fasthttpadaptor.NewFastHTTPHandlerFunc(handler.(http.Handler).ServeHTTP)
-
-		return ToHandlerFastHTTP(h)
-	case func(http.ResponseWriter, *http.Request):
-		//it's http.HandlerFunc
-		h := fasthttpadaptor.NewFastHTTPHandlerFunc(handler.(func(http.ResponseWriter, *http.Request)))
-		return ToHandlerFastHTTP(h)
-	default:
-		panic(ErrHandler.Format(handler, handler))
-	}
-}
-
-// ToHandlerFunc converts an http.Handler or http.HandlerFunc to an iris.HandlerFunc
-func ToHandlerFunc(handler interface{}) HandlerFunc {
-	return ToHandler(handler).Serve
-}
-
-// ToHandlerFastHTTP converts an fasthttp.RequestHandler to an iris.Handler
-func ToHandlerFastHTTP(h fasthttp.RequestHandler) Handler {
-	return HandlerFunc((func(ctx *Context) {
-		h(ctx.RequestCtx)
-	}))
-}
-
-// ConvertToHandlers accepts list of HandlerFunc and returns list of Handler
-// this can be renamed to convertToMiddleware also because it returns a list of []Handler which is what Middleware is
-func ConvertToHandlers(handlersFn []HandlerFunc) []Handler {
-	hlen := len(handlersFn)
-	mlist := make([]Handler, hlen)
-	for i := 0; i < hlen; i++ {
-		mlist[i] = Handler(handlersFn[i])
-	}
-	return mlist
-}
-
-// JoinMiddleware uses to create a copy of all middleware and return them in order to use inside the node
-func JoinMiddleware(middleware1 Middleware, middleware2 Middleware) Middleware {
-	nowLen := len(middleware1)
-	totalLen := nowLen + len(middleware2)
-	// create a new slice of middleware in order to store all handlers, the already handlers(middleware) and the new
-	newMiddleware := make(Middleware, totalLen)
-	//copy the already middleware to the just created
-	copy(newMiddleware, middleware1)
-	//start from there we finish, and store the new middleware too
-	copy(newMiddleware[nowLen:], middleware2)
-	return newMiddleware
-}
diff --git a/http.go b/http.go
new file mode 100644
index 00000000..9ada71af
--- /dev/null
+++ b/http.go
@@ -0,0 +1,1303 @@
+package iris
+
+import (
+	"bytes"
+	"net"
+	"net/http"
+	"net/http/pprof"
+	"os"
+	"strings"
+	"sync"
+
+	"github.com/kataras/iris/config"
+	"github.com/kataras/iris/errors"
+	"github.com/kataras/iris/utils"
+	"github.com/valyala/fasthttp"
+	"github.com/valyala/fasthttp/fasthttpadaptor"
+)
+
+const (
+	// MethodGet "GET"
+	MethodGet = "GET"
+	// MethodPost "POST"
+	MethodPost = "POST"
+	// MethodPut "PUT"
+	MethodPut = "PUT"
+	// MethodDelete "DELETE"
+	MethodDelete = "DELETE"
+	// MethodConnect "CONNECT"
+	MethodConnect = "CONNECT"
+	// MethodHead "HEAD"
+	MethodHead = "HEAD"
+	// MethodPatch "PATCH"
+	MethodPatch = "PATCH"
+	// MethodOptions "OPTIONS"
+	MethodOptions = "OPTIONS"
+	// MethodTrace "TRACE"
+	MethodTrace = "TRACE"
+)
+
+var (
+	// AllMethods "GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD", "PATCH", "OPTIONS", "TRACE"
+	AllMethods = [...]string{MethodGet, MethodPost, MethodPut, MethodDelete, MethodConnect, MethodHead, MethodPatch, MethodOptions, MethodTrace}
+
+	/* methods as []byte, these are really used by iris */
+	// methodGetBytes "GET"
+	methodGetBytes = []byte(MethodGet)
+	// methodPostBytes "POST"
+	methodPostBytes = []byte(MethodPost)
+	// methodPutBytes "PUT"
+	methodPutBytes = []byte(MethodPut)
+	// methodDeleteBytes "DELETE"
+	methodDeleteBytes = []byte(MethodDelete)
+	// methodConnectBytes "CONNECT"
+	methodConnectBytes = []byte(MethodConnect)
+	// methodHeadBytes "HEAD"
+	methodHeadBytes = []byte(MethodHead)
+	// methodPatchBytes "PATCH"
+	methodPatchBytes = []byte(MethodPatch)
+	// methodOptionsBytes "OPTIONS"
+	methodOptionsBytes = []byte(MethodOptions)
+	// methodTraceBytes "TRACE"
+	methodTraceBytes = []byte(MethodTrace)
+	/* */
+
+)
+
+const (
+	// StatusContinue http status '100'
+	StatusContinue = 100
+	// StatusSwitchingProtocols http status '101'
+	StatusSwitchingProtocols = 101
+
+	// StatusOK http status '200'
+	StatusOK = 200
+	// StatusCreated http status '201'
+	StatusCreated = 201
+	// StatusAccepted http status '202'
+	StatusAccepted = 202
+	// StatusNonAuthoritativeInfo http status '203'
+	StatusNonAuthoritativeInfo = 203
+	// StatusNoContent http status '204'
+	StatusNoContent = 204
+	// StatusResetContent http status '205'
+	StatusResetContent = 205
+	// StatusPartialContent http status '206'
+	StatusPartialContent = 206
+
+	// StatusMultipleChoices http status '300'
+	StatusMultipleChoices = 300
+	// StatusMovedPermanently http status '301'
+	StatusMovedPermanently = 301
+	// StatusFound http status '302'
+	StatusFound = 302
+	// StatusSeeOther http status '303'
+	StatusSeeOther = 303
+	// StatusNotModified http status '304'
+	StatusNotModified = 304
+	// StatusUseProxy http status '305'
+	StatusUseProxy = 305
+	// StatusTemporaryRedirect http status '307'
+	StatusTemporaryRedirect = 307
+
+	// StatusBadRequest http status '400'
+	StatusBadRequest = 400
+	// StatusUnauthorized http status '401'
+	StatusUnauthorized = 401
+	// StatusPaymentRequired http status '402'
+	StatusPaymentRequired = 402
+	// StatusForbidden http status '403'
+	StatusForbidden = 403
+	// StatusNotFound http status '404'
+	StatusNotFound = 404
+	// StatusMethodNotAllowed http status '405'
+	StatusMethodNotAllowed = 405
+	// StatusNotAcceptable http status '406'
+	StatusNotAcceptable = 406
+	// StatusProxyAuthRequired http status '407'
+	StatusProxyAuthRequired = 407
+	// StatusRequestTimeout http status '408'
+	StatusRequestTimeout = 408
+	// StatusConflict http status '409'
+	StatusConflict = 409
+	// StatusGone http status '410'
+	StatusGone = 410
+	// StatusLengthRequired http status '411'
+	StatusLengthRequired = 411
+	// StatusPreconditionFailed http status '412'
+	StatusPreconditionFailed = 412
+	// StatusRequestEntityTooLarge http status '413'
+	StatusRequestEntityTooLarge = 413
+	// StatusRequestURITooLong http status '414'
+	StatusRequestURITooLong = 414
+	// StatusUnsupportedMediaType http status '415'
+	StatusUnsupportedMediaType = 415
+	// StatusRequestedRangeNotSatisfiable http status '416'
+	StatusRequestedRangeNotSatisfiable = 416
+	// StatusExpectationFailed http status '417'
+	StatusExpectationFailed = 417
+	// StatusTeapot http status '418'
+	StatusTeapot = 418
+	// StatusPreconditionRequired http status '428'
+	StatusPreconditionRequired = 428
+	// StatusTooManyRequests http status '429'
+	StatusTooManyRequests = 429
+	// StatusRequestHeaderFieldsTooLarge http status '431'
+	StatusRequestHeaderFieldsTooLarge = 431
+	// StatusUnavailableForLegalReasons http status '451'
+	StatusUnavailableForLegalReasons = 451
+
+	// StatusInternalServerError http status '500'
+	StatusInternalServerError = 500
+	// StatusNotImplemented http status '501'
+	StatusNotImplemented = 501
+	// StatusBadGateway http status '502'
+	StatusBadGateway = 502
+	// StatusServiceUnavailable http status '503'
+	StatusServiceUnavailable = 503
+	// StatusGatewayTimeout http status '504'
+	StatusGatewayTimeout = 504
+	// StatusHTTPVersionNotSupported http status '505'
+	StatusHTTPVersionNotSupported = 505
+	// StatusNetworkAuthenticationRequired http status '511'
+	StatusNetworkAuthenticationRequired = 511
+)
+
+var statusText = map[int]string{
+	StatusContinue:           "Continue",
+	StatusSwitchingProtocols: "Switching Protocols",
+
+	StatusOK:                   "OK",
+	StatusCreated:              "Created",
+	StatusAccepted:             "Accepted",
+	StatusNonAuthoritativeInfo: "Non-Authoritative Information",
+	StatusNoContent:            "No Content",
+	StatusResetContent:         "Reset Content",
+	StatusPartialContent:       "Partial Content",
+
+	StatusMultipleChoices:   "Multiple Choices",
+	StatusMovedPermanently:  "Moved Permanently",
+	StatusFound:             "Found",
+	StatusSeeOther:          "See Other",
+	StatusNotModified:       "Not Modified",
+	StatusUseProxy:          "Use Proxy",
+	StatusTemporaryRedirect: "Temporary Redirect",
+
+	StatusBadRequest:                   "Bad Request",
+	StatusUnauthorized:                 "Unauthorized",
+	StatusPaymentRequired:              "Payment Required",
+	StatusForbidden:                    "Forbidden",
+	StatusNotFound:                     "Not Found",
+	StatusMethodNotAllowed:             "Method Not Allowed",
+	StatusNotAcceptable:                "Not Acceptable",
+	StatusProxyAuthRequired:            "Proxy Authentication Required",
+	StatusRequestTimeout:               "Request Timeout",
+	StatusConflict:                     "Conflict",
+	StatusGone:                         "Gone",
+	StatusLengthRequired:               "Length Required",
+	StatusPreconditionFailed:           "Precondition Failed",
+	StatusRequestEntityTooLarge:        "Request Entity Too Large",
+	StatusRequestURITooLong:            "Request URI Too Long",
+	StatusUnsupportedMediaType:         "Unsupported Media Type",
+	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
+	StatusExpectationFailed:            "Expectation Failed",
+	StatusTeapot:                       "I'm a teapot",
+	StatusPreconditionRequired:         "Precondition Required",
+	StatusTooManyRequests:              "Too Many Requests",
+	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
+	StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",
+
+	StatusInternalServerError:           "Internal Server Error",
+	StatusNotImplemented:                "Not Implemented",
+	StatusBadGateway:                    "Bad Gateway",
+	StatusServiceUnavailable:            "Service Unavailable",
+	StatusGatewayTimeout:                "Gateway Timeout",
+	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
+	StatusNetworkAuthenticationRequired: "Network Authentication Required",
+}
+
+// StatusText returns a text for the HTTP status code. It returns the empty
+// string if the code is unknown.
+func StatusText(code int) string {
+	return statusText[code]
+}
+
+// Errors introduced by server.
+var (
+	errServerPortAlreadyUsed = errors.New("Server can't run, port is already used")
+	errServerAlreadyStarted  = errors.New("Server is already started and listening")
+	errServerConfigMissing   = errors.New("Empty Config for server")
+	errServerHandlerMissing  = errors.New("Handler is missing from server, can't start without handler")
+	errServerIsClosed        = errors.New("Can't close the server, propably is already closed or never started")
+	errServerRemoveUnix      = errors.New("Unexpected error when trying to remove unix socket file. Addr: %s | Trace: %s")
+	errServerChmod           = errors.New("Cannot chmod %#o for %q: %s")
+)
+
+// Server the http server
+type Server struct {
+	*fasthttp.Server
+	listener net.Listener
+	Config   *config.Server
+	started  bool
+	tls      bool
+}
+
+// newServer returns a pointer to a Server object, and set it's options if any,  nothing more
+func newServer(c *config.Server) *Server {
+	s := &Server{Server: &fasthttp.Server{Name: config.ServerName}, Config: c}
+	return s
+}
+
+// SetHandler sets the handler in order to listen on client requests
+func (s *Server) SetHandler(mux *serveMux) {
+	if s.Server != nil {
+		s.Server.Handler = mux.ServeRequest()
+	}
+}
+
+// IsListening returns true if server is listening/started, otherwise false
+func (s *Server) IsListening() bool {
+	return s.started && s.listener != nil && s.listener.Addr().String() != ""
+}
+
+// IsSecure returns true if server uses TLS, otherwise false
+func (s *Server) IsSecure() bool {
+	return s.tls
+}
+
+// Listener returns the net.Listener which this server (is) listening to
+func (s *Server) Listener() net.Listener {
+	return s.listener
+}
+
+// Host returns the Listener().Addr().String(), if server is not listening it returns the config.ListeningAddr
+func (s *Server) Host() (host string) {
+	if s.IsListening() {
+		return s.Listener().Addr().String()
+	}
+	return s.Config.ListeningAddr
+
+}
+
+// VirtualHost returns the s.Config.ListeningAddr
+//
+func (s *Server) VirtualHost() (host string) {
+	return s.Config.ListeningAddr
+}
+
+// Hostname returns the hostname part only, if host == localhost:8080 it will return the localhost
+// if server is not listening it returns the config.ListeningAddr's hostname part
+func (s *Server) Hostname() (hostname string) {
+	if s.IsListening() {
+		fullhost := s.Listener().Addr().String()
+		hostname = fullhost[0:strings.IndexByte(fullhost, ':')] // no the port
+	} else {
+		hostname = s.VirtualHostname()
+	}
+	return
+}
+
+// VirtualHostname returns the hostname that user registers, host path maybe differs from the real which is HostString, which taken from a net.listener
+func (s *Server) VirtualHostname() (hostname string) {
+	hostname = s.Config.ListeningAddr
+	if idx := strings.IndexByte(hostname, ':'); idx > 1 { // at least after second char
+		hostname = hostname[0:idx]
+	}
+	return
+}
+
+func (s *Server) listen() error {
+	if s.started {
+		return errServerAlreadyStarted.Return()
+	}
+
+	listener, err := net.Listen("tcp4", s.Config.ListeningAddr)
+
+	if err != nil {
+		return err
+	}
+
+	go s.serve(listener) // we don't catch underline errors, we catched all already
+	return nil
+
+}
+
+func (s *Server) listenUNIX() error {
+
+	mode := s.Config.Mode
+	addr := s.Config.ListeningAddr
+
+	if errOs := os.Remove(addr); errOs != nil && !os.IsNotExist(errOs) {
+		return errServerRemoveUnix.Format(s.Config.ListeningAddr, errOs.Error())
+	}
+
+	listener, err := net.Listen("unix", addr)
+
+	if err != nil {
+		return errServerPortAlreadyUsed.Return()
+	}
+
+	if err = os.Chmod(addr, mode); err != nil {
+		return errServerChmod.Format(mode, addr, err.Error())
+	}
+
+	go s.serve(listener) // we don't catch underline errors, we catched all already
+	return nil
+
+}
+
+//Serve just serves a listener, it is a blocking action, plugin.PostListen is not fired here.
+func (s *Server) serve(l net.Listener) error {
+	s.listener = l
+	s.started = true
+
+	if s.Config.CertFile != "" && s.Config.KeyFile != "" {
+		s.tls = true
+		return s.Server.ServeTLS(s.listener, s.Config.CertFile, s.Config.KeyFile)
+	}
+	s.tls = false
+	return s.Server.Serve(s.listener)
+}
+
+// open opens/starts/runs/listens (to) the server, listen tls if Cert && Key is registed, listenUNIX if Mode is registed, otherwise listen
+func (s *Server) open() error {
+	if s.started {
+		return errServerAlreadyStarted.Return()
+	}
+
+	if s.Config.ListeningAddr == "" {
+		return errServerConfigMissing.Return()
+	}
+
+	if s.Handler == nil {
+		return errServerHandlerMissing.Return()
+	}
+
+	// check the addr if :8080 do it 0.0.0.0:8080 ,we need the hostname for many cases
+	a := s.Config.ListeningAddr
+	//check if contains hostname, we need the full host, :8080 should be : 127.0.0.1:8080
+	if portIdx := strings.IndexByte(a, ':'); portIdx == 0 {
+		// then the : is the first letter, so we dont have setted a hostname, lets set it
+		s.Config.ListeningAddr = "127.0.0.1" + a
+	}
+
+	if s.Config.Mode > 0 {
+		return s.listenUNIX()
+	}
+	return s.listen()
+}
+
+// close closes the server
+func (s *Server) close() error {
+	if !s.started {
+		return errServerIsClosed.Return()
+	}
+
+	if s.listener != nil {
+		s.started = false
+		return s.listener.Close()
+	}
+	return nil
+}
+
+// errHandler returns na error with message: 'Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)
+// It seems to be a  +type Points to: +pointer.'
+var errHandler = errors.New("Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)\n It seems to be a  %T Points to: %v.")
+
+type (
+	// Handler the main Iris Handler interface.
+	Handler interface {
+		Serve(ctx *Context)
+	}
+
+	// HandlerFunc type is an adapter to allow the use of
+	// ordinary functions as HTTP handlers.  If f is a function
+	// with the appropriate signature, HandlerFunc(f) is a
+	// Handler that calls f.
+	HandlerFunc func(*Context)
+	// Middleware is just a slice of Handler []func(c *Context)
+	Middleware []Handler
+
+	// HandlerAPI empty interface used for .API
+	HandlerAPI interface{}
+)
+
+// Serve implements the Handler, is like ServeHTTP but for Iris
+func (h HandlerFunc) Serve(ctx *Context) {
+	h(ctx)
+}
+
+// ToHandler converts an httapi.Handler or http.HandlerFunc to an iris.Handler
+func ToHandler(handler interface{}) Handler {
+	//this is not the best way to do it, but I dont have any options right now.
+	switch handler.(type) {
+	case Handler:
+		//it's already an iris handler
+		return handler.(Handler)
+	case http.Handler:
+		//it's http.Handler
+		h := fasthttpadaptor.NewFastHTTPHandlerFunc(handler.(http.Handler).ServeHTTP)
+
+		return ToHandlerFastHTTP(h)
+	case func(http.ResponseWriter, *http.Request):
+		//it's http.HandlerFunc
+		h := fasthttpadaptor.NewFastHTTPHandlerFunc(handler.(func(http.ResponseWriter, *http.Request)))
+		return ToHandlerFastHTTP(h)
+	default:
+		panic(errHandler.Format(handler, handler))
+	}
+}
+
+// ToHandlerFunc converts an http.Handler or http.HandlerFunc to an iris.HandlerFunc
+func ToHandlerFunc(handler interface{}) HandlerFunc {
+	return ToHandler(handler).Serve
+}
+
+// ToHandlerFastHTTP converts an fasthttp.RequestHandler to an iris.Handler
+func ToHandlerFastHTTP(h fasthttp.RequestHandler) Handler {
+	return HandlerFunc((func(ctx *Context) {
+		h(ctx.RequestCtx)
+	}))
+}
+
+// convertToHandlers just make []HandlerFunc to []Handler, although HandlerFunc and Handler are the same
+// we need this on some cases we explicit want a interface Handler, it is useless for users.
+func convertToHandlers(handlersFn []HandlerFunc) []Handler {
+	hlen := len(handlersFn)
+	mlist := make([]Handler, hlen)
+	for i := 0; i < hlen; i++ {
+		mlist[i] = Handler(handlersFn[i])
+	}
+	return mlist
+}
+
+// joinMiddleware uses to create a copy of all middleware and return them in order to use inside the node
+func joinMiddleware(middleware1 Middleware, middleware2 Middleware) Middleware {
+	nowLen := len(middleware1)
+	totalLen := nowLen + len(middleware2)
+	// create a new slice of middleware in order to store all handlers, the already handlers(middleware) and the new
+	newMiddleware := make(Middleware, totalLen)
+	//copy the already middleware to the just created
+	copy(newMiddleware, middleware1)
+	//start from there we finish, and store the new middleware too
+	copy(newMiddleware[nowLen:], middleware2)
+	return newMiddleware
+}
+
+func profileMiddleware(debugPath string) Middleware {
+	htmlMiddleware := HandlerFunc(func(ctx *Context) {
+		ctx.SetContentType(contentHTML + "; charset=" + config.Charset)
+		ctx.Next()
+	})
+	indexHandler := ToHandlerFunc(pprof.Index)
+	cmdlineHandler := ToHandlerFunc(pprof.Cmdline)
+	profileHandler := ToHandlerFunc(pprof.Profile)
+	symbolHandler := ToHandlerFunc(pprof.Symbol)
+	goroutineHandler := ToHandlerFunc(pprof.Handler("goroutine"))
+	heapHandler := ToHandlerFunc(pprof.Handler("heap"))
+	threadcreateHandler := ToHandlerFunc(pprof.Handler("threadcreate"))
+	debugBlockHandler := ToHandlerFunc(pprof.Handler("block"))
+
+	return Middleware{htmlMiddleware, HandlerFunc(func(ctx *Context) {
+		action := ctx.Param("action")
+		if len(action) > 1 {
+			if strings.Contains(action, "cmdline") {
+				cmdlineHandler.Serve((ctx))
+			} else if strings.Contains(action, "profile") {
+				profileHandler.Serve(ctx)
+			} else if strings.Contains(action, "symbol") {
+				symbolHandler.Serve(ctx)
+			} else if strings.Contains(action, "goroutine") {
+				goroutineHandler.Serve(ctx)
+			} else if strings.Contains(action, "heap") {
+				heapHandler.Serve(ctx)
+			} else if strings.Contains(action, "threadcreate") {
+				threadcreateHandler.Serve(ctx)
+			} else if strings.Contains(action, "debug/block") {
+				debugBlockHandler.Serve(ctx)
+			}
+		} else {
+			indexHandler.Serve(ctx)
+		}
+	})}
+}
+
+const (
+	// parameterStartByte is very used on the node, it's just contains the byte for the ':' rune/char
+	parameterStartByte = byte(':')
+	// slashByte is just a byte of '/' rune/char
+	slashByte = byte('/')
+	// slash is just a string of "/"
+	slash = "/"
+	// matchEverythingByte is just a byte of '*" rune/char
+	matchEverythingByte = byte('*')
+
+	isStatic entryCase = iota
+	isRoot
+	hasParams
+	matchEverything
+)
+
+type (
+	// PathParameter is a struct which contains Key and Value, used for named path parameters
+	PathParameter struct {
+		Key   string
+		Value string
+	}
+
+	// PathParameters type for a slice of PathParameter
+	// Tt's a slice of PathParameter type, because it's faster than map
+	PathParameters []PathParameter
+
+	// entryCase is the type which the type of muxEntryusing in order to determinate what type (parameterized, anything, static...) is the perticular node
+	entryCase uint8
+
+	// muxEntry is the node of a tree of the routes,
+	// in order to learn how this is working, google 'trie' or watch this lecture: https://www.youtube.com/watch?v=uhAUk63tLRM
+	// this method is used by the BSD's kernel also
+	muxEntry struct {
+		part        string
+		entryCase   entryCase
+		hasWildNode bool
+		tokens      string
+		nodes       []*muxEntry
+		middleware  Middleware
+		precedence  uint64
+		paramsLen   uint8
+	}
+)
+
+// Get returns a value from a key inside this Parameters
+// If no parameter with this key given then it returns an empty string
+func (params PathParameters) Get(key string) string {
+	for _, p := range params {
+		if p.Key == key {
+			return p.Value
+		}
+	}
+	return ""
+}
+
+// String returns a string implementation of all parameters that this PathParameters object keeps
+// hasthe form of key1=value1,key2=value2...
+func (params PathParameters) String() string {
+	var buff bytes.Buffer
+	for i := range params {
+		buff.WriteString(params[i].Key)
+		buff.WriteString("=")
+		buff.WriteString(params[i].Value)
+		if i < len(params)-1 {
+			buff.WriteString(",")
+		}
+
+	}
+	return buff.String()
+}
+
+// ParseParams receives a string and returns PathParameters (slice of PathParameter)
+// received string must have this form:  key1=value1,key2=value2...
+func ParseParams(str string) PathParameters {
+	_paramsstr := strings.Split(str, ",")
+	if len(_paramsstr) == 0 {
+		return nil
+	}
+
+	params := make(PathParameters, 0) // PathParameters{}
+
+	//	for i := 0; i < len(_paramsstr); i++ {
+	for i := range _paramsstr {
+		idxOfEq := strings.IndexRune(_paramsstr[i], '=')
+		if idxOfEq == -1 {
+			//error
+			return nil
+		}
+
+		key := _paramsstr[i][:idxOfEq]
+		val := _paramsstr[i][idxOfEq+1:]
+		params = append(params, PathParameter{key, val})
+	}
+	return params
+}
+
+// getParamsLen returns the parameters length from a given path
+func getParamsLen(path string) uint8 {
+	var n uint
+	for i := 0; i < len(path); i++ {
+		if path[i] != ':' && path[i] != '*' { // ParameterStartByte & MatchEverythingByte
+			continue
+		}
+		n++
+	}
+	if n >= 255 {
+		return 255
+	}
+	return uint8(n)
+}
+
+// add adds a muxEntry to the existing muxEntry or to the tree if no muxEntry has the prefix of
+func (e *muxEntry) add(path string, middleware Middleware) {
+	fullPath := path
+	e.precedence++
+	numParams := getParamsLen(path)
+
+	if len(e.part) > 0 || len(e.nodes) > 0 {
+	loop:
+		for {
+			if numParams > e.paramsLen {
+				e.paramsLen = numParams
+			}
+
+			i := 0
+			max := utils.FindLower(len(path), len(e.part))
+			for i < max && path[i] == e.part[i] {
+				i++
+			}
+
+			if i < len(e.part) {
+				node := muxEntry{
+					part:        e.part[i:],
+					hasWildNode: e.hasWildNode,
+					tokens:      e.tokens,
+					nodes:       e.nodes,
+					middleware:  e.middleware,
+					precedence:  e.precedence - 1,
+				}
+
+				for i := range node.nodes {
+					if node.nodes[i].paramsLen > node.paramsLen {
+						node.paramsLen = node.nodes[i].paramsLen
+					}
+				}
+
+				e.nodes = []*muxEntry{&node}
+				e.tokens = string([]byte{e.part[i]})
+				e.part = path[:i]
+				e.middleware = nil
+				e.hasWildNode = false
+			}
+
+			if i < len(path) {
+				path = path[i:]
+
+				if e.hasWildNode {
+					e = e.nodes[0]
+					e.precedence++
+
+					if numParams > e.paramsLen {
+						e.paramsLen = numParams
+					}
+					numParams--
+
+					if len(path) >= len(e.part) && e.part == path[:len(e.part)] {
+
+						if len(e.part) >= len(path) || path[len(e.part)] == '/' {
+							continue loop
+						}
+					}
+
+					return
+				}
+
+				c := path[0]
+
+				if e.entryCase == hasParams && c == '/' && len(e.nodes) == 1 {
+					e = e.nodes[0]
+					e.precedence++
+					continue loop
+				}
+				//we need the i here to be re-setting, so use the same i variable as we declare it on line 176
+				for i := range e.tokens {
+					if c == e.tokens[i] {
+						i = e.precedenceTo(i)
+						e = e.nodes[i]
+						continue loop
+					}
+				}
+
+				if c != parameterStartByte && c != matchEverythingByte {
+
+					e.tokens += string([]byte{c})
+					node := &muxEntry{
+						paramsLen: numParams,
+					}
+					e.nodes = append(e.nodes, node)
+					e.precedenceTo(len(e.tokens) - 1)
+					e = node
+				}
+				e.addNode(numParams, path, fullPath, middleware)
+				return
+
+			} else if i == len(path) {
+				if e.middleware != nil {
+					return
+				}
+				e.middleware = middleware
+			}
+			return
+		}
+	} else {
+		e.addNode(numParams, path, fullPath, middleware)
+		e.entryCase = isRoot
+	}
+}
+
+// addNode adds a muxEntry as children to other muxEntry
+func (e *muxEntry) addNode(numParams uint8, path string, fullPath string, middleware Middleware) {
+	var offset int
+
+	for i, max := 0, len(path); numParams > 0; i++ {
+		c := path[i]
+		if c != parameterStartByte && c != matchEverythingByte {
+			continue
+		}
+
+		end := i + 1
+		for end < max && path[end] != '/' {
+			switch path[end] {
+			case parameterStartByte, matchEverythingByte:
+
+			default:
+				end++
+			}
+		}
+
+		if len(e.nodes) > 0 {
+			return
+		}
+
+		if end-i < 2 {
+			return
+		}
+
+		if c == parameterStartByte {
+
+			if i > 0 {
+				e.part = path[offset:i]
+				offset = i
+			}
+
+			child := &muxEntry{
+				entryCase: hasParams,
+				paramsLen: numParams,
+			}
+			e.nodes = []*muxEntry{child}
+			e.hasWildNode = true
+			e = child
+			e.precedence++
+			numParams--
+
+			if end < max {
+				e.part = path[offset:end]
+				offset = end
+
+				child := &muxEntry{
+					paramsLen:  numParams,
+					precedence: 1,
+				}
+				e.nodes = []*muxEntry{child}
+				e = child
+			}
+
+		} else {
+			if end != max || numParams > 1 {
+				return
+			}
+
+			if len(e.part) > 0 && e.part[len(e.part)-1] == '/' {
+				return
+			}
+
+			i--
+			if path[i] != '/' {
+				return
+			}
+
+			e.part = path[offset:i]
+
+			child := &muxEntry{
+				hasWildNode: true,
+				entryCase:   matchEverything,
+				paramsLen:   1,
+			}
+			e.nodes = []*muxEntry{child}
+			e.tokens = string(path[i])
+			e = child
+			e.precedence++
+
+			child = &muxEntry{
+				part:       path[i:],
+				entryCase:  matchEverything,
+				paramsLen:  1,
+				middleware: middleware,
+				precedence: 1,
+			}
+			e.nodes = []*muxEntry{child}
+
+			return
+		}
+	}
+
+	e.part = path[offset:]
+	e.middleware = middleware
+}
+
+// get is used by the Router, it finds and returns the correct muxEntry for a path
+func (e *muxEntry) get(path string, _params PathParameters) (middleware Middleware, params PathParameters, mustRedirect bool) {
+	params = _params
+loop:
+	for {
+		if len(path) > len(e.part) {
+			if path[:len(e.part)] == e.part {
+				path = path[len(e.part):]
+
+				if !e.hasWildNode {
+					c := path[0]
+					for i := range e.tokens {
+						if c == e.tokens[i] {
+							e = e.nodes[i]
+							continue loop
+						}
+					}
+
+					mustRedirect = (path == slash && e.middleware != nil)
+					return
+				}
+
+				e = e.nodes[0]
+				switch e.entryCase {
+				case hasParams:
+
+					end := 0
+					for end < len(path) && path[end] != '/' {
+						end++
+					}
+
+					if cap(params) < int(e.paramsLen) {
+						params = make(PathParameters, 0, e.paramsLen)
+					}
+					i := len(params)
+					params = params[:i+1]
+					params[i].Key = e.part[1:]
+					params[i].Value = path[:end]
+
+					if end < len(path) {
+						if len(e.nodes) > 0 {
+							path = path[end:]
+							e = e.nodes[0]
+							continue loop
+						}
+
+						mustRedirect = (len(path) == end+1)
+						return
+					}
+
+					if middleware = e.middleware; middleware != nil {
+						return
+					} else if len(e.nodes) == 1 {
+						e = e.nodes[0]
+						mustRedirect = (e.part == slash && e.middleware != nil)
+					}
+
+					return
+
+				case matchEverything:
+					if cap(params) < int(e.paramsLen) {
+						params = make(PathParameters, 0, e.paramsLen)
+					}
+					i := len(params)
+					params = params[:i+1]
+					params[i].Key = e.part[2:]
+					params[i].Value = path
+
+					middleware = e.middleware
+					return
+
+				default:
+					return
+				}
+			}
+		} else if path == e.part {
+			if middleware = e.middleware; middleware != nil {
+				return
+			}
+
+			if path == slash && e.hasWildNode && e.entryCase != isRoot {
+				mustRedirect = true
+				return
+			}
+
+			for i := range e.tokens {
+				if e.tokens[i] == '/' {
+					e = e.nodes[i]
+					mustRedirect = (len(e.part) == 1 && e.middleware != nil) ||
+						(e.entryCase == matchEverything && e.nodes[0].middleware != nil)
+					return
+				}
+			}
+
+			return
+		}
+
+		mustRedirect = (path == slash) ||
+			(len(e.part) == len(path)+1 && e.part[len(path)] == '/' &&
+				path == e.part[:len(e.part)-1] && e.middleware != nil)
+		return
+	}
+}
+
+// precedenceTo just adds the priority of this muxEntry by an index
+func (e *muxEntry) precedenceTo(index int) int {
+	e.nodes[index].precedence++
+	_precedence := e.nodes[index].precedence
+
+	newindex := index
+	for newindex > 0 && e.nodes[newindex-1].precedence < _precedence {
+		tmpN := e.nodes[newindex-1]
+		e.nodes[newindex-1] = e.nodes[newindex]
+		e.nodes[newindex] = tmpN
+
+		newindex--
+	}
+
+	if newindex != index {
+		e.tokens = e.tokens[:newindex] +
+			e.tokens[index:index+1] +
+			e.tokens[newindex:index] + e.tokens[index+1:]
+	}
+
+	return newindex
+}
+
+type (
+	// Route contains some useful information about a route
+	Route interface {
+		// Name returns the name of the route
+		Name() string
+		// Subdomain returns the subdomain,if any
+		Subdomain() string
+		// Method returns the http method
+		Method() string
+		// Path returns the path
+		Path() string
+		// Middleware returns the slice of Handler([]Handler) registed to this route
+		Middleware() Middleware
+	}
+
+	route struct {
+		// if no name given then it's the subdomain+path
+		name           string
+		subdomain      string
+		method         string
+		path           string
+		middleware     Middleware
+		formattedPath  string
+		formattedParts int
+	}
+)
+
+var _ Route = &route{}
+
+func newRoute(method []byte, subdomain string, path string, middleware Middleware) *route {
+	r := &route{name: path + subdomain, method: string(method), subdomain: subdomain, path: path, middleware: middleware}
+	r.formatPath()
+	return r
+}
+
+func (r *route) formatPath() {
+	// we don't care about performance here.
+	n1Len := strings.Count(r.path, ":")
+	isMatchEverything := len(r.path) > 0 && r.path[len(r.path)-1] == matchEverythingByte
+	if n1Len == 0 && !isMatchEverything {
+		// its a static
+		return
+	}
+	if n1Len == 0 && isMatchEverything {
+		//if we have something like: /mypath/anything/* -> /mypatch/anything/%v
+		r.formattedPath = r.path[0:len(r.path)-2] + "%v"
+		r.formattedParts++
+		return
+	}
+
+	tempPath := r.path
+	splittedN1 := strings.Split(r.path, "/")
+
+	for _, v := range splittedN1 {
+		if len(v) > 0 {
+			if v[0] == ':' || v[0] == matchEverythingByte {
+				r.formattedParts++
+				tempPath = strings.Replace(tempPath, v, "%v", -1) // n1Len, but let it we don't care about performance here.
+			}
+		}
+
+	}
+	r.formattedPath = tempPath
+}
+
+func (r *route) setName(newName string) {
+	r.name = newName
+}
+
+func (r route) Name() string {
+	return r.name
+}
+
+func (r route) Subdomain() string {
+	return r.subdomain
+}
+
+func (r route) Method() string {
+	return r.method
+}
+
+func (r route) Path() string {
+	return r.path
+}
+
+func (r route) Middleware() Middleware {
+	return r.middleware
+}
+
+const (
+	// subdomainIndicator where './' exists in a registed path then it contains subdomain
+	subdomainIndicator = "./"
+	// dynamicSubdomainIndicator where a registed path starts with '*.' then it contains a dynamic subdomain, if subdomain == "*." then its dynamic
+	dynamicSubdomainIndicator = "*."
+)
+
+type (
+	muxTree struct {
+		method []byte
+		// subdomain is empty for default-hostname routes,
+		// ex: mysubdomain.
+		subdomain string
+		entry     *muxEntry
+		next      *muxTree
+	}
+
+	serveMux struct {
+		cPool   *sync.Pool
+		tree    *muxTree
+		lookups []*route
+
+		api           *muxAPI
+		errorHandlers map[int]Handler
+		// the main server host, ex:  localhost, 127.0.0.1:8080, iris-go.com
+		host string
+		// if any of the trees contains not empty subdomain
+		hosts bool
+		// if false then searching by unescaped path
+		// defaults to true
+		escapePath bool
+		// if false then the /something it's not the same as /something/
+		// defaults to true
+		correctPath bool
+		mu          sync.Mutex
+	}
+)
+
+func newServeMux(contextPool sync.Pool) *serveMux {
+	mux := &serveMux{
+		cPool:         &contextPool,
+		lookups:       make([]*route, 0),
+		errorHandlers: make(map[int]Handler, 0),
+		host:          config.DefaultServerAddr,
+		escapePath:    !config.DefaultDisablePathEscape,
+		correctPath:   !config.DefaultDisablePathCorrection,
+	}
+
+	return mux
+}
+
+func (mux *serveMux) setHost(h string) {
+	mux.host = h
+}
+
+func (mux *serveMux) setEscapePath(b bool) {
+	mux.escapePath = b
+}
+
+func (mux *serveMux) setCorrectPath(b bool) {
+	mux.correctPath = b
+}
+
+// registerError registers a handler to a http status
+func (mux *serveMux) registerError(statusCode int, handler Handler) {
+	mux.mu.Lock()
+	func(statusCode int, handler Handler) {
+		mux.errorHandlers[statusCode] = HandlerFunc(func(ctx *Context) {
+			ctx.ResetBody()
+			ctx.SetStatusCode(statusCode)
+			handler.Serve(ctx)
+		})
+	}(statusCode, handler)
+	mux.mu.Unlock()
+}
+
+// fireError fires an error
+func (mux *serveMux) fireError(statusCode int, ctx *Context) {
+	mux.mu.Lock()
+	errHandler := mux.errorHandlers[statusCode]
+	if errHandler == nil {
+		errHandler = HandlerFunc(func(ctx *Context) {
+			ctx.ResetBody()
+			ctx.SetBodyString(statusText[statusCode])
+			ctx.SetStatusCode(statusCode)
+		})
+		mux.errorHandlers[statusCode] = errHandler
+	}
+	mux.mu.Unlock()
+
+	errHandler.Serve(ctx)
+}
+
+func (mux *serveMux) getTree(method []byte, subdomain string) (tree *muxTree) {
+	tree = mux.tree
+	for tree != nil {
+		if bytes.Equal(tree.method, method) && tree.subdomain == subdomain {
+			return
+		}
+		tree = tree.next
+	}
+	// tree is nil here, return that.
+	return
+}
+
+func (mux *serveMux) register(method []byte, subdomain string, path string, middleware Middleware) *route {
+	mux.mu.Lock()
+	defer mux.mu.Unlock()
+
+	if subdomain != "" {
+		mux.hosts = true
+	}
+	// add to the registry tree
+	tree := mux.getTree(method, subdomain)
+	if tree == nil {
+		//first time we register a route to this method with this domain
+		tree = &muxTree{method: method, subdomain: subdomain, entry: &muxEntry{}, next: nil}
+		if mux.tree == nil {
+			// it's the first entry
+			mux.tree = tree
+		} else {
+			// find the last tree and make the .next to the tree we created before
+			lastTree := mux.tree
+			for lastTree != nil {
+				if lastTree.next == nil {
+					lastTree.next = tree
+					break
+				}
+				lastTree = lastTree.next
+			}
+		}
+	}
+	// I decide that it's better to explicit give subdomain and a path to it than registedPath(mysubdomain./something) now its: subdomain: mysubdomain., path: /something
+	// we have different tree for each of subdomains, now you can use everyting you can use with the normal paths ( before you couldn't set /any/*path)
+	tree.entry.add(path, middleware)
+
+	// add to the lookups, it's just a collection of routes information
+	lookup := newRoute(method, subdomain, path, middleware)
+	mux.lookups = append(mux.lookups, lookup)
+
+	return lookup
+
+}
+
+func (mux *serveMux) lookup(routeName string) *route {
+	for i := range mux.lookups {
+		if r := mux.lookups[i]; r.name == routeName {
+			return r
+		}
+	}
+	return nil
+}
+
+func (mux *serveMux) ServeRequest() fasthttp.RequestHandler {
+	// optimize this once once, we could do that: context.RequestPath(mux.escapePath), but we lose some nanoseconds on if :)
+	getRequestPath := func(reqCtx *fasthttp.RequestCtx) string {
+		return utils.BytesToString(reqCtx.Path())
+	}
+	if !mux.escapePath {
+		getRequestPath = func(reqCtx *fasthttp.RequestCtx) string { return utils.BytesToString(reqCtx.RequestURI()) }
+	}
+
+	return func(reqCtx *fasthttp.RequestCtx) {
+		context := mux.cPool.Get().(*Context)
+		context.Reset(reqCtx)
+
+		routePath := getRequestPath(reqCtx)
+		tree := mux.tree
+		for tree != nil {
+			if !bytes.Equal(tree.method, reqCtx.Method()) {
+				// we break any CORS OPTIONS method
+				// but for performance reasons if user wants http method OPTIONS to be served
+				// then must register it with .Options(...)
+				tree = tree.next
+				continue
+			}
+			// we have at least one subdomain on the root
+			if mux.hosts && tree.subdomain != "" {
+				// context.VirtualHost() is a slow method because it makes string.Replaces but user can understand that if subdomain then server will have some nano/or/milleseconds performance cost
+				requestHost := context.VirtualHostname()
+				if requestHost != mux.host {
+					// we have a subdomain
+					if strings.Index(tree.subdomain, dynamicSubdomainIndicator) != -1 {
+					} else {
+						// mux.host = iris-go.com:8080, the subdomain for example is api.,
+						// so the host must be api.iris-go.com:8080
+						if tree.subdomain+mux.host != requestHost {
+							// go to the next tree, we have a subdomain but it is not the correct
+							tree = tree.next
+							continue
+						}
+
+					}
+				} else {
+					//("it's subdomain but the request is the same as the listening addr mux.host == requestHost =>" + mux.host + "=" + requestHost + " ____ and tree's subdomain was: " + tree.subdomain)
+					tree = tree.next
+					continue
+				}
+			}
+			middleware, params, mustRedirect := tree.entry.get(routePath, context.Params) // pass the parameters here for 0 allocation
+			if middleware != nil {
+				// ok we found the correct route, serve it and exit entirely from here
+				context.Params = params
+				context.middleware = middleware
+				//ctx.Request.Header.SetUserAgentBytes(DefaultUserAgent)
+				context.Do()
+				mux.cPool.Put(context)
+				return
+			} else if mustRedirect && mux.correctPath && !bytes.Equal(reqCtx.Method(), methodConnectBytes) {
+
+				reqPath := routePath
+				pathLen := len(reqPath)
+
+				if pathLen > 1 {
+
+					if reqPath[pathLen-1] == '/' {
+						reqPath = reqPath[:pathLen-1] //remove the last /
+					} else {
+						//it has path prefix, it doesn't ends with / and it hasn't be found, then just add the slash
+						reqPath = reqPath + "/"
+					}
+
+					context.Request.URI().SetPath(reqPath)
+					urlToRedirect := utils.BytesToString(context.Request.RequestURI())
+
+					context.Redirect(urlToRedirect, StatusMovedPermanently) //	StatusMovedPermanently
+					// RFC2616 recommends that a short note "SHOULD" be included in the
+					// response because older user agents may not understand 301/307.
+					// Shouldn't send the response for POST or HEAD; that leaves GET.
+					if bytes.Equal(tree.method, methodGetBytes) {
+						note := "<a href=\"" + utils.HTMLEscape(urlToRedirect) + "\">Moved Permanently</a>.\n"
+						context.Write(note)
+					}
+					mux.cPool.Put(context)
+					return
+				}
+			}
+			// not found
+			break
+		}
+		mux.fireError(StatusNotFound, context)
+		mux.cPool.Put(context)
+	}
+}
diff --git a/httperror.go b/httperror.go
deleted file mode 100644
index b704ff57..00000000
--- a/httperror.go
+++ /dev/null
@@ -1,228 +0,0 @@
-package iris
-
-//taken from net/http
-const (
-	StatusContinue           = 100
-	StatusSwitchingProtocols = 101
-
-	StatusOK                   = 200
-	StatusCreated              = 201
-	StatusAccepted             = 202
-	StatusNonAuthoritativeInfo = 203
-	StatusNoContent            = 204
-	StatusResetContent         = 205
-	StatusPartialContent       = 206
-
-	StatusMultipleChoices   = 300
-	StatusMovedPermanently  = 301
-	StatusFound             = 302
-	StatusSeeOther          = 303
-	StatusNotModified       = 304
-	StatusUseProxy          = 305
-	StatusTemporaryRedirect = 307
-
-	StatusBadRequest                   = 400
-	StatusUnauthorized                 = 401
-	StatusPaymentRequired              = 402
-	StatusForbidden                    = 403
-	StatusNotFound                     = 404
-	StatusMethodNotAllowed             = 405
-	StatusNotAcceptable                = 406
-	StatusProxyAuthRequired            = 407
-	StatusRequestTimeout               = 408
-	StatusConflict                     = 409
-	StatusGone                         = 410
-	StatusLengthRequired               = 411
-	StatusPreconditionFailed           = 412
-	StatusRequestEntityTooLarge        = 413
-	StatusRequestURITooLong            = 414
-	StatusUnsupportedMediaType         = 415
-	StatusRequestedRangeNotSatisfiable = 416
-	StatusExpectationFailed            = 417
-	StatusTeapot                       = 418
-	StatusPreconditionRequired         = 428
-	StatusTooManyRequests              = 429
-	StatusRequestHeaderFieldsTooLarge  = 431
-	StatusUnavailableForLegalReasons   = 451
-
-	StatusInternalServerError           = 500
-	StatusNotImplemented                = 501
-	StatusBadGateway                    = 502
-	StatusServiceUnavailable            = 503
-	StatusGatewayTimeout                = 504
-	StatusHTTPVersionNotSupported       = 505
-	StatusNetworkAuthenticationRequired = 511
-)
-
-var statusText = map[int]string{
-	StatusContinue:           "Continue",
-	StatusSwitchingProtocols: "Switching Protocols",
-
-	StatusOK:                   "OK",
-	StatusCreated:              "Created",
-	StatusAccepted:             "Accepted",
-	StatusNonAuthoritativeInfo: "Non-Authoritative Information",
-	StatusNoContent:            "No Content",
-	StatusResetContent:         "Reset Content",
-	StatusPartialContent:       "Partial Content",
-
-	StatusMultipleChoices:   "Multiple Choices",
-	StatusMovedPermanently:  "Moved Permanently",
-	StatusFound:             "Found",
-	StatusSeeOther:          "See Other",
-	StatusNotModified:       "Not Modified",
-	StatusUseProxy:          "Use Proxy",
-	StatusTemporaryRedirect: "Temporary Redirect",
-
-	StatusBadRequest:                   "Bad Request",
-	StatusUnauthorized:                 "Unauthorized",
-	StatusPaymentRequired:              "Payment Required",
-	StatusForbidden:                    "Forbidden",
-	StatusNotFound:                     "Not Found",
-	StatusMethodNotAllowed:             "Method Not Allowed",
-	StatusNotAcceptable:                "Not Acceptable",
-	StatusProxyAuthRequired:            "Proxy Authentication Required",
-	StatusRequestTimeout:               "Request Timeout",
-	StatusConflict:                     "Conflict",
-	StatusGone:                         "Gone",
-	StatusLengthRequired:               "Length Required",
-	StatusPreconditionFailed:           "Precondition Failed",
-	StatusRequestEntityTooLarge:        "Request Entity Too Large",
-	StatusRequestURITooLong:            "Request URI Too Long",
-	StatusUnsupportedMediaType:         "Unsupported Media Type",
-	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
-	StatusExpectationFailed:            "Expectation Failed",
-	StatusTeapot:                       "I'm a teapot",
-	StatusPreconditionRequired:         "Precondition Required",
-	StatusTooManyRequests:              "Too Many Requests",
-	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
-	StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",
-
-	StatusInternalServerError:           "Internal Server Error",
-	StatusNotImplemented:                "Not Implemented",
-	StatusBadGateway:                    "Bad Gateway",
-	StatusServiceUnavailable:            "Service Unavailable",
-	StatusGatewayTimeout:                "Gateway Timeout",
-	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
-	StatusNetworkAuthenticationRequired: "Network Authentication Required",
-}
-
-// StatusText returns a text for the HTTP status code. It returns the empty
-// string if the code is unknown.
-func StatusText(code int) string {
-	return statusText[code]
-}
-
-//
-
-type (
-
-	// HTTPErrorHandler is just an object which stores a http status code and a handler
-	HTTPErrorHandler struct {
-		code    int
-		handler HandlerFunc
-	}
-
-	// HTTPErrorContainer is the struct which contains the handlers which will execute if http error occurs
-	// One struct per Server instance, the meaning of this is that the developer can change the default error message and replace them with his/her own completely custom handlers
-	//
-	// Example of usage:
-	// iris.OnError(405, func (ctx *iris.Context){ c.SendStatus(405,"Method not allowed!!!")})
-	// and inside the handler which you have access to the current Context:
-	// ctx.EmitError(405)
-	HTTPErrorContainer struct {
-		// Errors contains all the httperrorhandlers
-		Errors []*HTTPErrorHandler
-	}
-)
-
-// HTTPErrorHandlerFunc creates a handler which is responsible to send a particular error to the client
-func HTTPErrorHandlerFunc(statusCode int, message string) HandlerFunc {
-	return func(ctx *Context) {
-		ctx.SetStatusCode(statusCode)
-		ctx.SetBodyString(message)
-	}
-}
-
-// GetCode returns the http status code value
-func (e *HTTPErrorHandler) GetCode() int {
-	return e.code
-}
-
-// GetHandler returns the handler which is type of HandlerFunc
-func (e *HTTPErrorHandler) GetHandler() HandlerFunc {
-	return e.handler
-}
-
-// SetHandler sets the handler (type of HandlerFunc) to this particular ErrorHandler
-func (e *HTTPErrorHandler) SetHandler(h HandlerFunc) {
-	e.handler = h
-}
-
-// defaultHTTPErrors creates and returns an instance of HTTPErrorContainer with default handlers
-func defaultHTTPErrors() *HTTPErrorContainer {
-	httperrors := new(HTTPErrorContainer)
-	httperrors.Errors = make([]*HTTPErrorHandler, 0)
-	httperrors.OnError(StatusNotFound, HTTPErrorHandlerFunc(StatusNotFound, statusText[StatusNotFound]))
-	httperrors.OnError(StatusInternalServerError, HTTPErrorHandlerFunc(StatusInternalServerError, statusText[StatusInternalServerError]))
-	return httperrors
-}
-
-// GetByCode returns the error handler by it's http status code
-func (he *HTTPErrorContainer) GetByCode(httpStatus int) *HTTPErrorHandler {
-	if he != nil {
-		for _, h := range he.Errors {
-			if h.GetCode() == httpStatus {
-				return h
-			}
-		}
-	}
-
-	return nil
-}
-
-// OnError Registers a handler for a specific http error status
-func (he *HTTPErrorContainer) OnError(httpStatus int, handler HandlerFunc) {
-	if httpStatus == StatusOK {
-		return
-	}
-
-	if errH := he.GetByCode(httpStatus); errH != nil {
-
-		errH.SetHandler(handler)
-	} else {
-		he.Errors = append(he.Errors, &HTTPErrorHandler{code: httpStatus, handler: handler})
-	}
-
-}
-
-///TODO: the errors must have .Next too, as middlewares inside the Context, if I let it as it is then we have problem
-// we cannot set a logger and a custom handler at one error because now the error handler takes only one handelrFunc and executes there from here...
-
-// EmitError executes the handler of the given error http status code
-func (he *HTTPErrorContainer) EmitError(errCode int, ctx *Context) {
-	ctx.ResetBody()
-	if errHandler := he.GetByCode(errCode); errHandler != nil {
-		ctx.SetStatusCode(errCode) // for any case, user can change it after if want to
-		errHandler.GetHandler().Serve(ctx)
-	} else {
-		//if no error is registed, then register it with the default http error text, and re-run the Emit
-		he.OnError(errCode, func(c *Context) {
-			c.SetStatusCode(errCode)
-			c.SetBodyString(StatusText(errCode))
-		})
-		he.EmitError(errCode, ctx)
-	}
-}
-
-// OnNotFound sets the handler for http status 404,
-// default is a response with text: 'Not Found' and status: 404
-func (he *HTTPErrorContainer) OnNotFound(handlerFunc HandlerFunc) {
-	he.OnError(StatusNotFound, handlerFunc)
-}
-
-// OnPanic sets the handler for http status 500,
-// default is a response with text: The server encountered an unexpected condition which prevented it from fulfilling the request. and status: 500
-func (he *HTTPErrorContainer) OnPanic(handlerFunc HandlerFunc) {
-	he.OnError(StatusInternalServerError, handlerFunc)
-}
diff --git a/initiatory.go b/initiatory.go
new file mode 100644
index 00000000..128d599d
--- /dev/null
+++ b/initiatory.go
@@ -0,0 +1,193 @@
+package iris
+
+import (
+	"fmt"
+	"os"
+	"sync"
+	"time"
+
+	"github.com/kataras/iris/config"
+	"github.com/kataras/iris/logger"
+	"github.com/kataras/iris/websocket"
+
+	"github.com/kataras/iris/mail"
+	"github.com/kataras/iris/render/rest"
+	"github.com/kataras/iris/render/template"
+	"github.com/kataras/iris/sessions"
+	///NOTE: register the session providers, but the s.Config.Sessions.Provider will be used only, if this empty then sessions are disabled.
+	_ "github.com/kataras/iris/sessions/providers/memory"
+	_ "github.com/kataras/iris/sessions/providers/redis"
+)
+
+// Default entry, use it with iris.$anyPublicFunc
+var (
+	Default    *Framework
+	Config     *config.Iris
+	Logger     *logger.Logger
+	Plugins    PluginContainer
+	Websocket  websocket.Server
+	HTTPServer *Server
+)
+
+func init() {
+	Default = New()
+	Config = Default.Config
+	Logger = Default.Logger
+	Plugins = Default.Plugins
+	Websocket = Default.Websocket
+	HTTPServer = Default.HTTPServer
+}
+
+const (
+	/* conversional */
+
+	// HTMLEngine conversion for config.HTMLEngine
+	HTMLEngine = config.HTMLEngine
+	// PongoEngine conversion for config.PongoEngine
+	PongoEngine = config.PongoEngine
+	// MarkdownEngine conversion for config.MarkdownEngine
+	MarkdownEngine = config.MarkdownEngine
+	// JadeEngine conversion for config.JadeEngine
+	JadeEngine = config.JadeEngine
+	// AmberEngine conversion for config.AmberEngine
+	AmberEngine = config.AmberEngine
+
+	// DefaultEngine conversion for config.DefaultEngine
+	DefaultEngine = config.DefaultEngine
+	// NoEngine conversion for config.NoEngine
+	NoEngine = config.NoEngine
+	// NoLayout to disable layout for a particular template file
+	// conversion for config.NoLayout
+	NoLayout = config.NoLayout
+
+	/* end conversional */
+)
+
+// Framework is our God |\| Google.Search('Greek mythology Iris')
+//
+// Implements the FrameworkAPI
+type Framework struct {
+	*muxAPI
+	rest      *rest.Render
+	templates *template.Template
+	sessions  *sessions.Manager
+	mailer    mail.Service
+	// fields which are useful to the user/dev
+	HTTPServer *Server
+	Config     *config.Iris
+	Logger     *logger.Logger
+	Plugins    PluginContainer
+	Websocket  websocket.Server
+}
+
+// New creates and returns a new Iris station aka Framework.
+//
+// Receives an optional config.Iris as parameter
+// If empty then config.Default() is used instead
+func New(cfg ...config.Iris) *Framework {
+	c := config.Default().Merge(cfg)
+
+	// we always use 's' no 'f' because 's' is easier for me to remember because of 'station'
+	// some things never change :)
+	s := &Framework{Config: &c}
+	{
+		///NOTE: set all with s.Config pointer
+		// set the Logger
+		s.Logger = logger.New(s.Config.Logger)
+		// set the plugin container
+		s.Plugins = &pluginContainer{logger: s.Logger}
+		// set the websocket server
+		s.Websocket = websocket.NewServer(s.Config.Websocket)
+		// set the servemux, which will provide us the public API also, with its context pool
+		mux := newServeMux(sync.Pool{New: func() interface{} { return &Context{framework: s} }})
+		// set the public router API (and party)
+		s.muxAPI = &muxAPI{mux: mux, relativePath: "/"}
+		// set the server
+		s.HTTPServer = newServer(&s.Config.Server)
+	}
+
+	return s
+}
+
+func (s *Framework) initialize() {
+	// set sessions
+	if s.Config.Sessions.Provider != "" {
+		s.sessions = sessions.New(s.Config.Sessions)
+	}
+
+	//set the rest
+	s.rest = rest.New(s.Config.Render.Rest)
+
+	//set mail and templates if not already setted
+	s.prepareMailer()
+	s.prepareTemplates()
+
+	// listen to websocket connections
+	websocket.RegisterServer(s, s.Websocket, s.Logger)
+
+	//  prepare the mux
+	s.mux.setCorrectPath(!s.Config.DisablePathCorrection)
+	s.mux.setEscapePath(!s.Config.DisablePathEscape)
+	s.mux.setHost(s.HTTPServer.VirtualHostname())
+	// set the debug profiling handlers if ProfilePath is setted
+	if debugPath := s.Config.ProfilePath; debugPath != "" {
+		s.Handle(MethodGet, debugPath+"/*action", profileMiddleware(debugPath)...)
+	}
+
+	// prepare the server
+	s.HTTPServer.SetHandler(s.mux)
+
+	if s.Config.MaxRequestBodySize > 0 {
+		s.HTTPServer.MaxRequestBodySize = int(s.Config.MaxRequestBodySize)
+	}
+}
+
+// prepareMailer sets the mailer if not nil, we make this check because of .SendMail, which can be called before Listen
+func (s *Framework) prepareMailer() {
+	// prepare the mail service
+	if s.mailer == nil {
+		s.mailer = mail.New(s.Config.Mail)
+	}
+}
+
+// prepareTemplates sets the templates if not nil, we make this check  because of .TemplateString, which can be called before Listen
+func (s *Framework) prepareTemplates() {
+	// prepare the templates
+	if s.templates == nil {
+		// These functions are directly contact with Iris' functionality.
+		funcs := map[string]interface{}{
+			"url":     s.URL,
+			"urlpath": s.Path,
+		}
+
+		template.RegisterSharedFuncs(funcs)
+
+		s.templates = template.New(s.Config.Render.Template)
+	}
+}
+
+// openServer is internal method, open the server with specific options passed by the Listen and ListenTLS
+// it's a blocking func
+func (s *Framework) openServer() (err error) {
+	s.initialize()
+	s.Plugins.DoPreListen(s)
+	if err = s.HTTPServer.open(); err == nil {
+		// print the banner
+		if !s.Config.DisableBanner {
+			s.Logger.PrintBanner(banner,
+				fmt.Sprintf("%s: Running at %s\n", time.Now().Format(config.TimeFormat),
+					s.HTTPServer.Host()))
+		}
+		s.Plugins.DoPostListen(s)
+		ch := make(chan os.Signal)
+		<-ch
+		s.Close()
+	}
+	return
+}
+
+// closeServer is used to close the tcp listener from the server, returns an error
+func (s *Framework) closeServer() error {
+	s.Plugins.DoPreClose(s)
+	return s.HTTPServer.close()
+}
diff --git a/iris.go b/iris.go
index c43d52f2..51adc030 100644
--- a/iris.go
+++ b/iris.go
@@ -1,33 +1,75 @@
-// Package iris the fastest golang web framework, so far.
+//Package iris the fastest go web framework in (this) Earth.
+///NOTE: When you see 'framework' or 'station' we mean the Iris web framework's main implementation.
 //
-// Note: When 'Station', we mean the Iris type.
+//
+// Basic usage
+// ----------------------------------------------------------------------
+//
+// package main
+//
+// import  "github.com/kataras/iris"
+//
+// func main() {
+//     iris.Get("/hi_json", func(c *iris.Context) {
+//         c.JSON(200, iris.Map{
+//             "Name": "Iris",
+//             "Age":  2,
+//         })
+//     })
+//     iris.Listen(":8080")
+// }
+//
+// ----------------------------------------------------------------------
+//
+// package main
+//
+// import  "github.com/kataras/iris"
+//
+// func main() {
+// 	s1 := iris.New()
+// 	s1.Get("/hi_json", func(c *iris.Context) {
+// 		c.JSON(200, iris.Map{
+// 			"Name": "Iris",
+// 			"Age":  2,
+// 		})
+// 	})
+//
+// 	s2 := iris.New()
+// 	s2.Get("/hi_raw_html", func(c *iris.Context) {
+// 		c.HTML(iris.StatusOK, "<b> Iris </b> welcomes <h1>you!</h1>")
+// 	})
+//
+// 	go s1.Listen(":8080")
+// 	s2.Listen(":1993")
+// }
+//
+// -----------------------------DOCUMENTATION----------------------------
+// ----------------------------_______________---------------------------
+// For middleware, templates, sessions, websockets, mails, subdomains,
+// dynamic subdomains, routes, party of subdomains & routes and much more
+// visit https://www.gitbook.com/book/kataras/iris/details
 package iris
 
 import (
+	"fmt"
 	"os"
-	"sync"
+	"path"
+	"reflect"
+	"strconv"
+	"strings"
 	"time"
 
-	"github.com/kataras/iris/config"
-	"github.com/kataras/iris/logger"
-	"github.com/kataras/iris/mail"
-	"github.com/kataras/iris/render/rest"
-	"github.com/kataras/iris/render/template"
-	"github.com/kataras/iris/server"
-	"github.com/kataras/iris/sessions"
-	//  memory loads the memory session provider
-	_ "github.com/kataras/iris/sessions/providers/memory"
-	// _ redis loads the redis session provider
-	"fmt"
+	"github.com/kataras/iris/errors"
 
-	_ "github.com/kataras/iris/sessions/providers/redis"
-	"github.com/kataras/iris/websocket"
-	"github.com/klauspost/compress/gzip"
+	"github.com/kataras/iris/config"
+	"github.com/kataras/iris/context"
+	"github.com/kataras/iris/utils"
+	"github.com/valyala/fasthttp"
 )
 
 const (
 	// Version of the iris
-	Version = "v3.0.0-beta.4"
+	Version = "3.0.0-rc.1"
 	banner  = `         _____      _
         |_   _|    (_)
           | |  ____ _  ___
@@ -37,288 +79,1153 @@ const (
                                                  				 `
 )
 
-/* for conversion */
-
-var (
-	// HTMLEngine conversion for config.HTMLEngine
-	HTMLEngine = config.HTMLEngine
-	// PongoEngine conversion for config.PongoEngine
-	PongoEngine = config.PongoEngine
-	// MarkdownEngine conversion for config.MarkdownEngine
-	MarkdownEngine = config.MarkdownEngine
-	// JadeEngine conversion for config.JadeEngine
-	JadeEngine = config.JadeEngine
-	// AmberEngine conversion for config.AmberEngine
-	AmberEngine = config.AmberEngine
-
-	// DefaultEngine conversion for config.DefaultEngine
-	DefaultEngine = config.DefaultEngine
-	// NoEngine conversion for config.NoEngine
-	NoEngine = config.NoEngine
-	// NoLayout to disable layout for a particular template file
-	// conversion for config.NoLayout
-	NoLayout = config.NoLayout
-)
-
-/* */
-
 type (
+	// FrameworkAPI contains the main Iris Public API
+	FrameworkAPI interface {
+		MuxAPI
+		Must(error)
+		ListenWithErr(string) error
+		Listen(string)
+		ListenTLSWithErr(string, string, string) error
+		ListenTLS(string, string, string)
+		ListenUNIXWithErr(string, os.FileMode) error
+		ListenUNIX(string, os.FileMode)
+		NoListen() *Server
+		Close()
+		OnError(int, HandlerFunc)
+		EmitError(int, *Context)
+		Lookup(string) Route
+		Lookups() []Route
+		Path(string, ...interface{}) string
+		URL(string, ...interface{}) string
+		SendMail(string, string, ...string) error
+		TemplateString(string, interface{}, ...string) string
+	}
 
-	// Iris is the container of all, server, router, cache and the sync.Pool
-	Iris struct {
-		*router
-		config          *config.Iris
-		server          *server.Server
-		plugins         *PluginContainer
-		rest            *rest.Render
-		templates       *template.Template
-		sessionManager  *sessions.Manager
-		websocketServer websocket.Server
-		mailService     mail.Service
-		logger          *logger.Logger
-		gzipWriterPool  sync.Pool // this pool is used everywhere needed in the iris for example inside party-> StaticSimple
+	// RouteNameFunc the func returns from the MuxAPi's methods, optionally sets the name of the Route (*route)
+	RouteNameFunc func(string)
+	// MuxAPI the visible api for the serveMux
+	MuxAPI interface {
+		Party(string, ...HandlerFunc) MuxAPI
+
+		Use(...Handler)
+		UseFunc(...HandlerFunc)
+		Handle(string, string, ...Handler) RouteNameFunc
+		HandleFunc(string, string, ...HandlerFunc) RouteNameFunc
+		// H_ is used to convert a context.IContext handler func to iris.HandlerFunc, is used only inside iris internal package to avoid import cycles
+		H_(string, string, func(context.IContext)) func(string)
+		API(string, HandlerAPI, ...HandlerFunc)
+
+		Get(string, ...HandlerFunc) RouteNameFunc
+		Post(string, ...HandlerFunc) RouteNameFunc
+		Put(string, ...HandlerFunc) RouteNameFunc
+		Delete(string, ...HandlerFunc) RouteNameFunc
+		Connect(string, ...HandlerFunc) RouteNameFunc
+		Head(string, ...HandlerFunc) RouteNameFunc
+		Options(string, ...HandlerFunc) RouteNameFunc
+		Patch(string, ...HandlerFunc) RouteNameFunc
+		Trace(string, ...HandlerFunc) RouteNameFunc
+		Any(string, ...HandlerFunc)
+
+		StaticHandler(string, int, bool, bool, []string) HandlerFunc
+		Static(string, string, int) RouteNameFunc
+		StaticFS(string, string, int) RouteNameFunc
+		StaticWeb(string, string, int) RouteNameFunc
+		StaticServe(string, ...string) RouteNameFunc
+		StaticContent(string, string, []byte) func(string)
+		Favicon(string, ...string) RouteNameFunc
 	}
 )
 
-// New creates and returns a new iris station.
-//
-// Receives an optional config.Iris as parameter
-// If empty then config.Default() is used instead
-func New(cfg ...config.Iris) *Iris {
+// -------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------
+// --------------------------------Framework implementation-----------------------------
+// -------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------
 
-	c := config.Default().Merge(cfg)
+var _ FrameworkAPI = &Framework{}
 
-	// create the Iris
-	s := &Iris{config: &c}
-
-	// create & set the router
-	s.router = newRouter(s)
-
-	// set the Logger
-	s.logger = logger.New(c.Logger)
-
-	//set the plugin container
-	s.plugins = &PluginContainer{logger: s.logger}
-
-	// set the gzip writer pool
-	s.gzipWriterPool = sync.Pool{New: func() interface{} { return &gzip.Writer{} }}
-	return s
+// Must panics on error, it panics on registed iris' logger
+func Must(err error) {
+	Default.Must(err)
 }
 
-// newContextPool returns a new context pool, internal method used in tree and router
-func (s *Iris) newContextPool() sync.Pool {
-	return sync.Pool{New: func() interface{} {
-		return &Context{station: s}
-	}}
-}
-
-///TODO HERE MOVE THEM SOMEWHERE ELSE OR MAKE IT MORE BUETY->
-func (s *Iris) initTemplates() {
-	if s.templates == nil { // because if .Templates() called before server's listen, s.templates != nil when PreListen
-		//  init the templates
-		template.RegisterSharedFunc("url", func(routeName string, args ...interface{}) string {
-			if url, err := s.UriOf(routeName, args...); err == nil {
-				return url
-			} else {
-				return err.Error()
-			}
-		})
-
-		template.RegisterSharedFunc("urlpath", func(routeName string, args ...interface{}) string {
-			return s.RouteByName(routeName).ParsePath(args...)
-		})
-
-		s.templates = template.New(s.config.Render.Template)
-
+// Must panics on error, it panics on registed iris' logger
+func (s *Framework) Must(err error) {
+	if err != nil {
+		s.Logger.Panic(err.Error())
 	}
-
-}
-
-func (s *Iris) initWebsocketServer() {
-	if s.websocketServer == nil {
-		// enable websocket if config.Websocket.Endpoint != ""
-		if s.config.Websocket.Endpoint != "" {
-			s.websocketServer = websocket.New(s, s.config.Websocket)
-		}
-	}
-}
-
-func (s *Iris) initMailService() {
-	if s.mailService == nil {
-		// enable mail sender  service if configs are valid
-		if s.config.Mail.IsValid() {
-			s.mailService = mail.New(s.config.Mail)
-		}
-	}
-}
-
-// PreListen call router's optimize, sets the server's handler and notice the plugins
-// capital because we need it sometimes, for example inside the graceful
-// receives the config.Server
-// returns the station's Server (*server.Server)
-// it's a non-blocking func
-func (s *Iris) PreListen(opt config.Server) *server.Server {
-	// router preparation, runs only once even if called more than one time.
-	if !s.router.optimized {
-		s.router.optimize()
-
-		s.server = server.New(opt)
-		s.server.SetHandler(s.router.ServeRequest)
-
-		if s.config.MaxRequestBodySize > 0 {
-			s.server.MaxRequestBodySize = int(s.config.MaxRequestBodySize)
-		}
-	}
-
-	if !s.config.DisableBanner {
-		s.logger.PrintBanner(banner, fmt.Sprintf("%s: Running at %s\n", time.Now().Format(config.TimeFormat), s.server.Config.ListeningAddr))
-	}
-
-	s.plugins.DoPreListen(s)
-
-	return s.server
-}
-
-// PostListen sets the rest render, template engine, sessions and notice the plugins
-// capital because we need it sometimes, for example inside the graceful
-// it's a non-blocking func
-func (s *Iris) PostListen() {
-	//if not error opening the server, then:
-
-	//set the  rest (for Data, Text, JSON, JSONP, XML)
-	s.rest = rest.New(s.config.Render.Rest)
-	// set the templates
-	s.initTemplates()
-	// set the session manager if we have a provider
-	if s.config.Sessions.Provider != "" {
-		s.sessionManager = sessions.New(s.config.Sessions)
-	}
-
-	// set the websocket
-	s.initWebsocketServer()
-
-	s.plugins.DoPostListen(s)
-}
-
-// listen is internal method, open the server with specific options passed by the Listen and ListenTLS
-// it's a blocking func
-func (s *Iris) listen(opt config.Server) (err error) {
-	s.PreListen(opt)
-
-	if err = s.server.OpenServer(); err == nil {
-		s.PostListen()
-
-		ch := make(chan os.Signal)
-		<-ch
-		s.Close()
-	}
-	return
 }
 
 // ListenWithErr starts the standalone http server
 // which listens to the addr parameter which as the form of
-// host:port or just port
+// host:port
 //
 // It returns an error you are responsible how to handle this
 // if you need a func to panic on error use the Listen
 // ex: log.Fatal(iris.ListenWithErr(":8080"))
-func (s *Iris) ListenWithErr(addr string) error {
-	opt := config.Server{ListeningAddr: addr}
-	return s.listen(opt)
+func ListenWithErr(addr string) error {
+	return Default.ListenWithErr(addr)
 }
 
 // Listen starts the standalone http server
 // which listens to the addr parameter which as the form of
-// host:port or just port
+// host:port
 //
 // It panics on error if you need a func to return an error use the ListenWithErr
 // ex: iris.Listen(":8080")
-func (s *Iris) Listen(addr string) {
-	if err := s.ListenWithErr(addr); err != nil {
-		panic(err)
-	}
+func Listen(addr string) {
+	Default.Listen(addr)
+}
+
+// ListenWithErr starts the standalone http server
+// which listens to the addr parameter which as the form of
+// host:port
+//
+// It returns an error you are responsible how to handle this
+// if you need a func to panic on error use the Listen
+// ex: log.Fatal(iris.ListenWithErr(":8080"))
+func (s *Framework) ListenWithErr(addr string) error {
+	s.Config.Server.ListeningAddr = addr
+	return s.openServer()
+}
+
+// Listen starts the standalone http server
+// which listens to the addr parameter which as the form of
+// host:port
+//
+// It panics on error if you need a func to return an error use the ListenWithErr
+// ex: iris.Listen(":8080")
+func (s *Framework) Listen(addr string) {
+	s.Must(s.ListenWithErr(addr))
 }
 
 // ListenTLSWithErr Starts a https server with certificates,
 // if you use this method the requests of the form of 'http://' will fail
 // only https:// connections are allowed
 // which listens to the addr parameter which as the form of
-// host:port or just port
+// host:port
 //
 // It returns an error you are responsible how to handle this
 // if you need a func to panic on error use the ListenTLS
 // ex: log.Fatal(iris.ListenTLSWithErr(":8080","yourfile.cert","yourfile.key"))
-func (s *Iris) ListenTLSWithErr(addr string, certFile, keyFile string) error {
-	opt := config.Server{ListeningAddr: addr, CertFile: certFile, KeyFile: keyFile}
-	return s.listen(opt)
+func ListenTLSWithErr(addr string, certFile string, keyFile string) error {
+	return Default.ListenTLSWithErr(addr, certFile, keyFile)
 }
 
 // ListenTLS Starts a https server with certificates,
 // if you use this method the requests of the form of 'http://' will fail
 // only https:// connections are allowed
 // which listens to the addr parameter which as the form of
-// host:port or just port
+// host:port
 //
 // It panics on error if you need a func to return an error use the ListenTLSWithErr
 // ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
-func (s *Iris) ListenTLS(addr string, certFile, keyFile string) {
-	if err := s.ListenTLSWithErr(addr, certFile, keyFile); err != nil {
-		panic(err)
-	}
+func ListenTLS(addr string, certFile string, keyFile string) {
+	Default.ListenTLS(addr, certFile, keyFile)
 }
 
-// CloseWithErr is used to close the tcp listener from the server, returns an error
-func (s *Iris) CloseWithErr() error {
-	s.plugins.DoPreClose(s)
-	return s.server.CloseServer()
+// ListenTLSWithErr Starts a https server with certificates,
+// if you use this method the requests of the form of 'http://' will fail
+// only https:// connections are allowed
+// which listens to the addr parameter which as the form of
+// host:port
+//
+// It returns an error you are responsible how to handle this
+// if you need a func to panic on error use the ListenTLS
+// ex: log.Fatal(iris.ListenTLSWithErr(":8080","yourfile.cert","yourfile.key"))
+func (s *Framework) ListenTLSWithErr(addr string, certFile string, keyFile string) error {
+	s.Config.Server.ListeningAddr = addr
+	s.Config.Server.CertFile = certFile
+	s.Config.Server.KeyFile = keyFile
+	return s.openServer()
+}
+
+// ListenTLS Starts a https server with certificates,
+// if you use this method the requests of the form of 'http://' will fail
+// only https:// connections are allowed
+// which listens to the addr parameter which as the form of
+// host:port
+//
+// It panics on error if you need a func to return an error use the ListenTLSWithErr
+// ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
+func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
+	s.Must(s.ListenTLSWithErr(addr, certFile, keyFile))
+}
+
+// ListenUNIXWithErr starts the process of listening to the new requests using a 'socket file', this works only on unix
+// returns an error if something bad happens when trying to listen to
+func ListenUNIXWithErr(addr string, mode os.FileMode) error {
+	return Default.ListenUNIXWithErr(addr, mode)
+}
+
+// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
+// panics on error
+func ListenUNIX(addr string, mode os.FileMode) {
+	Default.ListenUNIX(addr, mode)
+}
+
+// ListenUNIXWithErr starts the process of listening to the new requests using a 'socket file', this works only on unix
+// returns an error if something bad happens when trying to listen to
+func (s *Framework) ListenUNIXWithErr(addr string, mode os.FileMode) error {
+	s.Config.Server.ListeningAddr = addr
+	s.Config.Server.Mode = mode
+	return s.openServer()
+}
+
+// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
+// panics on error
+func (s *Framework) ListenUNIX(addr string, mode os.FileMode) {
+	s.Must(s.ListenUNIXWithErr(addr, mode))
+}
+
+// NoListen is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
+func NoListen() *Server {
+	return Default.NoListen()
+}
+
+// NoListen is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
+func (s *Framework) NoListen() *Server {
+	s.initialize()
+	s.Plugins.DoPreListen(s)
+	s.Plugins.DoPostListen(s)
+	return s.HTTPServer
 }
 
 //Close terminates the server and panic if error occurs
-func (s *Iris) Close() {
-	if err := s.CloseWithErr(); err != nil {
-		panic(err)
+func Close() {
+	Default.Close()
+}
+
+//Close terminates the server and panic if error occurs
+func (s *Framework) Close() {
+	s.Must(s.closeServer())
+}
+
+// OnError registers a custom http error handler
+func OnError(statusCode int, handlerFn HandlerFunc) {
+	Default.OnError(statusCode, handlerFn)
+}
+
+// EmitError fires a custom http error handler to the client
+//
+// if no custom error defined with this statuscode, then iris creates one, and once at runtime
+func EmitError(statusCode int, ctx *Context) {
+	Default.EmitError(statusCode, ctx)
+}
+
+// OnError registers a custom http error handler
+func (s *Framework) OnError(statusCode int, handlerFn HandlerFunc) {
+	s.mux.registerError(statusCode, handlerFn)
+}
+
+// EmitError fires a custom http error handler to the client
+//
+// if no custom error defined with this statuscode, then iris creates one, and once at runtime
+func (s *Framework) EmitError(statusCode int, ctx *Context) {
+	s.mux.fireError(statusCode, ctx)
+}
+
+// Lookup returns a registed route by its name
+func Lookup(routeName string) Route {
+	return Default.Lookup(routeName)
+}
+
+// Lookups returns all registed routes
+func Lookups() []Route {
+	return Default.Lookups()
+}
+
+// Lookup returns a registed route by its name
+func (s *Framework) Lookup(routeName string) Route {
+	return s.mux.lookup(routeName)
+}
+
+// Lookups returns all registed routes
+func (s *Framework) Lookups() (routes []Route) {
+	// silly but...
+	for i := range s.mux.lookups {
+		routes = append(routes, s.mux.lookups[i])
+	}
+	return
+}
+
+// Path used to check arguments with the route's named parameters and return the correct url
+// if parse failed returns empty string
+func Path(routeName string, args ...interface{}) string {
+	return Default.Path(routeName, args...)
+}
+
+// Path used to check arguments with the route's named parameters and return the correct url
+// if parse failed returns empty string
+func (s *Framework) Path(routeName string, args ...interface{}) string {
+	r := s.mux.lookup(routeName)
+	if r == nil {
+		return ""
+	}
+
+	argsLen := len(args)
+
+	// we have named parameters but arguments not given
+	if argsLen == 0 && r.formattedParts > 0 {
+		return ""
+	} else if argsLen == 0 && r.formattedParts == 0 {
+		// it's static then just return the path
+		return r.path
+	}
+
+	// we have arguments but they are much more than the named parameters
+
+	// 1 check if we have /*, if yes then join all arguments to one as path and pass that as parameter
+	if argsLen > r.formattedParts {
+		if r.path[len(r.path)-1] == matchEverythingByte {
+			// we have to convert each argument to a string in this case
+
+			argsString := make([]string, argsLen, argsLen)
+
+			for i, v := range args {
+				if s, ok := v.(string); ok {
+					argsString[i] = s
+				} else if num, ok := v.(int); ok {
+					argsString[i] = strconv.Itoa(num)
+				} else if b, ok := v.(bool); ok {
+					argsString[i] = strconv.FormatBool(b)
+				} else if arr, ok := v.([]string); ok {
+					if len(arr) > 0 {
+						argsString[i] = arr[0]
+						argsString = append(argsString, arr[1:]...)
+					}
+				}
+			}
+
+			parameter := strings.Join(argsString, slash)
+			result := fmt.Sprintf(r.formattedPath, parameter)
+			return result
+		}
+		// 2 if !1 return false
+		return ""
+	}
+
+	arguments := args[0:]
+
+	// check for arrays
+	for i, v := range arguments {
+		if arr, ok := v.([]string); ok {
+			if len(arr) > 0 {
+				interfaceArr := make([]interface{}, len(arr))
+				for j, sv := range arr {
+					interfaceArr[j] = sv
+				}
+				arguments[i] = interfaceArr[0]
+				arguments = append(arguments, interfaceArr[1:]...)
+			}
+
+		}
+	}
+
+	return fmt.Sprintf(r.formattedPath, arguments...)
+}
+
+// URL returns the subdomain+ host + Path(...optional named parameters if route is dynamic)
+// returns an empty string if parse is failed
+func URL(routeName string, args ...interface{}) (url string) {
+	return Default.URL(routeName, args...)
+}
+
+// URL returns the subdomain+ host + Path(...optional named parameters if route is dynamic)
+// returns an empty string if parse is failed
+func (s *Framework) URL(routeName string, args ...interface{}) (url string) {
+	r := s.mux.lookup(routeName)
+	if r == nil {
+		return
+	}
+
+	scheme := "http://"
+	if s.HTTPServer.IsSecure() {
+		scheme = "https://"
+	}
+
+	host := s.HTTPServer.VirtualHost()
+	arguments := args[0:]
+
+	// join arrays as arguments
+	for i, v := range arguments {
+		if arr, ok := v.([]string); ok {
+			if len(arr) > 0 {
+				interfaceArr := make([]interface{}, len(arr))
+				for j, sv := range arr {
+					interfaceArr[j] = sv
+				}
+				arguments[i] = interfaceArr[0]
+				arguments = append(arguments, interfaceArr[1:]...)
+			}
+
+		}
+	}
+
+	// if it's dynamic subdomain then the first argument is the subdomain part
+	if r.subdomain == dynamicSubdomainIndicator {
+		if len(arguments) == 0 { // it's a wildcard subdomain but not arguments
+			return
+		}
+
+		if subdomain, ok := arguments[0].(string); ok {
+			host = subdomain + "." + host
+		} else {
+			// it is not array because we join them before. if not pass a string then this is not a subdomain part, return empty uri
+			return
+		}
+
+		arguments = arguments[1:]
+	}
+
+	if parsedPath := Path(routeName, arguments...); parsedPath != "" {
+		url = scheme + host + parsedPath
+	}
+
+	return
+}
+
+// SendMail sends a mail to recipients
+// the body can be html also
+func SendMail(subject string, body string, to ...string) error {
+	return Default.SendMail(subject, body, to...)
+}
+
+// SendMail sends a mail to recipients
+// the body can be html also
+func (s *Framework) SendMail(subject string, body string, to ...string) error {
+	s.prepareMailer()
+	return s.mailer.Send(subject, body, to...)
+}
+
+// TemplateString executes a template and returns its result as string, useful when you want it for sending rich e-mails
+// returns empty string on error
+func TemplateString(templateFile string, pageContext interface{}, layout ...string) string {
+	return Default.TemplateString(templateFile, pageContext, layout...)
+}
+
+// TemplateString executes a template and returns its result as string, useful when you want it for sending rich e-mails
+// returns empty string on error
+func (s *Framework) TemplateString(templateFile string, pageContext interface{}, layout ...string) string {
+	s.prepareTemplates()
+	res, err := s.templates.RenderString(templateFile, pageContext, layout...)
+	if err != nil {
+		return ""
+	}
+	return res
+}
+
+// -------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------
+// ----------------------------------MuxAPI implementation------------------------------
+// -------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------
+
+type muxAPI struct {
+	mux          *serveMux
+	relativePath string
+	middleware   Middleware
+}
+
+var (
+	// errAPIContextNotFound returns an error with message: 'From .API: "Context *iris.Context could not be found..'
+	errAPIContextNotFound = errors.New("From .API: Context *iris.Context could not be found.")
+	// errDirectoryFileNotFound returns an error with message: 'Directory or file %s couldn't found. Trace: +error trace'
+	errDirectoryFileNotFound = errors.New("Directory or file %s couldn't found. Trace: %s")
+)
+
+var _ MuxAPI = &muxAPI{}
+
+func pathIsSubdomain(s string) bool {
+	return strings.Index(s, subdomainIndicator) != -1
+}
+
+// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
+// Party can also be named as 'Join' or 'Node' or 'Group' , Party chosen because it has more fun
+func Party(relativePath string, handlersFn ...HandlerFunc) MuxAPI {
+	return Default.Party(relativePath, handlersFn...)
+}
+
+// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
+// Party can also be named as 'Join' or 'Node' or 'Group' , Party chosen because it has more fun
+func (api *muxAPI) Party(relativePath string, handlersFn ...HandlerFunc) MuxAPI {
+	parentPath := api.relativePath
+	dot := string(subdomainIndicator[0])
+	if len(parentPath) > 0 && parentPath[0] == slashByte && strings.HasSuffix(relativePath, dot) { // if ends with . , example: admin., it's subdomain->
+		parentPath = parentPath[1:] // remove first slash
+	}
+
+	fullpath := parentPath + relativePath
+	middleware := convertToHandlers(handlersFn)
+	// append the parent's +child's handlers
+	middleware = joinMiddleware(api.middleware, middleware)
+	return &muxAPI{relativePath: fullpath, mux: api.mux, middleware: middleware}
+}
+
+// Use registers a Handler middleware
+func Use(handlers ...Handler) {
+	Default.Use(handlers...)
+}
+
+// UseFunc registers a HandlerFunc middleware
+func UseFunc(handlersFn ...HandlerFunc) {
+	Default.UseFunc(handlersFn...)
+}
+
+// Use registers a Handler middleware
+func (api *muxAPI) Use(handlers ...Handler) {
+	api.middleware = append(api.middleware, handlers...)
+}
+
+// UseFunc registers a HandlerFunc middleware
+func (api *muxAPI) UseFunc(handlersFn ...HandlerFunc) {
+	api.Use(convertToHandlers(handlersFn)...)
+}
+
+// Handle registers a route to the server's router
+// if empty method is passed then registers handler(s) for all methods, same as .Any, but returns nil as result
+func Handle(method string, registedPath string, handlers ...Handler) RouteNameFunc {
+	return Default.Handle(method, registedPath, handlers...)
+}
+
+// HandleFunc registers and returns a route with a method string, path string and a handler
+// registedPath is the relative url path
+func HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.HandleFunc(method, registedPath, handlersFn...)
+}
+
+// Handle registers a route to the server's router
+// if empty method is passed then registers handler(s) for all methods, same as .Any, but returns nil as result
+func (api *muxAPI) Handle(method string, registedPath string, handlers ...Handler) RouteNameFunc {
+	if method == "" { // then use like it was .Any
+		for _, k := range AllMethods {
+			api.Handle(k, registedPath, handlers...)
+		}
+		return nil
+	}
+
+	fullpath := api.relativePath + registedPath // keep the last "/" if any,  "/xyz/"
+
+	middleware := joinMiddleware(api.middleware, handlers)
+
+	// here we separate the subdomain and relative path
+	subdomain := ""
+	path := fullpath
+
+	if dotWSlashIdx := strings.Index(path, subdomainIndicator); dotWSlashIdx > 0 {
+		subdomain = fullpath[0 : dotWSlashIdx+1] // admin.
+		path = fullpath[dotWSlashIdx+1:]         // /
+	}
+
+	path = strings.Replace(path, "//", "/", -1) // fix the path if double //
+	return api.mux.register([]byte(method), subdomain, path, middleware).setName
+}
+
+// HandleFunc registers and returns a route with a method string, path string and a handler
+// registedPath is the relative url path
+func (api *muxAPI) HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.Handle(method, registedPath, convertToHandlers(handlersFn)...)
+}
+
+// H_ is used to convert a context.IContext handler func to iris.HandlerFunc, is used only inside iris internal package to avoid import cycles
+func (api *muxAPI) H_(method string, registedPath string, fn func(context.IContext)) func(string) {
+	return api.HandleFunc(method, registedPath, func(ctx *Context) {
+		fn(ctx)
+	})
+}
+
+// API converts & registers a custom struct to the router
+// receives two parameters
+// first is the request path (string)
+// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
+// third is the common middlewares, it's optional
+//
+// Note that API's routes have their default-name to the full registed path,
+// no need to give a special name for it, because it's not supposed to be used inside your templates.
+//
+// Recommend to use when you retrieve data from an external database,
+// and the router-performance is not the (only) thing which slows the server's overall performance.
+//
+// This is a slow method, if you care about router-performance use the Handle/HandleFunc/Get/Post/Put/Delete/Trace/Options... instead
+func API(path string, restAPI HandlerAPI, middleware ...HandlerFunc) {
+	Default.API(path, restAPI, middleware...)
+}
+
+// API converts & registers a custom struct to the router
+// receives two parameters
+// first is the request path (string)
+// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
+// third is the common middleware, it's optional
+//
+// Note that API's routes have their default-name to the full registed path,
+// no need to give a special name for it, because it's not supposed to be used inside your templates.
+//
+// Recommend to use when you retrieve data from an external database,
+// and the router-performance is not the (only) thing which slows the server's overall performance.
+//
+// This is a slow method, if you care about router-performance use the Handle/HandleFunc/Get/Post/Put/Delete/Trace/Options... instead
+func (api *muxAPI) API(path string, restAPI HandlerAPI, middleware ...HandlerFunc) {
+	// here we need to find the registed methods and convert them to handler funcs
+	// methods are collected by method naming:  Get(),GetBy(...), Post(),PostBy(...), Put() and so on
+
+	typ := reflect.ValueOf(restAPI).Type()
+	contextField, found := typ.FieldByName("Context")
+	if !found {
+		panic(errAPIContextNotFound.Return())
+	}
+
+	// check & register the Get(),Post(),Put(),Delete() and so on
+	for _, methodName := range AllMethods {
+
+		methodCapitalName := strings.Title(strings.ToLower(methodName))
+
+		if method, found := typ.MethodByName(methodCapitalName); found {
+			methodFunc := method.Func
+			if !methodFunc.IsValid() || methodFunc.Type().NumIn() > 1 { // for any case
+				continue
+			}
+
+			func(path string, typ reflect.Type, contextField reflect.StructField, methodFunc reflect.Value, method string) {
+				var handlersFn []HandlerFunc
+
+				handlersFn = append(handlersFn, middleware...)
+				handlersFn = append(handlersFn, func(ctx *Context) {
+					newController := reflect.New(typ).Elem()
+					newController.FieldByName("Context").Set(reflect.ValueOf(ctx))
+					methodFunc.Call([]reflect.Value{newController})
+				})
+				// register route
+				api.HandleFunc(method, path, handlersFn...)
+			}(path, typ, contextField, methodFunc, methodName)
+
+		}
+
+	}
+
+	// check for GetBy/PostBy(id string, something_else string) , these must be requested by the same order.
+	// (we could do this in the same top loop but I don't want)
+	// GET, DELETE -> with url named parameters (/users/:id/:secondArgumentIfExists)
+	// POST, PUT -> with post values (form)
+	// all other with URL Parameters (?something=this&else=other
+	//
+	// or no, I changed my mind, let all be named parameters and let users to decide what info they need,
+	// using the Context to take more values (post form,url params and so on).-
+
+	for _, methodName := range AllMethods {
+		methodWithBy := strings.Title(strings.ToLower(methodName)) + "By"
+		if method, found := typ.MethodByName(methodWithBy); found {
+			methodFunc := method.Func
+			if !methodFunc.IsValid() || methodFunc.Type().NumIn() < 2 { //it's By but it has not receive any arguments so its not api's
+				continue
+			}
+			methodFuncType := methodFunc.Type()
+			numInLen := methodFuncType.NumIn() // how much data we should receive from the request
+			registedPath := path
+
+			for i := 1; i < numInLen; i++ { // from 1 because the first is the 'object'
+				if registedPath[len(registedPath)-1] == slashByte {
+					registedPath += ":param" + strconv.Itoa(i)
+				} else {
+					registedPath += "/:param" + strconv.Itoa(i)
+				}
+			}
+
+			func(registedPath string, typ reflect.Type, contextField reflect.StructField, methodFunc reflect.Value, paramsLen int, method string) {
+				var handlersFn []HandlerFunc
+
+				handlersFn = append(handlersFn, middleware...)
+				handlersFn = append(handlersFn, func(ctx *Context) {
+					newController := reflect.New(typ).Elem()
+					newController.FieldByName("Context").Set(reflect.ValueOf(ctx))
+					args := make([]reflect.Value, paramsLen+1, paramsLen+1)
+					args[0] = newController
+					for i := 0; i < paramsLen; i++ {
+						args[i+1] = reflect.ValueOf(ctx.Params[i].Value)
+					}
+					methodFunc.Call(args)
+				})
+				// register route
+				api.HandleFunc(method, registedPath, handlersFn...)
+			}(registedPath, typ, contextField, methodFunc, numInLen-1, methodName)
+
+		}
+
+	}
+
+}
+
+// Get registers a route for the Get http method
+func Get(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Get(path, handlersFn...)
+}
+
+// Post registers a route for the Post http method
+func Post(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Post(path, handlersFn...)
+}
+
+// Put registers a route for the Put http method
+func Put(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Put(path, handlersFn...)
+}
+
+// Delete registers a route for the Delete http method
+func Delete(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Delete(path, handlersFn...)
+}
+
+// Connect registers a route for the Connect http method
+func Connect(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Connect(path, handlersFn...)
+}
+
+// Head registers a route for the Head http method
+func Head(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Head(path, handlersFn...)
+}
+
+// Options registers a route for the Options http method
+func Options(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Options(path, handlersFn...)
+}
+
+// Patch registers a route for the Patch http method
+func Patch(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Patch(path, handlersFn...)
+}
+
+// Trace registers a route for the Trace http method
+func Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return Default.Trace(path, handlersFn...)
+}
+
+// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
+func Any(registedPath string, handlersFn ...HandlerFunc) {
+	Default.Any(registedPath, handlersFn...)
+
+}
+
+// Get registers a route for the Get http method
+func (api *muxAPI) Get(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodGet, path, handlersFn...)
+}
+
+// Post registers a route for the Post http method
+func (api *muxAPI) Post(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodPost, path, handlersFn...)
+}
+
+// Put registers a route for the Put http method
+func (api *muxAPI) Put(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodPut, path, handlersFn...)
+}
+
+// Delete registers a route for the Delete http method
+func (api *muxAPI) Delete(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodDelete, path, handlersFn...)
+}
+
+// Connect registers a route for the Connect http method
+func (api *muxAPI) Connect(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodConnect, path, handlersFn...)
+}
+
+// Head registers a route for the Head http method
+func (api *muxAPI) Head(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodHead, path, handlersFn...)
+}
+
+// Options registers a route for the Options http method
+func (api *muxAPI) Options(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodOptions, path, handlersFn...)
+}
+
+// Patch registers a route for the Patch http method
+func (api *muxAPI) Patch(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodPatch, path, handlersFn...)
+}
+
+// Trace registers a route for the Trace http method
+func (api *muxAPI) Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
+	return api.HandleFunc(MethodTrace, path, handlersFn...)
+}
+
+// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
+func (api *muxAPI) Any(registedPath string, handlersFn ...HandlerFunc) {
+	for _, k := range AllMethods {
+		api.HandleFunc(k, registedPath, handlersFn...)
 	}
 }
 
-// Server returns the server
-func (s *Iris) Server() *server.Server {
-	return s.server
+// StaticHandler returns a Handler to serve static system directory
+// Accepts 5 parameters
+//
+// first is the systemPath (string)
+// Path to the root directory to serve files from.
+//
+// second is the  stripSlashes (int) level
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+//
+// third is the compress (bool)
+// Transparently compresses responses if set to true.
+//
+// The server tries minimizing CPU usage by caching compressed files.
+// It adds fasthttp.FSCompressedFileSuffix suffix to the original file name and
+// tries saving the resulting compressed file under the new file name.
+// So it is advisable to give the server write access to Root
+// and to all inner folders in order to minimze CPU usage when serving
+// compressed responses.
+//
+// fourth is the generateIndexPages (bool)
+// Index pages for directories without files matching IndexNames
+// are automatically generated if set.
+//
+// Directory index generation may be quite slow for directories
+// with many files (more than 1K), so it is discouraged enabling
+// index pages' generation for such directories.
+//
+// fifth is the indexNames ([]string)
+// List of index file names to try opening during directory access.
+//
+// For example:
+//
+//     * index.html
+//     * index.htm
+//     * my-super-index.xml
+//
+func StaticHandler(systemPath string, stripSlashes int, compress bool, generateIndexPages bool, indexNames []string) HandlerFunc {
+	return Default.StaticHandler(systemPath, stripSlashes, compress, generateIndexPages, indexNames)
 }
 
-// Plugins returns the plugin container
-func (s *Iris) Plugins() *PluginContainer {
-	return s.plugins
+// StaticHandler returns a Handler to serve static system directory
+// Accepts 5 parameters
+//
+// first is the systemPath (string)
+// Path to the root directory to serve files from.
+//
+// second is the  stripSlashes (int) level
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+//
+// third is the compress (bool)
+// Transparently compresses responses if set to true.
+//
+// The server tries minimizing CPU usage by caching compressed files.
+// It adds fasthttp.FSCompressedFileSuffix suffix to the original file name and
+// tries saving the resulting compressed file under the new file name.
+// So it is advisable to give the server write access to Root
+// and to all inner folders in order to minimze CPU usage when serving
+// compressed responses.
+//
+// fourth is the generateIndexPages (bool)
+// Index pages for directories without files matching IndexNames
+// are automatically generated if set.
+//
+// Directory index generation may be quite slow for directories
+// with many files (more than 1K), so it is discouraged enabling
+// index pages' generation for such directories.
+//
+// fifth is the indexNames ([]string)
+// List of index file names to try opening during directory access.
+//
+// For example:
+//
+//     * index.html
+//     * index.htm
+//     * my-super-index.xml
+//
+func (api *muxAPI) StaticHandler(systemPath string, stripSlashes int, compress bool, generateIndexPages bool, indexNames []string) HandlerFunc {
+	if indexNames == nil {
+		indexNames = []string{}
+	}
+	fs := &fasthttp.FS{
+		// Path to directory to serve.
+		Root:       systemPath,
+		IndexNames: indexNames,
+		// Generate index pages if client requests directory contents.
+		GenerateIndexPages: generateIndexPages,
+
+		// Enable transparent compression to save network traffic.
+		Compress:             compress,
+		CacheDuration:        config.StaticCacheDuration,
+		CompressedFileSuffix: config.CompressedFileSuffix,
+	}
+
+	if stripSlashes > 0 {
+		fs.PathRewrite = fasthttp.NewPathSlashesStripper(stripSlashes)
+	}
+
+	// Create request handler for serving static files.
+	h := fs.NewRequestHandler()
+	return HandlerFunc(func(ctx *Context) {
+		h(ctx.RequestCtx)
+		errCode := ctx.RequestCtx.Response.StatusCode()
+		if errCode == StatusNotFound || errCode == StatusBadRequest || errCode == StatusInternalServerError {
+			api.mux.fireError(errCode, ctx)
+		}
+		if ctx.pos < uint8(len(ctx.middleware))-1 {
+			ctx.Next() // for any case
+		}
+
+	})
 }
 
-// Config returns the configs
-func (s *Iris) Config() *config.Iris {
-	return s.config
+// Static registers a route which serves a system directory
+// this doesn't generates an index page which list all files
+// no compression is used also, for these features look at StaticFS func
+// accepts three parameters
+// first parameter is the request url path (string)
+// second parameter is the system directory (string)
+// third parameter is the level (int) of stripSlashes
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+func Static(relative string, systemPath string, stripSlashes int) RouteNameFunc {
+	return Default.Static(relative, systemPath, stripSlashes)
 }
 
-// Logger returns the logger
-func (s *Iris) Logger() *logger.Logger {
-	return s.logger
+// Static registers a route which serves a system directory
+// this doesn't generates an index page which list all files
+// no compression is used also, for these features look at StaticFS func
+// accepts three parameters
+// first parameter is the request url path (string)
+// second parameter is the system directory (string)
+// third parameter is the level (int) of stripSlashes
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+func (api *muxAPI) Static(relative string, systemPath string, stripSlashes int) RouteNameFunc {
+	if relative[len(relative)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath
+		relative += slash
+	}
+
+	h := api.StaticHandler(systemPath, stripSlashes, false, false, nil)
+
+	api.Head(relative+"*filepath", h)
+	return api.Get(relative+"*filepath", h)
 }
 
-// Rest returns the rest render
-func (s *Iris) Rest() *rest.Render {
-	return s.rest
+// StaticFS registers a route which serves a system directory
+// this is the fastest method to serve static files
+// generates an index page which list all files
+// if you use this method it will generate compressed files also
+// think this function as small fileserver with http
+// accepts three parameters
+// first parameter is the request url path (string)
+// second parameter is the system directory (string)
+// third parameter is the level (int) of stripSlashes
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+func StaticFS(reqPath string, systemPath string, stripSlashes int) RouteNameFunc {
+	return Default.StaticFS(reqPath, systemPath, stripSlashes)
 }
 
-// Templates returns the template render
-func (s *Iris) Templates() *template.Template {
-	s.initTemplates() // for any case the user called .Templates() before server's listen
-	return s.templates
+// StaticFS registers a route which serves a system directory
+// this is the fastest method to serve static files
+// generates an index page which list all files
+// if you use this method it will generate compressed files also
+// think this function as small fileserver with http
+// accepts three parameters
+// first parameter is the request url path (string)
+// second parameter is the system directory (string)
+// third parameter is the level (int) of stripSlashes
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+func (api *muxAPI) StaticFS(reqPath string, systemPath string, stripSlashes int) RouteNameFunc {
+	if reqPath[len(reqPath)-1] != slashByte {
+		reqPath += "/"
+	}
+
+	h := api.StaticHandler(systemPath, stripSlashes, true, true, nil)
+	api.Head(reqPath+"*filepath", h)
+	return api.Get(reqPath+"*filepath", h)
 }
 
-// Websocket returns the websocket server
-func (s *Iris) Websocket() websocket.Server {
-	s.initWebsocketServer() // for any case the user called .Websocket() before server's listen
-	return s.websocketServer
+// StaticWeb same as Static but if index.html exists and request uri is '/' then display the index.html's contents
+// accepts three parameters
+// first parameter is the request url path (string)
+// second parameter is the system directory (string)
+// third parameter is the level (int) of stripSlashes
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+// * if you don't know what to put on stripSlashes just 1
+func StaticWeb(reqPath string, systemPath string, stripSlashes int) RouteNameFunc {
+	return Default.StaticWeb(reqPath, systemPath, stripSlashes)
 }
 
-// Mail returns the mail sender service
-func (s *Iris) Mail() mail.Service {
-	s.initMailService()
-	return s.mailService
+// StaticWeb same as Static but if index.html exists and request uri is '/' then display the index.html's contents
+// accepts three parameters
+// first parameter is the request url path (string)
+// second parameter is the system directory (string)
+// third parameter is the level (int) of stripSlashes
+// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
+// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
+// * stripSlashes = 2, original path: "/foo/bar", result: ""
+// * if you don't know what to put on stripSlashes just 1
+func (api *muxAPI) StaticWeb(reqPath string, systemPath string, stripSlashes int) RouteNameFunc {
+	if reqPath[len(reqPath)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath
+		reqPath += "/"
+	}
+
+	hasIndex := utils.Exists(systemPath + utils.PathSeparator + "index.html")
+	serveHandler := api.StaticHandler(systemPath, stripSlashes, false, !hasIndex, nil) // if not index.html exists then generate index.html which shows the list of files
+	indexHandler := func(ctx *Context) {
+		if len(ctx.Param("filepath")) < 2 && hasIndex {
+			ctx.Request.SetRequestURI("index.html")
+		}
+		ctx.Next()
+
+	}
+	api.Head(reqPath+"*filepath", indexHandler, serveHandler)
+	return api.Get(reqPath+"*filepath", indexHandler, serveHandler)
+}
+
+// StaticServe serves a directory as web resource
+// it's the simpliest form of the Static* functions
+// Almost same usage as StaticWeb
+// accepts only one required parameter which is the systemPath ( the same path will be used to register the GET&HEAD routes)
+// if second parameter is empty, otherwise the requestPath is the second parameter
+// it uses gzip compression (compression on each request, no file cache)
+func StaticServe(systemPath string, requestPath ...string) RouteNameFunc {
+	return Default.StaticServe(systemPath, requestPath...)
+}
+
+// StaticServe serves a directory as web resource
+// it's the simpliest form of the Static* functions
+// Almost same usage as StaticWeb
+// accepts only one required parameter which is the systemPath ( the same path will be used to register the GET&HEAD routes)
+// if second parameter is empty, otherwise the requestPath is the second parameter
+// it uses gzip compression (compression on each request, no file cache)
+func (api *muxAPI) StaticServe(systemPath string, requestPath ...string) RouteNameFunc {
+	var reqPath string
+
+	if len(requestPath) == 0 {
+		reqPath = strings.Replace(systemPath, utils.PathSeparator, slash, -1) // replaces any \ to /
+		reqPath = strings.Replace(reqPath, "//", slash, -1)                   // for any case, replaces // to /
+		reqPath = strings.Replace(reqPath, ".", "", -1)                       // replace any dots (./mypath -> /mypath)
+	} else {
+		reqPath = requestPath[0]
+	}
+
+	return api.Get(reqPath+"/*file", func(ctx *Context) {
+		filepath := ctx.Param("file")
+
+		spath := strings.Replace(filepath, "/", utils.PathSeparator, -1)
+		spath = path.Join(systemPath, spath)
+
+		if !utils.DirectoryExists(spath) {
+			ctx.NotFound()
+			return
+		}
+
+		ctx.ServeFile(spath, true)
+	})
+}
+
+// StaticContent serves bytes, memory cached, on the reqPath
+// a good example of this is how the websocket server uses that to auto-register the /iris-ws.js
+func StaticContent(reqPath string, contentType string, content []byte) RouteNameFunc {
+	return Default.StaticContent(reqPath, contentType, content)
+}
+
+// StaticContent serves bytes, memory cached, on the reqPath
+// a good example of this is how the websocket server uses that to auto-register the /iris-ws.js
+func (api *muxAPI) StaticContent(reqPath string, cType string, content []byte) func(string) { // func(string) because we use that on websockets
+	modtime := time.Now()
+	modtimeStr := modtime.UTC().Format(config.TimeFormat)
+
+	h := func(ctx *Context) {
+		if t, err := time.Parse(config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && modtime.Before(t.Add(config.StaticCacheDuration)) {
+			ctx.Response.Header.Del(contentType)
+			ctx.Response.Header.Del(contentLength)
+			ctx.SetStatusCode(StatusNotModified)
+			return
+		}
+
+		ctx.Response.Header.Set(contentType, cType)
+		ctx.Response.Header.Set(lastModified, modtimeStr)
+		ctx.SetStatusCode(StatusOK)
+		ctx.Response.SetBody(content)
+	}
+	api.Head(reqPath, h)
+	return api.Get(reqPath, h)
+}
+
+// Favicon serves static favicon
+// accepts 2 parameters, second is optional
+// favPath (string), declare the system directory path of the __.ico
+// requestPath (string), it's the route's path, by default this is the "/favicon.ico" because some browsers tries to get this by default first,
+// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
+//
+// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
+// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
+//
+// panics on error
+func Favicon(favPath string, requestPath ...string) RouteNameFunc {
+	return Default.Favicon(favPath, requestPath...)
+}
+
+// Favicon serves static favicon
+// accepts 2 parameters, second is optional
+// favPath (string), declare the system directory path of the __.ico
+// requestPath (string), it's the route's path, by default this is the "/favicon.ico" because some browsers tries to get this by default first,
+// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
+//
+// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
+// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
+//
+// panics on error
+func (api *muxAPI) Favicon(favPath string, requestPath ...string) RouteNameFunc {
+	f, err := os.Open(favPath)
+	if err != nil {
+		panic(errDirectoryFileNotFound.Format(favPath, err.Error()))
+	}
+	defer f.Close()
+	fi, _ := f.Stat()
+	if fi.IsDir() { // if it's dir the try to get the favicon.ico
+		fav := path.Join(favPath, "favicon.ico")
+		f, err = os.Open(fav)
+		if err != nil {
+			//we try again with .png
+			return api.Favicon(path.Join(favPath, "favicon.png"))
+		}
+		favPath = fav
+		fi, _ = f.Stat()
+	}
+	modtime := fi.ModTime().UTC().Format(config.TimeFormat)
+	cType := utils.TypeByExtension(favPath)
+	// copy the bytes here in order to cache and not read the ico on each request.
+	cacheFav := make([]byte, fi.Size())
+	if _, err = f.Read(cacheFav); err != nil {
+		panic(errDirectoryFileNotFound.Format(favPath, "Couldn't read the data bytes for Favicon: "+err.Error()))
+	}
+
+	h := func(ctx *Context) {
+		if t, err := time.Parse(config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && fi.ModTime().Before(t.Add(config.StaticCacheDuration)) {
+			ctx.Response.Header.Del(contentType)
+			ctx.Response.Header.Del(contentLength)
+			ctx.SetStatusCode(StatusNotModified)
+			return
+		}
+
+		ctx.Response.Header.Set(contentType, cType)
+		ctx.Response.Header.Set(lastModified, modtime)
+		ctx.SetStatusCode(StatusOK)
+		ctx.Response.SetBody(cacheFav)
+	}
+
+	reqPath := "/favicon" + path.Ext(fi.Name()) //we could use the filename, but because standards is /favicon.ico/.png.
+	if len(requestPath) > 0 {
+		reqPath = requestPath[0]
+	}
+
+	api.Head(reqPath, h)
+	return api.Get(reqPath, h)
 }
diff --git a/iris_singleton.go b/iris_singleton.go
deleted file mode 100644
index 4622d6bf..00000000
--- a/iris_singleton.go
+++ /dev/null
@@ -1,412 +0,0 @@
-package iris
-
-import (
-	"github.com/kataras/iris/config"
-	"github.com/kataras/iris/logger"
-	"github.com/kataras/iris/mail"
-	"github.com/kataras/iris/render/rest"
-	"github.com/kataras/iris/render/template"
-	"github.com/kataras/iris/server"
-	"github.com/kataras/iris/websocket"
-)
-
-// DefaultIris in order to use iris.Get(...,...) we need a default Iris on the package level
-var DefaultIris = New()
-
-// Listen starts the standalone http server
-// which listens to the addr parameter which as the form of
-// host:port or just port
-//
-// It panics on error if you need a func to return an error use the ListenWithErr
-// ex: iris.Listen(":8080")
-func Listen(addr string) {
-	DefaultIris.Listen(addr)
-}
-
-// ListenWithErr starts the standalone http server
-// which listens to the addr parameter which as the form of
-// host:port or just port
-//
-// It returns an error you are responsible how to handle this
-// if you need a func to panic on error use the Listen
-// ex: log.Fatal(iris.ListenWithErr(":8080"))
-func ListenWithErr(addr string) error {
-	return DefaultIris.ListenWithErr(addr)
-}
-
-// ListenTLS Starts a https server with certificates,
-// if you use this method the requests of the form of 'http://' will fail
-// only https:// connections are allowed
-// which listens to the addr parameter which as the form of
-// host:port or just port
-//
-// It panics on error if you need a func to return an error use the ListenTLSWithErr
-// ex: iris.ListenTLS(":8080","yourfile.cert","yourfile.key")
-func ListenTLS(addr string, certFile, keyFile string) {
-	DefaultIris.ListenTLS(addr, certFile, keyFile)
-}
-
-// ListenTLSWithErr Starts a https server with certificates,
-// if you use this method the requests of the form of 'http://' will fail
-// only https:// connections are allowed
-// which listens to the addr parameter which as the form of
-// host:port or just port
-//
-// It returns an error you are responsible how to handle this
-// if you need a func to panic on error use the ListenTLS
-// ex: log.Fatal(iris.ListenTLSWithErr(":8080","yourfile.cert","yourfile.key"))
-func ListenTLSWithErr(addr string, certFile, keyFile string) error {
-	return DefaultIris.ListenTLSWithErr(addr, certFile, keyFile)
-}
-
-// Close is used to close the net.Listener of the standalone http server which has already running via .Listen
-func Close() { DefaultIris.Close() }
-
-// Router implementation
-
-// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
-// Party can also be named as 'Join' or 'Node' or 'Group' , Party chosen because it has more fun
-func Party(path string, handlersFn ...HandlerFunc) IParty {
-	return DefaultIris.Party(path, handlersFn...)
-}
-
-// Handle registers a route to the server's router
-// if empty method is passed then registers handler(s) for all methods, same as .Any
-func Handle(method string, registedPath string, handlers ...Handler) IRoute {
-	return DefaultIris.Handle(method, registedPath, handlers...)
-}
-
-// HandleFunc registers a route with a method, path string, and a handler
-func HandleFunc(method string, path string, handlersFn ...HandlerFunc) IRoute {
-	return DefaultIris.HandleFunc(method, path, handlersFn...)
-}
-
-// Wildcard same as .Party("*.")
-// registers a route for Dynamic subdomain
-// receives three parameters
-// the first is the http method
-// the second is the request path, can be a dynamic path also like others
-// the third are the handlerfuncs
-//
-// example: subdomains_2
-func Wildcard(method string, registedPath string, handlersFn ...HandlerFunc) {
-	DefaultIris.Wildcard(method, registedPath, handlersFn...)
-}
-
-// API converts & registers a custom struct to the router
-// receives two parameters
-// first is the request path (string)
-// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
-// third are the common middlewares, is optional parameter
-//
-// Note that API's routes have their default-name to the full registed path,
-// no need to give a special name for it, because it's not supposed to be used inside your templates.
-//
-// Recommend to use when you retrieve data from an external database,
-// and the router-performance is not the (only) thing which slows the server's overall performance.
-//
-// This is a slow method, if you care about router-performance use the Handle/HandleFunc/Get/Post/Put/Delete/Trace/Options... instead
-//
-// Usage:
-// All the below methods are optional except the *iris.Context field,
-// example with /users :
-/*
-
-package main
-
-import (
-	"github.com/kataras/iris"
-)
-
-type UserAPI struct {
-	*iris.Context
-}
-
-// GET /users
-func (u UserAPI) Get() {
-	u.Write("Get from /users")
-	// u.JSON(iris.StatusOK,myDb.AllUsers())
-}
-
-// GET /:param1 which its value passed to the id argument
-func (u UserAPI) GetBy(id string) { // id equals to u.Param("param1")
-	u.Write("Get from /users/%s", id)
-	// u.JSON(iris.StatusOK, myDb.GetUserById(id))
-
-}
-
-// PUT /users
-func (u UserAPI) Put() {
-	name := u.FormValue("name")
-	// myDb.InsertUser(...)
-	println(string(name))
-	println("Put from /users")
-}
-
-// POST /users/:param1
-func (u UserAPI) PostBy(id string) {
-	name := u.FormValue("name") // you can still use the whole Context's features!
-	// myDb.UpdateUser(...)
-	println(string(name))
-	println("Post from /users/" + id)
-}
-
-// DELETE /users/:param1
-func (u UserAPI) DeleteBy(id string) {
-	// myDb.DeleteUser(id)
-	println("Delete from /" + id)
-}
-
-func main() {
-	iris.API("/users", UserAPI{})
-	iris.Listen(":80")
-}
-*/
-func API(registedPath string, controller HandlerAPI, middlewares ...HandlerFunc) error {
-	return DefaultIris.API(registedPath, controller, middlewares...)
-}
-
-// Use appends a middleware to the route or to the router if it's called from router
-func Use(handlers ...Handler) {
-	DefaultIris.Use(handlers...)
-}
-
-// UseFunc same as Use but it accepts/receives ...HandlerFunc instead of ...Handler
-// form of acceptable: func(c *iris.Context){//first middleware}, func(c *iris.Context){//second middleware}
-func UseFunc(handlersFn ...HandlerFunc) {
-	DefaultIris.UseFunc(handlersFn...)
-}
-
-// Get registers a route for the Get http method
-func Get(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Get(path, handlersFn...)
-}
-
-// Post registers a route for the Post http method
-func Post(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Post(path, handlersFn...)
-}
-
-// Put registers a route for the Put http method
-func Put(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Put(path, handlersFn...)
-}
-
-// Delete registers a route for the Delete http method
-func Delete(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Delete(path, handlersFn...)
-}
-
-// Connect registers a route for the Connect http method
-func Connect(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Connect(path, handlersFn...)
-}
-
-// Head registers a route for the Head http method
-func Head(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Head(path, handlersFn...)
-}
-
-// Options registers a route for the Options http method
-func Options(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Options(path, handlersFn...)
-}
-
-// Patch registers a route for the Patch http method
-func Patch(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Patch(path, handlersFn...)
-}
-
-// Trace registers a route for the Trace http methodd
-func Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return DefaultIris.Trace(path, handlersFn...)
-}
-
-// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
-func Any(path string, handlersFn ...HandlerFunc) []IRoute {
-	return DefaultIris.Any(path, handlersFn...)
-}
-
-// RouteByName returns a route by its name,if not found then returns a route with empty path
-// Note that the searching is case-sensitive
-func RouteByName(lookUpName string) IRoute {
-	return DefaultIris.RouteByName(lookUpName)
-}
-
-// StaticHandlerFunc returns a HandlerFunc to serve static system directory
-// Accepts 5 parameters
-//
-// first is the systemPath (string)
-// Path to the root directory to serve files from.
-//
-// second is the  stripSlashes (int) level
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-//
-// third is the compress (bool)
-// Transparently compresses responses if set to true.
-//
-// The server tries minimizing CPU usage by caching compressed files.
-// It adds FSCompressedFileSuffix suffix to the original file name and
-// tries saving the resulting compressed file under the new file name.
-// So it is advisable to give the server write access to Root
-// and to all inner folders in order to minimze CPU usage when serving
-// compressed responses.
-//
-// fourth is the generateIndexPages (bool)
-// Index pages for directories without files matching IndexNames
-// are automatically generated if set.
-//
-// Directory index generation may be quite slow for directories
-// with many files (more than 1K), so it is discouraged enabling
-// index pages' generation for such directories.
-//
-// fifth is the indexNames ([]string)
-// List of index file names to try opening during directory access.
-//
-// For example:
-//
-//     * index.html
-//     * index.htm
-//     * my-super-index.xml
-//
-func StaticHandlerFunc(systemPath string, stripSlashes int, compress bool, generateIndexPages bool, indexNames []string) HandlerFunc {
-	return DefaultIris.StaticHandlerFunc(systemPath, stripSlashes, compress, generateIndexPages, indexNames)
-}
-
-// Static registers a route which serves a system directory
-// this doesn't generates an index page which list all files
-// no compression is used also, for these features look at StaticFS func
-// accepts three parameters
-// first parameter is the request url path (string)
-// second parameter is the system directory (string)
-// third parameter is the level (int) of stripSlashes
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-func Static(reqPath string, systemPath string, stripSlashes int) {
-	DefaultIris.Static(reqPath, systemPath, stripSlashes)
-}
-
-// StaticFS registers a route which serves a system directory
-// generates an index page which list all files
-// uses compression which file cache, if you use this method it will generate compressed files also
-// think this function as small fileserver with http
-// accepts three parameters
-// first parameter is the request url path (string)
-// second parameter is the system directory (string)
-// third parameter is the level (int) of stripSlashes
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-func StaticFS(reqPath string, systemPath string, stripSlashes int) {
-	DefaultIris.StaticFS(reqPath, systemPath, stripSlashes)
-}
-
-// StaticWeb same as Static but if index.html exists and request uri is '/' then display the index.html's contents
-// accepts three parameters
-// first parameter is the request url path (string)
-// second parameter is the system directory (string)
-// third parameter is the level (int) of stripSlashes
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-func StaticWeb(reqPath string, systemPath string, stripSlashes int) {
-	DefaultIris.StaticWeb(reqPath, systemPath, stripSlashes)
-}
-
-// StaticServe serves a directory as web resource
-// it's the simpliest form of the Static* functions
-// Almost same usage as StaticWeb
-// accepts only one required parameter which is the systemPath ( the same path will be used to register the GET&HEAD routes)
-// if second parameter is empty, otherwise the requestPath is the second parameter
-// it uses gzip compression (compression on each request, no file cache)
-func StaticServe(systemPath string, requestPath ...string) {
-	DefaultIris.StaticServe(systemPath, requestPath...)
-}
-
-// Favicon serves static favicon
-// accepts 2 parameters, second is optionally
-// favPath (string), declare the system directory path of the __.ico
-// requestPath (string), it's the route's path, by default this is the "/favicon.ico" because some browsers tries to get this by default first,
-// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
-//
-// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
-// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
-//
-// returns an error if something goes bad
-func Favicon(favPath string, requestPath ...string) error {
-	return DefaultIris.Favicon(favPath)
-}
-
-// StaticContent serves bytes, memory cached, on the reqPath
-func StaticContent(reqPath string, contentType string, content []byte) {
-	DefaultIris.StaticContent(reqPath, contentType, content)
-}
-
-// OnError Registers a handler for a specific http error status
-func OnError(httpStatus int, handler HandlerFunc) {
-	DefaultIris.OnError(httpStatus, handler)
-}
-
-// EmitError executes the handler of the given error http status code
-func EmitError(httpStatus int, ctx *Context) {
-	DefaultIris.EmitError(httpStatus, ctx)
-}
-
-// OnNotFound sets the handler for http status 404,
-// default is a response with text: 'Not Found' and status: 404
-func OnNotFound(handlerFunc HandlerFunc) {
-	DefaultIris.OnNotFound(handlerFunc)
-}
-
-// OnPanic sets the handler for http status 500,
-// default is a response with text: The server encountered an unexpected condition which prevented it from fulfilling the request. and status: 500
-func OnPanic(handlerFunc HandlerFunc) {
-	DefaultIris.OnPanic(handlerFunc)
-}
-
-// ***********************
-// Export DefaultIris's  exported properties
-// ***********************
-
-// Server returns the server
-func Server() *server.Server {
-	return DefaultIris.Server()
-}
-
-// Plugins returns the plugin container
-func Plugins() *PluginContainer {
-	return DefaultIris.Plugins()
-}
-
-// Config returns the configs
-func Config() *config.Iris {
-	return DefaultIris.Config()
-}
-
-// Logger returns the logger
-func Logger() *logger.Logger {
-	return DefaultIris.Logger()
-}
-
-// Rest returns the rest render
-func Rest() *rest.Render {
-	return DefaultIris.Rest()
-}
-
-// Templates returns the template render
-func Templates() *template.Template {
-	return DefaultIris.Templates()
-}
-
-// Websocket returns the websocket server
-func Websocket() websocket.Server {
-	return DefaultIris.Websocket()
-}
-
-// Mail returns the mail sender service
-func Mail() mail.Service {
-	return DefaultIris.Mail()
-}
diff --git a/logger/logger.go b/logger/logger.go
index 931a0661..e23a02e5 100644
--- a/logger/logger.go
+++ b/logger/logger.go
@@ -17,7 +17,7 @@ var (
 
 // Logger the logger
 type Logger struct {
-	config    config.Logger
+	config    *config.Logger
 	underline *color.Color
 }
 
@@ -30,7 +30,7 @@ func attr(sgr int) color.Attribute {
 func New(c config.Logger) *Logger {
 	color.Output = colorable.NewColorable(c.Out)
 
-	l := &Logger{c, color.New(attr(c.ColorBgDefault), attr(c.ColorFgDefault), color.Bold)}
+	l := &Logger{&c, color.New(attr(c.ColorBgDefault), attr(c.ColorFgDefault), color.Bold)}
 	return l
 }
 
@@ -47,7 +47,7 @@ func (l *Logger) IsEnabled() bool {
 // ResetColors sets the colors to the default
 // this func is called every time a success, info, warning, or danger message is printed
 func (l *Logger) ResetColors() {
-	l.underline.Add(attr(l.config.ColorBgDefault), attr(l.config.ColorFgBanner), color.Bold)
+	l.underline.Add(attr(l.config.ColorBgDefault), attr(l.config.ColorFgDefault))
 }
 
 // PrintBanner prints a text (banner) with BannerFgColor, BannerBgColor and a success message at the end
@@ -83,6 +83,7 @@ func (l *Logger) Printf(format string, a ...interface{}) {
 // Arguments are handled in the manner of fmt.Print.
 func (l *Logger) Print(a interface{}) {
 	if !l.config.Disabled {
+		l.ResetColors()
 		l.Printf("%#v", a)
 	}
 }
@@ -125,7 +126,6 @@ func (l *Logger) Sucessf(format string, a ...interface{}) {
 	if !l.config.Disabled {
 		l.underline.Add(attr(l.config.ColorBgSuccess), attr(l.config.ColorFgSuccess))
 		l.Printf(format, a...)
-		l.ResetColors()
 	}
 }
 
@@ -135,7 +135,6 @@ func (l *Logger) Infof(format string, a ...interface{}) {
 	if !l.config.Disabled {
 		l.underline.Add(attr(l.config.ColorBgInfo), attr(l.config.ColorFgInfo))
 		l.Printf(format, a...)
-		l.ResetColors()
 	}
 }
 
@@ -145,7 +144,6 @@ func (l *Logger) Warningf(format string, a ...interface{}) {
 	if !l.config.Disabled {
 		l.underline.Add(attr(l.config.ColorBgWarning), attr(l.config.ColorFgWarning))
 		l.Printf(format, a...)
-		l.ResetColors()
 	}
 }
 
@@ -155,7 +153,6 @@ func (l *Logger) Dangerf(format string, a ...interface{}) {
 	if !l.config.Disabled {
 		l.underline.Add(attr(l.config.ColorBgDanger), attr(l.config.ColorFgDanger))
 		l.Printf(format, a...)
-		l.ResetColors()
 	}
 }
 
@@ -165,6 +162,5 @@ func (l *Logger) Otherf(format string, a ...interface{}) {
 	if !l.config.Disabled {
 		l.underline.Add(attr(l.config.ColorBgOther), attr(l.config.ColorFgOther))
 		l.Printf(format, a...)
-		l.ResetColors()
 	}
 }
diff --git a/mail/service.go b/mail/service.go
index 6cdbada1..703ce07d 100644
--- a/mail/service.go
+++ b/mail/service.go
@@ -6,23 +6,26 @@ import (
 	"net/mail"
 	"net/smtp"
 	"strings"
+	"sync"
 
 	"github.com/kataras/iris/config"
 	"github.com/kataras/iris/utils"
 )
 
 var buf = utils.NewBufferPool(64)
+var once sync.Once
 
 type (
 	// Service is the interface which mail sender should implement
 	Service interface {
 		// Send sends a mail to recipients
 		// the body can be html also
-		Send(to []string, subject, body string) error
+		Send(string, string, ...string) error
+		UpdateConfig(config.Mail)
 	}
 
 	mailer struct {
-		config        config.Mail
+		config        *config.Mail
 		fromAddr      mail.Address
 		auth          smtp.Auth
 		authenticated bool
@@ -31,44 +34,46 @@ type (
 
 // New creates and returns a new Service
 func New(cfg config.Mail) Service {
-	m := &mailer{config: cfg}
-
+	m := &mailer{config: &cfg}
 	if cfg.FromAlias == "" {
 		if !cfg.UseCommand && cfg.Username != "" && strings.Contains(cfg.Username, "@") {
-			m.fromAddr = mail.Address{cfg.Username[0:strings.IndexByte(cfg.Username, '@')], cfg.Username}
+			m.fromAddr = mail.Address{Name: cfg.Username[0:strings.IndexByte(cfg.Username, '@')], Address: cfg.Username}
 		}
 	} else {
-		m.fromAddr = mail.Address{cfg.FromAlias, cfg.Username}
+		m.fromAddr = mail.Address{Name: cfg.FromAlias, Address: cfg.Username}
 	}
-
 	return m
 }
 
+func (m *mailer) UpdateConfig(cfg config.Mail) {
+	m.config = &cfg
+}
+
 // Send sends a mail to recipients
 // the body can be html also
-func (m *mailer) Send(to []string, subject, body string) error {
+func (m *mailer) Send(subject string, body string, to ...string) error {
 	if m.config.UseCommand {
-		return m.sendCmd(to, subject, body)
+		return m.sendCmd(subject, body, to)
 	}
 
-	return m.sendSMTP(to, subject, body)
+	return m.sendSMTP(subject, body, to)
 }
 
-func (m *mailer) sendSMTP(to []string, subject, body string) error {
+func (m *mailer) sendSMTP(subject string, body string, to []string) error {
 	buffer := buf.Get()
 	defer buf.Put(buffer)
 
 	if !m.authenticated {
-		if m.config.Username == "" || m.config.Password == "" || m.config.Host == "" || m.config.Port <= 0 {
+		cfg := m.config
+		if cfg.Username == "" || cfg.Password == "" || cfg.Host == "" || cfg.Port <= 0 {
 			return fmt.Errorf("Username, Password, Host & Port cannot be empty when using SMTP!")
 		}
-		m.auth = smtp.PlainAuth("", m.config.Username, m.config.Password, m.config.Host)
+		m.auth = smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host)
 		m.authenticated = true
 	}
 
 	fullhost := fmt.Sprintf("%s:%d", m.config.Host, m.config.Port)
 
-	/* START: This one helped me https://gist.github.com/andelf/5004821 */
 	header := make(map[string]string)
 	header["From"] = m.fromAddr.String()
 	header["To"] = strings.Join(to, ",")
@@ -83,8 +88,6 @@ func (m *mailer) sendSMTP(to []string, subject, body string) error {
 	}
 	message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
 
-	/* END */
-
 	return smtp.SendMail(
 		fmt.Sprintf(fullhost),
 		m.auth,
@@ -94,14 +97,27 @@ func (m *mailer) sendSMTP(to []string, subject, body string) error {
 	)
 }
 
-func (m *mailer) sendCmd(to []string, subject, body string) error {
+func (m *mailer) sendCmd(subject string, body string, to []string) error {
 	buffer := buf.Get()
 	defer buf.Put(buffer)
 
-	cmd := utils.CommandBuilder("mail", "-s", subject, strings.Join(to, ","))
-	cmd.AppendArguments("-a", "Content-type: text/html") //always html on
+	header := make(map[string]string)
+	header["To"] = strings.Join(to, ",")
+	header["Subject"] = subject
+	header["MIME-Version"] = "1.0"
+	header["Content-Type"] = "text/html; charset=\"utf-8\""
+	header["Content-Transfer-Encoding"] = "base64"
+
+	message := ""
+	for k, v := range header {
+		message += fmt.Sprintf("%s: %s\r\n", k, v)
+	}
+	message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
+	buffer.WriteString(message)
+	// fix by @qskousen
+	cmd := utils.CommandBuilder("sendmail", "-F", m.fromAddr.Name, "-f", m.fromAddr.Address, "-t")
 
 	cmd.Stdin = buffer
-	_, err := cmd.Output()
+	_, err := cmd.CombinedOutput()
 	return err
 }
diff --git a/middleware/basicauth/basicauth.go b/middleware/basicauth/basicauth.go
index a366832a..f4b4dbc4 100644
--- a/middleware/basicauth/basicauth.go
+++ b/middleware/basicauth/basicauth.go
@@ -143,7 +143,7 @@ func (b *basicAuthMiddleware) Serve(ctx *iris.Context) {
 				auth.logged = true
 			}
 
-			if time.Now().Before(auth.expires) {
+			if time.Now().After(auth.expires) {
 				b.askForCredentials(ctx) // ask for authentication again
 				return
 			}
diff --git a/middleware/logger/logger.go b/middleware/logger/logger.go
index 7a3daf4d..5fa5f613 100644
--- a/middleware/logger/logger.go
+++ b/middleware/logger/logger.go
@@ -11,11 +11,9 @@ import (
 
 // Options are the options of the logger middlweare
 // contains 5 bools
-// Latency, Status, IP, Method, Path
+// Status, IP, Method, Path, EnableColors
 // if set to true then these will print
 type Options struct {
-	// Latency displays latency (bool)
-	Latency bool
 	// Status displays status code (bool)
 	Status bool
 	// IP displays request's remote address (bool)
@@ -24,11 +22,13 @@ type Options struct {
 	Method bool
 	// Path displays the request path (bool)
 	Path bool
+	// EnableColors defaults to false
+	EnableColors bool
 }
 
 // DefaultOptions returns an options which all properties are true
 func DefaultOptions() Options {
-	return Options{true, true, true, true, true}
+	return Options{true, true, true, true, false}
 }
 
 type loggerMiddleware struct {
@@ -45,17 +45,13 @@ func (l *loggerMiddleware) Serve(ctx *iris.Context) {
 	path = ctx.PathString()
 	method = ctx.MethodString()
 
-	if l.options.Latency {
-		startTime = time.Now()
-	}
+	startTime = time.Now()
 
 	ctx.Next()
-	if l.options.Latency {
-		//no time.Since in order to format it well after
-		endTime = time.Now()
-		date = endTime.Format("01/02 - 15:04:05")
-		latency = endTime.Sub(startTime)
-	}
+	//no time.Since in order to format it well after
+	endTime = time.Now()
+	date = endTime.Format("01/02 - 15:04:05")
+	latency = endTime.Sub(startTime)
 
 	if l.options.Status {
 		status = strconv.Itoa(ctx.Response.StatusCode())
@@ -74,14 +70,18 @@ func (l *loggerMiddleware) Serve(ctx *iris.Context) {
 	}
 
 	//finally print the logs
-	if l.options.Latency {
-		l.Otherf("%s %v %4v %s %s %s \n", date, status, latency, ip, method, path)
-	} else {
-		l.Otherf("%s %v %s %s %s \n", date, status, ip, method, path)
-	}
+	l.printf("%s %v %4v %s %s %s \n", date, status, latency, ip, method, path)
 
 }
 
+func (l *loggerMiddleware) printf(format string, a ...interface{}) {
+	if l.options.EnableColors {
+		l.Logger.Otherf(format, a...)
+	} else {
+		l.Logger.Printf(format, a...)
+	}
+}
+
 // Default returns the logger middleware as Handler with the default settings
 func New(theLogger *logger.Logger, options ...Options) iris.HandlerFunc {
 	if theLogger == nil {
diff --git a/npm/npm.go b/npm/npm.go
deleted file mode 100644
index 6ec2beef..00000000
--- a/npm/npm.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package npm
-
-import (
-	"fmt"
-	"strings"
-	"time"
-
-	"github.com/kataras/iris/utils"
-)
-
-var (
-	// NodeModules is the path of the root npm modules
-	// Ex: C:\\Users\\kataras\\AppData\\Roaming\\npm\\node_modules
-	NodeModules string
-)
-
-type (
-	// Result holds Message and Error, if error != nil then the npm command has failed
-	Result struct {
-		// Message the message (string)
-		Message string
-		// Error the error (if any)
-		Error error
-	}
-)
-
-// init sets the root directory for the node_modules
-func init() {
-	NodeModules = utils.MustCommand("npm", "root", "-g") //here it ends with \n we have to remove it
-	NodeModules = NodeModules[0 : len(NodeModules)-1]
-}
-
-func success(output string, a ...interface{}) Result {
-	return Result{fmt.Sprintf(output, a...), nil}
-}
-
-func fail(errMsg string, a ...interface{}) Result {
-	return Result{"", fmt.Errorf("\n"+errMsg, a...)}
-}
-
-// Output returns the error message if result.Error exists, otherwise returns the result.Message
-func (res Result) Output() (out string) {
-	if res.Error != nil {
-		out = res.Error.Error()
-	} else {
-		out = res.Message
-	}
-	return
-}
-
-// Install installs a module
-func Install(moduleName string) Result {
-	finish := make(chan bool)
-
-	go func() {
-		print("\n|")
-		print("_")
-		print("|")
-
-		for {
-			select {
-			case v := <-finish:
-				{
-					if v {
-						print("\010\010\010") //remove the loading chars
-						close(finish)
-						return
-					}
-
-				}
-			default:
-				print("\010\010-")
-				time.Sleep(time.Second / 2)
-				print("\010\\")
-				time.Sleep(time.Second / 2)
-				print("\010|")
-				time.Sleep(time.Second / 2)
-				print("\010/")
-				time.Sleep(time.Second / 2)
-				print("\010-")
-				time.Sleep(time.Second / 2)
-				print("|")
-			}
-		}
-
-	}()
-	out, err := utils.Command("npm", "install", moduleName, "-g")
-	finish <- true
-	if err != nil {
-		return fail("Error installing module %s. Trace: %s", moduleName, err.Error())
-	}
-
-	return success("\n%s installed %s", moduleName, out)
-
-}
-
-// Unistall removes a module
-func Unistall(moduleName string) Result {
-	out, err := utils.Command("npm", "unistall", "-g", moduleName)
-	if err != nil {
-		return fail("Error unstalling module %s. Trace: %s", moduleName, err.Error())
-	}
-	return success("\n %s unistalled %s", moduleName, out)
-
-}
-
-// Abs returns the absolute path of the global node_modules directory + relative
-func Abs(relativePath string) string {
-	return NodeModules + utils.PathSeparator + strings.Replace(relativePath, "/", utils.PathSeparator, -1)
-}
-
-// Exists returns true if a module exists
-// here we have two options
-//1 . search by command something like npm -ls -g --depth=x
-//2.  search on files, we choose the second
-func Exists(executableRelativePath string) bool {
-	execAbsPath := Abs(executableRelativePath)
-	if execAbsPath == "" {
-		return false
-	}
-
-	return utils.Exists(execAbsPath)
-}
diff --git a/party.go b/party.go
deleted file mode 100644
index bbdb1c27..00000000
--- a/party.go
+++ /dev/null
@@ -1,642 +0,0 @@
-package iris
-
-import (
-	"path"
-	"reflect"
-	"strconv"
-	"strings"
-
-	"os"
-
-	"time"
-
-	"github.com/kataras/iris/config"
-	"github.com/kataras/iris/context"
-	"github.com/kataras/iris/utils"
-	"github.com/valyala/fasthttp"
-)
-
-type (
-	// IParty is the interface which implements the whole Party of routes
-	IParty interface {
-		Handle(string, string, ...Handler) IRoute
-		HandleFunc(string, string, ...HandlerFunc) IRoute
-		Wildcard(string, string, ...HandlerFunc)
-		API(path string, controller HandlerAPI, middlewares ...HandlerFunc) error
-		Get(string, ...HandlerFunc) RouteNameFunc
-		Post(string, ...HandlerFunc) RouteNameFunc
-		Put(string, ...HandlerFunc) RouteNameFunc
-		Delete(string, ...HandlerFunc) RouteNameFunc
-		Connect(string, ...HandlerFunc) RouteNameFunc
-		Head(string, ...HandlerFunc) RouteNameFunc
-		Options(string, ...HandlerFunc) RouteNameFunc
-		Patch(string, ...HandlerFunc) RouteNameFunc
-		Trace(string, ...HandlerFunc) RouteNameFunc
-		Any(string, ...HandlerFunc) []IRoute
-		Use(...Handler)
-		UseFunc(...HandlerFunc)
-		StaticHandlerFunc(systemPath string, stripSlashes int, compress bool, generateIndexPages bool, indexNames []string) HandlerFunc
-		Static(string, string, int)
-		StaticFS(string, string, int)
-		StaticWeb(relative string, systemPath string, stripSlashes int)
-		StaticServe(systemPath string, requestPath ...string)
-		Party(string, ...HandlerFunc) IParty // Each party can have a party too
-		IsRoot() bool
-	}
-
-	// GardenParty  is the struct which makes all the job for registering routes and middlewares
-	GardenParty struct {
-		relativePath string
-		station      *Iris // this station is where the party is happening, this station's Garden is the same for all Parties per Station & Router instance
-		middleware   Middleware
-		root         bool
-	}
-)
-
-var _ IParty = &GardenParty{}
-
-// IsRoot returns true if this is the root party ("/")
-func (p *GardenParty) IsRoot() bool {
-	return p.root
-}
-
-// Handle registers a route to the server's router
-// if empty method is passed then registers handler(s) for all methods, same as .Any, but returns nil as result
-func (p *GardenParty) Handle(method string, registedPath string, handlers ...Handler) IRoute {
-	if method == "" { // then use like it was .Any
-		for _, k := range AllMethods {
-			p.Handle(k, registedPath, handlers...)
-		}
-		return nil
-	}
-	path := fixPath(p.relativePath + registedPath) // keep the last "/" as default ex: "/xyz/"
-	if !p.station.config.DisablePathCorrection {
-		// if we have path correction remove it with absPath
-		path = fixPath(absPath(p.relativePath, registedPath)) // "/xyz"
-	}
-	middleware := JoinMiddleware(p.middleware, handlers)
-	route := NewRoute(method, path, middleware, p.station)
-	p.station.plugins.DoPreHandle(route)
-	p.station.addRoute(route)
-	p.station.plugins.DoPostHandle(route)
-	return route
-}
-
-// HandleFunc registers and returns a route with a method string, path string and a handler
-// registedPath is the relative url path
-// handler is the iris.Handler which you can pass anything you want via iris.ToHandlerFunc(func(res,req){})... or just use func(c *iris.Context)
-func (p *GardenParty) HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) IRoute {
-	return p.Handle(method, registedPath, ConvertToHandlers(handlersFn)...)
-}
-
-// Wildcard same as .Party("*.")
-// registers a route for Dynamic subdomain
-// receives three parameters
-// the first is the http method
-// the second is the request path, can be a dynamic path also like others
-// the third are the handlerfuncs
-//
-// Note that this is just a global route, no party's route.
-// example: subdomains_2
-func (p *GardenParty) Wildcard(method string, registedPath string, handlersFn ...HandlerFunc) {
-	path := PrefixDynamicSubdomain + registedPath
-	p.station.router.HandleFunc(method, path, handlersFn...)
-}
-
-// API converts & registers a custom struct to the router
-// receives two parameters
-// first is the request path (string)
-// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
-// third are the common middlewares, is optional parameter
-//
-// Note that API's routes have their default-name to the full registed path,
-// no need to give a special name for it, because it's not supposed to be used inside your templates.
-//
-// Recommend to use when you retrieve data from an external database,
-// and the router-performance is not the (only) thing which slows the server's overall performance.
-//
-// This is a slow method, if you care about router-performance use the Handle/HandleFunc/Get/Post/Put/Delete/Trace/Options... instead
-//
-// Usage:
-// All the below methods are optional except the *iris.Context field,
-// example with /users :
-/*
-
-package main
-
-import (
-	"github.com/kataras/iris"
-)
-
-type UserAPI struct {
-	*iris.Context
-}
-
-// GET /users
-func (u UserAPI) Get() {
-	u.Write("Get from /users")
-	// u.JSON(iris.StatusOK,myDb.AllUsers())
-}
-
-// GET /:param1 which its value passed to the id argument
-func (u UserAPI) GetBy(id string) { // id equals to u.Param("param1")
-	u.Write("Get from /users/%s", id)
-	// u.JSON(iris.StatusOK, myDb.GetUserById(id))
-
-}
-
-// PUT /users
-func (u UserAPI) Put() {
-	name := u.FormValue("name")
-	// myDb.InsertUser(...)
-	println(string(name))
-	println("Put from /users")
-}
-
-// POST /users/:param1
-func (u UserAPI) PostBy(id string) {
-	name := u.FormValue("name") // you can still use the whole Context's features!
-	// myDb.UpdateUser(...)
-	println(string(name))
-	println("Post from /users/" + id)
-}
-
-// DELETE /users/:param1
-func (u UserAPI) DeleteBy(id string) {
-	// myDb.DeleteUser(id)
-	println("Delete from /" + id)
-}
-
-func main() {
-	iris.API("/users", UserAPI{})
-	iris.Listen(":80")
-}
-*/
-func (p *GardenParty) API(path string, controller HandlerAPI, middlewares ...HandlerFunc) error {
-	// here we need to find the registed methods and convert them to handler funcs
-	// methods are collected by method naming:  Get(),GetBy(...), Post(),PostBy(...), Put() and so on
-
-	typ := reflect.ValueOf(controller).Type()
-	contextField, found := typ.FieldByName("Context")
-	if !found {
-		return ErrControllerContextNotFound.Return()
-	}
-
-	// check & register the Get(),Post(),Put(),Delete() and so on
-	for _, methodName := range AllMethods {
-
-		methodCapitalName := strings.Title(strings.ToLower(methodName))
-
-		if method, found := typ.MethodByName(methodCapitalName); found {
-			methodFunc := method.Func
-			if !methodFunc.IsValid() || methodFunc.Type().NumIn() > 1 { // for any case
-				continue
-			}
-
-			func(path string, typ reflect.Type, contextField reflect.StructField, methodFunc reflect.Value, method string) {
-				var handlersFn []HandlerFunc
-
-				handlersFn = append(handlersFn, middlewares...)
-				handlersFn = append(handlersFn, func(ctx *Context) {
-					newController := reflect.New(typ).Elem()
-					newController.FieldByName("Context").Set(reflect.ValueOf(ctx))
-					methodFunc.Call([]reflect.Value{newController})
-				})
-				// register route
-				p.HandleFunc(method, path, handlersFn...)
-			}(path, typ, contextField, methodFunc, methodName)
-
-		}
-
-	}
-
-	// check for GetBy/PostBy(id string, something_else string) , these must be requested by the same order.
-	// (we could do this in the same top loop but I don't want)
-	// GET, DELETE -> with url named parameters (/users/:id/:secondArgumentIfExists)
-	// POST, PUT -> with post values (form)
-	// all other with URL Parameters (?something=this&else=other
-	//
-	// or no, I changed my mind, let all be named parameters and let users to decide what info they need,
-	// using the Context to take more values (post form,url params and so on).-
-
-	for _, methodName := range AllMethods {
-		methodWithBy := strings.Title(strings.ToLower(methodName)) + "By"
-		if method, found := typ.MethodByName(methodWithBy); found {
-			methodFunc := method.Func
-			if !methodFunc.IsValid() || methodFunc.Type().NumIn() < 2 { //it's By but it has not receive any arguments so its not api's
-				continue
-			}
-			methodFuncType := methodFunc.Type()
-			numInLen := methodFuncType.NumIn() // how much data we should receive from the request
-			registedPath := path
-
-			for i := 1; i < numInLen; i++ { // from 1 because the first is the 'object'
-				if registedPath[len(registedPath)-1] == SlashByte {
-					registedPath += ":param" + strconv.Itoa(i)
-				} else {
-					registedPath += "/:param" + strconv.Itoa(i)
-				}
-			}
-
-			func(registedPath string, typ reflect.Type, contextField reflect.StructField, methodFunc reflect.Value, paramsLen int, method string) {
-				var handlersFn []HandlerFunc
-
-				handlersFn = append(handlersFn, middlewares...)
-				handlersFn = append(handlersFn, func(ctx *Context) {
-					newController := reflect.New(typ).Elem()
-					newController.FieldByName("Context").Set(reflect.ValueOf(ctx))
-					args := make([]reflect.Value, paramsLen+1, paramsLen+1)
-					args[0] = newController
-					for i := 0; i < paramsLen; i++ {
-						args[i+1] = reflect.ValueOf(ctx.Params[i].Value)
-					}
-					methodFunc.Call(args)
-				})
-				// register route
-				p.HandleFunc(method, registedPath, handlersFn...)
-			}(registedPath, typ, contextField, methodFunc, numInLen-1, methodName)
-
-		}
-
-	}
-
-	return nil
-}
-
-// Get registers a route for the Get http method
-func (p *GardenParty) Get(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodGet, path, handlersFn...).Name
-}
-
-// Post registers a route for the Post http method
-func (p *GardenParty) Post(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodPost, path, handlersFn...).Name
-}
-
-// Put registers a route for the Put http method
-func (p *GardenParty) Put(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodPut, path, handlersFn...).Name
-}
-
-// Delete registers a route for the Delete http method
-func (p *GardenParty) Delete(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodDelete, path, handlersFn...).Name
-}
-
-// Connect registers a route for the Connect http method
-func (p *GardenParty) Connect(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodConnect, path, handlersFn...).Name
-}
-
-// Head registers a route for the Head http method
-func (p *GardenParty) Head(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodHead, path, handlersFn...).Name
-}
-
-// Options registers a route for the Options http method
-func (p *GardenParty) Options(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodOptions, path, handlersFn...).Name
-}
-
-// Patch registers a route for the Patch http method
-func (p *GardenParty) Patch(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodPatch, path, handlersFn...).Name
-}
-
-// Trace registers a route for the Trace http method
-func (p *GardenParty) Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
-	return p.HandleFunc(MethodTrace, path, handlersFn...).Name
-}
-
-// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
-func (p *GardenParty) Any(registedPath string, handlersFn ...HandlerFunc) []IRoute {
-	theRoutes := make([]IRoute, len(AllMethods), len(AllMethods))
-	for idx, k := range AllMethods {
-		r := p.HandleFunc(k, registedPath, handlersFn...)
-		theRoutes[idx] = r
-	}
-
-	return theRoutes
-}
-
-// H_ is used to convert a context.IContext handler func to iris.HandlerFunc, is used only inside iris internal package to avoid import cycles
-func (p *GardenParty) H_(method string, registedPath string, fn func(context.IContext)) {
-	p.HandleFunc(method, registedPath, func(ctx *Context) {
-		fn(ctx)
-	})
-}
-
-// Use registers a Handler middleware
-func (p *GardenParty) Use(handlers ...Handler) {
-	p.middleware = append(p.middleware, handlers...)
-}
-
-// UseFunc registers a HandlerFunc middleware
-func (p *GardenParty) UseFunc(handlersFn ...HandlerFunc) {
-	p.Use(ConvertToHandlers(handlersFn)...)
-}
-
-// StaticHandlerFunc returns a HandlerFunc to serve static system directory
-// Accepts 5 parameters
-//
-// first is the systemPath (string)
-// Path to the root directory to serve files from.
-//
-// second is the  stripSlashes (int) level
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-//
-// third is the compress (bool)
-// Transparently compresses responses if set to true.
-//
-// The server tries minimizing CPU usage by caching compressed files.
-// It adds fasthttp.FSCompressedFileSuffix suffix to the original file name and
-// tries saving the resulting compressed file under the new file name.
-// So it is advisable to give the server write access to Root
-// and to all inner folders in order to minimze CPU usage when serving
-// compressed responses.
-//
-// fourth is the generateIndexPages (bool)
-// Index pages for directories without files matching IndexNames
-// are automatically generated if set.
-//
-// Directory index generation may be quite slow for directories
-// with many files (more than 1K), so it is discouraged enabling
-// index pages' generation for such directories.
-//
-// fifth is the indexNames ([]string)
-// List of index file names to try opening during directory access.
-//
-// For example:
-//
-//     * index.html
-//     * index.htm
-//     * my-super-index.xml
-//
-func (p *GardenParty) StaticHandlerFunc(systemPath string, stripSlashes int, compress bool, generateIndexPages bool, indexNames []string) HandlerFunc {
-	if indexNames == nil {
-		indexNames = []string{}
-	}
-	fs := &fasthttp.FS{
-		// Path to directory to serve.
-		Root:       systemPath,
-		IndexNames: indexNames,
-		// Generate index pages if client requests directory contents.
-		GenerateIndexPages: generateIndexPages,
-
-		// Enable transparent compression to save network traffic.
-		Compress:             compress,
-		CacheDuration:        config.StaticCacheDuration,
-		CompressedFileSuffix: config.CompressedFileSuffix,
-	}
-
-	if stripSlashes > 0 {
-		fs.PathRewrite = fasthttp.NewPathSlashesStripper(stripSlashes)
-	}
-
-	// Create request handler for serving static files.
-	h := fs.NewRequestHandler()
-	return func(ctx *Context) {
-		h(ctx.RequestCtx)
-		errCode := ctx.RequestCtx.Response.StatusCode()
-
-		if errHandler := ctx.station.router.GetByCode(errCode); errHandler != nil {
-			ctx.RequestCtx.Response.ResetBody()
-			ctx.EmitError(errCode)
-		}
-		if ctx.pos < uint8(len(ctx.middleware))-1 {
-			ctx.Next() // for any case
-		}
-
-	}
-}
-
-// Static registers a route which serves a system directory
-// this doesn't generates an index page which list all files
-// no compression is used also, for these features look at StaticFS func
-// accepts three parameters
-// first parameter is the request url path (string)
-// second parameter is the system directory (string)
-// third parameter is the level (int) of stripSlashes
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-func (p *GardenParty) Static(relative string, systemPath string, stripSlashes int) {
-	if relative[len(relative)-1] != SlashByte { // if / then /*filepath, if /something then /something/*filepath
-		relative += Slash
-	}
-
-	h := p.StaticHandlerFunc(systemPath, stripSlashes, false, false, nil)
-
-	p.Get(relative+"*filepath", h)
-	p.Head(relative+"*filepath", h)
-}
-
-// StaticFS registers a route which serves a system directory
-// this is the fastest method to serve static files
-// generates an index page which list all files
-// if you use this method it will generate compressed files also
-// think this function as small fileserver with http
-// accepts three parameters
-// first parameter is the request url path (string)
-// second parameter is the system directory (string)
-// third parameter is the level (int) of stripSlashes
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-func (p *GardenParty) StaticFS(reqPath string, systemPath string, stripSlashes int) {
-	if reqPath[len(reqPath)-1] != SlashByte {
-		reqPath += "/"
-	}
-
-	h := p.StaticHandlerFunc(systemPath, stripSlashes, true, true, nil)
-	p.Get(reqPath+"*filepath", h)
-	p.Head(reqPath+"*filepath", h)
-}
-
-// StaticWeb same as Static but if index.html exists and request uri is '/' then display the index.html's contents
-// accepts three parameters
-// first parameter is the request url path (string)
-// second parameter is the system directory (string)
-// third parameter is the level (int) of stripSlashes
-// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
-// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
-// * stripSlashes = 2, original path: "/foo/bar", result: ""
-// * if you don't know what to put on stripSlashes just 1
-func (p *GardenParty) StaticWeb(reqPath string, systemPath string, stripSlashes int) {
-	if reqPath[len(reqPath)-1] != SlashByte { // if / then /*filepath, if /something then /something/*filepath
-		reqPath += "/"
-	}
-
-	hasIndex := utils.Exists(systemPath + utils.PathSeparator + "index.html")
-	serveHandler := p.StaticHandlerFunc(systemPath, stripSlashes, false, !hasIndex, nil) // if not index.html exists then generate index.html which shows the list of files
-	indexHandler := func(ctx *Context) {
-		if len(ctx.Param("filepath")) < 2 && hasIndex {
-			ctx.Request.SetRequestURI("index.html")
-		}
-		ctx.Next()
-
-	}
-	p.Get(reqPath+"*filepath", indexHandler, serveHandler)
-	p.Head(reqPath+"*filepath", indexHandler, serveHandler)
-}
-
-// StaticServe serves a directory as web resource
-// it's the simpliest form of the Static* functions
-// Almost same usage as StaticWeb
-// accepts only one required parameter which is the systemPath ( the same path will be used to register the GET&HEAD routes)
-// if second parameter is empty, otherwise the requestPath is the second parameter
-// it uses gzip compression (compression on each request, no file cache)
-func (p *GardenParty) StaticServe(systemPath string, requestPath ...string) {
-	var reqPath string
-
-	if len(reqPath) > 0 {
-		reqPath = requestPath[0]
-	}
-
-	reqPath = strings.Replace(systemPath, utils.PathSeparator, Slash, -1) // replaces any \ to /
-	reqPath = strings.Replace(reqPath, "//", Slash, -1)                   // for any case, replaces // to /
-	reqPath = strings.Replace(reqPath, ".", "", -1)                       // replace any dots (./mypath -> /mypath)
-
-	p.Get(reqPath+"/*file", func(ctx *Context) {
-		filepath := ctx.Param("file")
-
-		path := strings.Replace(filepath, "/", utils.PathSeparator, -1)
-		path = absPath(systemPath, path)
-
-		if !utils.DirectoryExists(path) {
-			ctx.NotFound()
-			return
-		}
-
-		ctx.ServeFile(path, true)
-	})
-}
-
-/* here in order to the subdomains be able to change favicon also */
-
-// Favicon serves static favicon
-// accepts 2 parameters, second is optionally
-// favPath (string), declare the system directory path of the __.ico
-// requestPath (string), it's the route's path, by default this is the "/favicon.ico" because some browsers tries to get this by default first,
-// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
-//
-// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
-// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
-//
-// returns an error if something goes bad
-func (p *GardenParty) Favicon(favPath string, requestPath ...string) error {
-	f, err := os.Open(favPath)
-	if err != nil {
-		return ErrDirectoryFileNotFound.Format(favPath, err.Error())
-	}
-	defer f.Close()
-	fi, _ := f.Stat()
-	if fi.IsDir() { // if it's dir the try to get the favicon.ico
-		fav := path.Join(favPath, "favicon.ico")
-		f, err = os.Open(fav)
-		if err != nil {
-			//we try again with .png
-			return p.Favicon(path.Join(favPath, "favicon.png"))
-		}
-		favPath = fav
-		fi, _ = f.Stat()
-	}
-	modtime := fi.ModTime().UTC().Format(TimeFormat)
-	contentType := utils.TypeByExtension(favPath)
-	// copy the bytes here in order to cache and not read the ico on each request.
-	cacheFav := make([]byte, fi.Size())
-	if _, err = f.Read(cacheFav); err != nil {
-		return ErrDirectoryFileNotFound.Format(favPath, "Couldn't read the data bytes from ico: "+err.Error())
-	}
-
-	h := func(ctx *Context) {
-		if t, err := time.Parse(TimeFormat, ctx.RequestHeader(IfModifiedSince)); err == nil && fi.ModTime().Before(t.Add(config.StaticCacheDuration)) {
-			ctx.Response.Header.Del(ContentType)
-			ctx.Response.Header.Del(ContentLength)
-			ctx.SetStatusCode(StatusNotModified)
-			return
-		}
-
-		ctx.Response.Header.Set(ContentType, contentType)
-		ctx.Response.Header.Set(LastModified, modtime)
-		ctx.SetStatusCode(StatusOK)
-		ctx.Response.SetBody(cacheFav)
-	}
-
-	reqPath := "/favicon" + path.Ext(fi.Name()) //we could use the filename, but because standards is /favicon.ico/.png.
-	if len(requestPath) > 0 {
-		reqPath = requestPath[0]
-	}
-	p.Get(reqPath, h)
-	p.Head(reqPath, h)
-	return nil
-}
-
-// StaticContent serves bytes, memory cached, on the reqPath
-func (p *GardenParty) StaticContent(reqPath string, contentType string, content []byte) {
-	modtime := time.Now()
-	modtimeStr := modtime.UTC().Format(TimeFormat)
-
-	h := func(ctx *Context) {
-		if t, err := time.Parse(TimeFormat, ctx.RequestHeader(IfModifiedSince)); err == nil && modtime.Before(t.Add(config.StaticCacheDuration)) {
-			ctx.Response.Header.Del(ContentType)
-			ctx.Response.Header.Del(ContentLength)
-			ctx.SetStatusCode(StatusNotModified)
-			return
-		}
-
-		ctx.Response.Header.Set(ContentType, contentType)
-		ctx.Response.Header.Set(LastModified, modtimeStr)
-		ctx.SetStatusCode(StatusOK)
-		ctx.Response.SetBody(content)
-	}
-	p.Get(reqPath, h)
-	p.Head(reqPath, h)
-}
-
-/* */
-
-// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
-// Party can also be named as 'Join' or 'Node' or 'Group' , Party chosen because it has more fun
-func (p *GardenParty) Party(path string, handlersFn ...HandlerFunc) IParty {
-	middleware := ConvertToHandlers(handlersFn)
-	if path[0] != SlashByte && strings.Contains(path, ".") {
-		//it's a domain so no handlers share (even the global ) or path, nothing.
-		if path[0] == MatchEverythingByte { // it's a dynamic subdomain
-			path = PrefixDynamicSubdomain
-		}
-	} else {
-		// set path to parent+child
-		path = absPath(p.relativePath, path)
-		// append the parent's +child's handlers
-		middleware = JoinMiddleware(p.middleware, middleware)
-	}
-
-	return &GardenParty{relativePath: path, station: p.station, middleware: middleware}
-}
-
-func absPath(rootPath string, relativePath string) (absPath string) {
-
-	if relativePath == "" {
-		absPath = rootPath
-	} else {
-		absPath = path.Join(rootPath, relativePath)
-	}
-
-	return
-}
-
-// fixPath fix the double slashes, (because of root,I just do that before the .Handle no need for anything else special)
-func fixPath(str string) string {
-
-	strafter := strings.Replace(str, "//", Slash, -1)
-
-	if strafter[0] == SlashByte && strings.Count(strafter, ".") >= 2 {
-		//it's domain, remove the first slash
-		strafter = strafter[1:]
-	}
-
-	return strafter
-}
diff --git a/plugin.go b/plugin.go
index 7b0c82ed..3d09f7bb 100644
--- a/plugin.go
+++ b/plugin.go
@@ -1,128 +1,133 @@
 package iris
 
 import (
+	"sync"
+
+	"github.com/kataras/iris/errors"
+
 	"github.com/kataras/iris/logger"
 	"github.com/kataras/iris/utils"
 )
 
+var (
+	// errPluginAlreadyExists returns an error with message: 'Cannot activate the same plugin again, plugin '+plugin name[+plugin description]' is already exists'
+	errPluginAlreadyExists = errors.New("Cannot use the same plugin again, '%s[%s]' is already exists")
+	// errPluginActivate returns an error with message: 'While trying to activate plugin '+plugin name'. Trace: +specific error'
+	errPluginActivate = errors.New("While trying to activate plugin '%s'. Trace: %s")
+	// errPluginRemoveNoPlugins returns an error with message: 'No plugins are registed yet, you cannot remove a plugin from an empty list!'
+	errPluginRemoveNoPlugins = errors.New("No plugins are registed yet, you cannot remove a plugin from an empty list!")
+	// errPluginRemoveEmptyName returns an error with message: 'Plugin with an empty name cannot be removed'
+	errPluginRemoveEmptyName = errors.New("Plugin with an empty name cannot be removed")
+	// errPluginRemoveNotFound returns an error with message: 'Cannot remove a plugin which doesn't exists'
+	errPluginRemoveNotFound = errors.New("Cannot remove a plugin which doesn't exists")
+)
+
 type (
-	// IPlugin just an empty base for plugins
-	// A Plugin can be added with: .Add(PreHandleFunc(func(IRoute))) and so on... or
-	// .Add(myPlugin{}) which myPlugin is  a struct with any of the methods below or
-	// .PreHandle(PreHandleFunc), .PostHandle(func(IRoute)) and so on...
-	IPlugin interface {
+	// Plugin just an empty base for plugins
+	// A Plugin can be added with: .Add(PreListenFunc(func(*Framework))) and so on... or
+	// .Add(myPlugin{},myPlugin2{}) which myPlugin is  a struct with any of the methods below or
+	// .PostListen(func(*Framework)) and so on...
+	Plugin interface {
 	}
 
-	// IPluginGetName implements the GetName() string method
-	IPluginGetName interface {
+	// pluginGetName implements the GetName() string method
+	pluginGetName interface {
 		// GetName has to returns the name of the plugin, a name is unique
 		// name has to be not dependent from other methods of the plugin,
 		// because it is being called even before the Activate
 		GetName() string
 	}
 
-	// IPluginGetDescription implements the GetDescription() string method
-	IPluginGetDescription interface {
+	// pluginGetDescription implements the GetDescription() string method
+	pluginGetDescription interface {
 		// GetDescription has to returns the description of what the plugins is used for
 		GetDescription() string
 	}
 
-	// IPluginActivate implements the Activate(IPluginContainer) error method
-	IPluginActivate interface {
+	// pluginActivate implements the Activate(pluginContainer) error method
+	pluginActivate interface {
 		// Activate called BEFORE the plugin being added to the plugins list,
 		// if Activate returns none nil error then the plugin is not being added to the list
 		// it is being called only one time
 		//
 		// PluginContainer parameter used to add other plugins if that's necessary by the plugin
-		Activate(IPluginContainer) error
+		Activate(PluginContainer) error
 	}
-
-	// IPluginPreHandle implements the PreHandle(IRoute) method
-	IPluginPreHandle interface {
-		// PreHandle it's being called every time BEFORE a Route is registed to the Router
-		//
-		//  parameter is the Route
-		PreHandle(IRoute)
-	}
-	// PreHandleFunc implements the simple function listener for the PreHandle(IRoute)
-	PreHandleFunc func(IRoute)
-	// IPluginPostHandle implements the PostHandle(IRoute) method
-	IPluginPostHandle interface {
-		// PostHandle it's being called every time AFTER a Route successfully registed to the Router
-		//
-		// parameter is the Route
-		PostHandle(IRoute)
-	}
-	// PostHandleFunc implements the simple function listener for the PostHandle(IRoute)
-	PostHandleFunc func(IRoute)
-	// IPluginPreListen implements the PreListen(*Iris) method
-	IPluginPreListen interface {
+	// pluginPreListen implements the PreListen(*Framework) method
+	pluginPreListen interface {
 		// PreListen it's being called only one time, BEFORE the Server is started (if .Listen called)
 		// is used to do work at the time all other things are ready to go
 		//  parameter is the station
-		PreListen(*Iris)
+		PreListen(*Framework)
 	}
-	// PreListenFunc implements the simple function listener for the PreListen(*Iris)
-	PreListenFunc func(*Iris)
-	// IPluginPostListen implements the PostListen(*Iris) method
-	IPluginPostListen interface {
+	// PreListenFunc implements the simple function listener for the PreListen(*Framework)
+	PreListenFunc func(*Framework)
+	// pluginPostListen implements the PostListen(*Framework) method
+	pluginPostListen interface {
 		// PostListen it's being called only one time, AFTER the Server is started (if .Listen called)
 		// parameter is the station
-		PostListen(*Iris)
+		PostListen(*Framework)
 	}
-	// PostListenFunc implements the simple function listener for the PostListen(*Iris)
-	PostListenFunc func(*Iris)
-	// IPluginPreClose implements the PreClose(*Iris) method
-	IPluginPreClose interface {
+	// PostListenFunc implements the simple function listener for the PostListen(*Framework)
+	PostListenFunc func(*Framework)
+	// pluginPreClose implements the PreClose(*Framework) method
+	pluginPreClose interface {
 		// PreClose it's being called only one time, BEFORE the Iris .Close method
 		// any plugin cleanup/clear memory happens here
 		//
 		// The plugin is deactivated after this state
-		PreClose(*Iris)
+		PreClose(*Framework)
 	}
-	// PreCloseFunc implements the simple function listener for the PreClose(*Iris)
-	PreCloseFunc func(*Iris)
+	// PreCloseFunc implements the simple function listener for the PreClose(*Framework)
+	PreCloseFunc func(*Framework)
 
-	// IPluginPreDownload It's for the future, not being used, I need to create
+	// pluginPreDownload It's for the future, not being used, I need to create
 	// and return an ActivatedPlugin type which will have it's methods, and pass it on .Activate
 	// but now we return the whole pluginContainer, which I can't determinate which plugin tries to
 	// download something, so we will leave it here for the future.
-	IPluginPreDownload interface {
+	pluginPreDownload interface {
 		// PreDownload it's being called every time a plugin tries to download something
 		//
 		// first parameter is the plugin
 		// second parameter is the download url
 		// must return a boolean, if false then the plugin is not permmited to download this file
-		PreDownload(plugin IPlugin, downloadURL string) // bool
+		PreDownload(plugin Plugin, downloadURL string) // bool
 	}
 
-	// PreDownloadFunc implements the simple function listener for the PreDownload(IPlugin,string)
-	PreDownloadFunc func(IPlugin, string)
+	// PreDownloadFunc implements the simple function listener for the PreDownload(plugin,string)
+	PreDownloadFunc func(Plugin, string)
 
-	// IPluginContainer is the interface which the PluginContainer should implements
-	IPluginContainer interface {
-		Add(plugin IPlugin) error
-		Remove(pluginName string) error
-		GetName(plugin IPlugin) string
-		GetDescription(plugin IPlugin) string
-		GetByName(pluginName string) IPlugin
-		Printf(format string, a ...interface{})
-		DoPreHandle(route IRoute)
-		DoPostHandle(route IRoute)
-		DoPreListen(station *Iris)
-		DoPostListen(station *Iris)
-		DoPreClose(station *Iris)
-		DoPreDownload(pluginTryToDownload IPlugin, downloadURL string)
-		GetAll() []IPlugin
+	// PluginContainer is the interface which the pluginContainer should implements
+	PluginContainer interface {
+		Add(...Plugin) error
+		Remove(string) error
+		GetName(Plugin) string
+		GetDescription(Plugin) string
+		GetByName(string) Plugin
+		Printf(string, ...interface{})
+		PreListen(PreListenFunc)
+		DoPreListen(*Framework)
+		DoPreListenParallel(*Framework)
+		PostListen(PostListenFunc)
+		DoPostListen(*Framework)
+		PreClose(PreCloseFunc)
+		DoPreClose(*Framework)
+		PreDownload(PreDownloadFunc)
+		DoPreDownload(Plugin, string)
+		// custom event callbacks
+		On(string, ...func())
+		Call(string)
+		//
+		GetAll() []Plugin
 		// GetDownloader is the only one module that is used and fire listeners at the same time in this file
-		GetDownloader() IDownloadManager
+		GetDownloader() PluginDownloadManager
 	}
-	// IDownloadManager is the interface which the DownloadManager should implements
-	IDownloadManager interface {
-		DirectoryExists(dir string) bool
-		DownloadZip(zipURL string, targetDir string) (string, error)
-		Unzip(archive string, target string) (string, error)
-		Remove(filePath string) error
+	// PluginDownloadManager is the interface which the DownloadManager should implements
+	PluginDownloadManager interface {
+		DirectoryExists(string) bool
+		DownloadZip(string, string) (string, error)
+		Unzip(string, string) (string, error)
+		Remove(string) error
 		// install is just the flow of: downloadZip -> unzip -> removeFile(zippedFile)
 		// accepts 2 parameters
 		//
@@ -136,37 +141,23 @@ type (
 		Install(remoteFileZip string, targetDirectory string) (string, error)
 	}
 
-	// DownloadManager is just a struch which exports the util's downloadZip, directoryExists, unzip methods, used by the plugins via the PluginContainer
-	DownloadManager struct {
+	// pluginDownloadManager is just a struch which exports the util's downloadZip, directoryExists, unzip methods, used by the plugins via the pluginContainer
+	pluginDownloadManager struct {
 	}
 )
 
-// convert the functions to IPlugin
-
-// PreHandle it's being called every time BEFORE a Route is registed to the Router
-//
-//  parameter is the Route
-func (fn PreHandleFunc) PreHandle(route IRoute) {
-	fn(route)
-}
-
-// PostHandle it's being called every time AFTER a Route successfully registed to the Router
-//
-// parameter is the Route
-func (fn PostHandleFunc) PostHandle(route IRoute) {
-	fn(route)
-}
+// convert the functions to plugin
 
 // PreListen it's being called only one time, BEFORE the Server is started (if .Listen called)
 // is used to do work at the time all other things are ready to go
 //  parameter is the station
-func (fn PreListenFunc) PreListen(station *Iris) {
+func (fn PreListenFunc) PreListen(station *Framework) {
 	fn(station)
 }
 
 // PostListen it's being called only one time, AFTER the Server is started (if .Listen called)
 // parameter is the station
-func (fn PostListenFunc) PostListen(station *Iris) {
+func (fn PostListenFunc) PostListen(station *Framework) {
 	fn(station)
 }
 
@@ -174,7 +165,7 @@ func (fn PostListenFunc) PostListen(station *Iris) {
 // any plugin cleanup/clear memory happens here
 //
 // The plugin is deactivated after this state
-func (fn PreCloseFunc) PreClose(station *Iris) {
+func (fn PreCloseFunc) PreClose(station *Framework) {
 	fn(station)
 }
 
@@ -183,83 +174,90 @@ func (fn PreCloseFunc) PreClose(station *Iris) {
 // first parameter is the plugin
 // second parameter is the download url
 // must return a boolean, if false then the plugin is not permmited to download this file
-func (fn PreDownloadFunc) PreDownload(pl IPlugin, downloadURL string) {
+func (fn PreDownloadFunc) PreDownload(pl Plugin, downloadURL string) {
 	fn(pl, downloadURL)
 }
 
 //
 
-var _ IDownloadManager = &DownloadManager{}
-var _ IPluginContainer = &PluginContainer{}
+var _ PluginDownloadManager = &pluginDownloadManager{}
+var _ PluginContainer = &pluginContainer{}
 
 // DirectoryExists returns true if a given local directory exists
-func (d *DownloadManager) DirectoryExists(dir string) bool {
+func (d *pluginDownloadManager) DirectoryExists(dir string) bool {
 	return utils.DirectoryExists(dir)
 }
 
 // DownloadZip downlodas a zip to the given local path location
-func (d *DownloadManager) DownloadZip(zipURL string, targetDir string) (string, error) {
+func (d *pluginDownloadManager) DownloadZip(zipURL string, targetDir string) (string, error) {
 	return utils.DownloadZip(zipURL, targetDir)
 }
 
 // Unzip unzips a zip to the given local path location
-func (d *DownloadManager) Unzip(archive string, target string) (string, error) {
+func (d *pluginDownloadManager) Unzip(archive string, target string) (string, error) {
 	return utils.Unzip(archive, target)
 }
 
 // Remove deletes/removes/rm a file
-func (d *DownloadManager) Remove(filePath string) error {
+func (d *pluginDownloadManager) Remove(filePath string) error {
 	return utils.RemoveFile(filePath)
 }
 
 // Install is just the flow of the: DownloadZip->Unzip->Remove the zip
-func (d *DownloadManager) Install(remoteFileZip string, targetDirectory string) (string, error) {
+func (d *pluginDownloadManager) Install(remoteFileZip string, targetDirectory string) (string, error) {
 	return utils.Install(remoteFileZip, targetDirectory)
 }
 
-// PluginContainer is the base container of all Iris, registed plugins
-type PluginContainer struct {
-	activatedPlugins []IPlugin
-	downloader       *DownloadManager
+// pluginContainer is the base container of all Iris, registed plugins
+type pluginContainer struct {
+	activatedPlugins []Plugin
+	customEvents     map[string][]func()
+	downloader       *pluginDownloadManager
 	logger           *logger.Logger
 }
 
 // Add activates the plugins and if succeed then adds it to the activated plugins list
-func (p *PluginContainer) Add(plugin IPlugin) error {
-	if p.activatedPlugins == nil {
-		p.activatedPlugins = make([]IPlugin, 0)
-	}
-
-	// Check if it's a plugin first, has Activate GetName
-
-	// Check if the plugin already exists
-	pName := p.GetName(plugin)
-	if pName != "" && p.GetByName(pName) != nil {
-		return ErrPluginAlreadyExists.Format(pName, p.GetDescription(plugin))
-	}
-	// Activate the plugin, if no error then add it to the plugins
-	if pluginObj, ok := plugin.(IPluginActivate); ok {
-		err := pluginObj.Activate(p)
-		if err != nil {
-			return ErrPluginActivate.Format(pName, err.Error())
+func (p *pluginContainer) Add(plugins ...Plugin) error {
+	for _, plugin := range plugins {
+		if p.activatedPlugins == nil {
+			p.activatedPlugins = make([]Plugin, 0)
 		}
-	}
 
-	// All ok, add it to the plugins list
-	p.activatedPlugins = append(p.activatedPlugins, plugin)
+		// Check if it's a plugin first, has Activate GetName
+
+		// Check if the plugin already exists
+		pName := p.GetName(plugin)
+		if pName != "" && p.GetByName(pName) != nil {
+			return errPluginAlreadyExists.Format(pName, p.GetDescription(plugin))
+		}
+		// Activate the plugin, if no error then add it to the plugins
+		if pluginObj, ok := plugin.(pluginActivate); ok {
+			err := pluginObj.Activate(p)
+			if err != nil {
+				return errPluginActivate.Format(pName, err.Error())
+			}
+		}
+
+		// All ok, add it to the plugins list
+		p.activatedPlugins = append(p.activatedPlugins, plugin)
+	}
 	return nil
 }
 
+func (p *pluginContainer) Reset() {
+
+}
+
 // Remove removes a plugin by it's name, if pluginName is empty "" or no plugin found with this name, then nothing is removed and a specific error is returned.
 // This doesn't calls the PreClose method
-func (p *PluginContainer) Remove(pluginName string) error {
+func (p *pluginContainer) Remove(pluginName string) error {
 	if p.activatedPlugins == nil {
-		return ErrPluginRemoveNoPlugins.Return()
+		return errPluginRemoveNoPlugins.Return()
 	}
 
 	if pluginName == "" {
 		//return error: cannot delete an unamed plugin
-		return ErrPluginRemoveEmptyName.Return()
+		return errPluginRemoveEmptyName.Return()
 	}
 
 	indexToRemove := -1
@@ -269,7 +267,7 @@ func (p *PluginContainer) Remove(pluginName string) error {
 		}
 	}
 	if indexToRemove == -1 { //if index stills -1 then no plugin was found with this name, just return an error. it is not a critical error.
-		return ErrPluginRemoveNotFound.Return()
+		return errPluginRemoveNotFound.Return()
 	}
 
 	p.activatedPlugins = append(p.activatedPlugins[:indexToRemove], p.activatedPlugins[indexToRemove+1:]...)
@@ -278,29 +276,29 @@ func (p *PluginContainer) Remove(pluginName string) error {
 }
 
 // GetName returns the name of a plugin, if no GetName() implemented it returns an empty string ""
-func (p *PluginContainer) GetName(plugin IPlugin) string {
-	if pluginObj, ok := plugin.(IPluginGetName); ok {
+func (p *pluginContainer) GetName(plugin Plugin) string {
+	if pluginObj, ok := plugin.(pluginGetName); ok {
 		return pluginObj.GetName()
 	}
 	return ""
 }
 
 // GetDescription returns the name of a plugin, if no GetDescription() implemented it returns an empty string ""
-func (p *PluginContainer) GetDescription(plugin IPlugin) string {
-	if pluginObj, ok := plugin.(IPluginGetDescription); ok {
+func (p *pluginContainer) GetDescription(plugin Plugin) string {
+	if pluginObj, ok := plugin.(pluginGetDescription); ok {
 		return pluginObj.GetDescription()
 	}
 	return ""
 }
 
 // GetByName returns a plugin instance by it's name
-func (p *PluginContainer) GetByName(pluginName string) IPlugin {
+func (p *pluginContainer) GetByName(pluginName string) Plugin {
 	if p.activatedPlugins == nil {
 		return nil
 	}
 
 	for i := range p.activatedPlugins {
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginGetName); ok {
+		if pluginObj, ok := p.activatedPlugins[i].(pluginGetName); ok {
 			if pluginObj.GetName() == pluginName {
 				return pluginObj
 			}
@@ -311,114 +309,130 @@ func (p *PluginContainer) GetByName(pluginName string) IPlugin {
 }
 
 // GetAll returns all activated plugins
-func (p *PluginContainer) GetAll() []IPlugin {
+func (p *pluginContainer) GetAll() []Plugin {
 	return p.activatedPlugins
 }
 
 // GetDownloader returns the download manager
-func (p *PluginContainer) GetDownloader() IDownloadManager {
+func (p *pluginContainer) GetDownloader() PluginDownloadManager {
 	// create it if and only if it used somewhere
 	if p.downloader == nil {
-		p.downloader = &DownloadManager{}
+		p.downloader = &pluginDownloadManager{}
 	}
 	return p.downloader
 }
 
 // Printf sends plain text to any registed logger (future), some plugins maybe want use this method
 // maybe at the future I change it, instead of sync even-driven to async channels...
-func (p *PluginContainer) Printf(format string, a ...interface{}) {
+func (p *pluginContainer) Printf(format string, a ...interface{}) {
 	if p.logger != nil {
 		p.logger.Printf(format, a...) //for now just this.
 	}
 
 }
 
-// PreHandle adds a PreHandle plugin-function to the plugin flow container
-func (p *PluginContainer) PreHandle(fn PreHandleFunc) {
-	p.Add(fn)
-}
-
-// DoPreHandle raise all plugins which has the PreHandle method
-func (p *PluginContainer) DoPreHandle(route IRoute) {
-	for i := range p.activatedPlugins {
-		// check if this method exists on our plugin obj, these are optionaly and call it
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginPreHandle); ok {
-			pluginObj.PreHandle(route)
-		}
-	}
-}
-
-// PostHandle adds a PostHandle plugin-function to the plugin flow container
-func (p *PluginContainer) PostHandle(fn PostHandleFunc) {
-	p.Add(fn)
-}
-
-// DoPostHandle raise all plugins which has the DoPostHandle method
-func (p *PluginContainer) DoPostHandle(route IRoute) {
-	for i := range p.activatedPlugins {
-		// check if this method exists on our plugin obj, these are optionaly and call it
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginPostHandle); ok {
-			pluginObj.PostHandle(route)
-		}
-	}
-}
-
 // PreListen adds a PreListen plugin-function to the plugin flow container
-func (p *PluginContainer) PreListen(fn PreListenFunc) {
+func (p *pluginContainer) PreListen(fn PreListenFunc) {
 	p.Add(fn)
 }
 
 // DoPreListen raise all plugins which has the DoPreListen method
-func (p *PluginContainer) DoPreListen(station *Iris) {
+func (p *pluginContainer) DoPreListen(station *Framework) {
 	for i := range p.activatedPlugins {
 		// check if this method exists on our plugin obj, these are optionaly and call it
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginPreListen); ok {
+		if pluginObj, ok := p.activatedPlugins[i].(pluginPreListen); ok {
 			pluginObj.PreListen(station)
 		}
 	}
 }
 
+// DoPreListenParallel raise all PreListen plugins 'at the same time'
+func (p *pluginContainer) DoPreListenParallel(station *Framework) {
+	var wg sync.WaitGroup
+
+	for _, plugin := range p.activatedPlugins {
+		wg.Add(1)
+		// check if this method exists on our plugin obj, these are optionaly and call it
+		go func(plugin Plugin) {
+			if pluginObj, ok := plugin.(pluginPreListen); ok {
+				pluginObj.PreListen(station)
+			}
+
+			wg.Done()
+
+		}(plugin)
+	}
+
+	wg.Wait()
+
+}
+
 // PostListen adds a PostListen plugin-function to the plugin flow container
-func (p *PluginContainer) PostListen(fn PostListenFunc) {
+func (p *pluginContainer) PostListen(fn PostListenFunc) {
 	p.Add(fn)
 }
 
 // DoPostListen raise all plugins which has the DoPostListen method
-func (p *PluginContainer) DoPostListen(station *Iris) {
+func (p *pluginContainer) DoPostListen(station *Framework) {
 	for i := range p.activatedPlugins {
 		// check if this method exists on our plugin obj, these are optionaly and call it
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginPostListen); ok {
+		if pluginObj, ok := p.activatedPlugins[i].(pluginPostListen); ok {
 			pluginObj.PostListen(station)
 		}
 	}
 }
 
 // PreClose adds a PreClose plugin-function to the plugin flow container
-func (p *PluginContainer) PreClose(fn PreCloseFunc) {
+func (p *pluginContainer) PreClose(fn PreCloseFunc) {
 	p.Add(fn)
 }
 
 // DoPreClose raise all plugins which has the DoPreClose method
-func (p *PluginContainer) DoPreClose(station *Iris) {
+func (p *pluginContainer) DoPreClose(station *Framework) {
 	for i := range p.activatedPlugins {
 		// check if this method exists on our plugin obj, these are optionaly and call it
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginPreClose); ok {
+		if pluginObj, ok := p.activatedPlugins[i].(pluginPreClose); ok {
 			pluginObj.PreClose(station)
 		}
 	}
 }
 
 // PreDownload adds a PreDownload plugin-function to the plugin flow container
-func (p *PluginContainer) PreDownload(fn PreDownloadFunc) {
+func (p *pluginContainer) PreDownload(fn PreDownloadFunc) {
 	p.Add(fn)
 }
 
 // DoPreDownload raise all plugins which has the DoPreDownload method
-func (p *PluginContainer) DoPreDownload(pluginTryToDownload IPlugin, downloadURL string) {
+func (p *pluginContainer) DoPreDownload(pluginTryToDownload Plugin, downloadURL string) {
 	for i := range p.activatedPlugins {
 		// check if this method exists on our plugin obj, these are optionaly and call it
-		if pluginObj, ok := p.activatedPlugins[i].(IPluginPreDownload); ok {
+		if pluginObj, ok := p.activatedPlugins[i].(pluginPreDownload); ok {
 			pluginObj.PreDownload(pluginTryToDownload, downloadURL)
 		}
 	}
 }
+
+// On registers a custom event
+// these are not registed as plugins, they are hidden events
+func (p *pluginContainer) On(name string, fns ...func()) {
+	if p.customEvents == nil {
+		p.customEvents = make(map[string][]func(), 0)
+	}
+	if p.customEvents[name] == nil {
+		p.customEvents[name] = make([]func(), 0)
+	}
+	p.customEvents[name] = append(p.customEvents[name], fns...)
+}
+
+// Call fires the custom event
+func (p *pluginContainer) Call(name string) {
+	if p.customEvents == nil {
+		return
+	}
+	if fns := p.customEvents[name]; fns != nil {
+		for _, fn := range fns {
+			fn()
+		}
+
+	}
+}
diff --git a/plugin/editor/README.md b/plugin/editor/README.md
index c672afb1..04f9f6a8 100644
--- a/plugin/editor/README.md
+++ b/plugin/editor/README.md
@@ -24,7 +24,7 @@ import (
 func main(){
 	e := editor.New("username","password").Port(4444).Dir("/path/to/the/client/side/directory")
 
-	iris.Plugins().Add(e)
+	iris.Plugins.Add(e)
 
 	iris.Get("/", func (ctx *iris.Context){})
 
diff --git a/plugin/editor/editor.go b/plugin/editor/editor.go
index e8c925ed..6666d9e3 100644
--- a/plugin/editor/editor.go
+++ b/plugin/editor/editor.go
@@ -11,10 +11,10 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/iris-contrib/npm"
 	"github.com/kataras/iris"
 	"github.com/kataras/iris/config"
 	"github.com/kataras/iris/logger"
-	"github.com/kataras/iris/npm"
 	"github.com/kataras/iris/utils"
 )
 
@@ -85,13 +85,13 @@ func (e *Plugin) GetDescription() string {
 }
 
 // PreListen runs before the server's listens, saves the keyfile,certfile and the host from the Iris station to listen for
-func (e *Plugin) PreListen(s *iris.Iris) {
-	e.logger = s.Logger()
-	e.keyfile = s.Server().Config.KeyFile
-	e.certfile = s.Server().Config.CertFile
+func (e *Plugin) PreListen(s *iris.Framework) {
+	e.logger = s.Logger
+	e.keyfile = s.Config.Server.KeyFile
+	e.certfile = s.Config.Server.CertFile
 
 	if e.config.Host == "" {
-		h := s.Server().Config.ListeningAddr
+		h := s.Config.Server.ListeningAddr
 
 		if idx := strings.Index(h, ":"); idx >= 0 {
 			h = h[0:idx]
@@ -107,7 +107,7 @@ func (e *Plugin) PreListen(s *iris.Iris) {
 }
 
 // PreClose kills the editor's server when Iris is closed
-func (e *Plugin) PreClose(s *iris.Iris) {
+func (e *Plugin) PreClose(s *iris.Framework) {
 	if e.process != nil {
 		err := e.process.Kill()
 		if err != nil {
diff --git a/plugin/iriscontrol/README.md b/plugin/iriscontrol/README.md
index b1ed1196..0be191b5 100644
--- a/plugin/iriscontrol/README.md
+++ b/plugin/iriscontrol/README.md
@@ -28,7 +28,7 @@ import (
 
 func main() {
 
-	iris.Plugins().Add(iriscontrol.Web(9090, map[string]string{
+	iris.Plugins.Add(iriscontrol.Web(9090, map[string]string{
 		"irisusername1": "irispassword1",
 		"irisusername2": "irispassowrd2",
 	}))
@@ -39,7 +39,6 @@ func main() {
 	iris.Post("/something", func(ctx *iris.Context) {
 	})
 
-	fmt.Printf("Iris is listening on :%d", 8080)
 	iris.Listen(":8080")
 }
 
diff --git a/plugin/iriscontrol/control_panel.go b/plugin/iriscontrol/control_panel.go
index bb33c005..a85c6793 100644
--- a/plugin/iriscontrol/control_panel.go
+++ b/plugin/iriscontrol/control_panel.go
@@ -7,7 +7,6 @@ import (
 
 	"github.com/kataras/iris"
 	"github.com/kataras/iris/config"
-	"github.com/kataras/iris/plugin/routesinfo"
 )
 
 var pathSeperator = string(os.PathSeparator)
@@ -27,13 +26,13 @@ func (i *irisControlPlugin) startControlPanel() {
 	}
 
 	i.server = iris.New()
-	i.server.Config().DisableBanner = true
-	i.server.Config().Render.Template.Directory = installationPath + "templates"
+	i.server.Config.DisableBanner = true
+	i.server.Config.Render.Template.Directory = installationPath + "templates"
 	//i.server.SetRenderConfig(i.server.Config.Render)
 	i.setPluginsInfo()
 	i.setPanelRoutes()
 
-	go i.server.Listen(strconv.Itoa(i.options.Port))
+	go i.server.Listen(":" + strconv.Itoa(i.options.Port))
 
 	i.pluginContainer.Printf("[%s] %s is running at port %d", time.Now().UTC().String(), Name, i.options.Port)
 
@@ -43,7 +42,7 @@ func (i *irisControlPlugin) startControlPanel() {
 // contains a boolean if server is running, the routes and the plugins
 type DashboardPage struct {
 	ServerIsRunning      bool
-	Routes               []routesinfo.RouteInfo
+	Routes               []iris.Route
 	Plugins              []PluginInfo
 	LastOperationDateStr string
 }
@@ -52,7 +51,18 @@ func (i *irisControlPlugin) setPluginsInfo() {
 	plugins := i.pluginContainer.GetAll()
 	i.plugins = make([]PluginInfo, 0, len(plugins))
 	for _, plugin := range plugins {
-		i.plugins = append(i.plugins, PluginInfo{Name: i.pluginContainer.GetName(plugin), Description: i.pluginContainer.GetDescription(plugin)})
+		name := i.pluginContainer.GetName(plugin)
+		desc := i.pluginContainer.GetDescription(plugin)
+		if name == "" {
+			// means an iris internaly plugin or a nameless plugin
+			name = "Internal Iris Plugin"
+		}
+		if desc == "" {
+			// means an iris internaly plugin or a descriptionless plugin
+			desc = "Propably an internal Iris Plugin - no description provided"
+		}
+
+		i.plugins = append(i.plugins, PluginInfo{Name: name, Description: desc})
 	}
 }
 
@@ -75,8 +85,8 @@ func (i *irisControlPlugin) setPanelRoutes() {
 	i.server.Use(i.authFunc)
 	i.server.Get("/", func(ctx *iris.Context) {
 		ctx.Render("index.html", DashboardPage{
-			ServerIsRunning:      i.station.Server().IsListening(),
-			Routes:               i.routes.All(),
+			ServerIsRunning:      i.station.HTTPServer.IsListening(),
+			Routes:               i.routes,
 			Plugins:              i.plugins,
 			LastOperationDateStr: i.lastOperationDate.Format(config.TimeFormat),
 		})
diff --git a/plugin/iriscontrol/index.go b/plugin/iriscontrol/index.go
index 4c0edb2e..4355dea2 100644
--- a/plugin/iriscontrol/index.go
+++ b/plugin/iriscontrol/index.go
@@ -1,11 +1,7 @@
 package iriscontrol
 
-// NOT READY YET
-
-// PluginInfo holds the Name and the description of the registed plugins
+// PluginInfo the name and the description of a plugin
 type PluginInfo struct {
 	Name        string
 	Description string
 }
-
-//func getPluginlist...
diff --git a/plugin/iriscontrol/iriscontrol.go b/plugin/iriscontrol/iriscontrol.go
index 1cabb579..1d9e91d1 100644
--- a/plugin/iriscontrol/iriscontrol.go
+++ b/plugin/iriscontrol/iriscontrol.go
@@ -6,8 +6,6 @@ import (
 	"github.com/kataras/iris"
 	"github.com/kataras/iris/config"
 	"github.com/kataras/iris/middleware/basicauth"
-	"github.com/kataras/iris/plugin/routesinfo"
-	"github.com/kataras/iris/server"
 )
 
 // Name the name(string) of this plugin which is Iris Control
@@ -16,17 +14,17 @@ const Name = "Iris Control"
 type irisControlPlugin struct {
 	options config.IrisControl
 	// the pluginContainer is the container which keeps this plugin from the main user's iris instance
-	pluginContainer iris.IPluginContainer
+	pluginContainer iris.PluginContainer
 	// the station object of the main  user's iris instance
-	station *iris.Iris
+	station *iris.Framework
 	//a copy of the server which the main user's iris is listening for
-	stationServer *server.Server
+	stationServer *iris.Server
 
 	// the server is this plugin's server object, it is managed by this plugin only
-	server *iris.Iris
+	server *iris.Framework
 	//
 	//infos
-	routes  *routesinfo.Plugin
+	routes  []iris.Route
 	plugins []PluginInfo
 	// last time the server was on
 	lastOperationDate time.Time
@@ -37,7 +35,7 @@ type irisControlPlugin struct {
 
 // New returns the plugin which is ready-to-use inside iris.Plugin method
 // receives config.IrisControl
-func New(cfg ...config.IrisControl) iris.IPlugin {
+func New(cfg ...config.IrisControl) iris.Plugin {
 	c := config.DefaultIrisControl()
 	if len(cfg) > 0 {
 		c = cfg[0]
@@ -48,21 +46,20 @@ func New(cfg ...config.IrisControl) iris.IPlugin {
 
 	auth := basicauth.Default(c.Users)
 
-	return &irisControlPlugin{options: c, authFunc: auth, routes: routesinfo.RoutesInfo()}
+	return &irisControlPlugin{options: c, authFunc: auth, routes: make([]iris.Route, 0)}
 }
 
 // Web set the options for the plugin and return the plugin which is ready-to-use inside iris.Plugin method
 // first parameter is port
 // second parameter is map of users (username:password)
-func Web(port int, users map[string]string) iris.IPlugin {
-	return New(config.IrisControl{port, users})
+func Web(port int, users map[string]string) iris.Plugin {
+	return New(config.IrisControl{Port: port, Users: users})
 }
 
 // implement the base IPlugin
 
-func (i *irisControlPlugin) Activate(container iris.IPluginContainer) error {
+func (i *irisControlPlugin) Activate(container iris.PluginContainer) error {
 	i.pluginContainer = container
-	container.Add(i.routes) // add the routesinfo plugin to the main server
 	return nil
 }
 
@@ -78,25 +75,21 @@ func (i irisControlPlugin) GetDescription() string {
 
 // implement the rest of the plugin
 
-// PostHandle
-func (i *irisControlPlugin) PostHandle(route iris.IRoute) {
-
-}
-
 // PostListen sets the station object after the main server starts
 // starts the actual work of the plugin
-func (i *irisControlPlugin) PostListen(s *iris.Iris) {
+func (i *irisControlPlugin) PostListen(s *iris.Framework) {
 	//if the first time, because other times start/stop of the server so listen and no listen will be only from the control panel
 	if i.station == nil {
 		i.station = s
-		i.stationServer = i.station.Server()
+		i.stationServer = i.station.HTTPServer
 		i.lastOperationDate = time.Now()
+		i.routes = s.Lookups()
 		i.startControlPanel()
 	}
 
 }
 
-func (i *irisControlPlugin) PreClose(s *iris.Iris) {
+func (i *irisControlPlugin) PreClose(s *iris.Framework) {
 	// Do nothing. This is a wrapper of the main server if we destroy when users stop the main server then we cannot continue the control panel i.Destroy()
 }
 
diff --git a/plugin/iriscontrol/main_controls.go b/plugin/iriscontrol/main_controls.go
index 4156ba2b..9b17124b 100644
--- a/plugin/iriscontrol/main_controls.go
+++ b/plugin/iriscontrol/main_controls.go
@@ -2,19 +2,19 @@ package iriscontrol
 
 // for the main server
 func (i *irisControlPlugin) StartServer() {
-	if i.station.Server().IsListening() == false {
-		if i.station.Server().IsSecure() {
+	if i.station.HTTPServer.IsListening() == false {
+		if i.station.HTTPServer.IsSecure() {
 			//listen with ListenTLS
-			i.station.ListenTLS(i.station.Server().Config.ListeningAddr, i.station.Server().Config.CertFile, i.station.Server().Config.KeyFile)
+			i.station.ListenTLS(i.station.Config.Server.ListeningAddr, i.station.Config.Server.CertFile, i.station.Config.Server.KeyFile)
 		} else {
 			//listen normal
-			i.station.Listen(i.station.Server().Config.ListeningAddr)
+			i.station.Listen(i.station.Config.Server.ListeningAddr)
 		}
 	}
 }
 
 func (i *irisControlPlugin) StopServer() {
-	if i.station.Server().IsListening() {
+	if i.station.HTTPServer.IsListening() {
 		i.station.Close()
 	}
 }
diff --git a/plugin/routesinfo/README.md b/plugin/routesinfo/README.md
deleted file mode 100644
index cd210554..00000000
--- a/plugin/routesinfo/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-## RoutesInfo plugin
-
-This plugin collects & stores all registered  routes and gives information about them.
-
-#### The RouteInfo
-
-```go
-
-type RouteInfo struct {
-	Method     string
-	Domain     string
-	Path       string
-	RegistedAt time.Time
-}
-
-```
-## How to use
-
-```go
-
-package main
-
-import (
-	"github.com/kataras/iris"
-	"github.com/kataras/iris/plugin/routesinfo"
-)
-
-func main() {
-
-	info := routesinfo.New()
-	iris.Plugins().Add(info)
-
-	iris.Get("/yourpath", func(c *iris.Context) {
-		c.Write("yourpath")
-	})
-
-	iris.Post("/otherpostpath", func(c *iris.Context) {
-		c.Write("other post path")
-	})
-
-	all := info.All()
-	// allget := info.ByMethod("GET") -> slice
-	// alllocalhost := info.ByDomain("localhost") -> slice
-	// bypath:= info.ByPath("/yourpath") -> slice
-	// bydomainandmethod:= info.ByDomainAndMethod("localhost","GET") -> slice
-	// bymethodandpath:= info.ByMethodAndPath("GET","/yourpath") -> single (it could be slice for all domains too but it's not)
-
-	println("The first registed route was: ", all[0].Path, "registed at: ", all[0].RegistedAt.String())
-	println("All routes info:")
-	for i:= range all {
-		println(all[i].String())
-		//outputs->
-		// Domain: localhost Method: GET Path: /yourpath RegistedAt: 2016/03/27 15:27:05:029 ...
-		// Domain: localhost Method: POST Path: /otherpostpath RegistedAt: 2016/03/27 15:27:05:030 ...
-	}
-	iris.Listen(":8080")
-
-}
-
-
-```
diff --git a/plugin/routesinfo/routesinfo.go b/plugin/routesinfo/routesinfo.go
deleted file mode 100644
index 97f0cda3..00000000
--- a/plugin/routesinfo/routesinfo.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package routesinfo
-
-import (
-	"fmt"
-	"strings"
-	"time"
-
-	"github.com/kataras/iris"
-)
-
-//Name the name of the plugin, is "RoutesInfo"
-const Name = "RoutesInfo"
-
-// RouteInfo holds the method, domain, path and registered time of a route
-type RouteInfo struct {
-	Method     string
-	Domain     string
-	Path       string
-	RegistedAt time.Time
-}
-
-// String returns the string presentation of the Route(Info)
-func (ri RouteInfo) String() string {
-	if ri.Domain == "" {
-		ri.Domain = "localhost" // only for printing, this doesn't save it, no pointer.
-	}
-	return fmt.Sprintf("Domain: %s Method: %s Path: %s RegistedAt: %s", ri.Domain, ri.Method, ri.Path, ri.RegistedAt.String())
-}
-
-// Plugin the routes info plugin, holds the routes as RouteInfo objects
-type Plugin struct {
-	routes []RouteInfo
-}
-
-// implement the base IPlugin
-
-// GetName ...
-func (r Plugin) GetName() string {
-	return Name
-}
-
-// GetDescription RoutesInfo gives information about the registed routes
-func (r Plugin) GetDescription() string {
-	return Name + " gives information about the registed routes.\n"
-}
-
-//
-
-// implement the rest of the plugin
-
-// PostHandle collect the registed routes information
-func (r *Plugin) PostHandle(route iris.IRoute) {
-	if r.routes == nil {
-		r.routes = make([]RouteInfo, 0)
-	}
-	r.routes = append(r.routes, RouteInfo{route.GetMethod(), route.GetDomain(), route.GetPath(), time.Now()})
-}
-
-// All returns all routeinfos
-// returns a slice
-func (r Plugin) All() []RouteInfo {
-	return r.routes
-}
-
-// ByDomain returns all routeinfos which registed to a specific domain
-// returns a slice, if nothing founds this slice has 0 len&cap
-func (r Plugin) ByDomain(domain string) []RouteInfo {
-	var routesByDomain []RouteInfo
-	rlen := len(r.routes)
-	if domain == "localhost" || domain == "127.0.0.1" || domain == ":" {
-		domain = ""
-	}
-	for i := 0; i < rlen; i++ {
-		if r.routes[i].Domain == domain {
-			routesByDomain = append(routesByDomain, r.routes[i])
-		}
-	}
-	return routesByDomain
-}
-
-// ByMethod returns all routeinfos by a http method
-// returns a slice, if nothing founds this slice has 0 len&cap
-func (r Plugin) ByMethod(method string) []RouteInfo {
-	var routesByMethod []RouteInfo
-	rlen := len(r.routes)
-	method = strings.ToUpper(method)
-	for i := 0; i < rlen; i++ {
-		if r.routes[i].Method == method {
-			routesByMethod = append(routesByMethod, r.routes[i])
-		}
-	}
-	return routesByMethod
-}
-
-// ByPath returns all routeinfos by a path
-// maybe one path is the same on GET and POST ( for example /login GET, /login POST)
-// because of that it returns a slice and not only one RouteInfo
-// returns a slice, if nothing founds this slice has 0 len&cap
-func (r Plugin) ByPath(path string) []RouteInfo {
-	var routesByPath []RouteInfo
-	rlen := len(r.routes)
-	for i := 0; i < rlen; i++ {
-		if r.routes[i].Path == path {
-			routesByPath = append(routesByPath, r.routes[i])
-		}
-	}
-	return routesByPath
-}
-
-// ByDomainAndMethod returns all routeinfos registed to a specific domain and has specific http method
-// returns a slice, if nothing founds this slice has 0 len&cap
-func (r Plugin) ByDomainAndMethod(domain string, method string) []RouteInfo {
-	var routesByDomainAndMethod []RouteInfo
-	rlen := len(r.routes)
-	method = strings.ToUpper(method)
-	if domain == "localhost" || domain == "127.0.0.1" || domain == ":" {
-		domain = ""
-	}
-
-	for i := 0; i < rlen; i++ {
-		if r.routes[i].Method == method && r.routes[i].Domain == domain {
-			routesByDomainAndMethod = append(routesByDomainAndMethod, r.routes[i])
-		}
-	}
-	return routesByDomainAndMethod
-}
-
-// ByMethodAndPath returns a single *RouteInfo which has specific http method and path
-// returns only the first match
-// if nothing founds returns nil
-func (r Plugin) ByMethodAndPath(method string, path string) *RouteInfo {
-
-	rlen := len(r.routes)
-	for i := 0; i < rlen; i++ {
-		if r.routes[i].Method == method && r.routes[i].Path == path {
-			return &r.routes[i]
-		}
-	}
-	return nil
-}
-
-//
-// RoutesInfo returns the Plugin, same as New()
-func RoutesInfo() *Plugin {
-	return &Plugin{}
-}
-
-// New returns the Plugin, same as RoutesInfo()
-func New() *Plugin {
-	return &Plugin{}
-}
diff --git a/plugin/typescript/README.md b/plugin/typescript/README.md
index b9463119..0c3b70a0 100644
--- a/plugin/typescript/README.md
+++ b/plugin/typescript/README.md
@@ -55,7 +55,7 @@ func main(){
 	ts = typescript.DefaultOptions()
 	//
 
-	iris.Plugins().Add(typescript.New(ts)) //or with the default options just: typescript.New()
+	iris.Plugins.Add(typescript.New(ts)) //or with the default options just: typescript.New()
 
 	iris.Get("/", func (ctx *iris.Context){})
 
diff --git a/plugin/typescript/typescript.go b/plugin/typescript/typescript.go
index 08381e12..6b9ebe2e 100644
--- a/plugin/typescript/typescript.go
+++ b/plugin/typescript/typescript.go
@@ -6,10 +6,10 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/iris-contrib/npm"
 	"github.com/kataras/iris"
 	"github.com/kataras/iris/config"
 	"github.com/kataras/iris/logger"
-	"github.com/kataras/iris/npm"
 	"github.com/kataras/iris/plugin/editor"
 	"github.com/kataras/iris/utils"
 )
@@ -46,7 +46,7 @@ type (
 	Plugin struct {
 		options Options
 		// taken from Activate
-		pluginContainer iris.IPluginContainer
+		pluginContainer iris.PluginContainer
 		// taken at the PreListen
 		logger *logger.Logger
 	}
@@ -106,7 +106,7 @@ func New(_opt ...Options) *Plugin {
 // implement the IPlugin & IPluginPreListen
 
 // Activate ...
-func (t *Plugin) Activate(container iris.IPluginContainer) error {
+func (t *Plugin) Activate(container iris.PluginContainer) error {
 	t.pluginContainer = container
 	return nil
 }
@@ -122,8 +122,8 @@ func (t *Plugin) GetDescription() string {
 }
 
 // PreListen ...
-func (t *Plugin) PreListen(s *iris.Iris) {
-	t.logger = s.Logger()
+func (t *Plugin) PreListen(s *iris.Framework) {
+	t.logger = s.Logger
 	t.start()
 }
 
diff --git a/render/template/engine/pongo/pongo.go b/render/template/engine/pongo/pongo.go
index e5f946e6..113d14ed 100644
--- a/render/template/engine/pongo/pongo.go
+++ b/render/template/engine/pongo/pongo.go
@@ -152,15 +152,11 @@ func getPongoContext(templateData interface{}) pongo2.Context {
 		return nil
 	}
 
-	if v, isMap := templateData.(map[string]interface{}); isMap {
-		return v
-	}
-
 	if contextData, isPongoContext := templateData.(pongo2.Context); isPongoContext {
 		return contextData
 	}
 
-	return nil
+	return templateData.(map[string]interface{})
 }
 
 func (p *Engine) fromCache(relativeName string) *pongo2.Template {
diff --git a/render/template/template.go b/render/template/template.go
index f0f8d6c2..5a5f9016 100644
--- a/render/template/template.go
+++ b/render/template/template.go
@@ -132,11 +132,23 @@ func RegisterSharedFunc(name string, fn interface{}) {
 	sharedFuncs[name] = fn
 }
 
+// RegisterSharedFuncs registers functionalities that should be inherited from all supported template engines
+func RegisterSharedFuncs(theFuncs map[string]interface{}) {
+	if sharedFuncs == nil || len(sharedFuncs) == 0 {
+		sharedFuncs = theFuncs
+		return
+	}
+	for k, v := range theFuncs {
+		sharedFuncs[k] = v
+	}
+
+}
+
 // Render renders a template using the context's writer
 func (t *Template) Render(ctx context.IContext, name string, binding interface{}, layout ...string) (err error) {
 
 	if t == nil { // No engine was given but .Render was called
-		ctx.WriteHTML(403, "<b> Iris </b> <br/> Templates are disabled via config.NoEngine, check your iris' configuration please.")
+		ctx.HTML(403, "<b> Iris </b> <br/> Templates are disabled via config.NoEngine, check your iris' configuration please.")
 		return fmt.Errorf("[IRIS TEMPLATES] Templates are disabled via config.NoEngine, check your iris' configuration please.\n")
 	}
 
diff --git a/route.go b/route.go
deleted file mode 100644
index fd063e3f..00000000
--- a/route.go
+++ /dev/null
@@ -1,280 +0,0 @@
-package iris
-
-import (
-	"fmt"
-	"strconv"
-	"strings"
-)
-
-type (
-	// IRoute is the interface which the Route should implements
-	// it useful to have it as an interface because this interface is passed to the plugins
-	IRoute interface {
-		GetMethod() string
-		GetDomain() string
-		GetPath() string
-		GetName() string
-		// Name sets the name of the route
-		Name(string) IRoute
-		GetMiddleware() Middleware
-		HasCors() bool
-		ParsePath(...interface{}) string
-		ParseURI(...interface{}) string
-	}
-
-	// RouteNameFunc is returned to from route handle
-	RouteNameFunc func(string) IRoute
-
-	// Route contains basic and temporary info about the route in order to be stored to the tree
-	Route struct {
-		method   string
-		domain   string
-		fullpath string
-		// the name of the route, the default name is just the registed path.
-		name       string
-		middleware Middleware
-		// station
-		station *Iris
-		// this is used to convert  /mypath/:aparam/:something to -> /mypath/%v/%v and /mypath/* -> mypath/%v
-		// we use %v to escape from the conversions between strings,booleans and integers.
-		// used inside custom html template func 'url'
-		formattedPath string
-		// formattedParts is just the formattedPath count, used to see if we have one path parameter then the url's function arguments will be passed as one string to the %v
-		formattedParts int
-	}
-)
-
-var _ IRoute = &Route{}
-
-// NewRoute creates, from a path string, and a slice of HandlerFunc
-func NewRoute(method string, registedPath string, middleware Middleware, station *Iris) *Route {
-	domain := ""
-	//dirdy but I'm not touching this again:P
-	if registedPath[0] != SlashByte && strings.Contains(registedPath, ".") && (strings.IndexByte(registedPath, SlashByte) == -1 || strings.IndexByte(registedPath, SlashByte) > strings.IndexByte(registedPath, '.')) {
-		//means that is a path with domain
-		//we have to extract the domain
-
-		//find the first '/'
-		firstSlashIndex := strings.IndexByte(registedPath, SlashByte)
-
-		//firt of all remove the first '/' if that exists and we have domain
-		if firstSlashIndex == 0 {
-			//e.g /admin.ideopod.com/hey
-			//then just remove the first slash and re-execute the NewRoute and return it
-			registedPath = registedPath[1:]
-			return NewRoute(method, registedPath, middleware, station)
-		}
-		//if it's just the domain, then set it(registedPath) as the domain
-		//and after set the registedPath to a slash '/' for the path part
-		if firstSlashIndex == -1 {
-			domain = registedPath
-			registedPath = Slash
-		} else {
-			//we have a domain + path
-			domain = registedPath[0:firstSlashIndex]
-			registedPath = registedPath[len(domain):]
-		}
-
-	}
-	r := &Route{method: method, domain: domain, fullpath: registedPath, middleware: middleware, name: registedPath, formattedPath: registedPath, station: station}
-	r.formatPath()
-	return r
-}
-
-func (r *Route) isWildcard() bool {
-	return r.domain != r.station.server.Hostname() && r.domain == PrefixDynamicSubdomain
-}
-
-func (r *Route) formatPath() {
-	// we don't care about performance here, no runtime func.
-
-	n1Len := strings.Count(r.fullpath, ":")
-	isMatchEverything := r.fullpath[len(r.fullpath)-1] == MatchEverythingByte
-	if n1Len == 0 && !isMatchEverything {
-		// its a static
-		return
-	}
-	if n1Len == 0 && isMatchEverything {
-		//if we have something like: /mypath/anything/* -> /mypatch/anything/%v
-		r.formattedPath = r.fullpath[0:len(r.fullpath)-2] + "%v"
-		r.formattedParts++
-		return
-	}
-
-	tempPath := r.fullpath
-
-	splittedN1 := strings.Split(r.fullpath, "/")
-
-	for _, v := range splittedN1 {
-		if len(v) > 0 {
-			if v[0] == ':' || v[0] == MatchEverythingByte {
-				r.formattedParts++
-				tempPath = strings.Replace(tempPath, v, "%v", -1) // n1Len, but let it we don't care about performance here.
-			}
-		}
-
-	}
-	r.formattedPath = tempPath
-}
-
-// GetMethod returns the http method
-func (r Route) GetMethod() string {
-	return r.method
-}
-
-// GetDomain returns the registed domain which this route is ( if none, is "" which is means "localhost"/127.0.0.1)
-func (r Route) GetDomain() string {
-	return r.domain
-}
-
-// GetPath returns the full registed path
-func (r Route) GetPath() string {
-	return r.fullpath
-}
-
-// GetName returns the name of the route
-func (r Route) GetName() string {
-	return r.name
-}
-
-// Name sets the route's name
-func (r *Route) Name(newName string) IRoute {
-	r.name = newName
-	return r
-}
-
-// GetMiddleware returns the chain of the []HandlerFunc registed to this Route
-func (r Route) GetMiddleware() Middleware {
-	return r.middleware
-}
-
-// HasCors check if middleware passsed to a route has cors
-func (r *Route) HasCors() bool {
-	return RouteConflicts(r, "httpmethod")
-}
-
-// ParsePath used to check arguments with the route's named parameters and return the correct url
-// if parse failed returns empty string
-func (r *Route) ParsePath(args ...interface{}) string {
-	argsLen := len(args)
-
-	// we have named parameters but arguments not given
-	if argsLen == 0 && r.formattedParts > 0 {
-		return ""
-	}
-
-	// we have arguments but they are much more than the named parameters
-
-	// 1 check if we have /*, if yes then join all arguments to one as path and pass that as parameter
-	if argsLen > r.formattedParts {
-		if r.fullpath[len(r.fullpath)-1] == MatchEverythingByte {
-			// we have to convert each argument to a string in this case
-
-			argsString := make([]string, argsLen, argsLen)
-
-			for i, v := range args {
-				if s, ok := v.(string); ok {
-					argsString[i] = s
-				} else if num, ok := v.(int); ok {
-					argsString[i] = strconv.Itoa(num)
-				} else if b, ok := v.(bool); ok {
-					argsString[i] = strconv.FormatBool(b)
-				} else if arr, ok := v.([]string); ok {
-					if len(arr) > 0 {
-						argsString[i] = arr[0]
-						argsString = append(argsString, arr[1:]...)
-					}
-				}
-			}
-
-			parameter := strings.Join(argsString, Slash)
-			result := fmt.Sprintf(r.formattedPath, parameter)
-			return result
-		}
-		// 2 if !1 return false
-		return ""
-	}
-
-	arguments := args[0:]
-
-	// check for arrays
-	for i, v := range arguments {
-		if arr, ok := v.([]string); ok {
-			if len(arr) > 0 {
-				interfaceArr := make([]interface{}, len(arr))
-				for j, sv := range arr {
-					interfaceArr[j] = sv
-				}
-				arguments[i] = interfaceArr[0]
-				arguments = append(arguments, interfaceArr[1:]...)
-			}
-
-		}
-	}
-
-	return fmt.Sprintf(r.formattedPath, arguments...)
-}
-
-// ParseURI returns the subdomain+ host + ParsePath(...optional named parameters if route is dynamic)
-// returns an empty string if parse is failed
-func (r *Route) ParseURI(args ...interface{}) (uri string) {
-	scheme := "http://"
-	if r.station.server.IsSecure() {
-		scheme = "https://"
-	}
-
-	host := r.station.server.VirtualHost()
-	arguments := args[0:]
-
-	// join arrays as arguments
-	for i, v := range arguments {
-		if arr, ok := v.([]string); ok {
-			if len(arr) > 0 {
-				interfaceArr := make([]interface{}, len(arr))
-				for j, sv := range arr {
-					interfaceArr[j] = sv
-				}
-				arguments[i] = interfaceArr[0]
-				arguments = append(arguments, interfaceArr[1:]...)
-			}
-
-		}
-	}
-
-	// if it's dynamic subdomain then the first argument is the subdomain part
-	if r.isWildcard() {
-		if len(arguments) == 0 { // it's a wildcard subdomain but not arguments
-			return
-		}
-
-		if subdomain, ok := arguments[0].(string); ok {
-			host = subdomain + "." + host
-		} else {
-			// it is not array because we join them before. if not pass a string then this is not a subdomain part, return empty uri
-			return
-		}
-
-		arguments = arguments[1:]
-	}
-
-	if parsedPath := r.ParsePath(arguments...); parsedPath != "" {
-		uri = scheme + host + parsedPath
-	}
-
-	return
-
-}
-
-// RouteConflicts checks for route's middleware conflicts
-func RouteConflicts(r *Route, with string) bool {
-	for _, h := range r.middleware {
-		if m, ok := h.(interface {
-			Conflicts() string
-		}); ok {
-			if c := m.Conflicts(); c == with {
-				return true
-			}
-		}
-	}
-	return false
-}
diff --git a/router.go b/router.go
deleted file mode 100644
index bd3ed3bd..00000000
--- a/router.go
+++ /dev/null
@@ -1,308 +0,0 @@
-package iris
-
-import (
-	"net/http/pprof"
-	"strings"
-	"sync"
-
-	"github.com/kataras/iris/utils"
-	"github.com/valyala/fasthttp"
-)
-
-const (
-
-	// ParameterStartByte is very used on the node, it's just contains the byte for the ':' rune/char
-	ParameterStartByte = byte(':')
-	// SlashByte is just a byte of '/' rune/char
-	SlashByte = byte('/')
-	// Slash is just a string of "/"
-	Slash = "/"
-	// MatchEverythingByte is just a byte of '*" rune/char
-	MatchEverythingByte = byte('*')
-	// PrefixDynamicSubdomain is the prefix which dynamic subdomains are registed to, as virtual. Used internaly by Iris but good to know.
-	PrefixDynamicSubdomain = "www.iris_subd0mAin.iris"
-
-	// HTTP Methods(1)
-
-	// MethodGet "GET"
-	MethodGet = "GET"
-	// MethodPost "POST"
-	MethodPost = "POST"
-	// MethodPut "PUT"
-	MethodPut = "PUT"
-	// MethodDelete "DELETE"
-	MethodDelete = "DELETE"
-	// MethodConnect "CONNECT"
-	MethodConnect = "CONNECT"
-	// MethodHead "HEAD"
-	MethodHead = "HEAD"
-	// MethodPatch "PATCH"
-	MethodPatch = "PATCH"
-	// MethodOptions "OPTIONS"
-	MethodOptions = "OPTIONS"
-	// MethodTrace "TRACE"
-	MethodTrace = "TRACE"
-)
-
-var (
-
-	// HTTP Methods(2)
-
-	// MethodConnectBytes []byte("CONNECT")
-	MethodConnectBytes = []byte(MethodConnect)
-	// AllMethods "GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD", "PATCH", "OPTIONS", "TRACE"
-	AllMethods = [...]string{"GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD", "PATCH", "OPTIONS", "TRACE"}
-)
-
-// router internal is the route serving service, one router per server
-type router struct {
-	*GardenParty
-	*HTTPErrorContainer
-	station        *Iris
-	garden         *Garden
-	methodMatch    func(m1, m2 string) bool
-	getRequestPath func(*fasthttp.RequestCtx) []byte
-	// routes useful information, this info can be used to make custom links inside templates
-	// the route's information (can be) changed after its registration
-	lookups      []IRoute
-	ServeRequest func(reqCtx *fasthttp.RequestCtx)
-	// errorPool is responsible to  get the Context to handle not found errors
-	errorPool sync.Pool
-	//it's true when optimize already ran
-	optimized bool
-	mu        sync.Mutex
-}
-
-// methodMatchCorsFunc is sets the methodMatch when cors enabled (look router.optimize), it's allowing OPTIONS method to all other methods except GET
-func methodMatchCorsFunc(m1, reqMethod string) bool {
-	return m1 == reqMethod || reqMethod == MethodOptions //(m1 != MethodGet && reqMethod == MethodOptions)
-}
-
-// methodMatchFunc for normal method match
-func methodMatchFunc(m1, m2 string) bool {
-	return m1 == m2
-}
-
-func getRequestPathDefault(reqCtx *fasthttp.RequestCtx) []byte {
-	// default to escape then
-	return reqCtx.Path()
-}
-
-// newRouter creates and returns an empty router
-func newRouter(station *Iris) *router {
-	r := &router{
-		station:            station,
-		garden:             &Garden{},
-		methodMatch:        methodMatchFunc,
-		getRequestPath:     getRequestPathDefault,
-		lookups:            make([]IRoute, 0),
-		HTTPErrorContainer: defaultHTTPErrors(),
-		GardenParty:        &GardenParty{relativePath: "/", station: station, root: true},
-		errorPool:          station.newContextPool()}
-
-	r.ServeRequest = r.serveFunc
-
-	return r
-
-}
-
-// addRoute is a middleware between router and garden
-// it just calls the garden's Plant method
-// is 'thread-safe'
-func (r *router) addRoute(route IRoute) {
-	r.mu.Lock()
-	defer r.mu.Unlock()
-	r.lookups = append(r.lookups, route)
-	r.garden.Plant(r.station, route)
-}
-
-// RouteByName returns a route by its name,if not found then returns a route with empty path
-// Note that the searching is case-sensitive
-func (r *router) RouteByName(routeName string) IRoute {
-	for _, route := range r.lookups {
-		if route.GetName() == routeName {
-			return route
-		}
-	}
-	return &Route{}
-}
-
-// UriOf returns the parsed URI of a route
-// receives two parameters
-// the first is the route's name (string)
-// the second is a variadic, if the route is dynamic (receives named parameters) then pass the value of these parameters here
-// overview of the result is: scheme(http or https if ListenTLS)/yourhost.com:PORT/profile/theusername/friends/theid
-//
-// example /profile/:username/friends/:friendId with name "profile" -> .UriOf("profile","kataras",8) will give http://127.0.0.1:8080/profile/kataras/friends/8
-func (r *router) UriOf(routeName string, args ...interface{}) (string, error) {
-	route := r.RouteByName(routeName)
-	// check if not found
-	if route.GetMethod() == "" {
-		return "", ErrRenderRouteNotFound.Format(routeName)
-	}
-
-	return route.ParseURI(args...), nil
-}
-
-//check if any tree has cors setted to true, means that cors middleware is added
-func (r *router) cors() (has bool) {
-	r.garden.visitAll(func(i int, tree *tree) {
-		if tree.cors {
-			has = true
-		}
-	})
-	return
-}
-
-// check if any tree has subdomains
-func (r *router) hosts() (has bool) {
-	r.garden.visitAll(func(i int, tree *tree) {
-		if tree.hosts {
-			has = true
-		}
-	})
-	return
-}
-
-// optimize runs once before listen, it checks if cors or hosts enabled and make the necessary changes to the Router itself
-func (r *router) optimize() {
-	if r.optimized {
-		return
-	}
-
-	if r.cors() {
-		r.methodMatch = methodMatchCorsFunc
-	}
-
-	// For performance only,in order to not check at runtime for hosts and subdomains, I think it's better to do this:
-	if r.hosts() {
-		r.ServeRequest = r.serveDomainFunc
-	}
-
-	//if PathEscape disabled, then take the raw URI
-	if r.station.config.DisablePathEscape {
-		r.getRequestPath = func(reqCtx *fasthttp.RequestCtx) []byte {
-			// RequestURI fixes the https://github.com/kataras/iris/issues/135
-			return reqCtx.RequestURI()
-		}
-	}
-
-	// set the debug profiling handlers if Profile enabled, before the server startup, not earlier
-	if r.station.config.Profile && r.station.config.ProfilePath != "" {
-		debugPath := r.station.config.ProfilePath
-
-		htmlMiddleware := func(ctx *Context) {
-			ctx.SetContentType(ContentHTML + r.station.rest.CompiledCharset)
-			ctx.Next()
-		}
-
-		indexHandler := ToHandlerFunc(pprof.Index)
-		cmdlineHandler := ToHandlerFunc(pprof.Cmdline)
-		profileHandler := ToHandlerFunc(pprof.Profile)
-		symbolHandler := ToHandlerFunc(pprof.Symbol)
-
-		goroutineHandler := ToHandlerFunc(pprof.Handler("goroutine"))
-		heapHandler := ToHandlerFunc(pprof.Handler("heap"))
-		threadcreateHandler := ToHandlerFunc(pprof.Handler("threadcreate"))
-		debugBlockHandler := ToHandlerFunc(pprof.Handler("block"))
-
-		r.Get(debugPath+"/*action", htmlMiddleware, func(ctx *Context) {
-			action := ctx.Param("action")
-			if len(action) > 1 {
-				if strings.Contains(action, "cmdline") {
-					cmdlineHandler.Serve((ctx))
-				} else if strings.Contains(action, "profile") {
-					profileHandler.Serve(ctx)
-				} else if strings.Contains(action, "symbol") {
-					symbolHandler.Serve(ctx)
-				} else if strings.Contains(action, "goroutine") {
-					goroutineHandler.Serve(ctx)
-				} else if strings.Contains(action, "heap") {
-					heapHandler.Serve(ctx)
-				} else if strings.Contains(action, "threadcreate") {
-					threadcreateHandler.Serve(ctx)
-				} else if strings.Contains(action, "debug/block") {
-					debugBlockHandler.Serve(ctx)
-				}
-			} else {
-				indexHandler.Serve(ctx)
-			}
-
-		})
-
-	}
-
-	r.optimized = true
-}
-
-// notFound internal method, it justs takes the context from pool ( in order to have the custom errors available) and procedure a Not Found 404 error
-// this is being called when no route was found used on the ServeRequest.
-func (r *router) notFound(reqCtx *fasthttp.RequestCtx) {
-	ctx := r.errorPool.Get().(*Context)
-	ctx.Reset(reqCtx)
-	ctx.NotFound()
-	r.errorPool.Put(ctx)
-}
-
-//************************************************************************************
-// serveFunc & serveDomainFunc selected on router.optimize, which runs before station's listen
-// they are not used directly.
-//************************************************************************************
-
-// serve finds and serves a route by it's request context
-// If no route found, it sends an http status 404
-func (r *router) serveFunc(reqCtx *fasthttp.RequestCtx) {
-	method := utils.BytesToString(reqCtx.Method())
-	tree := r.garden.first
-	path := utils.BytesToString(r.getRequestPath(reqCtx))
-	for tree != nil {
-		if r.methodMatch(tree.method, method) {
-			if !tree.serve(reqCtx, path) {
-				r.notFound(reqCtx)
-			}
-			return
-		}
-		tree = tree.next
-	}
-	//not found, get the first's pool and use that  to send a custom http error(if setted)
-
-	r.notFound(reqCtx)
-
-}
-
-// serveDomainFunc finds and serves a domain tree's route by it's request context
-// If no route found, it sends an http status 404
-func (r *router) serveDomainFunc(reqCtx *fasthttp.RequestCtx) {
-	method := utils.BytesToString(reqCtx.Method())
-	host := utils.BytesToString(reqCtx.Host())
-	fulldomain := ""
-	if strings.Count(host, ".") >= 2 && host != r.station.server.Host() {
-		if portIdx := strings.Index(host, ":"); portIdx != -1 {
-			fulldomain = host[0:portIdx]
-		} else {
-			fulldomain = host
-		}
-	}
-
-	path := utils.BytesToString(r.getRequestPath(reqCtx))
-	tree := r.garden.first
-	for tree != nil {
-		if tree.hosts && tree.domain != "" && fulldomain != "" {
-			if tree.domain == fulldomain { // it's a static subdomain
-				path = fulldomain + path
-			} else if strings.Index(tree.domain, PrefixDynamicSubdomain) != -1 { // it's a dynamic virtual subdomain
-				path = PrefixDynamicSubdomain + path
-			}
-		}
-
-		if r.methodMatch(tree.method, method) {
-			if tree.serve(reqCtx, path) {
-				return
-			}
-		}
-		tree = tree.next
-	}
-
-	//not found, get the first's pool and use that  to send a custom http error(if setted)
-	r.notFound(reqCtx)
-}
diff --git a/server/README.md b/server/README.md
deleted file mode 100644
index b3c57301..00000000
--- a/server/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-## Package information
-
-I decide to split the whole server from the main iris package because these files don't depends on any of the iris' types.
-
-
-**That's it.**
diff --git a/server/errors.go b/server/errors.go
deleted file mode 100644
index 31333fa6..00000000
--- a/server/errors.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package server
-
-import "github.com/kataras/iris/errors"
-
-var (
-	// ErrServerPortAlreadyUsed returns an error with message: 'Server can't run, port is already used'
-	ErrServerPortAlreadyUsed = errors.New("Server can't run, port is already used")
-	// ErrServerAlreadyStarted returns an error with message: 'Server is already started and listening'
-	ErrServerAlreadyStarted = errors.New("Server is already started and listening")
-	// ErrServerOptionsMissing returns an error with message: 'You have to pass iris.ServerOptions'
-	ErrServerOptionsMissing = errors.New("You have to pass iris.ServerOptions")
-	// ErrServerTLSOptionsMissing returns an error with message: 'You have to set CertFile and KeyFile to iris.ServerOptions before ListenTLS'
-	ErrServerTLSOptionsMissing = errors.New("You have to set CertFile and KeyFile to iris.ServerOptions before ListenTLS")
-	// ErrServerIsClosed returns an error with message: 'Can't close the server, propably is already closed or never started'
-	ErrServerIsClosed = errors.New("Can't close the server, propably is already closed or never started")
-	// ErrServerUnknown returns an error with message: 'Unknown reason from Server, please report this as bug!'
-	ErrServerUnknown = errors.New("Unknown reason from Server, please report this as bug!")
-	// ErrParsedAddr returns an error with message: 'ListeningAddr error, for TCP and UDP, the syntax of ListeningAddr is host:port, like 127.0.0.1:8080.
-	// If host is omitted, as in :8080, Listen listens on all available interfaces instead of just the interface with the given host address.
-	// See Dial for more details about address syntax'
-	ErrParsedAddr = errors.New("ListeningAddr error, for TCP and UDP, the syntax of ListeningAddr is host:port, like 127.0.0.1:8080. If host is omitted, as in :8080, Listen listens on all available interfaces instead of just the interface with the given host address. See Dial for more details about address syntax")
-	// ErrServerRemoveUnix returns an error with message: 'Unexpected error when trying to remove unix socket file +filename: +specific error"'
-	ErrServerRemoveUnix = errors.New("Unexpected error when trying to remove unix socket file. Addr: %s | Trace: %s")
-	// ErrServerChmod returns an error with message: 'Cannot chmod +mode for +host:+specific error
-	ErrServerChmod = errors.New("Cannot chmod %#o for %q: %s")
-)
diff --git a/server/server.go b/server/server.go
deleted file mode 100644
index 6a1966be..00000000
--- a/server/server.go
+++ /dev/null
@@ -1,248 +0,0 @@
-package server
-
-import (
-	"net"
-	"os"
-	"strings"
-
-	"github.com/kataras/iris/config"
-	"github.com/valyala/fasthttp"
-)
-
-// Server is the IServer's implementation, holds the fasthttp's Server, a net.Listener, the ServerOptions, and the handler
-// handler is registed at the Station/Iris level
-type Server struct {
-	*fasthttp.Server
-	listener net.Listener
-	Config   config.Server
-	started  bool
-	tls      bool
-	handler  fasthttp.RequestHandler
-}
-
-// New returns a pointer to a Server object, and set it's options if any,  nothing more
-func New(cfg ...config.Server) *Server {
-	c := config.DefaultServer().Merge(cfg)
-	s := &Server{Server: &fasthttp.Server{Name: config.ServerName}, Config: c}
-
-	s.Config.ListeningAddr = parseAddr(s.Config.ListeningAddr)
-
-	return s
-}
-
-// SetHandler sets the handler in order to listen on new requests, this is done at the Station/Iris level
-func (s *Server) SetHandler(h fasthttp.RequestHandler) {
-	s.handler = h
-	if s.Server != nil {
-		s.Server.Handler = s.handler
-	}
-}
-
-// Handler returns the fasthttp.RequestHandler which is registed to the Server
-func (s *Server) Handler() fasthttp.RequestHandler {
-	return s.handler
-}
-
-// IsListening returns true if server is listening/started, otherwise false
-func (s *Server) IsListening() bool {
-	return s.started
-}
-
-// IsSecure returns true if server uses TLS, otherwise false
-func (s *Server) IsSecure() bool {
-	return s.tls
-}
-
-// Listener returns the net.Listener which this server (is) listening to
-func (s *Server) Listener() net.Listener {
-	return s.listener
-}
-
-// Host returns the Listener().Addr().String(), if server is not listening it returns the config.ListeningAddr
-func (s *Server) Host() (host string) {
-	if s.IsListening() {
-		return s.Listener().Addr().String()
-	} else {
-		return s.Config.ListeningAddr
-	}
-}
-
-// VirtualHost returns the s.Config.ListeningAddr, if host provided else returns the Listener's (Host())
-//
-// Note: currently this is used only on iris/route.ParseURI.
-//
-func (s *Server) VirtualHost() (host string) {
-	// we always have at least the :PORT because  of parseAddr, so we just
-	// check if we have anything before PORT
-	a := s.Config.ListeningAddr
-	if len(a[0:strings.IndexByte(a, ':')]) > 0 {
-		return a
-	} else {
-		return s.Host()
-	}
-}
-
-// Hostname returns the hostname part only, if host == 0.0.0.0:8080 it will return the 0.0.0.0
-// if server is not listening it returns the config.ListeningAddr's hostname part
-func (s *Server) Hostname() (hostname string) {
-	if s.IsListening() {
-		fullhost := s.Listener().Addr().String()
-		hostname = fullhost[0:strings.IndexByte(fullhost, ':')] // no the port
-	} else {
-		fullhost := s.Config.ListeningAddr
-		if idx := strings.IndexByte(fullhost, ':'); idx > 1 { // at least after second char
-			hostname = hostname[0:idx]
-		} else {
-			hostname = "0.0.0.0"
-		}
-
-	}
-	return
-}
-
-//Serve just serves a listener, it is a blocking action, plugin.PostListen is not fired here.
-func (s *Server) Serve(l net.Listener) error {
-	s.listener = l
-	return s.Server.Serve(l)
-}
-
-// listen starts the process of listening to the new requests
-func (s *Server) listen() (err error) {
-
-	if s.started {
-		err = ErrServerAlreadyStarted.Return()
-		return
-	}
-	s.listener, err = net.Listen("tcp4", s.Config.ListeningAddr)
-
-	if err != nil {
-		err = ErrServerPortAlreadyUsed.Return()
-		return
-	}
-
-	//Non-block way here because I want the plugin's PostListen ability...
-	go s.Server.Serve(s.listener)
-
-	s.started = true
-	s.tls = false
-
-	return
-}
-
-// listenTLS starts the process of listening to the new requests using TLS, keyfile and certfile are given before this method fires
-func (s *Server) listenTLS() (err error) {
-
-	if s.started {
-		err = ErrServerAlreadyStarted.Return()
-		return
-	}
-
-	if s.Config.CertFile == "" || s.Config.KeyFile == "" {
-		err = ErrServerTLSOptionsMissing.Return()
-		return
-	}
-
-	s.listener, err = net.Listen("tcp4", s.Config.ListeningAddr)
-
-	if err != nil {
-		err = ErrServerPortAlreadyUsed.Return()
-		return
-	}
-
-	go s.Server.ServeTLS(s.listener, s.Config.CertFile, s.Config.KeyFile)
-
-	s.started = true
-	s.tls = true
-
-	return
-}
-
-// listenUnix  starts the process of listening to the new requests using a 'socket file', this works only on unix
-func (s *Server) listenUnix() (err error) {
-
-	if s.started {
-		err = ErrServerAlreadyStarted.Return()
-		return
-	}
-
-	mode := s.Config.Mode
-
-	//this code is from fasthttp ListenAndServeUNIX, I extracted it because we need the tcp.Listener
-	if errOs := os.Remove(s.Config.ListeningAddr); errOs != nil && !os.IsNotExist(errOs) {
-		err = ErrServerRemoveUnix.Format(s.Config.ListeningAddr, errOs.Error())
-		return
-	}
-	//
-	s.listener, err = net.Listen("unix", s.Config.ListeningAddr)
-
-	if err != nil {
-		err = ErrServerPortAlreadyUsed.Return()
-		return
-	}
-
-	if err = os.Chmod(s.Config.ListeningAddr, mode); err != nil {
-		err = ErrServerChmod.Format(mode, s.Config.ListeningAddr, err.Error())
-		return
-	}
-
-	s.Server.Handler = s.handler
-	go s.Server.Serve(s.listener)
-
-	s.started = true
-	s.tls = false
-
-	return
-
-}
-
-// OpenServer opens/starts/runs/listens (to) the server, listenTLS if Cert && Key is registed, listenUnix if Mode is registed, otherwise listen
-// instead of return an error this is panics on any server's error
-func (s *Server) OpenServer() (err error) {
-	if s.Config.CertFile != "" && s.Config.KeyFile != "" {
-		err = s.listenTLS()
-	} else if s.Config.Mode > 0 {
-		err = s.listenUnix()
-	} else {
-		err = s.listen()
-	}
-
-	return
-}
-
-// CloseServer closes the server
-func (s *Server) CloseServer() error {
-
-	if !s.started {
-		return ErrServerIsClosed.Return()
-	}
-
-	if s.listener != nil {
-		s.started = false
-		return s.listener.Close()
-	}
-	return nil
-}
-
-// parseAddr gets a slice of string and returns the address of which the Iris' server can listen
-func parseAddr(fullHostOrPort ...string) string {
-
-	if len(fullHostOrPort) > 1 {
-		fullHostOrPort = fullHostOrPort[0:1]
-	}
-	addr := config.DefaultServerAddr // default address
-	// if nothing passed, then use environment's port (if any) or just :8080
-	if len(fullHostOrPort) == 0 {
-		if envPort := os.Getenv("PORT"); len(envPort) > 0 {
-			addr = ":" + envPort
-		}
-
-	} else if len(fullHostOrPort) == 1 {
-		addr = fullHostOrPort[0]
-		if strings.IndexRune(addr, ':') == -1 {
-			//: doesn't found on the given address, so maybe it's only a port
-			addr = ":" + addr
-		}
-	}
-
-	return addr
-}
diff --git a/sessions/providers/memory/register.go b/sessions/providers/memory/register.go
index ba61e718..cc2c998c 100644
--- a/sessions/providers/memory/register.go
+++ b/sessions/providers/memory/register.go
@@ -21,7 +21,6 @@ var (
 func register() {
 	// the actual work is here.
 	Provider.NewStore = func(sessionId string, cookieLifeDuration time.Duration) store.IStore {
-		//println("memory.go:49-> requesting new memory store with sessionid: " + sessionId)
 		return &Store{sid: sessionId, lastAccessedTime: time.Now(), values: make(map[interface{}]interface{}, 0)}
 	}
 	sessions.Register(Provider)
diff --git a/sessions/sessions.go b/sessions/sessions.go
index bd8a8142..ba347949 100644
--- a/sessions/sessions.go
+++ b/sessions/sessions.go
@@ -4,7 +4,12 @@ import "github.com/kataras/iris/config"
 
 // New creates & returns a new Manager and start its GC
 func New(cfg ...config.Sessions) *Manager {
-	manager, err := newManager(config.DefaultSessions().Merge(cfg))
+	c := config.DefaultSessions().Merge(cfg)
+	// If provider is empty then return nil manager, means that the sessions are disabled
+	if c.Provider == "" {
+		return nil
+	}
+	manager, err := newManager(c)
 	if err != nil {
 		panic(err.Error()) // we have to panic here because we will start GC after and if provider is nil then many panics will come
 	}
diff --git a/tests/httperror_test.go b/tests/httperror_test.go
index 2808ab45..b9a82daa 100644
--- a/tests/httperror_test.go
+++ b/tests/httperror_test.go
@@ -6,7 +6,6 @@ import (
 	"github.com/gavv/httpexpect"
 	"github.com/gavv/httpexpect/fasthttpexpect"
 	"github.com/kataras/iris"
-	"github.com/kataras/iris/config"
 )
 
 var notFoundMessage = "Iris custom message for 404 not found"
@@ -46,15 +45,7 @@ func TestCustomErrors(t *testing.T) {
 		}
 	}
 
-	api.PreListen(config.Server{ListeningAddr: ""})
-
-	// create httpexpect instance that will call fasthtpp.RequestHandler directly
-	e := httpexpect.WithConfig(httpexpect.Config{
-		Reporter: httpexpect.NewAssertReporter(t),
-		Client:   fasthttpexpect.NewBinder(api.ServeRequest),
-	})
-	// first register the custom errors
-
+	// register the custom errors
 	api.OnError(404, func(ctx *iris.Context) {
 		ctx.Write("%s", notFoundMessage)
 	})
@@ -63,6 +54,12 @@ func TestCustomErrors(t *testing.T) {
 		ctx.Write("%s", internalServerMessage)
 	})
 
+	// create httpexpect instance that will call fasthtpp.RequestHandler directly
+	e := httpexpect.WithConfig(httpexpect.Config{
+		Reporter: httpexpect.NewAssertReporter(t),
+		Client:   fasthttpexpect.NewBinder(api.NoListen().Handler),
+	})
+
 	// run the tests
 	for _, r := range routesCustomErrors {
 		e.Request(r.Method, r.RequestPath).
diff --git a/tests/party_test.go b/tests/party_test.go
new file mode 100644
index 00000000..b5a582e8
--- /dev/null
+++ b/tests/party_test.go
@@ -0,0 +1,53 @@
+package tests
+
+import (
+	"testing"
+
+	"github.com/gavv/httpexpect"
+	"github.com/gavv/httpexpect/fasthttpexpect"
+	"github.com/kataras/iris"
+)
+
+func TestSimpleParty(t *testing.T) {
+	h := func(c *iris.Context) { c.WriteString(c.HostString() + c.PathString()) }
+
+	/*
+		// subdomain first, but this test will fail on your machine, so I just commend it, you can imagine what will be
+		party2 := iris.Party("kataras.")
+		{
+			party2.Get("/", h)
+			party2.Get("/path1", h)
+			party2.Get("/path2", h)
+			party2.Get("/namedpath/:param1/something/:param2", h)
+			party2.Get("/namedpath/:param1/something/:param2/else", h)
+		}*/
+
+	// simple
+	party1 := iris.Party("/party1")
+	{
+		party1.Get("/", h)
+		party1.Get("/path1", h)
+		party1.Get("/path2", h)
+		party1.Get("/namedpath/:param1/something/:param2", h)
+		party1.Get("/namedpath/:param1/something/:param2/else", h)
+	}
+
+	// create httpexpect instance that will call fasthtpp.RequestHandler directly
+	e := httpexpect.WithConfig(httpexpect.Config{
+		Reporter: httpexpect.NewAssertReporter(t),
+		Client:   fasthttpexpect.NewBinder(iris.NoListen().Handler),
+	})
+
+	request := func(reqPath string) {
+		e.Request("GET", reqPath).
+			Expect().
+			Status(iris.StatusOK).Body().Equal(reqPath)
+	}
+
+	// run the tests
+	request("/party1/")
+	request("/party1/path1")
+	request("/party1/path2")
+	request("/party1/namedpath/theparam1/something/theparam2")
+	request("/party1/namedpath/theparam1/something/theparam2/else")
+}
diff --git a/tests/router_test.go b/tests/route_test.go
similarity index 94%
rename from tests/router_test.go
rename to tests/route_test.go
index 04e6e9fa..02a2ebfe 100644
--- a/tests/router_test.go
+++ b/tests/route_test.go
@@ -7,7 +7,6 @@ import (
 	"github.com/gavv/httpexpect"
 	"github.com/gavv/httpexpect/fasthttpexpect"
 	"github.com/kataras/iris"
-	"github.com/kataras/iris/config"
 )
 
 type param struct {
@@ -59,7 +58,6 @@ var routes = []route{
 
 func TestRouter(t *testing.T) {
 	api := iris.New()
-
 	for idx := range routes {
 		r := routes[idx]
 		if r.Register {
@@ -88,11 +86,10 @@ func TestRouter(t *testing.T) {
 		}
 	}
 
-	api.PreListen(config.Server{ListeningAddr: ""})
 	// create httpexpect instance that will call fasthtpp.RequestHandler directly
 	e := httpexpect.WithConfig(httpexpect.Config{
 		Reporter: httpexpect.NewAssertReporter(t),
-		Client:   fasthttpexpect.NewBinder(api.ServeRequest),
+		Client:   fasthttpexpect.NewBinder(api.NoListen().Handler),
 	})
 
 	// run the tests (1)
@@ -107,15 +104,14 @@ func TestRouter(t *testing.T) {
 
 func TestPathEscape(t *testing.T) {
 	api := iris.New()
+
 	api.Get("/details/:name", func(ctx *iris.Context) {
 		name := ctx.Param("name")
 		highlight := ctx.URLParam("highlight")
 		ctx.Text(iris.StatusOK, fmt.Sprintf("name=%s,highlight=%s", name, highlight))
 	})
 
-	api.PreListen(config.Server{ListeningAddr: ""})
-	api.PostListen()
-	e := httpexpect.WithConfig(httpexpect.Config{Reporter: httpexpect.NewAssertReporter(t), Client: fasthttpexpect.NewBinder(api.ServeRequest)})
+	e := httpexpect.WithConfig(httpexpect.Config{Reporter: httpexpect.NewAssertReporter(t), Client: fasthttpexpect.NewBinder(api.NoListen().Handler)})
 
 	e.Request("GET", "/details/Sakamoto desu ga?highlight=text").Expect().Status(iris.StatusOK).Body().Equal("name=Sakamoto desu ga,highlight=text")
 }
diff --git a/tree.go b/tree.go
deleted file mode 100644
index 7e162892..00000000
--- a/tree.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package iris
-
-import (
-	"bytes"
-	"sync"
-
-	"github.com/kataras/iris/utils"
-	"github.com/valyala/fasthttp"
-)
-
-type (
-	tree struct {
-		station    *Iris
-		method     string
-		rootBranch *Branch
-		domain     string
-		hosts      bool //if domain != "" we set it directly on .Plant
-		cors       bool // if cross domain allow enabled
-		pool       sync.Pool
-		next       *tree
-	}
-
-	// Garden is the main area which routes are planted/placed
-	Garden struct {
-		first *tree
-	}
-)
-
-// garden
-
-func (g *Garden) visitAll(f func(i int, tr *tree)) {
-	t := g.first
-	i := 0
-	for t != nil {
-
-		f(i, t)
-		t = t.next
-	}
-}
-
-// visitAllBreak like visitAll but if true to the function then it breaks
-func (g *Garden) visitAllBreak(f func(i int, tr *tree) bool) {
-	t := g.first
-	i := 0
-	for t != nil {
-
-		if f(i, t) {
-			break
-		}
-		t = t.next
-	}
-}
-
-func (g *Garden) last() (t *tree) {
-
-	t = g.first
-	for t.next != nil {
-		t = t.next
-	}
-	return
-}
-
-// getRootByMethodAndDomain returns the correct branch which it's method&domain is equal to the given method&domain, from a garden's tree
-// trees with  no domain means that their domain==""
-func (g *Garden) getRootByMethodAndDomain(method string, domain string) (b *Branch) {
-	g.visitAll(func(i int, t *tree) {
-		if t.domain == domain && t.method == method {
-			b = t.rootBranch
-		}
-	})
-
-	return
-}
-
-// Plant plants/adds a route to the garden
-func (g *Garden) Plant(station *Iris, _route IRoute) {
-	method := _route.GetMethod()
-	domain := _route.GetDomain()
-	path := _route.GetPath()
-	theRoot := g.getRootByMethodAndDomain(method, domain)
-	if theRoot == nil {
-		theRoot = new(Branch)
-		theNewTree := newTree(station, method, theRoot, domain, len(domain) > 0, _route.HasCors())
-		if g.first == nil {
-			g.first = theNewTree
-		} else {
-			g.last().next = theNewTree
-		}
-
-	}
-	theRoot.AddBranch(domain+path, _route.GetMiddleware())
-}
-
-// tree
-
-func newTree(station *Iris, method string, theRoot *Branch, domain string, hosts bool, hasCors bool) *tree {
-	t := &tree{station: station, method: method, rootBranch: theRoot, domain: domain, hosts: hosts, cors: hasCors, pool: station.newContextPool()}
-	return t
-}
-
-// serve serves the route
-func (_tree *tree) serve(reqCtx *fasthttp.RequestCtx, path string) bool {
-	ctx := _tree.pool.Get().(*Context)
-	ctx.Reset(reqCtx)
-	middleware, params, mustRedirect := _tree.rootBranch.GetBranch(path, ctx.Params) // pass the parameters here for 0 allocation
-	if middleware != nil {
-		ctx.Params = params
-		ctx.middleware = middleware
-		//ctx.Request.Header.SetUserAgentBytes(DefaultUserAgent)
-		ctx.Do()
-		_tree.pool.Put(ctx)
-		return true
-	} else if mustRedirect && !_tree.station.config.DisablePathCorrection && !bytes.Equal(reqCtx.Method(), MethodConnectBytes) {
-
-		reqPath := path
-		pathLen := len(reqPath)
-
-		if pathLen > 1 {
-
-			if reqPath[pathLen-1] == '/' {
-				reqPath = reqPath[:pathLen-1] //remove the last /
-			} else {
-				//it has path prefix, it doesn't ends with / and it hasn't be found, then just add the slash
-				reqPath = reqPath + "/"
-			}
-
-			ctx.Request.URI().SetPath(reqPath)
-			urlToRedirect := utils.BytesToString(ctx.Request.RequestURI())
-
-			ctx.Redirect(urlToRedirect, 301) //	StatusMovedPermanently
-			// RFC2616 recommends that a short note "SHOULD" be included in the
-			// response because older user agents may not understand 301/307.
-			// Shouldn't send the response for POST or HEAD; that leaves GET.
-			if _tree.method == MethodGet {
-				note := "<a href=\"" + utils.HTMLEscape(urlToRedirect) + "\">Moved Permanently</a>.\n"
-				ctx.Write(note)
-			}
-			_tree.pool.Put(ctx)
-			return true
-		}
-	}
-
-	_tree.pool.Put(ctx)
-	return false
-}
diff --git a/utils/README.md b/utils/README.md
index e82e25aa..99e37f94 100644
--- a/utils/README.md
+++ b/utils/README.md
@@ -1,6 +1,6 @@
 ## Package information
 
-This package contains helpful functions that iris uses, you can use them to your project also!
+This package contains helpful functions that iris, internally, uses
 
 
 **That's it.**
diff --git a/websocket/server.go b/websocket/server.go
index 8c3bed60..274312d0 100644
--- a/websocket/server.go
+++ b/websocket/server.go
@@ -20,6 +20,8 @@ type (
 		Upgrade(context.IContext) error
 		// OnConnection registers a callback which fires when a connection/client is connected to the server
 		OnConnection(ConnectionFunc)
+		// Config returns a pointer to server's configs
+		Config() *config.Websocket
 	}
 
 	// roomPayload is used as payload from the connection to the server
@@ -57,9 +59,10 @@ var _ Server = &server{}
 
 // server implementation
 
-func newServer(c config.Websocket) *server {
+// newServer creates a websocket server and returns it
+func newServer(c *config.Websocket) *server {
 	s := &server{
-		config:                &c,
+		config:                c,
 		put:                   make(chan *connection),
 		free:                  make(chan *connection),
 		connections:           make(map[string]*connection),
@@ -72,10 +75,13 @@ func newServer(c config.Websocket) *server {
 
 	s.upgrader = websocket.New(s.handleConnection)
 	go s.serve() // start the server automatically
-
 	return s
 }
 
+func (s *server) Config() *config.Websocket {
+	return s.config
+}
+
 func (s *server) Upgrade(ctx context.IContext) error {
 	return s.upgrader.Upgrade(ctx)
 }
diff --git a/websocket/websocket.go b/websocket/websocket.go
index 8b1550d1..dc7e31b9 100644
--- a/websocket/websocket.go
+++ b/websocket/websocket.go
@@ -9,9 +9,8 @@ import (
 // to avoid the import cycle to /kataras/iris. The ws package is used inside iris' station configuration
 // inside Iris' configuration like kataras/iris/sessions, kataras/iris/render/rest, kataras/iris/render/template, kataras/iris/server and so on.
 type irisStation interface {
-	H_(string, string, func(context.IContext))
-	StaticContent(string, string, []byte)
-	Logger() *logger.Logger
+	H_(string, string, func(context.IContext)) func(string)
+	StaticContent(string, string, []byte) func(string)
 }
 
 //
@@ -22,16 +21,34 @@ type irisStation interface {
 // This is not usable for you, unless you need more than one websocket server,
 // because iris' station already has one which you can configure and start
 //
-func New(station irisStation, cfg ...config.Websocket) Server {
-	c := config.DefaultWebsocket().Merge(cfg)
+// This is deprecated after rc-1, now we create the server and after register it
+// because I want to be able to call the Websocket via a property and no via func before iris.Listen.
+func New(station irisStation, c *config.Websocket, logger *logger.Logger) Server {
 	if c.Endpoint == "" {
-		station.Logger().Panicf("Websockets - config's Endpoint is empty, you have to set it in order to enable and start the websocket server!!. Refer to the docs if you can't figure out.")
+		//station.Logger().Panicf("Websockets - config's Endpoint is empty, you have to set it in order to enable and start the websocket server!!. Refer to the docs if you can't figure out.")
+		return nil
 	}
 	server := newServer(c)
+	RegisterServer(station, server, logger)
+	return server
+}
+
+// NewServer creates a websocket server and returns it
+func NewServer(c *config.Websocket) Server {
+	return newServer(c)
+}
+
+// RegisterServer registers the handlers for the websocket server
+// it's a bridge between station and websocket server
+func RegisterServer(station irisStation, server Server, logger *logger.Logger) {
+	c := server.Config()
+	if c.Endpoint == "" {
+		return
+	}
 
 	websocketHandler := func(ctx context.IContext) {
 		if err := server.Upgrade(ctx); err != nil {
-			station.Logger().Panic(err)
+			logger.Panic(err)
 		}
 	}
 
@@ -42,7 +59,7 @@ func New(station irisStation, cfg ...config.Websocket) Server {
 			}
 
 			if err := server.Upgrade(ctx); err != nil {
-				station.Logger().Panic(err)
+				logger.Panic(err)
 			}
 		}
 	}
@@ -51,7 +68,6 @@ func New(station irisStation, cfg ...config.Websocket) Server {
 	// serve the client side on domain:port/iris-ws.js
 	station.StaticContent("/iris-ws.js", "application/json", clientSource)
 
-	return server
 }
 
 var clientSource = []byte(`var stringMessageType = 0;