func AlignTime(tm time.Time, interval time.Duration) time.Time {
	truncated := tm.Truncate(interval)
	if truncated == tm {
		return tm
	}
	return truncated.Add(interval)
}
AlignTime returns the time of the next aligned interval.
If the current time is aligned the current time is returned.
package internal
import (
	"bufio"
	"compress/gzip"
	"context"
	"errors"
	"fmt"
	"io"
	"math"
	"math/rand"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
	"unicode"
)
const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var (
	ErrTimeout             = errors.New("command timed out")
	ErrorNotImplemented    = errors.New("not implemented yet")
	ErrorVersionAlreadySet = errors.New("version has already been set")
)
var version string
type ReadWaitCloser struct {
	pipeReader *io.PipeReader
	wg         sync.WaitGroup
}
func SetVersion(v string) error {
	if version != "" {
		return ErrorVersionAlreadySet
	}
	version = v
	return nil
}
func Version() string {
	return version
}
func ProductToken() string {
	return fmt.Sprintf("Telegraf/%s Go/%s",
		Version(), strings.TrimPrefix(runtime.Version(), "go"))
}
func ReadLines(filename string) ([]string, error) {
	return ReadLinesOffsetN(filename, 0, -1)
}
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return []string{""}, err
	}
	defer f.Close()
	var ret []string
	r := bufio.NewReader(f)
	for i := 0; i < n+int(offset) || n < 0; i++ {
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		if i < int(offset) {
			continue
		}
		ret = append(ret, strings.Trim(line, "\n"))
	}
	return ret, nil
}
func RandomString(n int) string {
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}
func SnakeCase(in string) string {
	runes := []rune(in)
	length := len(runes)
	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}
	return string(out)
}
func RandomSleep(max time.Duration, shutdown chan struct{}) {
	if max == 0 {
		return
	}
	sleepns := rand.Int63n(max.Nanoseconds())
	t := time.NewTimer(time.Nanosecond * time.Duration(sleepns))
	select {
	case <-t.C:
		return
	case <-shutdown:
		t.Stop()
		return
	}
}
func RandomDuration(max time.Duration) time.Duration {
	if max == 0 {
		return 0
	}
	sleepns := rand.Int63n(max.Nanoseconds())
	return time.Duration(sleepns)
}
func SleepContext(ctx context.Context, duration time.Duration) error {
	if duration == 0 {
		return nil
	}
	t := time.NewTimer(duration)
	select {
	case <-t.C:
		return nil
	case <-ctx.Done():
		t.Stop()
		return ctx.Err()
	}
}
func AlignDuration(tm time.Time, interval time.Duration) time.Duration {
	return AlignTime(tm, interval).Sub(tm)
}