anchor.diff:              to_tokens([{T1, C1}, {Tag, R1} | Rest],
                         [{start_tag, T1, A1, false} | Acc])
       end;
  -to_tokens([{Tag, [L | R1]} | Rest], Acc) when is_list(L) ->
  -    to_tokens([{Tag, R1} | Rest], [{data, L, false} | Acc]).
  +to_tokens([{Tag0, [L | R1]} | Rest], Acc) when is_list(L) ->
  +    Tag = to_tag(Tag0),
  +    to_tokens([{Tag, R1} | Rest], [{data, L, false} | Acc]);
  +to_tokens([{Tag0, [B | R1]} | Rest], Acc) when is_binary(B) ->
  +    Tag = to_tag(Tag0),
  +    to_tokens([{Tag, R1} | Rest], [{data, binary_to_list(B), false} | Acc]).
   
   test_tokens() ->
       [{start_tag, "foo", [{"bar", "baz"},
  
positive.code:     test_parse_tokens(),
      test_escape(),
      test_escape_attr(),
      ok.
  
  
  %% Internal API
  
  to_html([], Acc) ->
      lists:reverse(Acc);
  to_html([{data, Data, _Whitespace} | Rest], Acc) ->
      to_html(Rest, [escape(Data) | Acc]);
  to_html([{start_tag, Tag, Attrs, Singleton} | Rest], Acc) ->
      Open = "<" ++ Tag ++ attrs_to_html(Attrs, []) ++ case Singleton of
                                                           true -> " />";
                                                           false -> ">"
                                                       end,
      to_html(Rest, [Open | Acc]);
  to_html([{end_tag, Tag} | Rest], Acc) ->
      to_html(Rest, ["</" ++ Tag ++ ">" | Acc]).
  
  attrs_to_html([], Acc) ->
      lists:reverse(Acc);
  attrs_to_html([{K, V} | Rest], Acc) ->
      attrs_to_html(Rest, [" " ++ K ++ "=\"" ++ escape_attr(V) ++ "\"" | Acc]).
      
  test_escape() ->
      "&amp;quot;\"word &lt;&lt;up!&amp;quot;" =
  
negative.code: %% @doc Transform the input UTF-8 HTML into a token stream.
  tokens(Input) when is_binary(Input) ->
      tokens(binary_to_list(Input), #decoder{}, []);
  tokens(Input) when is_list(Input) ->
      tokens(Input, #decoder{}, []).
  
  %% @spec to_tokens(html_node()) -> [html_token()]
  %% @doc Convert a html_node() tree to a list of tokens.
  to_tokens({Tag0, Attrs, Acc}) ->
      Tag = to_tag(Tag0),
      to_tokens([{Tag, Acc}], [{start_tag, Tag, Attrs, is_singleton(Tag)}]).
  
  %% @spec to_html([html_token()] | html_node()) -> iolist()
  %% @doc Convert a list of html_token() to a HTML document.
  to_html(Node={_Tag, _Attrs, _Acc}) ->
      to_html(to_tokens(Node));
  to_html(Tokens) when is_list(Tokens) ->
      to_html(Tokens, []).
  
  %% @spec escape(string() | binary()) -> string()
  %% @doc Escape a string such that it's safe for HTML (amp; lt; gt;).
  escape(B) when is_binary(B) ->
      escape(binary_to_list(B), []);
  escape(A) when is_atom(A) ->
      escape(atom_to_list(A), []);
  escape(S) when is_list(S) ->
      escape(S, []).
  
  %% @spec escape(S::string()) -> string()
  %% @doc Escape a string such that it's safe for HTML attrs
  %%      (amp; lt; gt; quot;).
  escape_attr(B) when is_binary(B) ->
      escape_attr(binary_to_list(B), []);
  escape_attr(A) when is_atom(A) ->
      escape_attr(atom_to_list(A), []);
  escape_attr(S) when is_list(S) ->
      escape_attr(S, []).
  
  %% @spec test() -> ok
  