def evaluateAggregateFunction(node, sphinxContext, name):
    # determine if evaluating args found hyperspace (first time)
    args = []
    iterateAbove, bindingsLen = getattr(node, "aggregationHsBindings", (None, None))
    firstTime = bindingsLen is None
    hsBindings = sphinxContext.hyperspaceBindings
    parentAggregationNode = hsBindings.aggregationNode
    parentIsValuesIteration = hsBindings.isValuesIteration
    hsBindings.aggregationNode = node # block removing nested aspect bindings
    hsBindings.isValuesIteration = False
    prevHsBindingsLen = len(hsBindings.hyperspaceBindings)
    hsBoundFact = aggreateFunctionAcceptsFactArgs[name]
    arg = node.args[0]
    try:
        while (True):   # possibly multiple bindings
            # evaluate local variables
            for localVar in node.localVariables:
                evaluate(localVar, sphinxContext)
                
            value = evaluate(arg, sphinxContext, value=True, hsBoundFact=hsBoundFact)
            if isinstance(value, (list,set)):
                for listArg in value:
                    if value is not UNBOUND:
                        args.append(evaluate(listArg, sphinxContext, value=True))
            elif value is not UNBOUND:
                args.append(value)
            if firstTime:
                if len(hsBindings.hyperspaceBindings) == prevHsBindingsLen:
                    # no hs bindings, just scalar
                    break
                else:    # has hs bindings, evaluate rest of them
                    firstTime = False
                    iterateAbove = prevHsBindingsLen - 1
                    bindingsLen = len(hsBindings.hyperspaceBindings)
                    node.aggregationHsBindings = (iterateAbove, bindingsLen)
            hsBindings.next(iterateAbove, bindingsLen)
    except StopIteration:
        pass # no more bindings
    hsBindings.isValuesIteration = parentIsValuesIteration
    hsBindings.aggregationNode = parentAggregationNode
    # remove local variables
    for localVar in node.localVariables:
        if localVar in sphinxContext.localVariables:
            del sphinxContext.localVariables[localVar.name]
    if sphinxContext.formulaOptions.traceVariableExpressionEvaluation:
        sphinxContext.modelXbrl.info("sphinx:trace",
             _("Aggregative function %(name)s arguments: %(args)s"), 
             sourceFileLine=node.sourceFileLine, name=name, 
             args=",".join(str(a) for a in args))
    try:
        return aggreateFunctionImplementation[name](node, sphinxContext, args)
    except (__HOLE__, ZeroDivisionError) as err:
        sphinxContext.modelXbrl.error("sphinx:error",
             _("Function %(name)s raises exception %(error)s in %(node)s"), 
             sourceFileLine=node.sourceFileLine, name=name, node=str(node), error=str(err))
        return None
dataset/ETHPy150Open Arelle/Arelle/arelle/plugin/sphinx/SphinxEvaluator.py/evaluateAggregateFunction