func HumanBytesString(s uint64) string {
	sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
	return humanizeBytes(s, 1000, sizes)
}
HumanBytesString produces a human readable representation of an SI size.

Bytes(82854982) -> 83MB
noinspection GoUnusedExportedFunction
package util
import (
	"crypto/rand"
	"fmt"
	"math"
)
func GenRandomBytes(size int) (blk []byte, err error) {
	blk = make([]byte, size)
	_, err = rand.Read(blk)
	return
}
func MinInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}
func UMax64(a, b uint64) uint64 {
	if a > b {
		return a
	}
	return b
}
func UMax32(a, b uint32) uint32 {
	if a > b {
		return a
	}
	return b
}
func UMax16(a, b uint16) uint16 {
	if a > b {
		return a
	}
	return b
}
func UMax(a, b uint) uint {
	if a > b {
		return a
	}
	return b
}
func Min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
func UMin64(a, b uint64) uint64 {
	if a < b {
		return a
	}
	return b
}
func EstSpeed(startTime int64, lastTime int64, bytesSent uint64) uint64 {
	if startTime <= 0 || lastTime <= 0 || bytesSent == 0 || lastTime < startTime {
		return 0
	}
	return uint64(float64(bytesSent) / (float64(lastTime) - float64(startTime)))
}
func logN(n, b float64) float64 {
	return math.Log(n) / math.Log(b)
}
func humanizeBytes(s uint64, base float64, sizes []string) string {
	if s < 10 {
		return fmt.Sprintf("%dB", s)
	}
	e := math.Floor(logN(float64(s), base))
	suffix := sizes[int(e)]
	val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
	f := "%.0f%s"
	if val < 10 {
		f = "%.1f%s"
	}
	return fmt.Sprintf(f, val, suffix)
}