anchor.diff:      % they will change the Etag. For more granular Etags we'd need to keep
       % track of the last Db seq that caused an index change.
       chttpd:make_etag({Sig, CurrentSeq, Extra}).
  -
  -% the view row has an error
  -view_row_obj(_Db, {{Key, error}, Value}, _IncludeDocs) ->
  -    {[{key, Key}, {error, Value}]};
  -% include docs in the view output
  -view_row_obj(Db, {{Key, DocId}, {Props}}, true) ->
  -    Rev = case couch_util:get_value(<<"_rev">>, Props) of
  -    undefined ->
  -        nil;
  -    Rev0 ->
  -        couch_doc:parse_rev(Rev0)
  -    end,
  -    view_row_with_doc(Db, {{Key, DocId}, {Props}}, Rev);
  -view_row_obj(Db, {{Key, DocId}, Value}, true) ->
  -    view_row_with_doc(Db, {{Key, DocId}, Value}, nil);
  -% the normal case for rendering a view row
  -view_row_obj(_Db, {{Key, DocId}, Value}, _IncludeDocs) ->
  -    {[{id, DocId}, {key, Key}, {value, Value}]}.
  -
  -view_row_with_doc(Db, {{Key, DocId}, Value}, Rev) ->
  -    ?LOG_DEBUG("Include Doc: ~p ~p", [DocId, Rev]),
  -    case (catch chttpd_db:couch_doc_open(Db, DocId, Rev, [])) of
  -      {{not_found, missing}, _RevId} ->
  -          {[{id, DocId}, {key, Key}, {value, Value}, {error, missing}]};
  -      {not_found, missing} ->
  -          {[{id, DocId}, {key, Key}, {value, Value}, {error, missing}]};
  -      {not_found, deleted} ->
  -          {[{id, DocId}, {key, Key}, {value, Value}]};
  -      Doc ->
  -        JsonDoc = couch_doc:to_json_obj(Doc, []),
  -        {[{id, DocId}, {key, Key}, {value, Value}, {doc, JsonDoc}]}
  -    end.
  -
  -finish_view_fold(Req, TotalRows, FoldResult) ->
  -    case FoldResult of
  -    {ok, {_, _, undefined, _, Offset}} ->
  -        % nothing found in the view, nothing has been returned
  -        % send empty view
  -        NewOffset = case Offset of
  -            nil -> TotalRows;
  -            _ -> Offset
  -        end,
  -        send_json(Req, 200, {[
  -            {total_rows, TotalRows},
  -            {offset, NewOffset},
  -            {rows, []}
  -        ]});
  -    {ok, {_, _, Resp, _, _}} ->
  -        % end the view
  -        send_chunk(Resp, "\r\n]}"),
  -        end_json_response(Resp);
  -    Error ->
  -        throw(Error)
  -    end.
  -
  -finish_reduce_fold(Req, Resp) ->
  -    case Resp of
  -    undefined ->
  -        send_json(Req, 200, {[
  -            {rows, []}
  -        ]});
  -    Resp ->
  -        send_chunk(Resp, "\r\n]}"),
  -        end_json_response(Resp)
  -    end.
   
   parse_bool_param("true") -> true;
   parse_bool_param("false") -> false;
  
