func TempFile(content []byte, dir, prefix string) (*os.File, error) {
	if dir == "" {
		home, err := HomeDir()
		if err != nil {
			return nil, err
		}
		dir = path.Join(home, "tmp")
	}
	if prefix == "" {
		prefix = "temp"
	}
	if !CheckFileExists(dir) {
		err := os.MkdirAll(dir, 0744)
		if err != nil {
			return nil, err
		}
	}
	tmpfile, err := ioutil.TempFile(dir, prefix)
	if err != nil {
		return nil, err
	}
	if content != nil {
		if _, err := tmpfile.Write(content); err != nil {
			return nil, err
		}
	}
	_, err = tmpfile.Seek(0, 0)
	if err != nil {
		return nil, err
	}
	return tmpfile, nil
}
TempFile generates a temp file with separated content.
package util
import (
	"bytes"
	"crypto/aes"
	"crypto/hmac"
	"crypto/md5"
	srand "crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/url"
	"os"
	"os/exec"
	"path"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"
)
func GetURL(protocol, host, uriPath string, params map[string]string) string {
	if strings.Index(uriPath, "/") == 0 {
		uriPath = uriPath[1:]
	}
	query := strings.Trim(ToCanonicalQueryString(params), " ")
	if query == "" {
		return fmt.Sprintf("%s/%s", HostToURL(host, protocol), uriPath)
	}
	return fmt.Sprintf("%s/%s?%s", HostToURL(host, protocol), uriPath, query)
}
func GetURIPath(uri string) string {
	uri = strings.Replace(uri, "://", "", 1)
	index := strings.Index(uri, "/")
	return uri[index:]
}
func URIEncodeExceptSlash(uri string) string {
	var result string
	for _, char := range uri {
		str := fmt.Sprintf("%c", char)
		if str == "/" {
			result += str
		} else {
			result += URLEncode(str)
		}
	}
	return result
}
func HmacSha256Hex(key, message string) string {
	mac := hmac.New(sha256.New, []byte(key))
	mac.Write([]byte(message))
	return hex.EncodeToString(mac.Sum(nil))
}
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}
func AesECBEncryptHex(key, message string) (string, error) {
	if len(key) < 16 {
		return "", fmt.Errorf("Invalid SecretKey")
	}
	keyBytes := []byte(key[:16])
	msgBytes := []byte(message)
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	msgBytes = PKCS7Padding(msgBytes, blockSize)
	blockMode := NewECBEncrypter(block)
	crypted := make([]byte, len(msgBytes))
	blockMode.CryptBlocks(crypted, msgBytes)
	return hex.EncodeToString(crypted), nil
}
func GetMD5(data interface{}, base64Encode bool) string {
	hash := md5.New()
	if str, ok := data.(string); ok {
		io.Copy(hash, strings.NewReader(str))
	} else if byteArray, ok := data.([]byte); ok {
		io.Copy(hash, bytes.NewReader(byteArray))
	} else if reader, ok := data.(io.Reader); ok {
		if f, ok := data.(io.Seeker); ok {
			f.Seek(0, 0)
			io.Copy(hash, reader)
			f.Seek(0, 0)
		} else {
			io.Copy(hash, reader)
		}
	} else {
		panic("data type should be string or []byte or io.Reader.")
	}
	if base64Encode {
		return Base64Encode(hash.Sum(nil))
	}
	return hex.EncodeToString(hash.Sum(nil))
}
func GetSha256(data interface{}) string {
	hash := sha256.New()
	if str, ok := data.(string); ok {
		io.Copy(hash, strings.NewReader(str))
	} else if byteArray, ok := data.([]byte); ok {
		io.Copy(hash, bytes.NewReader(byteArray))
	} else if reader, ok := data.(io.Reader); ok {
		if f, ok := data.(io.Seeker); ok {
			f.Seek(0, 0)
			io.Copy(hash, reader)
			f.Seek(0, 0)
		} else {
			io.Copy(hash, reader)
		}
	} else {
		panic("data type should be string or []byte or io.Reader.")
	}
	return hex.EncodeToString(hash.Sum(nil))
}
func Base64Encode(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}
func Contains(slice []string, value string, caseInsensitive bool) bool {
	if caseInsensitive {
		value = strings.ToLower(value)
	}
	for _, v := range slice {
		if caseInsensitive {
			v = strings.ToLower(v)
		}
		if value == v {
			return true
		}
	}
	return false
}
func MapContains(m map[string]string, compareFunc func(string, string) bool) bool {
	for key, value := range m {
		if compareFunc(key, value) {
			return true
		}
	}
	return false
}
func GetMapKey(m map[string]string, key string, caseInsensitive bool) string {
	if caseInsensitive {
		key = strings.ToLower(key)
	}
	var tempKey string
	for k := range m {
		tempKey = k
		if caseInsensitive {
			tempKey = strings.ToLower(k)
		}
		if tempKey == key {
			return k
		}
	}
	return ""
}
func GetMapValue(m map[string]string, key string, caseInsensitive bool) string {
	if caseInsensitive {
		for k, v := range m {
			if strings.ToLower(k) == strings.ToLower(key) {
				return v
			}
		}
	}
	return m[key]
}
func TimeToUTCString(t time.Time) string {
	format := time.RFC3339  
	return t.UTC().Format(format)
}
func TimeStringToRFC1123(str string) string {
	t, err := time.Parse(time.RFC3339, str)
	if err != nil {
		t, err = time.Parse(time.RFC1123, str)
		if err != nil {
			panic("Time format invalid. The time format must be time.RFC3339 or time.RFC1123")
		}
	}
	return t.Format(time.RFC1123)
}
func HostToURL(host, protocol string) string {
	if matched, _ := regexp.MatchString("^[[:alpha:]]+:", host); matched {
		return host
	}
	if protocol == "" {
		protocol = "http"
	}
	return fmt.Sprintf("%s://%s", protocol, host)
}
func ToCanonicalQueryString(params map[string]string) string {
	if params == nil {
		return ""
	}
	encodedQueryStrings := make([]string, 0, 10)
	var query string
	for key, value := range params {
		if key != "" {
			query = URLEncode(key) + "="
			if value != "" {
				query += URLEncode(value)
			}
			encodedQueryStrings = append(encodedQueryStrings, query)
		}
	}
	sort.Strings(encodedQueryStrings)
	return strings.Join(encodedQueryStrings, "&")
}
func ToCanonicalHeaderString(headerMap map[string]string) string {
	headers := make([]string, 0, len(headerMap))
	for key, value := range headerMap {
		headers = append(headers,
			fmt.Sprintf("%s:%s", URLEncode(strings.ToLower(key)),
				URLEncode(strings.TrimSpace(value))))
	}
	sort.Strings(headers)
	return strings.Join(headers, "\n")
}
func URLEncode(str string) string {
	return strings.Replace(url.QueryEscape(str), "+", "%20", -1)
}
func SliceToLower(slice []string) {
	for index, value := range slice {
		slice[index] = strings.ToLower(value)
	}
}
func MapKeyToLower(m map[string]string) {
	temp := make(map[string]string, len(m))
	for key, value := range m {
		temp[strings.ToLower(key)] = value
		delete(m, key)
	}
	for key, value := range temp {
		m[key] = value
	}
}
func ToMap(i interface{}, keys ...string) (map[string]interface{}, error) {
	var m map[string]interface{}
	var byteArray []byte
	if str, ok := i.(string); ok {
		byteArray = []byte(str)
	} else if b, ok := i.([]byte); ok {
		byteArray = b
	} else {
		b, err := json.Marshal(i)
		if err != nil {
			return nil, err
		}
		byteArray = b
	}
	if err := json.Unmarshal(byteArray, &m); err != nil {
		return nil, err
	}
	if keys != nil && len(keys) > 0 {
		result := make(map[string]interface{}, len(keys))
		for _, k := range keys {
			if v, ok := m[k]; ok {
				result[k] = v
			}
		}
		return result, nil
	}
	return m, nil
}
func ToJson(i interface{}, keys ...string) ([]byte, error) {
	byteArray, err := json.Marshal(i)
	if keys == nil || len(keys) == 0 {
		return byteArray, err
	}
	if err == nil {
		m, err := ToMap(byteArray, keys...)
		if err != nil {
			return nil, err
		}
		byteArray, err = json.Marshal(m)
	}
	return byteArray, err
}
func CheckFileExists(filename string) bool {
	exist := true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}
func TempFileWithSize(fileSize int64) (*os.File, error) {
	f, err := TempFile(nil, "", "")
	if err != nil {
		return nil, err
	}
	if err = f.Truncate(fileSize); err != nil {
		return nil, err
	}
	return f, nil
}