func (ctx *Context) Params(name string) string {
	if len(name) == 0 {
		return ""
	}
	if len(name) > 1 && name[0] != ':' {
		name = ":" + name
	}
	return ctx.params[name]
}
Params returns value of given param name.
e.g. ctx.Params(":uid") or ctx.Params("uid")
package macaron
import (
	"crypto/sha256"
	"encoding/hex"
	"html/template"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"time"
	"github.com/go-macaron/inject"
	"github.com/unknwon/com"
	"golang.org/x/crypto/pbkdf2"
)
type Locale interface {
	Language() string
	Tr(string, ...interface{}) string
}
type RequestBody struct {
	reader io.ReadCloser
}
func (rb *RequestBody) Bytes() ([]byte, error) {
	return ioutil.ReadAll(rb.reader)
}
func (rb *RequestBody) String() (string, error) {
	data, err := rb.Bytes()
	return string(data), err
}
func (rb *RequestBody) ReadCloser() io.ReadCloser {
	return rb.reader
}
type Request struct {
	*http.Request
}
func (r *Request) Body() *RequestBody {
	return &RequestBody{r.Request.Body}
}
type ContextInvoker func(ctx *Context)
func (invoke ContextInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
	invoke(params[0].(*Context))
	return nil, nil
}
type Context struct {
	inject.Injector
	handlers []Handler
	action   Handler
	index    int
	*Router
	Req    Request
	Resp   ResponseWriter
	params Params
	Render
	Locale
	Data map[string]interface{}
}
func (ctx *Context) handler() Handler {
	if ctx.index < len(ctx.handlers) {
		return ctx.handlers[ctx.index]
	}
	if ctx.index == len(ctx.handlers) {
		return ctx.action
	}
	panic("invalid index for context handler")
}
func (ctx *Context) Next() {
	ctx.index++
	ctx.run()
}
func (ctx *Context) Written() bool {
	return ctx.Resp.Written()
}
func (ctx *Context) run() {
	for ctx.index <= len(ctx.handlers) {
		vals, err := ctx.Invoke(ctx.handler())
		if err != nil {
			panic(err)
		}
		ctx.index++
		if len(vals) > 0 {
			ev := ctx.GetVal(reflect.TypeOf(ReturnHandler(nil)))
			handleReturn := ev.Interface().(ReturnHandler)
			handleReturn(ctx, vals)
		}
		if ctx.Written() {
			return
		}
	}
}
func (ctx *Context) RemoteAddr() string {
	addr := ctx.Req.Header.Get("X-Real-IP")
	if len(addr) == 0 {
		addr = ctx.Req.Header.Get("X-Forwarded-For")
		if addr == "" {
			addr = ctx.Req.RemoteAddr
			if i := strings.LastIndex(addr, ":"); i > -1 {
				addr = addr[:i]
			}
		}
	}
	return addr
}
func (ctx *Context) renderHTML(status int, setName, tplName string, data ...interface{}) {
	if len(data) <= 0 {
		ctx.Render.HTMLSet(status, setName, tplName, ctx.Data)
	} else if len(data) == 1 {
		ctx.Render.HTMLSet(status, setName, tplName, data[0])
	} else {
		ctx.Render.HTMLSet(status, setName, tplName, data[0], data[1].(HTMLOptions))
	}
}
func (ctx *Context) HTML(status int, name string, data ...interface{}) {
	ctx.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data...)
}
func (ctx *Context) HTMLSet(status int, setName, tplName string, data ...interface{}) {
	ctx.renderHTML(status, setName, tplName, data...)
}
func (ctx *Context) Redirect(location string, status ...int) {
	code := http.StatusFound
	if len(status) == 1 {
		code = status[0]
	}
	http.Redirect(ctx.Resp, ctx.Req.Request, location, code)
}
var MaxMemory = int64(1024 * 1024 * 10)
func (ctx *Context) parseForm() {
	if ctx.Req.Form != nil {
		return
	}
	contentType := ctx.Req.Header.Get(_CONTENT_TYPE)
	if (ctx.Req.Method == "POST" || ctx.Req.Method == "PUT") &&
		len(contentType) > 0 && strings.Contains(contentType, "multipart/form-data") {
		_ = ctx.Req.ParseMultipartForm(MaxMemory)
	} else {
		_ = ctx.Req.ParseForm()
	}
}
func (ctx *Context) Query(name string) string {
	ctx.parseForm()
	return ctx.Req.Form.Get(name)
}
func (ctx *Context) QueryTrim(name string) string {
	return strings.TrimSpace(ctx.Query(name))
}
func (ctx *Context) QueryStrings(name string) []string {
	ctx.parseForm()
	vals, ok := ctx.Req.Form[name]
	if !ok {
		return []string{}
	}
	return vals
}
func (ctx *Context) QueryEscape(name string) string {
	return template.HTMLEscapeString(ctx.Query(name))
}
func (ctx *Context) QueryBool(name string) bool {
	v, _ := strconv.ParseBool(ctx.Query(name))
	return v
}
func (ctx *Context) QueryInt(name string) int {
	return com.StrTo(ctx.Query(name)).MustInt()
}
func (ctx *Context) QueryInt64(name string) int64 {
	return com.StrTo(ctx.Query(name)).MustInt64()
}
func (ctx *Context) QueryFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.Query(name), 64)
	return v
}