positive.code: handle_view_req(Req, _Db, _DDoc) ->
      send_method_not_allowed(Req, "GET,POST,HEAD").
  
  handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
      throw(not_implemented),
      couch_stats_collector:increment({httpd, temporary_view_reads}),
      {Props} = chttpd:json_body_obj(Req),
      Language = couch_util:get_value(<<"language">>, Props, <<"javascript">>),
      {DesignOptions} = couch_util:get_value(<<"options">>, Props, {[]}),
      MapSrc = couch_util:get_value(<<"map">>, Props),
      Keys = couch_util:get_value(<<"keys">>, Props, nil),
      case couch_util:get_value(<<"reduce">>, Props, null) of
      null ->
          QueryArgs = parse_view_params(Req, Keys, map),
          {ok, View, Group} = ?COUCH:get_temp_map_view(Db, Language,
              DesignOptions, MapSrc),
          output_map_view(Req, View, Group, Db, QueryArgs, Keys);
      RedSrc ->
          QueryArgs = parse_view_params(Req, Keys, reduce),
          {ok, View, Group} = ?COUCH:get_temp_reduce_view(Db, Language,
              DesignOptions, MapSrc, RedSrc),
          output_reduce_view(Req, Db, View, Group, QueryArgs, Keys)
      end;
  
  handle_temp_view_req(Req, _Db) ->
      send_method_not_allowed(Req, "POST").
  
  output_map_view(Req, View, Group, Db, QueryArgs, nil) ->
      #view_query_args{
          limit = Limit,
          direction = Dir,
          skip = SkipCount,
          start_key = StartKey,
          start_docid = StartDocId
      } = QueryArgs,
      CurrentEtag = view_group_etag(Group, Db),
      chttpd:etag_respond(Req, CurrentEtag, fun() ->
          {ok, RowCount} = ?COUCH:get_row_count(View),
          Start = {StartKey, StartDocId},
          FoldlFun = make_view_fold_fun(Req, QueryArgs, CurrentEtag, Db, RowCount, #view_fold_helper_funs{reduce_count=fun ?COUCH:reduce_to_count/1}),
          FoldAccInit = {Limit, SkipCount, undefined, [], nil},
          FoldResult = ?COUCH:view_fold(View, Start, Dir, FoldlFun, FoldAccInit),
          finish_view_fold(Req, RowCount, FoldResult)
      end);
  
  output_map_view(Req, View, Group, Db, QueryArgs, Keys) ->
      #view_query_args{
          limit = Limit,
          direction = Dir,
          skip = SkipCount,
          start_docid = StartDocId
      } = QueryArgs,
      CurrentEtag = view_group_etag(Group, Db, Keys),
      chttpd:etag_respond(Req, CurrentEtag, fun() ->
          {ok, RowCount} = ?COUCH:get_row_count(View),
          FoldAccInit = {Limit, SkipCount, undefined, [], nil},
          FoldResult = lists:foldl(
              fun(Key, {ok, FoldAcc}) ->
                  Start = {Key, StartDocId},
                  FoldlFun = make_view_fold_fun(Req,
                      QueryArgs#view_query_args{
                          start_key = Key,
                          end_key = Key
                      }, CurrentEtag, Db, RowCount,
                      #view_fold_helper_funs{
                          reduce_count = fun ?COUCH:reduce_to_count/1
                      }),
                  ?COUCH:view_fold(View, Start, Dir, FoldlFun, FoldAcc)
              end, {ok, FoldAccInit}, Keys),
          finish_view_fold(Req, RowCount, FoldResult)
      end).
  
  output_reduce_view(Req, Db, View, Group, QueryArgs, nil) ->
      #view_query_args{
          start_key = StartKey,
          end_key = EndKey,
          limit = Limit,
          skip = Skip,
          direction = Dir,
          start_docid = StartDocId,
          end_docid = EndDocId,
          group_level = GroupLevel
      } = QueryArgs,
      CurrentEtag = view_group_etag(Group, Db),
      chttpd:etag_respond(Req, CurrentEtag, fun() ->
          {ok, GroupRowsFun, RespFun} = make_reduce_fold_funs(Req, GroupLevel, QueryArgs, CurrentEtag, #reduce_fold_helper_funs{}),
          FoldAccInit = {Limit, Skip, undefined, []},
          {ok, {_, _, Resp, _}} = ?COUCH:view_fold_reduce(View, Dir, {StartKey, StartDocId},
              {EndKey, EndDocId}, GroupRowsFun, RespFun, FoldAccInit),
          finish_reduce_fold(Req, Resp)
      end);
  
  output_reduce_view(Req, Db, View, Group, QueryArgs, Keys) ->
      #view_query_args{
          limit = Limit,
          skip = Skip,
          direction = Dir,
          start_docid = StartDocId,
          end_docid = EndDocId,
          group_level = GroupLevel
      } = QueryArgs,
      CurrentEtag = view_group_etag(Group, Db),
      chttpd:etag_respond(Req, CurrentEtag, fun() ->
          {ok, GroupRowsFun, RespFun} = make_reduce_fold_funs(Req, GroupLevel, QueryArgs, CurrentEtag, #reduce_fold_helper_funs{}),
          {Resp, _RedAcc3} = lists:foldl(
              fun(Key, {Resp, RedAcc}) ->
                  % run the reduce once for each key in keys, with limit etc reapplied for each key
                  FoldAccInit = {Limit, Skip, Resp, RedAcc},
                  {_, {_, _, Resp2, RedAcc2}} = ?COUCH:view_fold_reduce(View, Dir, {Key, StartDocId},
                      {Key, EndDocId}, GroupRowsFun, RespFun, FoldAccInit),
                  % Switch to comma
                  {Resp2, RedAcc2}
              end,
          {undefined, []}, Keys), % Start with no comma
          finish_reduce_fold(Req, Resp)
      end).
  
  reverse_key_default(?MIN_STR) -> ?MAX_STR;
  reverse_key_default(?MAX_STR) -> ?MIN_STR;
  reverse_key_default(Key) -> Key.
  
  get_stale_type(Req) ->
      list_to_atom(chttpd:qs_value(Req, "stale", "nil")).
  
  get_reduce_type(Req) ->
      list_to_atom(chttpd:qs_value(Req, "reduce", "true")).
  
negative.code: -module(chttpd_view).
  -include_lib("couch/include/couch_db.hrl").
  
  -export([handle_view_req/3, handle_temp_view_req/2, get_reduce_type/1,
      parse_view_params/3, view_group_etag/2, view_group_etag/3,
      parse_bool_param/1, extract_view_type/3]).
  
  -import(chttpd,
      [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,send_chunk/2,
  