anchor.diff:  allowed_methods(RD, Ctx) ->
       {['GET', 'DELETE', 'HEAD', 'OPTIONS'], RD, Ctx}.
   
  -malformed_request(RD, {_Resource, Relation}=Ctx) when ?is_object(Relation) ->
  +-spec malformed_request(rd(), object_type()) ->
  +			       {boolean(), rd(), object_type()};
  +		       (rd(), collection_type()) ->
  +			       {boolean(), rd(), {collection_type(), range()}};
  +		       (rd(), {object_type(), object_type()}) ->
  +			       {boolean(), rd(), {object_type(), object_type()}};
  +		       (rd(), {object_type(), collection_type()}) ->
  +			       {boolean(), rd(), {collection_type(), range()}}.
  +malformed_request(RD, {_Resource, Relation} = Ctx) when ?is_object(Relation) ->
       {false, RD, Ctx};
  -malformed_request(RD, {_Resource, Relation}=Ctx) when ?is_collection(Relation) ->
  +malformed_request(RD, {_Resource, Relation} = Ctx)
  +  when ?is_collection(Relation) ->
       case erli_utils:parse_range_header(RD, Relation) of
   	{error, invalid_range} ->
  -	    ContentRange = "*/" ++ integer_to_list(erli_storage:count(Relation)),
  -	    NRD = wrq:set_resp_header("Content-Range", ContentRange, RD),
  +	    ContentRange = "*/" ++
  +		integer_to_list(erli_storage:count(Relation)),
  +	    NRD = wrq:set_resp_header("Content-Range", ContentRange,
  +				      RD),
   	    {true, NRD, Ctx};
  -	Range ->
  -	    {false, RD, {Ctx, Range}}
  +	Range -> {false, RD, {Ctx, Range}}
       end;
   malformed_request(RD, Ctx) when ?is_collection(Ctx) ->
       case erli_utils:parse_range_header(RD, Ctx) of
   	{error, invalid_range} ->
  -	    ContentRange = "*/" ++ integer_to_list(erli_storage:count(Ctx)),
  -	    NRD = wrq:set_resp_header("Content-Range", ContentRange, RD),
  +	    ContentRange = "*/" ++
  +		integer_to_list(erli_storage:count(Ctx)),
  +	    NRD = wrq:set_resp_header("Content-Range", ContentRange,
  +				      RD),
   	    {true, NRD, Ctx};
  -	Range ->
  -	    {false, RD, {Ctx, Range}}
  -    end;
  -malformed_request(RD, Ctx) ->
  -    {false, RD, Ctx}.
  -
  -
  -options(RD, {visits, _Range}=Ctx) ->
  +	Range -> {false, RD, {Ctx, Range}}
  +    end;
  +malformed_request(RD, Ctx) -> {false, RD, Ctx}.
  +
  +-spec options(rd(), object_type()) ->
  +		     {[{string(), string()}], rd(), object_type()};
  +	     (rd(), {collection_type(), range()}) ->
  +		     {[{string(), string()}], rd(), {collection_type(), range()}}.
  +options(RD, {visits, _Range} = Ctx) ->
  +    {[{"Content-Length", "0"}, {"Accept-Ranges", visits},
  +      {"Allow", "GET, HEAD, OPTIONS"}],
  +     RD, Ctx};
  +options(RD, {CollectionType, _Range} = Ctx) ->
  +    ColType = atom_to_list(CollectionType),
  +    {[{"Content-Length", "0"}, {"Accept-Ranges", ColType},
  +      {"Allow", "GET, POST, HEAD, OPTIONS"}],
  +     RD, Ctx};
  +options(RD, visit = Ctx) ->
       {[{"Content-Length", "0"},
  -      {"Accept-Ranges", visits},
  -      {"Allow", "GET, HEAD, OPTIONS"}], RD, Ctx};
  -options(RD, {CollectionType, _Range}=Ctx) ->
  -    ColType = atom_to_list(CollectionType),
  -    {[{"Content-Length", "0"},
  -      {"Accept-Ranges", ColType},
  -      {"Allow", "GET, POST, HEAD, OPTIONS"}], RD, Ctx};
  -options(RD, visit=Ctx) ->
  -    {[{"Content-Length", "0"},
  -      {"Allow", "GET, HEAD, OPTIONS"}], RD, Ctx};
  +      {"Allow", "GET, HEAD, OPTIONS"}],
  +     RD, Ctx};
   options(RD, Ctx) ->
       {[{"Content-Length", "0"},
  -      {"Allow", "GET, DELETE, HEAD, OPTIONS"}], RD, Ctx}.
  -
  -
  +      {"Allow", "GET, DELETE, HEAD, OPTIONS"}],
  +     RD, Ctx}.
  +
  +-spec resource_exists(rd(), object_type()) ->
  +			     {boolean(), rd(), {object_type(), object()}};
  +		     (rd(), {A :: object_type(), B :: object_type()}) ->
  +			     {boolean(), rd(), {object_type(), B::object()}};
  +		     (rd(), {collection_type(), range()}) ->
  +			     {boolean(), rd(), {collection_type(), collection()}};
  +		     (rd(), {{object_type(), collection_type()}, range()}) ->
  +			     {boolean(), rd(), {collection_type(), collection()}};
  +		     (rd(), {object_type(), object_type()}) ->
  +			     {boolean(), rd(), {object_type(), object()}}.
   resource_exists(RD, ObjectType) when ?is_object(ObjectType) ->
       Id = list_to_binary(wrq:path_info(id, RD)),
       case erli_storage:read(ObjectType, Id) of
  -	{error, _Error} ->
  -	    {false, RD, ObjectType};
  +	{error, _Error} -> {false, RD, ObjectType};
   	Obj when is_record(Obj, target) ->
   	    {not Obj#target.is_banned, RD, {ObjectType, Obj}};
   	Obj when is_record(Obj, path) ->
   	    {not Obj#path.is_banned, RD, {ObjectType, Obj}};
  -	Obj ->
  -	    {true, RD, {ObjectType, Obj}}
  -    end;
  -resource_exists(RD, {path, target}=Ctx) ->
  +	Obj -> {true, RD, {ObjectType, Obj}}
  +    end;
  +resource_exists(RD, {path, target} = Ctx) ->
       Id = list_to_binary(wrq:path_info(id, RD)),
       case root_elem_exists(path, Id) of
  -	false ->
  -	    {false, RD, Ctx};
  -	{false, Obj} ->
  -	    {false, RD, {path, Obj}};
  +	false -> {false, RD, Ctx};
  +	{false, Obj} -> {false, RD, {path, Obj}};
   	{true, Obj} ->
   	    %% this assumes that the many-to-one relationship is enforced
   	    Record = erli_storage:read(target, Obj#path.target_id),
   	    {true, RD, {target, Record}}
  -	end;
  -resource_exists(RD, {{ObjectType, Relation}, Range}=Ctx)
  +    end;
  +resource_exists(RD, {{ObjectType, Relation}, Range} = Ctx)
     when ?is_collection(Relation) ->
       Id = list_to_binary(wrq:path_info(id, RD)),
       case root_elem_exists(ObjectType, Id) of
  -	false ->
  -	    {false, RD, Ctx};
  -	{false, Obj} ->
  -	    {false, RD, {ObjectType, Obj}};
  +	false -> {false, RD, Ctx};
  +	{false, Obj} -> {false, RD, {ObjectType, Obj}};
   	{true, _Obj} ->
   	    Data = erli_storage:read_multiple(Relation, Range),
   	    Meta = erli_utils:meta_proplist(Relation, Range),
   	    {true, RD, {Relation, {Meta, Data}}}
       end;
   resource_exists(RD, {CollectionType, Range}) ->
  -    Data = erli_storage:read_multiple(CollectionType, Range),
  +    Data = erli_storage:read_multiple(CollectionType,
  +				      Range),
       Meta = erli_utils:meta_proplist(CollectionType, Range),
  -    ContentRangeHeader = erli_utils:build_content_range_header(CollectionType,
  -							       Meta),
  -    NRD = wrq:set_resp_header("Content-Range", ContentRangeHeader, RD),
  +    ContentRangeHeader =
  +	erli_utils:build_content_range_header(CollectionType,
  +					      Meta),
  +    NRD = wrq:set_resp_header("Content-Range",
  +			      ContentRangeHeader, RD),
       {true, NRD, {CollectionType, {Meta, Data}}}.
   
  -
  -previously_existed(RD, {path, Rec}=Ctx) ->
  +-spec previously_existed(rd(), {object_type(), object()}) ->
  +				{boolean(), rd(), {object_type(), object()}};
  +			(rd(), {collection_type(), collection()}) ->
  +				{false, rd(), {collection_type(), collection()}}.
  +previously_existed(RD, {path, Rec} = Ctx) ->
       {Rec#path.is_banned, RD, Ctx};
  -previously_existed(RD, {target, Rec}=Ctx) ->
  +previously_existed(RD, {target, Rec} = Ctx) ->
       {Rec#target.is_banned, RD, Ctx};
  -previously_existed(RD, Ctx) ->
  -    {false, RD, Ctx}.
  -
  -
  +previously_existed(RD, Ctx) -> {false, RD, Ctx}.
  +
  +-spec generate_etag(rd(), term()) -> {string(), rd(), term()}.
   generate_etag(RD, Ctx) ->
       Etag = erli_utils:generate_etag(Ctx),
       {Etag, RD, Ctx}.
   
  -
  +-spec content_types_provided(rd(), term()) ->
  +				    {[{string(), atom()}], rd(), term()}.
   content_types_provided(RD, Ctx) ->
       {[{"application/json", as_json}], RD, Ctx}.
   
  -
  -as_json(RD, {ObjectType, Rec}=Ctx) when ?is_object(ObjectType) ->
  +-spec as_json(rd(), {object_type(), object()}) ->
  +		     {bitstring(), rd(), {object_type(), object()}};
  +	     (rd(), {collection_type(), collection()}) ->
  +		     {bitstring(), rd(), {collection_type(), collection()}}.
  +as_json(RD, {ObjectType, Rec} = Ctx) when ?is_object(ObjectType) ->
       maybe_record_visit(RD, Ctx),
  -    CollectionType = erli_utils:obj_type_to_col_type(ObjectType),
  +    CollectionType =
  +	erli_utils:obj_type_to_col_type(ObjectType),
       Key = atom_to_binary(CollectionType, latin1),
       Data = jsx:encode([{Key, erli_utils:to_proplist(Rec)}]),
       {Data, RD, Ctx};
  -as_json(RD, {CollectionType, {Meta, Collection}}=Ctx) ->
  +as_json(RD,
  +	{CollectionType, {Meta, Collection}} = Ctx) ->
       Key = atom_to_binary(CollectionType, latin1),
  -    Data = jsx:encode([{Key, erli_utils:to_proplist(Collection)},
  +    Data = jsx:encode([{Key,
  +			erli_utils:to_proplist(Collection)},
   		       {<<"meta">>, Meta}]),
       {Data, RD, Ctx}.
   
  -
  +-spec process_post(rd(), term()) ->
  +			  {true, rd(), term()} |
  +			  {{halt, 409}, rd(), term()} |
  +			  {{halt, 415}, rd(), term()} |
  +			  {{halt, 422}, rd(), term()}.
   process_post(RD, Ctx) ->
  -    case mochiweb_util:parse_header(wrq:get_req_header("Content-Type", RD)) of
  +    case
  +	mochiweb_util:parse_header(wrq:get_req_header("Content-Type",
  +						      RD))
  +    of
   	{"application/x-www-form-urlencoded", _} ->
   	    Form = erli_forms:http_body_to_form(wrq:req_body(RD)),
   	    handle_post(Form, RD, Ctx);
   	{"application/json", _} ->
   	    Form = jsx:decode(wrq:req_body(RD)),
   	    handle_post(Form, RD, Ctx);
  -	_ ->
  -	    {{halt, 415}, RD, Ctx}
  -    end.
  -
  -
  +	_ -> {{halt, 415}, RD, Ctx}
  +    end.
  +
  +-spec delete_resource(rd(), {object_type(), object()}) ->
  +			     {true, rd(), {object_type(), object()}}.
   delete_resource(RD, {ObjectType, Obj}) when ?is_object(ObjectType) ->
  -    {_RemovalState, NewObj} =  erli_storage:request_removal(Obj),
  +    {_RemovalState, NewObj} =
  +	erli_storage:request_removal(Obj),
       {true, RD, {ObjectType, NewObj}}.
   
  -
  -delete_completed(RD, {_ObjectType, Obj}=Ctx) when is_record(Obj, target) ->
  +-spec delete_completed(rd(), {object_type(), object()}) ->
  +			      {boolean(), rd(), {object_type(), object()}}.
  +delete_completed(RD, {_ObjectType, Obj} = Ctx) when is_record(Obj, target) ->
       {Obj#target.is_banned, RD, Ctx};
  -delete_completed(RD, {_ObjectType, Obj}=Ctx) when is_record(Obj, path) ->
  +delete_completed(RD, {_ObjectType, Obj} = Ctx) when is_record(Obj, path) ->
       {Obj#path.is_banned, RD, Ctx}.
   
   
  
positive.code: 	    {{halt, 422}, NRD, Ctx}
      end.
  
  
  -spec build_record(object_type(), proplist()) -> object().
  build_record(path, Form) ->
      TargetId = proplists:get_value(<<"target_id">>, Form),
      case proplists:get_value(<<"custom_id">>, Form) of
  	undefined ->
  	    #path{target_id=TargetId};
  	Id ->
  	    #path{target_id=TargetId, id=Id}
      end.
  
  
  -spec maybe_store(collection_type(), object(), #wm_reqdata{}, term()) ->
  			 {true | {halt, 409 | 422}, #wm_reqdata{}, term()}.
  maybe_store(CollectionType, Record, RD, Ctx) ->
      case erli_storage:create(Record) of
  	{error, {conflict, {SubmittedRecord, ExistingRecord}}} ->
  	    Body = jsx:encode([{<<"conflictingEntity">>,
  				erli_utils:to_proplist(ExistingRecord)},
  			       {<<"submittedEntity">>,
  
negative.code: -module(erli_generic_resource).
  
  %% Webmachine Callbacks
  -export([allowed_methods/2, as_json/2,
  	 content_types_provided/2, delete_completed/2,
  	 delete_resource/2, generate_etag/2, init/1,
  	 malformed_request/2, options/2, previously_existed/2,
  	 process_post/2, resource_exists/2]).
  
  -include("models.hrl").
  
  -include_lib("webmachine/include/webmachine.hrl").
  
  %%-----------------------------------------------------------
  