func funcStddevOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return aggrOverTime(vals, enh, func(values []Point) float64 {
		var aux, count, mean float64
		for _, v := range values {
			count++
			delta := v.V - mean
			mean += delta / count
			aux += delta * (v.V - mean)
		}
		return math.Sqrt(aux / count)
	})
}
=== stddev_over_time(Matrix ValueTypeMatrix) Vector ===
package promql
import (
	"math"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
	"github.com/pkg/errors"
	"github.com/prometheus/common/model"
	"github.com/prometheus/prometheus/pkg/labels"
)
type Function struct {
	Name       string
	ArgTypes   []ValueType
	Variadic   int
	ReturnType ValueType
	Call func(vals []Value, args Expressions, enh *EvalNodeHelper) Vector
}
func funcTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return Vector{Sample{Point: Point{
		V: float64(enh.ts) / 1000,
	}}}
}
func extrapolatedRate(vals []Value, args Expressions, enh *EvalNodeHelper, isCounter bool, isRate bool) Vector {
	ms := args[0].(*MatrixSelector)
	var (
		matrix     = vals[0].(Matrix)
		rangeStart = enh.ts - durationMilliseconds(ms.Range+ms.Offset)
		rangeEnd   = enh.ts - durationMilliseconds(ms.Offset)
	)
	for _, samples := range matrix {
		if len(samples.Points) < 2 {
			continue
		}
		var (
			counterCorrection float64
			lastValue         float64
		)
		for _, sample := range samples.Points {
			if isCounter && sample.V < lastValue {
				counterCorrection += lastValue
			}
			lastValue = sample.V
		}
		resultValue := lastValue - samples.Points[0].V + counterCorrection
		durationToStart := float64(samples.Points[0].T-rangeStart) / 1000
		durationToEnd := float64(rangeEnd-samples.Points[len(samples.Points)-1].T) / 1000
		sampledInterval := float64(samples.Points[len(samples.Points)-1].T-samples.Points[0].T) / 1000
		averageDurationBetweenSamples := sampledInterval / float64(len(samples.Points)-1)
		if isCounter && resultValue > 0 && samples.Points[0].V >= 0 {
			durationToZero := sampledInterval * (samples.Points[0].V / resultValue)
			if durationToZero < durationToStart {
				durationToStart = durationToZero
			}
		}
		extrapolationThreshold := averageDurationBetweenSamples * 1.1
		extrapolateToInterval := sampledInterval
		if durationToStart < extrapolationThreshold {
			extrapolateToInterval += durationToStart
		} else {
			extrapolateToInterval += averageDurationBetweenSamples / 2
		}
		if durationToEnd < extrapolationThreshold {
			extrapolateToInterval += durationToEnd
		} else {
			extrapolateToInterval += averageDurationBetweenSamples / 2
		}
		resultValue = resultValue * (extrapolateToInterval / sampledInterval)
		if isRate {
			resultValue = resultValue / ms.Range.Seconds()
		}
		enh.out = append(enh.out, Sample{
			Point: Point{V: resultValue},
		})
	}
	return enh.out
}
func funcDelta(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return extrapolatedRate(vals, args, enh, false, false)
}
func funcRate(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return extrapolatedRate(vals, args, enh, true, true)
}
func funcIncrease(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return extrapolatedRate(vals, args, enh, true, false)
}
func funcIrate(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return instantValue(vals, enh.out, true)
}
func funcIdelta(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return instantValue(vals, enh.out, false)
}
func instantValue(vals []Value, out Vector, isRate bool) Vector {
	for _, samples := range vals[0].(Matrix) {
		if len(samples.Points) < 2 {
			continue
		}
		lastSample := samples.Points[len(samples.Points)-1]
		previousSample := samples.Points[len(samples.Points)-2]
		var resultValue float64
		if isRate && lastSample.V < previousSample.V {
			resultValue = lastSample.V
		} else {
			resultValue = lastSample.V - previousSample.V
		}
		sampledInterval := lastSample.T - previousSample.T
		if sampledInterval == 0 {
			continue
		}
		if isRate {
			resultValue /= float64(sampledInterval) / 1000
		}
		out = append(out, Sample{
			Point: Point{V: resultValue},
		})
	}
	return out
}
func calcTrendValue(i int, sf, tf, s0, s1, b float64) float64 {
	if i == 0 {
		return b
	}
	x := tf * (s1 - s0)
	y := (1 - tf) * b
	return x + y
}
func funcHoltWinters(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	mat := vals[0].(Matrix)
	sf := vals[1].(Vector)[0].V
	tf := vals[2].(Vector)[0].V
	if sf <= 0 || sf >= 1 {
		panic(errors.Errorf("invalid smoothing factor. Expected: 0 < sf < 1, got: %f", sf))
	}
	if tf <= 0 || tf >= 1 {
		panic(errors.Errorf("invalid trend factor. Expected: 0 < tf < 1, got: %f", tf))
	}
	var l int
	for _, samples := range mat {
		l = len(samples.Points)
		if l < 2 {
			continue
		}
		var s0, s1, b float64
		s1 = samples.Points[0].V
		b = samples.Points[1].V - samples.Points[0].V
		var x, y float64
		for i := 1; i < l; i++ {
			x = sf * samples.Points[i].V
			b = calcTrendValue(i-1, sf, tf, s0, s1, b)
			y = (1 - sf) * (s1 + b)
			s0, s1 = s1, x+y
		}
		enh.out = append(enh.out, Sample{
			Point: Point{V: s1},
		})
	}
	return enh.out
}
func funcSort(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	byValueSorter := vectorByReverseValueHeap(vals[0].(Vector))
	sort.Sort(sort.Reverse(byValueSorter))
	return Vector(byValueSorter)
}
func funcSortDesc(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	byValueSorter := vectorByValueHeap(vals[0].(Vector))
	sort.Sort(sort.Reverse(byValueSorter))
	return Vector(byValueSorter)
}
func funcClampMax(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	vec := vals[0].(Vector)
	max := vals[1].(Vector)[0].Point.V
	for _, el := range vec {
		enh.out = append(enh.out, Sample{
			Metric: enh.dropMetricName(el.Metric),
			Point:  Point{V: math.Min(max, el.V)},
		})
	}
	return enh.out
}
func funcClampMin(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	vec := vals[0].(Vector)
	min := vals[1].(Vector)[0].Point.V
	for _, el := range vec {
		enh.out = append(enh.out, Sample{
			Metric: enh.dropMetricName(el.Metric),
			Point:  Point{V: math.Max(min, el.V)},
		})
	}
	return enh.out
}
func funcRound(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	vec := vals[0].(Vector)
	toNearest := float64(1)
	if len(args) >= 2 {
		toNearest = vals[1].(Vector)[0].Point.V
	}
	toNearestInverse := 1.0 / toNearest
	for _, el := range vec {
		v := math.Floor(el.V*toNearestInverse+0.5) / toNearestInverse
		enh.out = append(enh.out, Sample{
			Metric: enh.dropMetricName(el.Metric),
			Point:  Point{V: v},
		})
	}
	return enh.out
}
func funcScalar(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	v := vals[0].(Vector)
	if len(v) != 1 {
		return append(enh.out, Sample{
			Point: Point{V: math.NaN()},
		})
	}
	return append(enh.out, Sample{
		Point: Point{V: v[0].V},
	})
}
func aggrOverTime(vals []Value, enh *EvalNodeHelper, aggrFn func([]Point) float64) Vector {
	mat := vals[0].(Matrix)
	for _, el := range mat {
		if len(el.Points) == 0 {
			continue
		}
		enh.out = append(enh.out, Sample{
			Point: Point{V: aggrFn(el.Points)},
		})
	}
	return enh.out
}
func funcAvgOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return aggrOverTime(vals, enh, func(values []Point) float64 {
		var mean, count float64
		for _, v := range values {
			count++
			mean += (v.V - mean) / count
		}
		return mean
	})
}
func funcCountOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return aggrOverTime(vals, enh, func(values []Point) float64 {
		return float64(len(values))
	})
}
func funcMaxOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return aggrOverTime(vals, enh, func(values []Point) float64 {
		max := values[0].V
		for _, v := range values {
			if v.V > max || math.IsNaN(max) {
				max = v.V
			}
		}
		return max
	})
}
func funcMinOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return aggrOverTime(vals, enh, func(values []Point) float64 {
		min := values[0].V
		for _, v := range values {
			if v.V < min || math.IsNaN(min) {
				min = v.V
			}
		}
		return min
	})
}
func funcSumOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	return aggrOverTime(vals, enh, func(values []Point) float64 {
		var sum float64
		for _, v := range values {
			sum += v.V
		}
		return sum
	})
}
func funcQuantileOverTime(vals []Value, args Expressions, enh *EvalNodeHelper) Vector {
	q := vals[0].(Vector)[0].V
	mat := vals[1].(Matrix)
	for _, el := range mat {
		if len(el.Points) == 0 {
			continue
		}
		values := make(vectorByValueHeap, 0, len(el.Points))
		for _, v := range el.Points {
			values = append(values, Sample{Point: Point{V: v.V}})
		}
		enh.out = append(enh.out, Sample{
			Point: Point{V: quantile(q, values)},
		})
	}
	return enh.out
}