func (p *ProgressBar) State() State {
	p.lock.Lock()
	defer p.lock.Unlock()
	s := State{}
	s.CurrentPercent = float64(p.state.currentNum) / float64(p.config.max)
	s.CurrentBytes = p.state.currentBytes
	s.MaxBytes = p.config.maxBytes
	s.SecondsSince = time.Since(p.state.startTime).Seconds()
	if p.state.currentNum > 0 {
		s.SecondsLeft = s.SecondsSince / float64(p.state.currentNum) * (float64(p.config.max) - float64(p.state.currentNum))
	}
	s.KBsPerSecond = float64(p.state.currentBytes) / 1000.0 / s.SecondsSince
	return s
}
State returns the current state
package progressbar
import (
	"errors"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
	"github.com/mitchellh/colorstring"
)
type ProgressBar struct {
	state  state
	config config
	lock sync.Mutex
}
type State struct {
	CurrentPercent float64
	CurrentBytes   float64
	MaxBytes       int64
	SecondsSince   float64
	SecondsLeft    float64
	KBsPerSecond   float64
}
type state struct {
	currentNum        int64
	currentPercent    int
	lastPercent       int
	currentSaucerSize int
	lastShown time.Time
	startTime time.Time
	maxLineWidth int
	currentBytes float64
	finished bool
}
type config struct {
	max                  int64  
	width                int
	writer               io.Writer
	theme                Theme
	renderWithBlankState bool
	description          string
	colorCodes bool
	maxBytes   int64
	showIterationsPerSecond bool
	showIterationsCount     bool
	throttleDuration time.Duration
	clearOnFinish bool
}
type Theme struct {
	Saucer        string
	SaucerHead    string
	SaucerPadding string
	BarStart      string
	BarEnd        string
}
type Option func(p *ProgressBar)
func OptionSetWidth(s int) Option {
	return func(p *ProgressBar) {
		p.config.width = s
	}
}
func OptionSetTheme(t Theme) Option {
	return func(p *ProgressBar) {
		p.config.theme = t
	}
}
func OptionSetWriter(w io.Writer) Option {
	return func(p *ProgressBar) {
		p.config.writer = w
	}
}
func OptionSetRenderBlankState(r bool) Option {
	return func(p *ProgressBar) {
		p.config.renderWithBlankState = r
	}
}
func OptionSetDescription(description string) Option {
	return func(p *ProgressBar) {
		p.config.description = description
	}
}
func OptionEnableColorCodes(colorCodes bool) Option {
	return func(p *ProgressBar) {
		p.config.colorCodes = colorCodes
	}
}
func OptionSetBytes(maxBytes int) Option {
	return OptionSetBytes64(int64(maxBytes))
}
func OptionSetBytes64(maxBytes int64) Option {
	return func(p *ProgressBar) {
		p.config.maxBytes = maxBytes
	}
}
func OptionShowCount() Option {
	return func(p *ProgressBar) {
		p.config.showIterationsCount = true
	}
}
func OptionShowIts() Option {
	return func(p *ProgressBar) {
		p.config.showIterationsPerSecond = true
	}
}
func OptionThrottle(duration time.Duration) Option {
	return func(p *ProgressBar) {
		p.config.throttleDuration = duration
	}
}
func OptionClearOnFinish() Option {
	return func(p *ProgressBar) {
		p.config.clearOnFinish = true
	}
}
var defaultTheme = Theme{Saucer: "█", SaucerPadding: " ", BarStart: "|", BarEnd: "|"}
func NewOptions(max int, options ...Option) *ProgressBar {
	return NewOptions64(int64(max), options...)
}
func NewOptions64(max int64, options ...Option) *ProgressBar {
	b := ProgressBar{
		state: getBlankState(),
		config: config{
			writer:           os.Stdout,
			theme:            defaultTheme,
			width:            40,
			max:              max,
			throttleDuration: 0 * time.Nanosecond,
		},
	}
	for _, o := range options {
		o(&b)
	}
	if b.config.renderWithBlankState {
		b.RenderBlank()
	}
	return &b
}
func getBlankState() state {
	now := time.Now()
	return state{
		startTime: now,
		lastShown: now,
	}
}
func New(max int) *ProgressBar {
	return NewOptions(max)
}
func (p *ProgressBar) RenderBlank() error {
	return p.render()
}
func (p *ProgressBar) Reset() {
	p.lock.Lock()
	defer p.lock.Unlock()
	p.state = getBlankState()
}
func (p *ProgressBar) Finish() error {
	p.lock.Lock()
	p.state.currentNum = p.config.max
	p.lock.Unlock()
	return p.Add(0)
}
func (p *ProgressBar) Set(num int) error {
	return p.Set64(int64(num))
}
func (p *ProgressBar) Set64(num int64) error {
	p.lock.Lock()
	defer p.lock.Unlock()
	if p.config.max == 0 {
		return errors.New("max must be greater than 0")
	}
	p.state.currentNum = num
	percent := float64(p.state.currentNum) / float64(p.config.max)
	p.state.currentSaucerSize = int(percent * float64(p.config.width))
	p.state.currentPercent = int(percent * 100)
	updateBar := p.state.currentPercent != p.state.lastPercent && p.state.currentPercent > 0
	p.state.currentBytes = float64(percent) * float64(p.config.maxBytes)
	p.state.lastPercent = p.state.currentPercent
	if p.state.currentNum > p.config.max {
		return errors.New("current number exceeds max")
	}
	if updateBar || p.config.showIterationsPerSecond || p.config.maxBytes > 0 {
		return p.render()
	}
	return nil
}
func (p *ProgressBar) Add(num int) error {
	return p.Add64(int64(num))
}
func (p *ProgressBar) Add64(num int64) error {
	return p.Set64(p.state.currentNum + num)
}
func (p *ProgressBar) Clear() error {
	return clearProgressBar(p.config, p.state)
}
func (p *ProgressBar) Describe(description string) {
	p.config.description = description
}
func (p *ProgressBar) render() error {
	if time.Since(p.state.lastShown).Nanoseconds() < p.config.throttleDuration.Nanoseconds() &&
		p.state.currentNum < p.config.max {
		return nil
	}
	err := clearProgressBar(p.config, p.state)
	if err != nil {
		return err
	}
	if p.state.finished || p.state.currentNum >= p.config.max {
		p.state.finished = true
		if p.config.clearOnFinish {
			return nil
		}
	}
	w, err := renderProgressBar(p.config, p.state)
	if err != nil {
		return err
	}
	if w > p.state.maxLineWidth {
		p.state.maxLineWidth = w
	}
	p.state.lastShown = time.Now()
	return nil
}