anchor.diff:  validate_urls(Urls) ->
       [] == (catch lists:flatten([[1 || X <- L, not is_binary(X)] || L <- Urls])).
   
  --spec make_tagdata(tagcontent()) -> binary().
  -make_tagdata(D) ->
  -    list_to_binary(mochijson2:encode({struct,
  -        [
  -            {<<"id">>, D#tagcontent.id},
  -            {<<"version">>, 1},
  -            {<<"urls">>, D#tagcontent.urls},
  -            {<<"last-modified">>, D#tagcontent.last_modified},
  -            {<<"user-data">>, D#tagcontent.user}
  -        ]})).
  -
  --spec tag_lookup(any(), [binary()], [any()]) ->
  -     {'ok', [any()]} | {'error', _}.
  -tag_lookup(_, [], Results) ->
  -    {ok, lists:reverse(Results)};
  -tag_lookup(JsonBody, [Key|Rest], Results) ->
  -    case lists:keysearch(Key, 1, JsonBody) of
  -        {value, {_, Attrib}} ->
  -            tag_lookup(JsonBody, Rest, [Attrib|Results]);
  -        false ->
  -            case Key of
  -                <<"user-data">> ->
  -                    tag_lookup(JsonBody, Rest, [[] | Results]);
  -                _ ->
  -                    {error, not_found}
  -            end
  -    end.
  -
  --spec parse_tagcontent(binary()) -> {'error', _} | {'ok', tagcontent()}.
  -parse_tagcontent(TagData) ->
  -    case catch mochijson2:decode(TagData) of
  -        {'EXIT', _} ->
  -            {error, corrupted_json};
  -        {struct, Body} ->
  -            case tag_lookup(Body,
  -                            [<<"id">>, <<"urls">>, <<"last-modified">>, <<"user-data">>],
  -                            []) of
  -                {ok, [Id, Urls, LastModified, UserData]} ->
  -                    {ok, #tagcontent{id = Id,
  -                                     last_modified = LastModified,
  -                                     urls = Urls,
  -                                     user = UserData}};
  -                _ -> {error, invalid_object}
  -            end
  -    end.
  -
   % Put transaction:
   % 1. choose nodes
   % 2. multicall nodes, send TagData -> receive temporary file names
  
positive.code:                         ?TAG_EXPIRES
                      end
      }}.
  
  
  %%% Note to the reader!
  %%%
  
negative.code:                     | [{replica(), node()}],
                  url_cache :: 'false' | gb_set()}).
  
  -spec make_tagdata(tagcontent()) -> binary().
  make_tagdata(D) ->
      list_to_binary(mochijson2:encode({struct,
          [
              {<<"id">>, D#tagcontent.id},
              {<<"version">>, 1},
              {<<"urls">>, D#tagcontent.urls},
              {<<"last-modified">>, D#tagcontent.last_modified},
              {<<"user-data">>, D#tagcontent.user}
          ]})).
  
  -spec tag_lookup(any(), [binary()], [any()]) ->
       {'ok', [any()]} | {'error', _}.
  tag_lookup(_, [], Results) ->
      {ok, lists:reverse(Results)};
  tag_lookup(JsonBody, [Key|Rest], Results) ->
      case lists:keysearch(Key, 1, JsonBody) of
          {value, {_, Attrib}} ->
              tag_lookup(JsonBody, Rest, [Attrib|Results]);
          false ->
              case Key of
                  <<"user-data">> ->
                      tag_lookup(JsonBody, Rest, [[] | Results]);
                  _ ->
                      {error, not_found}
              end
      end.
  
  -spec parse_tagcontent(binary()) -> {'error', _} | {'ok', tagcontent()}.
  parse_tagcontent(TagData) ->
      case catch mochijson2:decode(TagData) of
          {'EXIT', _} ->
              {error, corrupted_json};
          {struct, Body} ->
              case tag_lookup(Body,
                              [<<"id">>, <<"urls">>, <<"last-modified">>, <<"user-data">>],
                              []) of
                  {ok, [Id, Urls, LastModified, UserData]} ->
                      {ok, #tagcontent{id = Id,
                                       last_modified = LastModified,
                                       urls = Urls,
                                       user = UserData}};
                  _ -> {error, invalid_object}
              end
      end.
  
  % THOUGHT: Eventually we want to partition tag keyspace instead
  % of using a single global keyspace. This can be done relatively 
  % easily with consistent hashing: Each tag has a set of nodes 
  