Instruction:
Create a Python 3 function to
call multiplySeries after inserting wildcards at the given position(s). Example:: &target=multiplySeriesWithWildcards( web.host-[0-7].{avg-response,total-request}.value, 2) This would be the equivalent of:: &target=multiplySeries(web.host-0.{avg-response,total-request}.value) &target=multiplySeries(web.host-1.{avg-response,total-request}.value) ...

Response:
def multiplySeriesWithWildcards(requestContext, seriesList, *position):
    """
    Call multiplySeries after inserting wildcards at the given position(s).

    Example::

        &target=multiplySeriesWithWildcards(
            web.host-[0-7].{avg-response,total-request}.value, 2)

    This would be the equivalent of::

        &target=multiplySeries(web.host-0.{avg-response,total-request}.value)
        &target=multiplySeries(web.host-1.{avg-response,total-request}.value)
        ...
    """
    positions = [position] if isinstance(position, int) else position

    newSeries = {}
    newNames = []

    for series in seriesList:
        new_name = ".".join(map(lambda x: x[1],
                                filter(lambda i: i[0] not in positions,
                                       enumerate(series.name.split('.')))))

        if new_name in newSeries:
            [newSeries[new_name]] = multiplySeries(requestContext,
                                                   (newSeries[new_name],
                                                    series))
        else:
            newSeries[new_name] = series
            newNames.append(new_name)
        newSeries[new_name].name = new_name
    return [newSeries[name] for name in newNames]


Instruction:
Implement a function in Python 3 to
take a wildcard seriesList. Distills down a set of inputs into the range of the series.

Response:
def rangeOfSeries(requestContext, *seriesLists):
    """
    Takes a wildcard seriesList.
    Distills down a set of inputs into the range of the series

    Example::

        &target=rangeOfSeries(Server*.connections.total)

    """
    if not seriesLists or not any(seriesLists):
        return []
    seriesList, start, end, step = normalize(seriesLists)
    name = "rangeOfSeries(%s)" % formatPathExpressions(seriesList)
    values = (safeSubtract(max(row),
                           min(row)) for row in zip_longest(*seriesList))
    series = TimeSeries(name, start, end, step, values)
    series.pathExpression = name
    return [series]


Instruction:
Explain what the following Python 3 code does
def percentileOfSeries(requestContext, seriesList, n, interpolate=False):
    if n <= 0:
        raise ValueError(
            'The requested percent is required to be greater than 0')

    if not seriesList:
        return []
    name = 'percentileOfSeries(%s,%g)' % (seriesList[0].pathExpression, n)
    start, end, step = normalize([seriesList])[1:]
    values = [_getPercentile(row, n, interpolate)
              for row in zip_longest(*seriesList)]
    resultSeries = TimeSeries(name, start, end, step, values)
    resultSeries.pathExpression = name
    return [resultSeries]

Response: Returns a single series which is composed of the n - percentile values taken across a wildcard series at each point.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def keepLastValue(requestContext, seriesList, limit=INF):
    for series in seriesList:
        series.name = "keepLastValue(%s)" % (series.name)
        series.pathExpression = series.name
        consecutiveNones = 0
        for i, value in enumerate(series):
            series[i] = value

            # No 'keeping' can be done on the first value because we have no
            # idea what came before it.
            if i == 0:
                continue

            if value is None:
                consecutiveNones += 1
            else:
                if 0 < consecutiveNones <= limit:
                    # If a non-None value is seen before the limit of Nones is
                    # hit, backfill all the missing datapoints with the last
                    # known value.
                    for index in range(i - consecutiveNones, i):
                        series[index] = series[i - consecutiveNones - 1]

                consecutiveNones = 0

        # If the series ends with some None values, try to backfill a bit to
        # cover it.
        if 0 < consecutiveNones <= limit:
            for index in range(len(series) - consecutiveNones, len(series)):
                series[index] = series[len(series) - consecutiveNones - 1]

    return seriesList

Response: Keep the last value in the given seriesList.


Instruction:
Can you write a function in Python 3 where it
interpolates the given seriesList with the last known value.

Response:
def interpolate(requestContext, seriesList, limit=INF):
    """
    Takes one metric or a wildcard seriesList, and optionally a limit to the
    number of 'None' values to skip over. Continues the line with the last
    received value when gaps ('None' values) appear in your data, rather than
    breaking your line.

    Example::

        &target=interpolate(Server01.connections.handled)
        &target=interpolate(Server01.connections.handled, 10)
    """
    for series in seriesList:
        series.name = "interpolate(%s)" % (series.name)
        series.pathExpression = series.name
        consecutiveNones = 0
        for i, value in enumerate(series):
            series[i] = value

            # No 'keeping' can be done on the first value because we have no
            # idea what came before it.
            if i == 0:
                continue

            if value is None:
                consecutiveNones += 1
            elif consecutiveNones == 0:
                # Have a value but no need to interpolate
                continue
            elif series[i - consecutiveNones - 1] is None:
                # Have a value but can't interpolate: reset count
                consecutiveNones = 0
                continue
            else:
                # Have a value and can interpolate. If a non-None value is
                # seen before the limit of Nones is hit, backfill all the
                # missing datapoints with the last known value.
                if consecutiveNones > 0 and consecutiveNones <= limit:
                    lastIndex = i - consecutiveNones - 1
                    lastValue = series[lastIndex]
                    for index in range(i - consecutiveNones, i):
                        nextValue = lastValue + (index - lastIndex)
                        nextValue = nextValue * (value - lastValue)
                        nextValue = nextValue / (consecutiveNones + 1)
                        series[index] = nextValue

                consecutiveNones = 0

    return seriesList


Instruction:
Here you have a function in Python 3, explain what it does
def changed(requestContext, seriesList):
    for series in seriesList:
        series.name = series.pathExpression = 'changed(%s)' % series.name
        previous = None
        for index, value in enumerate(series):
            if previous is None:
                series[index] = 0
            elif value is not None and previous != value:
                series[index] = 1
            else:
                series[index] = 0
            previous = value
    return seriesList

Response:
Takes one metric or a wildcard seriesList.
    Output 1 when the value changed 0 when the same
racket


