func JSONDecode(data []byte, to interface{}) error {
	if !StringContains(reflect.ValueOf(to).Type().String(), "*") {
		return errors.New("json decode error - memory address not supplied")
	}
	return json.Unmarshal(data, to)
}
JSONDecode decodes JSON data into a structure
package common
import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"encoding/csv"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"
)
const (
	HashSHA1 = iota
	HashSHA256
	HashSHA512
	HashSHA512_384
	SatoshisPerBTC = 100000000
	SatoshisPerLTC = 100000000
	WeiPerEther    = 1000000000000000000
)
func GetMD5(input []byte) []byte {
	hash := md5.New()
	hash.Write(input)
	return hash.Sum(nil)
}
func GetSHA512(input []byte) []byte {
	sha := sha512.New()
	sha.Write(input)
	return sha.Sum(nil)
}
func GetSHA256(input []byte) []byte {
	sha := sha256.New()
	sha.Write(input)
	return sha.Sum(nil)
}
func GetHMAC(hashType int, input, key []byte) []byte {
	var hash func() hash.Hash
	switch hashType {
	case HashSHA1:
		{
			hash = sha1.New
		}
	case HashSHA256:
		{
			hash = sha256.New
		}
	case HashSHA512:
		{
			hash = sha512.New
		}
	case HashSHA512_384:
		{
			hash = sha512.New384
		}
	}
	hmac := hmac.New(hash, []byte(key))
	hmac.Write(input)
	return hmac.Sum(nil)
}
func HexEncodeToString(input []byte) string {
	return hex.EncodeToString(input)
}
func Base64Decode(input string) ([]byte, error) {
	result, err := base64.StdEncoding.DecodeString(input)
	if err != nil {
		return nil, err
	}
	return result, nil
}
func Base64Encode(input []byte) string {
	return base64.StdEncoding.EncodeToString(input)
}
func StringSliceDifference(slice1 []string, slice2 []string) []string {
	var diff []string
	for i := 0; i < 2; i++ {
		for _, s1 := range slice1 {
			found := false
			for _, s2 := range slice2 {
				if s1 == s2 {
					found = true
					break
				}
			}
			if !found {
				diff = append(diff, s1)
			}
		}
		if i == 0 {
			slice1, slice2 = slice2, slice1
		}
	}
	return diff
}
func StringContains(input, substring string) bool {
	return strings.Contains(input, substring)
}
func DataContains(haystack []string, needle string) bool {
	data := strings.Join(haystack, ",")
	return strings.Contains(data, needle)
}
func JoinStrings(input []string, separator string) string {
	return strings.Join(input, separator)
}
func SplitStrings(input, separator string) []string {
	return strings.Split(input, separator)
}
func TrimString(input, cutset string) string {
	return strings.Trim(input, cutset)
}
func ReplaceString(input, old, new string, n int) string {
	return strings.Replace(input, old, new, n)
}
func StringToUpper(input string) string {
	return strings.ToUpper(input)
}
func StringToLower(input string) string {
	return strings.ToLower(input)
}
func RoundFloat(x float64, prec int) float64 {
	var rounder float64
	pow := math.Pow(10, float64(prec))
	intermed := x * pow
	_, frac := math.Modf(intermed)
	intermed += .5
	x = .5
	if frac < 0.0 {
		x = -.5
		intermed--
	}
	if frac >= x {
		rounder = math.Ceil(intermed)
	} else {
		rounder = math.Floor(intermed)
	}
	return rounder / pow
}
func IsEnabled(isEnabled bool) string {
	if isEnabled {
		return "Enabled"
	}
	return "Disabled"
}
func IsValidCryptoAddress(address, crypto string) (bool, error) {
	switch StringToLower(crypto) {
	case "btc":
		return regexp.MatchString("^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$", address)
	case "ltc":
		return regexp.MatchString("^[L3M][a-km-zA-HJ-NP-Z1-9]{25,34}$", address)
	case "eth":
		return regexp.MatchString("^0x[a-km-z0-9]{40}$", address)
	default:
		return false, errors.New("Invalid crypto currency")
	}
}
func YesOrNo(input string) bool {
	if StringToLower(input) == "y" || StringToLower(input) == "yes" {
		return true
	}
	return false
}
func CalculateAmountWithFee(amount, fee float64) float64 {
	return amount + CalculateFee(amount, fee)
}
func CalculateFee(amount, fee float64) float64 {
	return amount * (fee / 100)
}
func CalculatePercentageGainOrLoss(priceNow, priceThen float64) float64 {
	return (priceNow - priceThen) / priceThen * 100
}
func CalculatePercentageDifference(amount, secondAmount float64) float64 {
	return (amount - secondAmount) / ((amount + secondAmount) / 2) * 100
}
func CalculateNetProfit(amount, priceThen, priceNow, costs float64) float64 {
	return (priceNow * amount) - (priceThen * amount) - costs
}
func SendHTTPRequest(method, path string, headers map[string]string, body io.Reader) (string, error) {
	upperMethod := strings.ToUpper(method)
	if upperMethod != "POST" && upperMethod != "GET" && upperMethod != "DELETE" {
		return "", errors.New("invalid HTTP method specified")
	}
	req, err := http.NewRequest(upperMethod, path, body)
	if err != nil {
		return "", err
	}
	for k, v := range headers {
		req.Header.Add(k, v)
	}
	requestDump, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(requestDump))
	timeout := time.Duration(3 * time.Second)
	if upperMethod == "POST" {
		timeout = time.Duration(15 * time.Second)
	}
	httpClient := &http.Client{Timeout: timeout}
	resp, err := httpClient.Do(req)
	if err != nil {
		return "", err
	}
	contents, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return "", err
	}
	return string(contents), nil
}
func SendHTTPRequest2(method, path string, headers http.Header, body io.Reader) (string, int, error) {
	upperMethod := strings.ToUpper(method)
	if upperMethod != "POST" && upperMethod != "GET" && upperMethod != "DELETE" {
		return "", 0, errors.New("invalid HTTP method specified")
	}
	req, err := http.NewRequest(upperMethod, path, body)
	if err != nil {
		return "", 0, err
	}
	req.Header = headers
	requestDump, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(requestDump))
	timeout := time.Duration(3 * time.Second)
	if upperMethod == "POST" {
		timeout = time.Duration(15 * time.Second)
	}
	httpClient := &http.Client{Timeout: timeout}
	resp, err := httpClient.Do(req)
	if err != nil {
		return "", 0, err
	}
	contents, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return "", 0, err
	}
	return string(contents), resp.StatusCode, nil
}
func SendHTTPGetRequest(url string, jsonDecode, isVerbose bool, result interface{}) error {
	if isVerbose {
		log.Println("Raw URL: ", url)
	}
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	if res.StatusCode != 200 {
		return fmt.Errorf("common.SendHTTPGetRequest() error: HTTP status code %d", res.StatusCode)
	}
	contents, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}
	if isVerbose {
		log.Println("Raw Resp: ", string(contents[:]))
	}
	defer res.Body.Close()
	if jsonDecode {
		err := JSONDecode(contents, result)
		if err != nil {
			log.Println(string(contents[:]))
			return err
		}
	}
	return nil
}
func JSONEncode(v interface{}) ([]byte, error) {
	return json.Marshal(v)
}