func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
	val := ctx.GetCookie(name)
	if val == "" {
		return "", false
	}
	text, err := hex.DecodeString(val)
	if err != nil {
		return "", false
	}
	key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
	text, err = com.AESGCMDecrypt(key, text)
	return string(text), err == nil
}
GetSuperSecureCookie returns given cookie value from request header with secret string.
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
}
func (ctx *Context) Params(name string) string {
	if len(name) == 0 {
		return ""
	}
	if len(name) > 1 && name[0] != ':' {
		name = ":" + name
	}
	return ctx.params[name]
}
func (ctx *Context) AllParams() Params {
	return ctx.params
}
func (ctx *Context) SetParams(name, val string) {
	if name != "*" && !strings.HasPrefix(name, ":") {
		name = ":" + name
	}
	ctx.params[name] = val
}
func (ctx *Context) ReplaceAllParams(params Params) {
	ctx.params = params
}
func (ctx *Context) ParamsEscape(name string) string {
	return template.HTMLEscapeString(ctx.Params(name))
}
func (ctx *Context) ParamsInt(name string) int {
	return com.StrTo(ctx.Params(name)).MustInt()
}
func (ctx *Context) ParamsInt64(name string) int64 {
	return com.StrTo(ctx.Params(name)).MustInt64()
}
func (ctx *Context) ParamsFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.Params(name), 64)
	return v
}
func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) {
	return ctx.Req.FormFile(name)
}
func (ctx *Context) SaveToFile(name, savePath string) error {
	fr, _, err := ctx.GetFile(name)
	if err != nil {
		return err
	}
	defer fr.Close()
	fw, err := os.OpenFile(savePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	defer fw.Close()
	_, err = io.Copy(fw, fr)
	return err
}
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = url.QueryEscape(value)
	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int64:
			cookie.MaxAge = int(v)
		case int32:
			cookie.MaxAge = int(v)
		case func(*http.Cookie):
			v(&cookie)
		}
	}
	cookie.Path = "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		} else if v, ok := others[1].(func(*http.Cookie)); ok {
			v(&cookie)
		}
	}
	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		} else if v, ok := others[1].(func(*http.Cookie)); ok {
			v(&cookie)
		}
	}
	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		case func(*http.Cookie):
			v(&cookie)
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}
	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		} else if v, ok := others[1].(func(*http.Cookie)); ok {
			v(&cookie)
		}
	}
	if len(others) > 5 {
		if v, ok := others[5].(time.Time); ok {
			cookie.Expires = v
			cookie.RawExpires = v.Format(time.UnixDate)
		} else if v, ok := others[1].(func(*http.Cookie)); ok {
			v(&cookie)
		}
	}
	if len(others) > 6 {
		for _, other := range others[6:] {
			if v, ok := other.(func(*http.Cookie)); ok {
				v(&cookie)
			}
		}
	}
	ctx.Resp.Header().Add("Set-Cookie", cookie.String())
}
func (ctx *Context) GetCookie(name string) string {
	cookie, err := ctx.Req.Cookie(name)
	if err != nil {
		return ""
	}
	val, _ := url.QueryUnescape(cookie.Value)
	return val
}
func (ctx *Context) GetCookieInt(name string) int {
	return com.StrTo(ctx.GetCookie(name)).MustInt()
}
func (ctx *Context) GetCookieInt64(name string) int64 {
	return com.StrTo(ctx.GetCookie(name)).MustInt64()
}
func (ctx *Context) GetCookieFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.GetCookie(name), 64)
	return v
}
var defaultCookieSecret string
func (m *Macaron) SetDefaultCookieSecret(secret string) {
	defaultCookieSecret = secret
}
func (ctx *Context) SetSecureCookie(name, value string, others ...interface{}) {
	ctx.SetSuperSecureCookie(defaultCookieSecret, name, value, others...)
}
func (ctx *Context) GetSecureCookie(key string) (string, bool) {
	return ctx.GetSuperSecureCookie(defaultCookieSecret, key)
}
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) {
	key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
	text, err := com.AESGCMEncrypt(key, []byte(value))
	if err != nil {
		panic("error encrypting cookie: " + err.Error())
	}
	ctx.SetCookie(name, hex.EncodeToString(text), others...)
}