whole_func_string: function(expr, context, subIntegral) {
        var MaxExponentExpanded = 10;
  
        if(expr.type === 'OperatorNode' && expr.op === '^') {
          var multipliedOut = tryMultiplyOut(expr);
          if(multipliedOut) {
            var int = subIntegral(multipliedOut, context, "reducing power");
            if(int) {
              return int;
            }
          }
        } else if(expr.type === 'OperatorNode' && expr.op === '*') {
          for(var i = 0; i < expr.args.length; i++) {
            var multipliedOutChild = tryMultiplyOut(expr.args[i]);
            if(multipliedOutChild) {
              var int = subIntegral(new OperatorNode('*', 'multiply', multipliedOutChild.args.concat(
                expr.args.slice(0, i),
                expr.args.slice(i+1)
              )), context, "reducing power");
  
              if(int) {
                return int;
              }
            }
          }
        }
  
        //
        function tryMultiplyOut(expr) {
          if(expr.type === 'OperatorNode' && expr.op === '^' && !context.isConstant(expr.args[0])) {
            var exponentValue = getNumericValue(expr.args[1]);
            if(Number.isInteger(exponentValue) && exponentValue > 1 && exponentValue <= MaxExponentExpanded) {
              return new OperatorNode('*', 'multiply', [
                expr.args[0],
                exponentValue === 2 ? expr.args[0] : new OperatorNode('^', 'pow', [
                  expr.args[0],
                  new ConstantNode(exponentValue-1)
                ])
              ]);
            }
          }
  
          return null;
        }
      }
func_code_string: function(expr, context, subIntegral) {
        var MaxExponentExpanded = 10;
  
        if(expr.type === 'OperatorNode' && expr.op === '^') {
          var multipliedOut = tryMultiplyOut(expr);
          if(multipliedOut) {
            var int = subIntegral(multipliedOut, context, "reducing power");
            if(int) {
              return int;
            }
          }
        } else if(expr.type === 'OperatorNode' && expr.op === '*') {
          for(var i = 0; i < expr.args.length; i++) {
            var multipliedOutChild = tryMultiplyOut(expr.args[i]);
            if(multipliedOutChild) {
              var int = subIntegral(new OperatorNode('*', 'multiply', multipliedOutChild.args.concat(
                expr.args.slice(0, i),
                expr.args.slice(i+1)
              )), context, "reducing power");
  
              if(int) {
                return int;
              }
            }
          }
        }
  
        //
        function tryMultiplyOut(expr) {
          if(expr.type === 'OperatorNode' && expr.op === '^' && !context.isConstant(expr.args[0])) {
            var exponentValue = getNumericValue(expr.args[1]);
            if(Number.isInteger(exponentValue) && exponentValue > 1 && exponentValue <= MaxExponentExpanded) {
              return new OperatorNode('*', 'multiply', [
                expr.args[0],
                exponentValue === 2 ? expr.args[0] : new OperatorNode('^', 'pow', [
                  expr.args[0],
                  new ConstantNode(exponentValue-1)
                ])
              ]);
            }
          }
  
          return null;
        }
      }
func_documentation_string: integral(f(x)^c [* g(x)], x) = integral(f(x) * f(x)^(c-1) [* g(x)], x) However, we only expand for c<=10 to save computational resources