Instruction:
Make a summary of the following Python 3 code
def divideSeriesLists(requestContext, dividendSeriesList, divisorSeriesList):

    if len(dividendSeriesList) != len(divisorSeriesList):
        raise ValueError("dividendSeriesList and divisorSeriesList argument\
                         must have equal length")

    results = []

    for dividendSeries, divisorSeries in zip(dividendSeriesList,
                                             divisorSeriesList):
        name = "divideSeries(%s,%s)" % (dividendSeries.name,
                                        divisorSeries.name)
        bothSeries = (dividendSeries, divisorSeries)
        step = reduce(lcm, [s.step for s in bothSeries])

        for s in bothSeries:
            s.consolidate(step // s.step)

        start = min([s.start for s in bothSeries])
        end = max([s.end for s in bothSeries])
        end -= (end - start) % step

        values = (safeDiv(v1, v2) for v1, v2 in zip(*bothSeries))

        quotientSeries = TimeSeries(name, start, end, step, values)
        results.append(quotientSeries)

    return results

Response: Divides two lists of time series into two lists of time series.


Instruction:
Can you create a Python 3 function that
takes a dividend metric and a divisor metric and draws the division result. A constant may *not* be passed. To divide by a constant, use the scale() function (which is essentially a multiplication operation) and use the inverse of the dividend. (Division by 8 = multiplication by 1/8 or 0.125) Example:: &target=divideSeries(Series.dividends,Series.divisors)

Response:
def divideSeries(requestContext, dividendSeriesList, divisorSeriesList):
    """
    Takes a dividend metric and a divisor metric and draws the division result.
    A constant may *not* be passed. To divide by a constant, use the scale()
    function (which is essentially a multiplication operation) and use the
    inverse of the dividend. (Division by 8 = multiplication by 1/8 or 0.125)

    Example::

        &target=divideSeries(Series.dividends,Series.divisors)

    """
    if len(divisorSeriesList) == 0:
        for series in dividendSeriesList:
            series.name = "divideSeries(%s,MISSING)" % series.name
            series.pathExpression = series.name
            for i in range(len(series)):
                series[i] = None
            return dividendSeriesList
    if len(divisorSeriesList) > 1:
        raise ValueError(
            "divideSeries second argument must reference exactly 1 series"
            " (got {0})".format(len(divisorSeriesList)))

    [divisorSeries] = divisorSeriesList
    results = []

    for dividendSeries in dividendSeriesList:
        name = "divideSeries(%s,%s)" % (dividendSeries.name,
                                        divisorSeries.name)
        bothSeries = (dividendSeries, divisorSeries)
        step = reduce(lcm, [s.step for s in bothSeries])

        for s in bothSeries:
            s.consolidate(step / s.step)

        start = min([s.start for s in bothSeries])
        end = max([s.end for s in bothSeries])
        end -= (end - start) % step

        values = (safeDiv(v1, v2) for v1, v2 in zip_longest(*bothSeries))

        quotientSeries = TimeSeries(name, start, end, step, values)
        quotientSeries.pathExpression = name
        results.append(quotientSeries)

    return results


Instruction:
Write a Python 3 function for
taking two or more series and multiplies their points.

Response:
def multiplySeries(requestContext, *seriesLists):
    """
    Takes two or more series and multiplies their points. A constant may not be
    used. To multiply by a constant, use the scale() function.

    Example::

        &target=multiplySeries(Series.dividends,Series.divisors)

    """

    if not seriesLists or not any(seriesLists):
        return []
    seriesList, start, end, step = normalize(seriesLists)

    if len(seriesList) == 1:
        return seriesList

    name = "multiplySeries(%s)" % ','.join([s.name for s in seriesList])
    product = map(lambda x: safeMul(*x), zip_longest(*seriesList))
    resultSeries = TimeSeries(name, start, end, step, product)
    resultSeries.pathExpression = name
    return [resultSeries]


Instruction:
Can you create a Python 3 function that
takes a series of average values and a series of weights and produces a weighted average for all values.

Response:
def weightedAverage(requestContext, seriesListAvg, seriesListWeight, *nodes):
    """
    Takes a series of average values and a series of weights and
    produces a weighted average for all values.

    The corresponding values should share one or more zero-indexed nodes.

    Example::

        &target=weightedAverage(*.transactions.mean,*.transactions.count,0)
        &target=weightedAverage(*.transactions.mean,*.transactions.count,1,3,4)

    """

    if isinstance(nodes, int):
        nodes = [nodes]

    sortedSeries = {}

    for seriesAvg, seriesWeight in zip_longest(
            seriesListAvg, seriesListWeight):
        key = ''
        for node in nodes:
            key += seriesAvg.name.split(".")[node]

        sortedSeries.setdefault(key, {})
        sortedSeries[key]['avg'] = seriesAvg

        key = ''
        for node in nodes:
            key += seriesWeight.name.split(".")[node]

        sortedSeries.setdefault(key, {})
        sortedSeries[key]['weight'] = seriesWeight

    productList = []

    for key in sortedSeries:
        if 'weight' not in sortedSeries[key]:
            continue
        if 'avg' not in sortedSeries[key]:
            continue

        seriesWeight = sortedSeries[key]['weight']
        seriesAvg = sortedSeries[key]['avg']

        productValues = [safeMul(val1, val2)
                         for val1, val2
                         in zip_longest(seriesAvg, seriesWeight)]
        name = 'product(%s,%s)' % (seriesWeight.name, seriesAvg.name)
        productSeries = TimeSeries(name, seriesAvg.start, seriesAvg.end,
                                   seriesAvg.step, productValues)
        productSeries.pathExpression = name
        productList.append(productSeries)

    if not productList:
        return []

    [sumProducts] = sumSeries(requestContext, productList)
    [sumWeights] = sumSeries(requestContext, seriesListWeight)

    resultValues = [safeDiv(val1, val2)
                    for val1, val2 in zip_longest(sumProducts, sumWeights)]
    name = "weightedAverage(%s, %s, %s)" % (
        ','.join(sorted(set(s.pathExpression for s in seriesListAvg))),
        ','.join(sorted(set(s.pathExpression for s in seriesListWeight))),
        ','.join(map(str, nodes)))
    resultSeries = TimeSeries(name, sumProducts.start, sumProducts.end,
                              sumProducts.step, resultValues)
    resultSeries.pathExpression = name
    return resultSeries


Instruction:
Can you tell what is the following Python 3 function doing
def exponentialMovingAverage(requestContext, seriesList, windowSize):
    # EMA = C * (current_value) + (1 - C) + EMA
    # C = 2 / (windowSize + 1)

    # The following was copied from movingAverage, and altered for ema
    if not seriesList:
        return []
    windowInterval = None
    if isinstance(windowSize, six.string_types):
        delta = parseTimeOffset(windowSize)
        windowInterval = abs(delta.seconds + (delta.days * 86400))

    # set previewSeconds and constant based on windowSize string or integer
    if windowInterval:
        previewSeconds = windowInterval
        constant = (float(2) / (int(windowInterval) + 1))
    else:
        previewSeconds = max([s.step for s in seriesList]) * int(windowSize)
        constant = (float(2) / (int(windowSize) + 1))

    # ignore original data and pull new, including our preview
    # data from earlier is needed to calculate the early results
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    result = []

    for series in previewList:
        if windowInterval:
            windowPoints = windowInterval // series.step
        else:
            windowPoints = int(windowSize)

        if isinstance(windowSize, six.string_types):
            newName = 'exponentialMovingAverage(%s,"%s")' % (
                series.name, windowSize)
        else:
            newName = "exponentialMovingAverage(%s,%s)" % (
                series.name, windowSize)

        newSeries = TimeSeries(newName, series.start + previewSeconds,
                               series.end, series.step, [])
        newSeries.pathExpression = newName
        window_sum = safeSum(series[:windowPoints]) or 0
        count = safeLen(series[:windowPoints])
        ema = safeDiv(window_sum, count)
        newSeries.append(ema)

        if ema is None:
            ema = 0.0
        else:
            ema = float(ema)

        for i in range(windowPoints, len(series) - 1):
            if series[i] is not None:
                ema = (float(constant) * float(series[i]) +
                       (1 - float(constant)) * float(ema))
                newSeries.append(round(ema, 3))
            else:
                newSeries.append(None)

        result.append(newSeries)

    return result

Response: Generates an exponential Moving Average for a list of series and a window size.


Instruction:
Write a Python 3 script for
returning a list of nodes that can be used to build a moving median of a metric or metric or a wildcard seriesList followed by a number N of datapoints or a time interval.

Response:
def movingMedian(requestContext, seriesList, windowSize):
    """
    Graphs the moving median of a metric (or metrics) over a fixed number of
    past points, or a time interval.

    Takes one metric or a wildcard seriesList followed by a number N of
    datapoints or a quoted string with a length of time like '1hour' or '5min'
    (See ``from / until`` in the render\_api_ for examples of time formats).
    Graphs the median of the preceding datapoints for each point on the graph.

    Example::

        &target=movingMedian(Server.instance01.threads.busy,10)
        &target=movingMedian(Server.instance*.threads.idle,'5min')

    """
    if not seriesList:
        return []
    windowInterval = None
    if isinstance(windowSize, six.string_types):
        delta = parseTimeOffset(windowSize)
        windowInterval = to_seconds(delta)

    if windowInterval:
        previewSeconds = windowInterval
    else:
        previewSeconds = max([s.step for s in seriesList]) * int(windowSize)

    # ignore original data and pull new, including our preview
    # data from earlier is needed to calculate the early results
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    result = []

    for series in previewList:
        if windowInterval:
            windowPoints = windowInterval // series.step
        else:
            windowPoints = int(windowSize)

        if isinstance(windowSize, six.string_types):
            newName = 'movingMedian(%s,"%s")' % (series.name, windowSize)
        else:
            newName = "movingMedian(%s,%s)" % (series.name, windowSize)
        newSeries = TimeSeries(newName, series.start + previewSeconds,
                               series.end, series.step, [])
        newSeries.pathExpression = newName

        for i in range(windowPoints, len(series)):
            window = series[i - windowPoints:i]
            nonNull = [v for v in window if v is not None]
            if nonNull:
                m_index = len(nonNull) // 2
                newSeries.append(sorted(nonNull)[m_index])
            else:
                newSeries.append(None)
        result.append(newSeries)

    return result


Instruction:
Can you implement a function in Python 3 that
takes one metric or a wildcard seriesList followed by a constant and multiplies the datapoint by the constant provided at each point.

Response:
def scale(requestContext, seriesList, factor):
    """
    Takes one metric or a wildcard seriesList followed by a constant, and
    multiplies the datapoint by the constant provided at each point.

    Example::

        &target=scale(Server.instance01.threads.busy,10)
        &target=scale(Server.instance*.threads.busy,10)

    """
    for series in seriesList:
        series.name = "scale(%s,%g)" % (series.name, float(factor))
        series.pathExpression = series.name
        for i, value in enumerate(series):
            series[i] = safeMul(value, factor)
    return seriesList


Instruction:
Can you create a Python 3 function that
scales the values of a seriesList to a number of seconds.

Response:
def scaleToSeconds(requestContext, seriesList, seconds):
    """
    Takes one metric or a wildcard seriesList and returns "value per seconds"
    where seconds is a last argument to this functions.

    Useful in conjunction with derivative or integral function if you want
    to normalize its result to a known resolution for arbitrary retentions
    """

    for series in seriesList:
        series.name = "scaleToSeconds(%s,%d)" % (series.name, seconds)
        series.pathExpression = series.name
        factor = seconds * 1.0 / series.step
        for i, value in enumerate(series):
            series[i] = safeMul(value, factor)
    return seriesList


Instruction:
Implement a Python 3 function for
taking one metric or a wildcard seriesList followed by a constant and raises the datapoint by the power of the constant provided at each point.

Response:
def pow(requestContext, seriesList, factor):
    """
    Takes one metric or a wildcard seriesList followed by a constant, and
    raises the datapoint by the power of the constant provided at each point.

    Example::

        &target=pow(Server.instance01.threads.busy,10)
        &target=pow(Server.instance*.threads.busy,10)

    """
    for series in seriesList:
        series.name = "pow(%s,%g)" % (series.name, float(factor))
        series.pathExpression = series.name
        for i, value in enumerate(series):
            series[i] = safePow(value, factor)
    return seriesList


Instruction:
Write a Python 3 script to
take two or more series and pows their points. A constant line may be be used.

Response:
def powSeries(requestContext, *seriesLists):
    """
    Takes two or more series and pows their points. A constant line may be
    used.

    Example::

        &target=powSeries(Server.instance01.app.requests,
                          Server.instance01.app.replies)

    """
    if not seriesLists or not any(seriesLists):
        return []
    seriesList, start, end, step = normalize(seriesLists)
    name = "powSeries(%s)" % ','.join([s.name for s in seriesList])
    values = []
    for row in zip_longest(*seriesList):
        first = True
        tmpVal = None
        for element in row:
            # If it is a first iteration - tmpVal needs to be element
            if first:
                tmpVal = element
                first = False
            else:
                tmpVal = safePow(tmpVal, element)
        values.append(tmpVal)
    series = TimeSeries(name, start, end, step, values)
    series.pathExpression = name
    return [series]


Instruction:
Can you write a function in Python 3 where it
takes one metric or a wildcard seriesList and computes the square root of each datapoint.

Response:
def squareRoot(requestContext, seriesList):
    """
    Takes one metric or a wildcard seriesList, and computes the square root
    of each datapoint.

    Example::

        &target=squareRoot(Server.instance01.threads.busy)

    """
    for series in seriesList:
        series.name = "squareRoot(%s)" % (series.name)
        for i, value in enumerate(series):
            series[i] = safePow(value, 0.5)
    return seriesList


Instruction:
Can you create a Python 3 function that
takes one metric or a wildcard seriesList and applies the mathematical abs function to each datapoint transforming it to its absolute value.

Response:
def absolute(requestContext, seriesList):
    """
    Takes one metric or a wildcard seriesList and applies the mathematical abs
    function to each datapoint transforming it to its absolute value.

    Example::

        &target=absolute(Server.instance01.threads.busy)
        &target=absolute(Server.instance*.threads.busy)
    """
    for series in seriesList:
        series.name = "absolute(%s)" % (series.name)
        series.pathExpression = series.name
        for i, value in enumerate(series):
            series[i] = safeAbs(value)
    return seriesList


Instruction:
Given the following Python 3 function, write the documentation
def offset(requestContext, seriesList, factor):
    for series in seriesList:
        series.name = "offset(%s,%g)" % (series.name, float(factor))
        series.pathExpression = series.name
        for i, value in enumerate(series):
            if value is not None:
                series[i] = value + factor
    return seriesList

Response: Adds a constant to each datapoint in seriesList and returns the seriesList with the given factor.


Instruction:
Write a Python 3 script to
offset a metric or wildcard seriesList by subtracting the minimum value in each datapoint.

Response:
def offsetToZero(requestContext, seriesList):
    """
    Offsets a metric or wildcard seriesList by subtracting the minimum
    value in the series from each datapoint.

    Useful to compare different series where the values in each series
    may be higher or lower on average but you're only interested in the
    relative difference.

    An example use case is for comparing different round trip time
    results. When measuring RTT (like pinging a server), different
    devices may come back with consistently different results due to
    network latency which will be different depending on how many
    network hops between the probe and the device. To compare different
    devices in the same graph, the network latency to each has to be
    factored out of the results. This is a shortcut that takes the
    fastest response (lowest number in the series) and sets that to zero
    and then offsets all of the other datapoints in that series by that
    amount. This makes the assumption that the lowest response is the
    fastest the device can respond, of course the more datapoints that
    are in the series the more accurate this assumption is.

    Example::

        &target=offsetToZero(Server.instance01.responseTime)
        &target=offsetToZero(Server.instance*.responseTime)

    """
    for series in seriesList:
        series.name = "offsetToZero(%s)" % (series.name)
        minimum = safeMin(series)
        for i, value in enumerate(series):
            if value is not None:
                series[i] = value - minimum
    return seriesList


Instruction:
Can you generate the documentation for the following Python 3 function
def movingAverage(requestContext, seriesList, windowSize):
    if not seriesList:
        return []
    windowInterval = None
    if isinstance(windowSize, six.string_types):
        delta = parseTimeOffset(windowSize)
        windowInterval = to_seconds(delta)

    if windowInterval:
        previewSeconds = windowInterval
    else:
        previewSeconds = max([s.step for s in seriesList]) * int(windowSize)

    # ignore original data and pull new, including our preview
    # data from earlier is needed to calculate the early results
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    result = []

    for series in previewList:
        if windowInterval:
            windowPoints = windowInterval // series.step
        else:
            windowPoints = int(windowSize)

        if isinstance(windowSize, six.string_types):
            newName = 'movingAverage(%s,"%s")' % (series.name, windowSize)
        else:
            newName = "movingAverage(%s,%s)" % (series.name, windowSize)
        newSeries = TimeSeries(newName, series.start + previewSeconds,
                               series.end, series.step, [])
        newSeries.pathExpression = newName

        windowSum = safeSum(series[:windowPoints]) or 0
        count = safeLen(series[:windowPoints])
        newSeries.append(safeDiv(windowSum, count))
        for n, last in enumerate(series[windowPoints:-1]):
            if series[n] is not None:
                windowSum -= series[n]
                count -= 1
            if last is not None:
                windowSum += last
                count += 1
            newSeries.append(safeDiv(windowSum, count))

        result.append(newSeries)

    return result

Response: Returns a list of nodes that can be used to calculate the moving average of a metric or metric or metric at a fixed number of points.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def movingSum(requestContext, seriesList, windowSize):
    if not seriesList:
        return []
    windowInterval = None
    if isinstance(windowSize, six.string_types):
        delta = parseTimeOffset(windowSize)
        windowInterval = abs(delta.seconds + (delta.days * 86400))

    if windowInterval:
        previewSeconds = windowInterval
    else:
        previewSeconds = max([s.step for s in seriesList]) * int(windowSize)

    # ignore original data and pull new, including our preview
    # data from earlier is needed to calculate the early results
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    result = []

    for series in previewList:
        if windowInterval:
            windowPoints = windowInterval // series.step
        else:
            windowPoints = int(windowSize)

        if isinstance(windowSize, six.string_types):
            newName = 'movingSum(%s,"%s")' % (series.name, windowSize)
        else:
            newName = "movingSum(%s,%s)" % (series.name, windowSize)

        newSeries = TimeSeries(newName, series.start + previewSeconds,
                               series.end, series.step, [])
        newSeries.pathExpression = newName

        window_sum = safeSum(series[:windowPoints])
        newSeries.append(window_sum)
        for n, last in enumerate(series[windowPoints:-1]):
            if series[n] is not None:
                window_sum -= series[n]
            if last is not None:
                window_sum = (window_sum or 0) + last
            newSeries.append(window_sum)

        result.append(newSeries)

    return result

Response: Returns a list of all the moving sums of a metric or metric or a wildcard seriesList followed by a number N of datapoints or a time interval.


Instruction:
Implement a Python 3 function for
returning a list of time series that can be moved over a fixed number of points or a wildcard seriesList followed by a time interval.

Response:
def movingMax(requestContext, seriesList, windowSize):
    """
    Graphs the moving maximum of a metric (or metrics) over a fixed number of
    past points, or a time interval.

    Takes one metric or a wildcard seriesList followed by a number N of
    datapoints or a quoted string with a length of time like '1hour' or '5min'
    (See ``from / until`` in the render\_api_ for examples of time formats).
    Graphs the maximum of the preceeding datapoints for each point on the
    graph.

    Example::

      &target=movingMax(Server.instance01.requests,10)
      &target=movingMax(Server.instance*.errors,'5min')

    """
    if not seriesList:
        return []
    windowInterval = None
    if isinstance(windowSize, six.string_types):
        delta = parseTimeOffset(windowSize)
        windowInterval = abs(delta.seconds + (delta.days * 86400))

    if windowInterval:
        previewSeconds = windowInterval
    else:
        previewSeconds = max([s.step for s in seriesList]) * int(windowSize)

    # ignore original data and pull new, including our preview
    # data from earlier is needed to calculate the early results
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    result = []

    for series in previewList:
        if windowInterval:
            windowPoints = windowInterval // series.step
        else:
            windowPoints = int(windowSize)

        if isinstance(windowSize, six.string_types):
            newName = 'movingMax(%s,"%s")' % (series.name, windowSize)
        else:
            newName = "movingMax(%s,%s)" % (series.name, windowSize)

        newSeries = TimeSeries(newName, series.start + previewSeconds,
                               series.end, series.step, [])
        newSeries.pathExpression = newName
        for i in range(windowPoints, len(series)):
            window = series[i - windowPoints:i]
            newSeries.append(safeMax(window))

        result.append(newSeries)

    return result


Instruction:
Explain what the following Python 3 code does
def consolidateBy(requestContext, seriesList, consolidationFunc):
    for series in seriesList:
        # datalib will throw an exception, so it's not necessary to validate
        # here
        series.consolidationFunc = consolidationFunc
        series.name = 'consolidateBy(%s,"%s")' % (series.name,
                                                  series.consolidationFunc)
        series.pathExpression = series.name
    return seriesList

Response: This function is used to consolidate the values of one metric or a wildcard seriesList.


Instruction:
Can you generate the documentation for the following Python 3 function
def delay(requestContext, seriesList, steps):
    results = []
    for series in seriesList:
        newValues = []
        prev = []
        for val in series:
            if len(prev) < steps:
                newValues.append(None)
                prev.append(val)
                continue
            newValues.append(prev.pop(0))
            prev.append(val)
        newName = "delay(%s,%d)" % (series.name, steps)
        newSeries = TimeSeries(newName, series.start, series.end, series.step,
                               newValues)
        newSeries.pathExpression = newName
        results.append(newSeries)
    return results

Response: This function takes a list of series and returns a list of new time - displacement series that will be shifted later by an integer number of steps.


Instruction:
Can you generate the documentation for the following Python 3 function
def integral(requestContext, seriesList):
    results = []
    for series in seriesList:
        newValues = []
        current = 0.0
        for val in series:
            if val is None:
                newValues.append(None)
            else:
                current += val
                newValues.append(current)
        newName = "integral(%s)" % series.name
        newSeries = TimeSeries(newName, series.start, series.end, series.step,
                               newValues)
        newSeries.pathExpression = newName
        results.append(newSeries)
    return results

Response: This function is used to add a series to the graph.


Instruction:
How would you explain what the following Python 3 function does
def integralByInterval(requestContext, seriesList, intervalUnit):
    intervalDuration = int(to_seconds(parseTimeOffset(intervalUnit)))
    startTime = int(epoch(requestContext['startTime']))
    results = []
    for series in seriesList:
        newValues = []
        # current time within series iteration
        currentTime = series.start
        # current accumulated value
        current = 0.0
        for val in series:
            # reset integral value if crossing an interval boundary
            if (
                ((currentTime - startTime) // intervalDuration) !=
                ((currentTime - startTime - series.step) // intervalDuration)
            ):
                current = 0.0
            if val is None:
                # keep previous value since val can be None when resetting
                # current to 0.0
                newValues.append(current)
            else:
                current += val
                newValues.append(current)
            currentTime += series.step
        newName = "integralByInterval(%s,'%s')" % (series.name, intervalUnit)
        newSeries = TimeSeries(newName, series.start, series.end, series.step,
                               newValues)
        newSeries.pathExpression = newName
        results.append(newSeries)
    return results

Response: This function is used to integrate a list of seriesList by a given interval.


Instruction:
How would you implement a function in Python 3 that
takes one metric or a wildcard seriesList and creates a new series that is stacked.

Response:
def stacked(requestContext, seriesLists, stackName='__DEFAULT__'):
    """
    Takes one metric or a wildcard seriesList and change them so they are
    stacked. This is a way of stacking just a couple of metrics without having
    to use the stacked area mode (that stacks everything). By means of this a
    mixed stacked and non stacked graph can be made

    It can also take an optional argument with a name of the stack, in case
    there is more than one, e.g. for input and output metrics.

    Example::

        &target=stacked(company.server.application01.ifconfig.TXPackets, 'tx')

    """
    if 'totalStack' in requestContext:
        totalStack = requestContext['totalStack'].get(stackName, [])
    else:
        requestContext['totalStack'] = {}
        totalStack = []
    results = []
    for series in seriesLists:
        newValues = []
        for i in range(len(series)):
            if len(totalStack) <= i:
                totalStack.append(0)

            if series[i] is not None:
                totalStack[i] += series[i]
                newValues.append(totalStack[i])
            else:
                newValues.append(None)

        # Work-around for the case when legend is set
        if stackName == '__DEFAULT__':
            newName = "stacked(%s)" % series.name
        else:
            newName = series.name

        newSeries = TimeSeries(newName, series.start, series.end, series.step,
                               newValues)
        newSeries.options['stacked'] = True
        newSeries.pathExpression = newName
        results.append(newSeries)
    requestContext['totalStack'][stackName] = totalStack
    return results


Instruction:
Create a Python 3 function to
return the vertical area in between the two series in seriesList.

Response:
def areaBetween(requestContext, *seriesLists):
    """
    Draws the vertical area in between the two series in seriesList. Useful for
    visualizing a range such as the minimum and maximum latency for a service.

    areaBetween expects **exactly one argument** that results in exactly two
    series (see example below). The order of the lower and higher values
    series does not matter. The visualization only works when used in
    conjunction with ``areaMode=stacked``.

    Most likely use case is to provide a band within which another metric
    should move. In such case applying an ``alpha()``, as in the second
    example, gives best visual results.

    Example::

      &target=areaBetween(service.latency.{min,max})&areaMode=stacked

      &target=alpha(areaBetween(service.latency.{min,max}),0.3)&areaMode=stacked

    If for instance, you need to build a seriesList, you should use the
    ``group`` function, like so::

      &target=areaBetween(group(minSeries(a.*.min),maxSeries(a.*.max)))
    """
    if len(seriesLists) == 1:
        [seriesLists] = seriesLists
    assert len(seriesLists) == 2, ("areaBetween series argument must "
                                   "reference *exactly* 2 series")
    lower, upper = seriesLists
    if len(lower) == 1:
        [lower] = lower
    if len(upper) == 1:
        [upper] = upper
    lower.options['stacked'] = True
    lower.options['invisible'] = True

    upper.options['stacked'] = True
    lower.name = upper.name = "areaBetween(%s)" % upper.pathExpression
    return [lower, upper]


Instruction:
Create a Python 3 function to
run series names through a regex search and replace.

Response:
def aliasSub(requestContext, seriesList, search, replace):
    """
    Runs series names through a regex search/replace.

   Example::

        &target=aliasSub(ip.*TCP*,"^.*TCP(\d+)","\\1")
    """
    try:
        seriesList.name = re.sub(search, replace, seriesList.name)
    except AttributeError:
        for series in seriesList:
            series.name = re.sub(search, replace, series.name)
    return seriesList


Instruction:
Write a Python 3 script for
adding a metric name to the seriesList.

Response:
def alias(requestContext, seriesList, newName):
    """
    Takes one metric or a wildcard seriesList and a string in quotes.
    Prints the string instead of the metric name in the legend.

    Example::

        &target=alias(Sales.widgets.largeBlue,"Large Blue Widgets")

    """
    try:
        seriesList.name = newName
    except AttributeError:
        for series in seriesList:
            series.name = newName
    return seriesList


Instruction:
Make a summary of the following Python 3 code
def cactiStyle(requestContext, seriesList, system=None, units=None):
    def fmt(x):
        if system:
            if units:
                return "%.2f %s" % format_units(x, system=system, units=units)
            else:
                return "%.2f%s" % format_units(x, system=system)
        else:
            if units:
                return "%.2f %s" % (x, units)
            else:
                return "%.2f" % x
    nameLen = max([0] + [len(series.name) for series in seriesList])
    lastLen = max([0] + [len(fmt(int(safeLast(series) or 3)))
                         for series in seriesList]) + 3
    maxLen = max([0] + [len(fmt(int(safeMax(series) or 3)))
                        for series in seriesList]) + 3
    minLen = max([0] + [len(fmt(int(safeMin(series) or 3)))
                        for series in seriesList]) + 3
    for series in seriesList:
        last = safeLast(series)
        maximum = safeMax(series)
        minimum = safeMin(series)
        if last is None:
            last = NAN
        else:
            last = fmt(float(last))

        if maximum is None:
            maximum = NAN
        else:
            maximum = fmt(float(maximum))
        if minimum is None:
            minimum = NAN
        else:
            minimum = fmt(float(minimum))

        series.name = "%*s Current:%*s Max:%*s Min:%*s " % (
            -nameLen, series.name, -lastLen, last,
            -maxLen, maximum, -minLen, minimum)
    return seriesList

Response: Returns a string that can be used to align a list of series in a cacti file.


Instruction:
Write a Python 3 script to
return the first metric path in an expression.

Response:
def _getFirstPathExpression(name):
    """Returns the first metric path in an expression."""
    tokens = grammar.parseString(name)
    pathExpression = None
    while pathExpression is None:
        if tokens.pathExpression:
            pathExpression = tokens.pathExpression
        elif tokens.expression:
            tokens = tokens.expression
        elif tokens.call:
            tokens = tokens.call.args[0]
        else:
            break
    return pathExpression


Instruction:
Can you create a Python 3 function that
takes a seriesList and applies an alias derived from one or more node names.

Response:
def aliasByNode(requestContext, seriesList, *nodes):
    """
    Takes a seriesList and applies an alias derived from one or more "node"
    portion/s of the target name. Node indices are 0 indexed.

    Example::

        &target=aliasByNode(ganglia.*.cpu.load5,1)

    """
    for series in seriesList:
        pathExpression = _getFirstPathExpression(series.name)
        metric_pieces = pathExpression.split('.')
        series.name = '.'.join(metric_pieces[n] for n in nodes)
    return seriesList


Instruction:
Here you have a function in Python 3, explain what it does
def legendValue(requestContext, seriesList, *valueTypes):
    valueFuncs = {
        'avg': lambda s: safeDiv(safeSum(s), safeLen(s)),
        'total': safeSum,
        'min': safeMin,
        'max': safeMax,
        'last': safeLast,
    }
    system = None
    if valueTypes[-1] in ('si', 'binary'):
        system = valueTypes[-1]
        valueTypes = valueTypes[:-1]
    for valueType in valueTypes:
        valueFunc = valueFuncs.get(valueType, lambda s: '(?)')
        if system is None:
            for series in seriesList:
                series.name += " (%s: %s)" % (valueType, valueFunc(series))
        else:
            for series in seriesList:
                value = valueFunc(series)
                formatted = None
                if value is not None:
                    formatted = "%.2f%s" % format_units(value, system=system)
                series.name = "%-20s%-5s%-10s" % (series.name, valueType,
                                                  formatted)
    return seriesList

Response: Adds a value to the name of the current resource in the legend.


Instruction:
Write a Python 3 function for
assigning the given alpha transparency setting to the series. Takes a float between 0 and 1.

Response:
def alpha(requestContext, seriesList, alpha):
    """
    Assigns the given alpha transparency setting to the series. Takes a float
    value between 0 and 1.
    """
    for series in seriesList:
        series.options['alpha'] = alpha
    return seriesList


Instruction:
How would you explain what the following Python 3 function does
def color(requestContext, seriesList, theColor):
    for series in seriesList:
        series.color = theColor
    return seriesList

Response: Assigns the given color to the seriesList


Instruction:
Explain what the following Python 3 code does
def substr(requestContext, seriesList, start=0, stop=0):
    for series in seriesList:
        left = series.name.rfind('(') + 1
        right = series.name.find(')')
        if right < 0:
            right = len(series.name)+1
        cleanName = series.name[left:right:].split('.')
        if int(stop) == 0:
            series.name = '.'.join(cleanName[int(start)::])
        else:
            series.name = '.'.join(cleanName[int(start):int(stop):])

        # substr(func(a.b,'c'),1) becomes b instead of b,'c'
        series.name = re.sub(',.*$', '', series.name)
    return seriesList

Response: Takes one metric or a wildcard seriesList followed by 1 or 2 integers. Prints the metric name in the seriesList followed by dots.


Instruction:
Explain what the following Python 3 code does
def logarithm(requestContext, seriesList, base=10):
    results = []
    for series in seriesList:
        newValues = []
        for val in series:
            if val is None:
                newValues.append(None)
            elif val <= 0:
                newValues.append(None)
            else:
                newValues.append(math.log(val, base))
        newName = "log(%s, %s)" % (series.name, base)
        newSeries = TimeSeries(newName, series.start, series.end, series.step,
                               newValues)
        newSeries.pathExpression = newName
        results.append(newSeries)
    return results

Response:
Takes one metric or a wildcard seriesList a base and draws the y - axis in
    logarithmic format.


Instruction:
How would you implement a function in Python 3 that
takes one metric or a wildcard seriesList followed by a constant n Draws only the metrics with a maximum value below n

Response:
def maximumBelow(requestContext, seriesList, n):
    """
    Takes one metric or a wildcard seriesList followed by a constant n.
    Draws only the metrics with a maximum value below n.

    Example::

        &target=maximumBelow(system.interface.eth*.packetsSent,1000)

    This would only display interfaces which always sent less than 1000
    packets/min.
    """
    results = []
    for series in seriesList:
        val = safeMax(series)
        if val is None or val <= n:
            results.append(series)
    return results


Instruction:
Write a Python 3 function for
taking one metric or a wildcard seriesList followed by a constant n Draws only the metrics with a minimum value below n

Response:
def minimumBelow(requestContext, seriesList, n):
    """
    Takes one metric or a wildcard seriesList followed by a constant n.
    Draws only the metrics with a minimum value below n.

    Example::

        &target=minimumBelow(system.interface.eth*.packetsSent,1000)

    This would only display interfaces which sent at one point less than
    1000 packets/min.
    """
    results = []
    for series in seriesList:
        val = safeMin(series)
        if val is None or val <= n:
            results.append(series)
    return results


Instruction:
Make a summary of the following Python 3 code
def highestMax(requestContext, seriesList, n=1):
    result_list = sorted(seriesList, key=lambda s: safeMax(s))[-n:]
    return sorted(result_list, key=lambda s: max(s), reverse=True)

Response: Takes one metric or a wildcard seriesList followed by an integer N. Returns a seriesList with the N most busy threads in the time period specified.


Instruction:
Write a Python 3 function that can
take one metric or a wildcard seriesList followed by an integer N. Returns a list of metrics that are above n.

Response:
def currentAbove(requestContext, seriesList, n):
    """
    Takes one metric or a wildcard seriesList followed by an integer N.
    Out of all metrics passed, draws only the metrics whose value is above N
    at the end of the time period specified.

    Example::

        &target=currentAbove(server*.instance*.threads.busy,50)

    Draws the servers with more than 50 busy threads.

    """
    results = []
    for series in seriesList:
        val = safeLast(series)
        if val is not None and val >= n:
            results.append(series)
    return results


Instruction:
Here you have a function in Python 3, explain what it does
def averageAbove(requestContext, seriesList, n):
    results = []
    for series in seriesList:
        val = safeAvg(series)
        if val is not None and val >= n:
            results.append(series)
    return results

Response: Takes one metric or a wildcard seriesList followed by an integer N and draws only the metrics with an average value above N for the time period specified.


Instruction:
Implement a Python 3 function for
calculating the percentile of a set of points.

Response:
def _getPercentile(points, n, interpolate=False):
    """
    Percentile is calculated using the method outlined in the NIST Engineering
    Statistics Handbook:
    http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm
    """
    sortedPoints = sorted(not_none(points))
    if len(sortedPoints) == 0:
        return None
    fractionalRank = (n/100.0) * (len(sortedPoints) + 1)
    rank = int(fractionalRank)
    rankFraction = fractionalRank - rank

    if not interpolate:
        rank += int(math.ceil(rankFraction))

    if rank == 0:
        percentile = sortedPoints[0]
    elif rank - 1 == len(sortedPoints):
        percentile = sortedPoints[-1]
    else:
        percentile = sortedPoints[rank - 1]  # Adjust for 0-index

    if interpolate:
        if rank != len(sortedPoints):  # if a next value exists
            nextValue = sortedPoints[rank]
            percentile = percentile + rankFraction * (nextValue - percentile)

    return percentile


Instruction:
How would you implement a function in Python 3 that
returns n - percent of each series in the seriesList.

Response:
def nPercentile(requestContext, seriesList, n):
    """Returns n-percent of each series in the seriesList."""
    assert n, 'The requested percent is required to be greater than 0'

    results = []
    for s in seriesList:
        # Create a sorted copy of the TimeSeries excluding None values in the
        # values list.
        s_copy = TimeSeries(s.name, s.start, s.end, s.step,
                            sorted(not_none(s)))
        if not s_copy:
            continue    # Skip this series because it is empty.

        perc_val = _getPercentile(s_copy, n)
        if perc_val is not None:
            name = 'nPercentile(%s, %g)' % (s_copy.name, n)
            point_count = int((s.end - s.start)/s.step)
            perc_series = TimeSeries(name, s_copy.start, s_copy.end,
                                     s_copy.step, [perc_val] * point_count)
            perc_series.pathExpression = name
            results.append(perc_series)
    return results


Instruction:
Make a summary of the following Python 3 code
def averageOutsidePercentile(requestContext, seriesList, n):
    averages = [safeAvg(s) for s in seriesList]

    if n < 50:
        n = 100 - n

    lowPercentile = _getPercentile(averages, 100 - n)
    highPercentile = _getPercentile(averages, n)

    return [s for s in seriesList
            if not lowPercentile < safeAvg(s) < highPercentile]

Response: Returns a list of functions lying outside an average percentile interval.


Instruction:
Given the following Python 3 function, write the documentation
def removeBetweenPercentile(requestContext, seriesList, n):
    if n < 50:
        n = 100 - n

    transposed = list(zip_longest(*seriesList))

    lowPercentiles = [_getPercentile(col, 100-n) for col in transposed]
    highPercentiles = [_getPercentile(col, n) for col in transposed]

    return [l for l in seriesList
            if sum([not lowPercentiles[index] < val < highPercentiles[index]
                    for index, val in enumerate(l)]) > 0]

Response: Removes lines who do not have a value lying in the x - percentile of all


Instruction:
Given the following Python 3 function, write the documentation
def removeAboveValue(requestContext, seriesList, n):
    for s in seriesList:
        s.name = 'removeAboveValue(%s, %g)' % (s.name, n)
        s.pathExpression = s.name
        for (index, val) in enumerate(s):
            if val is None:
                continue
            if val > n:
                s[index] = None

    return seriesList

Response: Removes data above the given threshold from the series or list of seriesList provided.


Instruction:
Can you write a function in Python 3 where it
removes data below the nth percentile from the series or list of seriesList provided. Values below this percentile are assigned a value of None.

Response:
def removeBelowPercentile(requestContext, seriesList, n):
    """
    Removes data below the nth percentile from the series or list of series
    provided. Values below this percentile are assigned a value of None.
    """
    for s in seriesList:
        s.name = 'removeBelowPercentile(%s, %g)' % (s.name, n)
        s.pathExpression = s.name
        try:
            percentile = nPercentile(requestContext, [s], n)[0][0]
        except IndexError:
            continue
        for (index, val) in enumerate(s):
            if val is None:
                continue
            if val < percentile:
                s[index] = None

    return seriesList


Instruction:
Write a Python 3 function for
sorting the list of metrics by the metric name using either alphabetical or natural sorting.

Response:
def sortByName(requestContext, seriesList, natural=False):
    """
    Takes one metric or a wildcard seriesList.

    Sorts the list of metrics by the metric name using either alphabetical
    order or natural sorting. Natural sorting allows names containing numbers
    to be sorted more naturally, e.g:

    - Alphabetical sorting: server1, server11, server12, server2
    - Natural sorting: server1, server2, server11, server12

    """
    if natural:
        return list(sorted(seriesList, key=lambda x: paddedName(x.name)))
    else:
        return list(sorted(seriesList, key=lambda x: x.name))


Instruction:
Can you generate the documentation for the following Python 3 function
def sortByTotal(requestContext, seriesList):
    return list(sorted(seriesList, key=safeSum, reverse=True))

Response:
Sorts the list of metrics by the sum of values across the time period
   .


Instruction:
Can you tell what is the following Python 3 function doing
def useSeriesAbove(requestContext, seriesList, value, search, replace):
    newSeries = []

    for series in seriesList:
        newname = re.sub(search, replace, series.name)
        if safeMax(series) > value:
            n = evaluateTarget(requestContext, newname)
            if n is not None and len(n) > 0:
                newSeries.append(n[0])

    return newSeries

Response: Compares the maximum of each series against the given value.


Instruction:
Given the following Python 3 function, write the documentation
def mostDeviant(requestContext, seriesList, n):

    deviants = []
    for series in seriesList:
        mean = safeAvg(series)
        if mean is None:
            continue
        square_sum = sum([(value - mean) ** 2 for value in series
                          if value is not None])
        sigma = safeDiv(square_sum, safeLen(series))
        if sigma is None:
            continue
        deviants.append((sigma, series))
    return [series for sig, series in sorted(deviants,  # sort by sigma
                                             key=itemgetter(0),
                                             reverse=True)][:n]

Response: Returns the most deviant metrics in a seriesList.


Instruction:
Here you have a function in Python 3, explain what it does
def stdev(requestContext, seriesList, points, windowTolerance=0.1):

    # For this we take the standard deviation in terms of the moving average
    # and the moving average of series squares.
    for seriesIndex, series in enumerate(seriesList):
        stdevSeries = TimeSeries("stdev(%s,%d)" % (series.name, int(points)),
                                 series.start, series.end, series.step, [])
        stdevSeries.pathExpression = "stdev(%s,%d)" % (series.name,
                                                       int(points))

        validPoints = 0
        currentSum = 0
        currentSumOfSquares = 0
        for index, newValue in enumerate(series):
            # Mark whether we've reached our window size - dont drop points
            # out otherwise
            if index < points:
                bootstrapping = True
                droppedValue = None
            else:
                bootstrapping = False
                droppedValue = series[index - points]

            # Track non-None points in window
            if not bootstrapping and droppedValue is not None:
                validPoints -= 1
            if newValue is not None:
                validPoints += 1

            # Remove the value that just dropped out of the window
            if not bootstrapping and droppedValue is not None:
                currentSum -= droppedValue
                currentSumOfSquares -= droppedValue**2

            # Add in the value that just popped in the window
            if newValue is not None:
                currentSum += newValue
                currentSumOfSquares += newValue**2

            if (
                validPoints > 0 and
                float(validPoints) / points >= windowTolerance
            ):
                try:
                    deviation = math.sqrt(validPoints * currentSumOfSquares -
                                          currentSum**2) / validPoints
                except ValueError:
                    deviation = None
                stdevSeries.append(deviation)
            else:
                stdevSeries.append(None)

        seriesList[seriesIndex] = stdevSeries

    return seriesList

Response: This function is used to draw the standard deviation of all the datapoints in a seriesList. The points parameter can be specified as a wildcard seriesList followed by an integer N. The window size is calculated by the number of points in the seriesList.


Instruction:
How would you explain what the following Python 3 function does
def secondYAxis(requestContext, seriesList):
    for series in seriesList:
        series.options['secondYAxis'] = True
        series.name = 'secondYAxis(%s)' % series.name
    return seriesList

Response: Sets the series options for the secondary Y axis.


Instruction:
Write a Python 3 function for
performing a Holt - Winters forecast using the series as input data.

Response:
def holtWintersForecast(requestContext, seriesList):
    """
    Performs a Holt-Winters forecast using the series as input data. Data from
    one week previous to the series is used to bootstrap the initial forecast.
    """
    previewSeconds = 7 * 86400  # 7 days
    # ignore original data and pull new, including our preview
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    results = []
    for series in previewList:
        analysis = holtWintersAnalysis(series)
        predictions = analysis['predictions']
        windowPoints = previewSeconds // predictions.step
        result = TimeSeries("holtWintersForecast(%s)" % series.name,
                            predictions.start + previewSeconds,
                            predictions.end, predictions.step,
                            predictions[windowPoints:])
        result.pathExpression = result.name
        results.append(result)
    return results


Instruction:
Write a Python 3 function that can
perform a Holt-Winters forecast using the series as input data and plots upper and lower bands with the predicted forecast deviations.

Response:
def holtWintersConfidenceBands(requestContext, seriesList, delta=3):
    """
    Performs a Holt-Winters forecast using the series as input data and plots
    upper and lower bands with the predicted forecast deviations.
    """
    previewSeconds = 7 * 86400  # 7 days
    # ignore original data and pull new, including our preview
    newContext = requestContext.copy()
    newContext['startTime'] = (requestContext['startTime'] -
                               timedelta(seconds=previewSeconds))
    previewList = evaluateTokens(newContext, requestContext['args'][0])
    results = []
    for series in previewList:
        analysis = holtWintersAnalysis(series)

        data = analysis['predictions']
        windowPoints = previewSeconds // data.step
        forecast = TimeSeries(data.name, data.start + previewSeconds,
                              data.end, data.step, data[windowPoints:])
        forecast.pathExpression = data.pathExpression

        data = analysis['deviations']
        windowPoints = previewSeconds // data.step
        deviation = TimeSeries(data.name, data.start + previewSeconds,
                               data.end, data.step, data[windowPoints:])
        deviation.pathExpression = data.pathExpression

        seriesLength = len(forecast)
        i = 0
        upperBand = list()
        lowerBand = list()
        while i < seriesLength:
            forecast_item = forecast[i]
            deviation_item = deviation[i]
            i = i + 1
            if forecast_item is None or deviation_item is None:
                upperBand.append(None)
                lowerBand.append(None)
            else:
                scaled_deviation = delta * deviation_item
                upperBand.append(forecast_item + scaled_deviation)
                lowerBand.append(forecast_item - scaled_deviation)

        upperName = "holtWintersConfidenceUpper(%s)" % series.name
        lowerName = "holtWintersConfidenceLower(%s)" % series.name
        upperSeries = TimeSeries(upperName, forecast.start, forecast.end,
                                 forecast.step, upperBand)
        lowerSeries = TimeSeries(lowerName, forecast.start, forecast.end,
                                 forecast.step, lowerBand)
        upperSeries.pathExpression = series.pathExpression
        lowerSeries.pathExpression = series.pathExpression
        results.append(lowerSeries)
        results.append(upperSeries)
    return results


Instruction:
Can you generate a brief explanation for the following Python 3 code
def holtWintersAberration(requestContext, seriesList, delta=3):
    results = []
    for series in seriesList:
        confidenceBands = holtWintersConfidenceBands(requestContext, [series],
                                                     delta)
        lowerBand = confidenceBands[0]
        upperBand = confidenceBands[1]
        aberration = list()
        for i, actual in enumerate(series):
            if actual is None:
                aberration.append(0)
            elif upperBand[i] is not None and actual > upperBand[i]:
                aberration.append(actual - upperBand[i])
            elif lowerBand[i] is not None and actual < lowerBand[i]:
                aberration.append(actual - lowerBand[i])
            else:
                aberration.append(0)

        newName = "holtWintersAberration(%s)" % series.name
        results.append(TimeSeries(newName, series.start, series.end,
                                  series.step, aberration))
    return results

Response:
Performs a Holt - Winters forecast using the series as input data and plots
    positive or negative deviation of the series data from the forecast.


Instruction:
Given the following Python 3 function, write the documentation
def holtWintersConfidenceArea(requestContext, seriesList, delta=3):
    bands = holtWintersConfidenceBands(requestContext, seriesList, delta)
    results = areaBetween(requestContext, bands)
    for series in results:
        series.name = series.name.replace('areaBetween',
                                          'holtWintersConfidenceArea')
    return results

Response:
Performs a Holt - Winters forecast using the series as input data and plots
    the area between the upper and lower bands of the predicted forecast
    deviations.


Instruction:
Create a Python 3 function to
calculate factor and offset of linear regression function by least squares method.

Response:
def linearRegressionAnalysis(series):
    """
    Returns factor and offset of linear regression function by least
    squares method.

    """
    n = safeLen(series)
    sumI = sum([i for i, v in enumerate(series) if v is not None])
    sumV = sum([v for i, v in enumerate(series) if v is not None])
    sumII = sum([i * i for i, v in enumerate(series) if v is not None])
    sumIV = sum([i * v for i, v in enumerate(series) if v is not None])
    denominator = float(n * sumII - sumI * sumI)
    if denominator == 0:
        return None
    else:
        factor = (n * sumIV - sumI * sumV) / denominator / series.step
        offset = sumII * sumV - sumIV * sumI
        offset = offset / denominator - factor * series.start
        return factor, offset


Instruction:
Write a Python 3 script for
returning a list of TimeSeries objects that can be used to linear regression.

Response:
def linearRegression(requestContext, seriesList, startSourceAt=None,
                     endSourceAt=None):
    """
    Graphs the liner regression function by least squares method.

    Takes one metric or a wildcard seriesList, followed by a quoted string
    with the time to start the line and another quoted string with the time
    to end the line. The start and end times are inclusive (default range is
    from to until). See ``from / until`` in the render\_api_ for examples of
    time formats. Datapoints in the range is used to regression.

    Example::

        &target=linearRegression(Server.instance01.threads.busy,'-1d')
        &target=linearRegression(Server.instance*.threads.busy,
                                 "00:00 20140101","11:59 20140630")

    """
    from .app import evaluateTarget
    results = []
    sourceContext = requestContext.copy()
    if startSourceAt is not None:
        sourceContext['startTime'] = parseATTime(startSourceAt)
    if endSourceAt is not None:
        sourceContext['endTime'] = parseATTime(endSourceAt)

    sourceList = []
    for series in seriesList:
        source = evaluateTarget(sourceContext, series.pathExpression)
        sourceList.extend(source)

    for source, series in zip(sourceList, seriesList):
        newName = 'linearRegression(%s, %s, %s)' % (
            series.name,
            int(epoch(sourceContext['startTime'])),
            int(epoch(sourceContext['endTime'])))
        forecast = linearRegressionAnalysis(source)
        if forecast is None:
            continue
        factor, offset = forecast
        values = [offset + (series.start + i * series.step) * factor
                  for i in range(len(series))]
        newSeries = TimeSeries(newName, series.start, series.end,
                               series.step, values)
        newSeries.pathExpression = newSeries.name
        results.append(newSeries)
    return results


Instruction:
Can you generate a brief explanation for the following Python 3 code
def drawAsInfinite(requestContext, seriesList):
    for series in seriesList:
        series.options['drawAsInfinite'] = True
        series.name = 'drawAsInfinite(%s)' % series.name
    return seriesList

Response: Draw a line at infinity if the value is zero.


Instruction:
Create a Python 3 function to
set the line width of the selected metrics in a seriesList.

Response:
def lineWidth(requestContext, seriesList, width):
    """
    Takes one metric or a wildcard seriesList, followed by a float F.

    Draw the selected metrics with a line width of F, overriding the default
    value of 1, or the &lineWidth=X.X parameter.

    Useful for highlighting a single metric out of many, or having multiple
    line widths in one graph.

    Example::

        &target=lineWidth(server01.instance01.memory.free,5)

    """
    for series in seriesList:
        series.options['lineWidth'] = width
    return seriesList


Instruction:
Can you write a function in Python 3 where it
adds a dashed line to the seriesList.

Response:
def dashed(requestContext, seriesList, dashLength=5):
    """
    Takes one metric or a wildcard seriesList, followed by a float F.

    Draw the selected metrics with a dotted line with segments of length F
    If omitted, the default length of the segments is 5.0

    Example::

        &target=dashed(server01.instance01.memory.free,2.5)

    """
    for series in seriesList:
        series.name = 'dashed(%s, %g)' % (series.name, dashLength)
        series.options['dashed'] = dashLength
    return seriesList


Instruction:
Write a Python 3 script to
take one metric or a wildcard seriesList, followed by a quoted string with the length of time (See ``from / until`` in the render\_api_ for examples of time formats). Also takes a start multiplier and end multiplier for the length of time- Create a seriesList which is composed the original metric series stacked with time shifts starting time shifts from the start multiplier through the end multiplier. Useful for looking at history, or feeding into averageSeries or stddevSeries. Example:: # create a series for today and each of the previous 7 days &target=timeStack(Sales.widgets.largeBlue,"1d",0,7)

Response:
def timeStack(requestContext, seriesList, timeShiftUnit, timeShiftStart,
              timeShiftEnd):
    """
    Takes one metric or a wildcard seriesList, followed by a quoted string
    with the length of time (See ``from / until`` in the render\_api_ for
    examples of time formats). Also takes a start multiplier and end
    multiplier for the length of time-

    Create a seriesList which is composed the original metric series stacked
    with time shifts starting time shifts from the start multiplier through
    the end multiplier.

    Useful for looking at history, or feeding into averageSeries or
    stddevSeries.

    Example::

        # create a series for today and each of the previous 7 days
        &target=timeStack(Sales.widgets.largeBlue,"1d",0,7)
    """
    # Default to negative. parseTimeOffset defaults to +
    if timeShiftUnit[0].isdigit():
        timeShiftUnit = '-' + timeShiftUnit
    delta = parseTimeOffset(timeShiftUnit)
    # if len(seriesList) > 1, they will all have the same pathExpression,
    # which is all we care about.
    series = seriesList[0]
    results = []
    timeShiftStartint = int(timeShiftStart)
    timeShiftEndint = int(timeShiftEnd)

    for shft in range(timeShiftStartint, timeShiftEndint):
        myContext = requestContext.copy()
        innerDelta = delta * shft
        myContext['startTime'] = requestContext['startTime'] + innerDelta
        myContext['endTime'] = requestContext['endTime'] + innerDelta
        for shiftedSeries in evaluateTarget(myContext, series.pathExpression):
            shiftedSeries.name = 'timeShift(%s, %s, %s)' % (shiftedSeries.name,
                                                            timeShiftUnit,
                                                            shft)
            shiftedSeries.pathExpression = shiftedSeries.name
            shiftedSeries.start = series.start
            shiftedSeries.end = series.end
            results.append(shiftedSeries)

    return results


Instruction:
How would you code a function in Python 3 to
return a new base stateless version of the given seriesList shifted in time.

Response:
def timeShift(requestContext, seriesList, timeShift, resetEnd=True,
              alignDST=False):
    """
    Takes one metric or a wildcard seriesList, followed by a quoted string
    with the length of time (See ``from / until`` in the render\_api_ for
    examples of time formats).

    Draws the selected metrics shifted in time. If no sign is given, a minus
    sign ( - ) is implied which will shift the metric back in time. If a plus
    sign ( + ) is given, the metric will be shifted forward in time.

    Will reset the end date range automatically to the end of the base stat
    unless resetEnd is False. Example case is when you timeshift to last week
    and have the graph date range set to include a time in the future, will
    limit this timeshift to pretend ending at the current time. If resetEnd is
    False, will instead draw full range including future time.

    Because time is shifted by a fixed number of seconds, comparing a time
    period with DST to a time period without DST, and vice-versa, will result
    in an apparent misalignment. For example, 8am might be overlaid with 7am.
    To compensate for this, use the alignDST option.

    Useful for comparing a metric against itself at a past periods or
    correcting data stored at an offset.

    Example::

        &target=timeShift(Sales.widgets.largeBlue,"7d")
        &target=timeShift(Sales.widgets.largeBlue,"-7d")
        &target=timeShift(Sales.widgets.largeBlue,"+1h")

    """
    # Default to negative. parseTimeOffset defaults to +
    if timeShift[0].isdigit():
        timeShift = '-' + timeShift
    delta = parseTimeOffset(timeShift)
    myContext = requestContext.copy()
    myContext['startTime'] = requestContext['startTime'] + delta
    myContext['endTime'] = requestContext['endTime'] + delta

    if alignDST:
        reqStartDST = localDST(requestContext['startTime'])
        reqEndDST = localDST(requestContext['endTime'])
        myStartDST = localDST(myContext['startTime'])
        myEndDST = localDST(myContext['endTime'])

        dstOffset = timedelta(hours=0)
        # If the requestContext is entirely in DST, and we are entirely
        # NOT in DST
        if (
            (reqStartDST and reqEndDST) and
            (not myStartDST and not myEndDST)
        ):
            dstOffset = timedelta(hours=1)
        # Or if the requestContext is entirely NOT in DST, and we are
        # entirely in DST
        elif (
            (not reqStartDST and not reqEndDST) and
            (myStartDST and myEndDST)
        ):
            dstOffset = timedelta(hours=-1)
        # Otherwise, we don't do anything, because it would be visually
        # confusing
        myContext['startTime'] += dstOffset
        myContext['endTime'] += dstOffset

    results = []
    if not seriesList:
        return results

    # if len(seriesList) > 1, they will all have the same pathExpression,
    # which is all we care about.
    series = seriesList[0]

    for shiftedSeries in evaluateTarget(myContext, series.pathExpression):
        shiftedSeries.name = 'timeShift(%s, %s)' % (shiftedSeries.name,
                                                    timeShift)
        if resetEnd:
            shiftedSeries.end = series.end
        else:
            shiftedSeries.end = (
                shiftedSeries.end - shiftedSeries.start + series.start)
        shiftedSeries.start = series.start
        results.append(shiftedSeries)

    return results


Instruction:
Implement a function in Python 3 to
return a list of timeSlice objects for the given seriesList.

Response:
def timeSlice(requestContext, seriesList, startSliceAt, endSliceAt='now'):
    """
    Takes one metric or a wildcard metric, followed by a quoted
    string with the time to start the line and another quoted string
    with the time to end the line. The start and end times are
    inclusive. See ``from / until`` in the render api for examples of
    time formats.

    Useful for filtering out a part of a series of data from a wider
    range of data.

    Example::

        &target=timeSlice(network.core.port1,"00:00 20140101","11:59 20140630")
        &target=timeSlice(network.core.port1,"12:00 20140630","now")
    """
    results = []
    start = epoch(parseATTime(startSliceAt))
    end = epoch(parseATTime(endSliceAt))

    for slicedSeries in seriesList:
        slicedSeries.name = 'timeSlice(%s, %s, %s)' % (slicedSeries.name,
                                                       int(start), int(end))
        curr = epoch(requestContext["startTime"])
        for i, v in enumerate(slicedSeries):
            if v is None or curr < start or curr > end:
                slicedSeries[i] = None
            curr += slicedSeries.step
        results.append(slicedSeries)
    return results


Instruction:
How would you implement a function in Python 3 that
takes a float F Draws a horizontal line at value F across the graph.

Response:
def constantLine(requestContext, value):
    """
    Takes a float F.

    Draws a horizontal line at value F across the graph.

    Example::

        &target=constantLine(123.456)

    """
    name = "constantLine(%s)" % str(value)
    start = int(epoch(requestContext['startTime']))
    end = int(epoch(requestContext['endTime']))
    step = int((end - start) / 2.0)
    series = TimeSeries(str(value), start, end, step, [value, value, value])
    series.pathExpression = name
    return [series]


Instruction:
How would you explain what the following Python 3 function does
def aggregateLine(requestContext, seriesList, func='avg'):
    t_funcs = {'avg': safeAvg, 'min': safeMin, 'max': safeMax}

    if func not in t_funcs:
        raise ValueError("Invalid function %s" % func)

    results = []
    for series in seriesList:
        value = t_funcs[func](series)
        if value is not None:
            name = 'aggregateLine(%s, %g)' % (series.name, value)
        else:
            name = 'aggregateLine(%s, None)' % (series.name)

        [series] = constantLine(requestContext, value)
        series.name = name
        series.pathExpression = series.name
        results.append(series)
    return results

Response: Takes a metric or wildcard seriesList and draws a horizontal line of the available data points by applying a function to each series.


Instruction:
Can you write a function in Python 3 where it
returns a list of vertical lines at the designated timestamp.

Response:
def verticalLine(requestContext, ts, label=None, color=None):
    """
    Takes a timestamp string ts.

    Draws a vertical line at the designated timestamp with optional
    'label' and 'color'. Supported timestamp formats include both
    relative (e.g. -3h) and absolute (e.g. 16:00_20110501) strings,
    such as those used with ``from`` and ``until`` parameters. When
    set, the 'label' will appear in the graph legend.

    Note: Any timestamps defined outside the requested range will
    raise a 'ValueError' exception.

    Example::

        &target=verticalLine("12:3420131108","event","blue")
        &target=verticalLine("16:00_20110501","event")
        &target=verticalLine("-5mins")

    """
    ts = int(epoch(parseATTime(ts, requestContext['tzinfo'])))
    start = int(epoch(requestContext['startTime']))
    end = int(epoch(requestContext['endTime']))
    if ts < start:
        raise ValueError("verticalLine(): timestamp %s exists "
                         "before start of range" % ts)
    elif ts > end:
        raise ValueError("verticalLine(): timestamp %s exists "
                         "after end of range" % ts)
    start = end = ts
    step = 1.0
    series = TimeSeries(label, start, end, step, [1.0, 1.0])
    series.options['drawAsInfinite'] = True
    if color:
        series.color = color
    return [series]


Instruction:
Create a Python 3 function for
taking a float F, followed by a label (in double quotes) and a color. (See ``bgcolor`` in the render\_api_ for valid color names & formats.) Draws a horizontal line at value F across the graph. Example:: &target=threshold(123.456, "omgwtfbbq", "red")

Response:
def threshold(requestContext, value, label=None, color=None):
    """
    Takes a float F, followed by a label (in double quotes) and a color.
    (See ``bgcolor`` in the render\_api_ for valid color names & formats.)

    Draws a horizontal line at value F across the graph.

    Example::

        &target=threshold(123.456, "omgwtfbbq", "red")

    """
    [series] = constantLine(requestContext, value)
    if label:
        series.name = label
    if color:
        series.color = color
    return [series]


Instruction:
Write a Python 3 function that can
take a metric or wildcard seriesList and replaces null values with the value specified by default.

Response:
def transformNull(requestContext, seriesList, default=0, referenceSeries=None):
    """
    Takes a metric or wildcard seriesList and replaces null values with
    the value specified by `default`.  The value 0 used if not specified.
    The optional referenceSeries, if specified, is a metric or wildcard
    series list that governs which time intervals nulls should be replaced.
    If specified, nulls are replaced only in intervals where a non-null is
    found for the same interval in any of referenceSeries. This method
    compliments the drawNullAsZero function in graphical mode, but also
    works in text-only mode.

    Example::

        &target=transformNull(webapp.pages.*.views,-1)

    This would take any page that didn't have values and supply negative 1 as
    a default. Any other numeric value may be used as well.
    """
    def transform(v, d):
        if v is None:
            return d
        else:
            return v

    if referenceSeries:
        defaults = [default if any(v is not None for v in x) else None
                    for x in zip_longest(*referenceSeries)]
    else:
        defaults = None

    for series in seriesList:
        if referenceSeries:
            series.name = "transformNull(%s,%g,referenceSeries)" % (
                series.name, default)
        else:
            series.name = "transformNull(%s,%g)" % (series.name, default)
        series.pathExpression = series.name
        if defaults:
            values = [transform(v, d) for v, d in zip_longest(series,
                                                              defaults)]
        else:
            values = [transform(v, default) for v in series]
        series.extend(values)
        del series[:len(values)]
    return seriesList


Instruction:
Can you tell what is the following Python 3 function doing
def isNonNull(requestContext, seriesList):

    def transform(v):
        if v is None:
            return 0
        else:
            return 1

    for series in seriesList:
        series.name = "isNonNull(%s)" % (series.name)
        series.pathExpression = series.name
        values = [transform(v) for v in series]
        series.extend(values)
        del series[:len(values)]
    return seriesList

Response:
Takes a metric or wild card seriesList and counts up how many
vms non - null values are specified.


Instruction:
Can you tell what is the following Python 3 function doing
def identity(requestContext, name, step=60):
    start = int(epoch(requestContext["startTime"]))
    end = int(epoch(requestContext["endTime"]))
    values = range(start, end, step)
    series = TimeSeries(name, start, end, step, values)
    series.pathExpression = 'identity("%s")' % name

    return [series]

Response: This function returns a series with the given name equal to the timestamp of the datapoint.


Instruction:
Given the following Python 3 function, write the documentation
def countSeries(requestContext, *seriesLists):
    if not seriesLists or not any(seriesLists):
        series = constantLine(requestContext, 0).pop()
        series.pathExpression = "countSeries()"
    else:
        seriesList, start, end, step = normalize(seriesLists)
        name = "countSeries(%s)" % formatPathExpressions(seriesList)
        values = (int(len(row)) for row in zip_longest(*seriesList))
        series = TimeSeries(name, start, end, step, values)
        series.pathExpression = name

    return [series]

Response: Draw a horizontal line representing the number of nodes found in the specified seriesList.


Instruction:
Implement a Python 3 function for
returning a seriesList that contains all the seriesLists in seriesLists.

Response:
def group(requestContext, *seriesLists):
    """
    Takes an arbitrary number of seriesLists and adds them to a single
    seriesList. This is used to pass multiple seriesLists to a function which
    only takes one.
    """
    seriesGroup = []
    for s in seriesLists:
        seriesGroup.extend(s)

    return seriesGroup


Instruction:
Write a Python 3 function for
taking a seriesList and maps it to a list of sub - seriesList.

Response:
def mapSeries(requestContext, seriesList, mapNode):
    """
    Short form: ``map()``.

    Takes a seriesList and maps it to a list of sub-seriesList. Each
    sub-seriesList has the given mapNode in common.

    Example (note: This function is not very useful alone. It should be used
    with :py:func:`reduceSeries`)::

        mapSeries(servers.*.cpu.*,1) =>
            [
                servers.server1.cpu.*,
                servers.server2.cpu.*,
                ...
                servers.serverN.cpu.*
            ]
    """
    metaSeries = {}
    keys = []
    for series in seriesList:
        key = series.name.split(".")[mapNode]
        if key not in metaSeries:
            metaSeries[key] = [series]
            keys.append(key)
        else:
            metaSeries[key].append(series)
    return [metaSeries[k] for k in keys]


Instruction:
Can you create a Python 3 function that
shorts form: ``reduce()``. Takes a list of seriesLists and reduces it to a list of series by means of the reduceFunction. Reduction is performed by matching the reduceNode in each series against the list of reduceMatchers. The each series is then passed to the reduceFunction as arguments in the order given by reduceMatchers. The reduceFunction should yield a single series. The resulting list of series are aliased so that they can easily be nested in other functions. **Example**: Map/Reduce asPercent(bytes_used,total_bytes) for each server. Assume that metrics in the form below exist:: servers.server1.disk.bytes_used servers.server1.disk.total_bytes servers.server2.disk.bytes_used servers.server2.disk.total_bytes servers.server3.disk.bytes_used servers.server3.disk.total_bytes ... servers.serverN.disk.bytes_used servers.serverN.disk.total_bytes To get the percentage of disk used for each server:: reduceSeries(mapSeries(servers.*.disk.*,1), "asPercent",3,"bytes_used","total_bytes") => alias(asPercent(servers.server1.disk.bytes_used, servers.server1.disk.total_bytes), "servers.server1.disk.reduce.asPercent"), alias(asPercent(servers.server2.disk.bytes_used, servers.server2.disk.total_bytes), "servers.server2.disk.reduce.asPercent"), ... alias(asPercent(servers.serverN.disk.bytes_used, servers.serverN.disk.total_bytes), "servers.serverN.disk.reduce.asPercent") In other words, we will get back the following metrics:: servers.server1.disk.reduce.asPercent, servers.server2.disk.reduce.asPercent, ... servers.serverN.disk.reduce.asPercent .. seealso:: :py:func:`mapSeries`

Response:
def reduceSeries(requestContext, seriesLists, reduceFunction, reduceNode,
                 *reduceMatchers):
    """
    Short form: ``reduce()``.

    Takes a list of seriesLists and reduces it to a list of series by means of
    the reduceFunction.

    Reduction is performed by matching the reduceNode in each series against
    the list of reduceMatchers. The each series is then passed to the
    reduceFunction as arguments in the order given by reduceMatchers. The
    reduceFunction should yield a single series.

    The resulting list of series are aliased so that they can easily be
    nested in other functions.

    **Example**: Map/Reduce asPercent(bytes_used,total_bytes) for each server.

    Assume that metrics in the form below exist::

        servers.server1.disk.bytes_used
        servers.server1.disk.total_bytes
        servers.server2.disk.bytes_used
        servers.server2.disk.total_bytes
        servers.server3.disk.bytes_used
        servers.server3.disk.total_bytes
        ...
        servers.serverN.disk.bytes_used
        servers.serverN.disk.total_bytes

    To get the percentage of disk used for each server::

        reduceSeries(mapSeries(servers.*.disk.*,1),
                     "asPercent",3,"bytes_used","total_bytes") =>

            alias(asPercent(servers.server1.disk.bytes_used,
                            servers.server1.disk.total_bytes),
                  "servers.server1.disk.reduce.asPercent"),
            alias(asPercent(servers.server2.disk.bytes_used,
                            servers.server2.disk.total_bytes),
                  "servers.server2.disk.reduce.asPercent"),
            ...
            alias(asPercent(servers.serverN.disk.bytes_used,
                            servers.serverN.disk.total_bytes),
                  "servers.serverN.disk.reduce.asPercent")

    In other words, we will get back the following metrics::

        servers.server1.disk.reduce.asPercent,
        servers.server2.disk.reduce.asPercent,
        ...
        servers.serverN.disk.reduce.asPercent

    .. seealso:: :py:func:`mapSeries`
    """
    metaSeries = {}
    keys = []
    for seriesList in seriesLists:
        for series in seriesList:
            nodes = series.name.split('.')
            node = nodes[reduceNode]
            reduceSeriesName = '.'.join(
                nodes[0:reduceNode]) + '.reduce.' + reduceFunction
            if node in reduceMatchers:
                if reduceSeriesName not in metaSeries:
                    metaSeries[reduceSeriesName] = [None] * len(reduceMatchers)
                    keys.append(reduceSeriesName)
                i = reduceMatchers.index(node)
                metaSeries[reduceSeriesName][i] = series
    for key in keys:
        metaSeries[key] = app.functions[reduceFunction](
            requestContext, *[[s] for s in metaSeries[key]])[0]
        metaSeries[key].name = key
    return [metaSeries[key] for key in keys]


Instruction:
Write a Python 3 script for
taking a seriesList and applies a template function to each series in the seriesList and replaces any % characters with the unique prefix of the series.

Response:
def applyByNode(requestContext, seriesList, nodeNum, templateFunction,
                newName=None):
    """
    Takes a seriesList and applies some complicated function (described by
    a string), replacing templates with unique prefixes of keys from the
    seriesList (the key is all nodes up to the index given as `nodeNum`).

    If the `newName` parameter is provided, the name of the resulting series
    will be given by that parameter, with any "%" characters replaced by the
    unique prefix.

    Example::

        &target=applyByNode(servers.*.disk.bytes_free,1,
                "divideSeries(%.disk.bytes_free,sumSeries(%.disk.bytes_*))")

    Would find all series which match `servers.*.disk.bytes_free`, then trim
    them down to unique series up to the node given by nodeNum, then fill them
    into the template function provided (replacing % by the prefixes).

    """
    from .app import evaluateTarget
    prefixes = set()
    for series in seriesList:
        prefix = '.'.join(series.name.split('.')[:nodeNum + 1])
        prefixes.add(prefix)
    results = []
    for prefix in sorted(prefixes):
        target = templateFunction.replace('%', prefix)
        for resultSeries in evaluateTarget(requestContext, target):
            if newName:
                resultSeries.name = newName.replace('%', prefix)
            resultSeries.pathExpression = prefix
            resultSeries.start = series.start
            resultSeries.end = series.end
            results.append(resultSeries)
    return results


Instruction:
How would you code a function in Python 3 to
take a serieslist and maps a callback to subgroups within a common node.

Response:
def groupByNode(requestContext, seriesList, nodeNum, callback):
    """
    Takes a serieslist and maps a callback to subgroups within as defined by a
    common node.

    Example::

        &target=groupByNode(ganglia.by-function.*.*.cpu.load5,2,"sumSeries")

    Would return multiple series which are each the result of applying the
    "sumSeries" function to groups joined on the second node (0 indexed)
    resulting in a list of targets like::

        sumSeries(ganglia.by-function.server1.*.cpu.load5),
        sumSeries(ganglia.by-function.server2.*.cpu.load5),...

    """
    return groupByNodes(requestContext, seriesList, callback, nodeNum)


Instruction:
Given the following Python 3 function, write the documentation
def groupByNodes(requestContext, seriesList, callback, *nodes):
    from .app import app
    metaSeries = {}
    keys = []
    if isinstance(nodes, int):
        nodes = [nodes]
    for series in seriesList:
        key = '.'.join(series.name.split(".")[n] for n in nodes)
        if key not in metaSeries:
            metaSeries[key] = [series]
            keys.append(key)
        else:
            metaSeries[key].append(series)
    for key in metaSeries:
        metaSeries[key] = app.functions[callback](requestContext,
                                                  metaSeries[key])[0]
        metaSeries[key].name = key
    return [metaSeries[key] for key in keys]

Response: Takes a seriesList and maps a callback to subgroups within a set of nodes. Returns a list of series which are grouped by the given nodes.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def exclude(requestContext, seriesList, pattern):
    regex = re.compile(pattern)
    return [s for s in seriesList if not regex.search(s.name)]

Response: Exclude metrics that match the regular expression pattern.


Instruction:
Given the following Python 3 function, write the documentation
def smartSummarize(requestContext, seriesList, intervalString, func='sum'):
    results = []
    delta = parseTimeOffset(intervalString)
    interval = to_seconds(delta)

    # Adjust the start time to fit an entire day for intervals >= 1 day
    requestContext = requestContext.copy()
    tzinfo = requestContext['tzinfo']
    s = requestContext['startTime']
    if interval >= DAY:
        requestContext['startTime'] = datetime(s.year, s.month, s.day,
                                               tzinfo=tzinfo)
    elif interval >= HOUR:
        requestContext['startTime'] = datetime(s.year, s.month, s.day, s.hour,
                                               tzinfo=tzinfo)
    elif interval >= MINUTE:
        requestContext['startTime'] = datetime(s.year, s.month, s.day, s.hour,
                                               s.minute, tzinfo=tzinfo)

    paths = []
    for series in seriesList:
        paths.extend(pathsFromTarget(requestContext, series.pathExpression))
    data_store = fetchData(requestContext, paths)

    for series in seriesList:
        # XXX: breaks with summarize(metric.{a,b})
        #            each series.pathExpression == metric.{a,b}
        newSeries = evaluateTarget(requestContext,
                                   series.pathExpression,
                                   data_store)[0]
        series[0:len(series)] = newSeries
        series.start = newSeries.start
        series.end = newSeries.end
        series.step = newSeries.step

    for series in seriesList:
        buckets = {}  # {timestamp: [values]}

        timestamps = range(int(series.start), int(series.end),
                           int(series.step))
        datapoints = zip_longest(timestamps, series)

        # Populate buckets
        for timestamp, value in datapoints:
            # ISSUE: Sometimes there is a missing timestamp in datapoints when
            #        running a smartSummary
            if not timestamp:
                continue
            bucketInterval = int((timestamp - series.start) / interval)

            if bucketInterval not in buckets:
                buckets[bucketInterval] = []

            if value is not None:
                buckets[bucketInterval].append(value)

        newValues = []
        for timestamp in range(series.start, series.end, interval):
            bucketInterval = int((timestamp - series.start) / interval)
            bucket = buckets.get(bucketInterval, [])

            if bucket:
                if func == 'avg':
                    newValues.append(float(sum(bucket)) / float(len(bucket)))
                elif func == 'last':
                    newValues.append(bucket[len(bucket)-1])
                elif func == 'max':
                    newValues.append(max(bucket))
                elif func == 'min':
                    newValues.append(min(bucket))
                else:
                    newValues.append(sum(bucket))
            else:
                newValues.append(None)

        newName = "smartSummarize(%s, \"%s\", \"%s\")" % (series.name,
                                                          intervalString,
                                                          func)
        alignedEnd = series.start + (bucketInterval * interval) + interval
        newSeries = TimeSeries(newName, series.start, alignedEnd, interval,
                               newValues)
        newSeries.pathExpression = newName
        results.append(newSeries)

    return results

Response: Smarter experimental version of summarize.