anchor.diff:      ?assertEqual(Z, sum_values(X, Y)),
       ?assertEqual(Z, sum_values(Y, X)).
   
  +stat_values_test() ->
  +    ?assertEqual({1, 2, 0, 1, 1}, stat_values(1, 0)),
  +    ?assertEqual({11, 2, 1, 10, 101}, stat_values(1, 10)),
  +    ?assertEqual([{9, 2, 2, 7, 53},
  +                  {14, 2, 3, 11, 130},
  +                  {18, 2, 5, 13, 194}
  +                 ], stat_values([2,3,5], [7,11,13])).
  +
   -endif.
  
positive.code: sum_arrays(_, _) ->
      throw({invalid_value, ?SUMERROR}).
  
  
  builtin_stats(reduce, [[_,First]|Rest]) ->
      Acc0 = build_initial_accumulator(First),
      Stats = lists:foldl(fun
          ([_K,V], {S,C,Mi,Ma,Sq}) when is_number(V) ->
              {S+V, C+1, erlang:min(Mi,V), erlang:max(Ma,V), Sq+(V*V)};
          ([_K,{PreRed}], {S,C,Mi,Ma,Sq}) when is_list(PreRed) ->
              {
                  S + get_number(<<"sum">>, PreRed),
                  C + get_number(<<"count">>, PreRed),
                  erlang:min(get_number(<<"min">>, PreRed), Mi),
                  erlang:max(get_number(<<"max">>, PreRed), Ma),
                  Sq + get_number(<<"sumsqr">>, PreRed)
              };
          ([_K,V], _) ->
              Msg = io_lib:format("non-numeric _stats input: ~w", [V]),
              throw({invalid_value, iolist_to_binary(Msg)})
      end, Acc0, Rest),
      {Sum, Cnt, Min, Max, Sqr} = Stats,
      {[{sum,Sum}, {count,Cnt}, {min,Min}, {max,Max}, {sumsqr,Sqr}]};
  
  builtin_stats(rereduce, [[_,First]|Rest]) ->
      {[{sum,Sum0}, {count,Cnt0}, {min,Min0}, {max,Max0}, {sumsqr,Sqr0}]} = First,
      Stats = lists:foldl(fun([_K,Red], {S,C,Mi,Ma,Sq}) ->
          {[{sum,Sum}, {count,Cnt}, {min,Min}, {max,Max}, {sumsqr,Sqr}]} = Red,
          {Sum+S, Cnt+C, lists:min([Min, Mi]), lists:max([Max, Ma]), Sqr+Sq}
      end, {Sum0,Cnt0,Min0,Max0,Sqr0}, Rest),
      {Sum, Cnt, Min, Max, Sqr} = Stats,
      {[{sum,Sum}, {count,Cnt}, {min,Min}, {max,Max}, {sumsqr,Sqr}]}.
  
  build_initial_accumulator(X) when is_number(X) ->
      {X, 1, X, X, X*X};
  build_initial_accumulator({Props}) ->
      {
          get_number(<<"sum">>, Props),
          get_number(<<"count">>, Props),
          get_number(<<"min">>, Props),
          get_number(<<"max">>, Props),
          get_number(<<"sumsqr">>, Props)
      };
  build_initial_accumulator(Else) ->
      Msg = io_lib:format("non-numeric _stats input: ~w", [Else]),
      throw({invalid_value, iolist_to_binary(Msg)}).
  
  get_number(Key, Props) ->
      case couch_util:get_value(Key, Props) of
  
negative.code:     "arrays of numbers, or objects. Objects cannot be mixed with other data "
      "structures. Objects can be arbitrarily nested, provided that the values "
      "for all fields are themselves numbers, arrays of numbers, or objects.">>).
  
  -define(STATERROR, <<"The _stats function requires that map values be numbers "
      "or arrays of numbers.">>).
  
  % https://gist.github.com/df10284c76d85f988c3f
  -define(SUMREGEX, {re_pattern,3,0,<<69,82,67,80,194,0,0,0,8,0,0,0,5,0,0,0,3,0,
  