anchor.diff:  
   -module(couch_httpd_changes).
   
  --export([handle_changes_req/2]).
  +-export([handle_changes_req/2,
  +         handle_changes/3,
  +         handle_view_changes/3]).
   
   -include_lib("couch/include/couch_db.hrl").
   
  
positive.code:         {httpd, clients_requesting_changes}
      )
      end.
  
  parse_changes_query(Req, Db) ->
      ChangesArgs = lists:foldl(fun({Key, Value}, Args) ->
  
negative.code:         _ ->
              ChangesArgs
      end.
  
  parse_view_param({json_req, {Props}}) ->
      {Query} = couch_util:get_value(<<"query">>, Props),
      parse_view_param1(couch_util:get_value(<<"view">>, Query, <<"">>));
  parse_view_param(Req) ->
      parse_view_param1(list_to_binary(couch_httpd:qs_value(Req, "view", ""))).
  
  parse_view_param1(ViewParam) ->
      case re:split(ViewParam, <<"/">>) of
          [DName, ViewName] ->
              {<< "_design/", DName/binary >>, ViewName};
          _ ->
              throw({bad_request, "Invalid `view` parameter."})
      end.
  
  parse_view_options([], Acc) ->
      Acc;
  parse_view_options([{K, V} | Rest], Acc) ->
      Acc1 = case couch_util:to_binary(K) of
          <<"reduce">> ->
              [{reduce, couch_mrview_http:parse_boolean(V)}];
          <<"key">> ->
              V1 = parse_json(V),
              [{start_key, V1}, {end_key, V1} | Acc];
          <<"keys">> ->
              [{keys, parse_json(V)} | Acc];
          <<"startkey">> ->
              [{start_key, parse_json(V)} | Acc];
          <<"start_key">> ->
              [{start_key, parse_json(V)} | Acc];
          <<"startkey_docid">> ->
              [{start_key_docid, couch_util:to_binary(V)} | Acc];
          <<"start_key_docid">> ->
              [{start_key_docid, couch_util:to_binary(V)} | Acc];
          <<"endkey">> ->
              [{end_key, parse_json(V)} | Acc];
          <<"end_key">> ->
              [{end_key, parse_json(V)} | Acc];
          <<"endkey_docid">> ->
              [{start_key_docid, couch_util:to_binary(V)} | Acc];
          <<"end_key_docid">> ->
              [{start_key_docid, couch_util:to_binary(V)} | Acc];
          <<"limit">> ->
              [{limit, couch_mrview_http:parse_pos_int(V)} | Acc];
          <<"count">> ->
              throw({query_parse_error, <<"QS param `count` is not `limit`">>});
          <<"stale">> when V =:= <<"ok">> orelse V =:= "ok" ->
              [{stale, ok} | Acc];
          <<"stale">> when V =:= <<"update_after">> orelse V =:= "update_after" ->
              [{stale, update_after} | Acc];
          <<"stale">> ->
              throw({query_parse_error, <<"Invalid value for `stale`.">>});
          <<"descending">> ->
              case couch_mrview_http:parse_boolean(V) of
                  true ->
                      [{direction, rev} | Acc];
                  _ ->
                      [{direction, fwd} | Acc]
              end;
          <<"skip">> ->
              [{skip, couch_mrview_http:parse_pos_int(V)} | Acc];
          <<"group">> ->
              case couch_mrview_http:parse_booolean(V) of
                  true ->
                      [{group_level, exact} | Acc];
                  _ ->
                      [{group_level, 0} | Acc]
              end;
          <<"group_level">> ->
              [{group_level, couch_mrview_http:parse_pos_int(V)} | Acc];
          <<"inclusive_end">> ->
              [{inclusive_end, couch_mrview_http:parse_boolean(V)}];
          _ ->
              Acc
      end,
      parse_view_options(Rest, Acc1).
  
  parse_json(V) when is_list(V) ->
      ?JSON_DECODE(V);
  parse_json(V) ->
      V.
  
  deleted_item(true) -> [{<<"deleted">>, true}];
  deleted_item(_) -> [].
  