anchor.diff:  validate_options([{transitional, B}|Rs]) when is_boolean(B) -> validate_options(Rs);
   validate_options([_]) -> erlang:error(badarg).
   
  -to_ascii([], _Options, Acc) ->
  +encode_1([], Acc) ->
       lists:reverse(Acc);
  -to_ascii([Label|Labels], Options, []) ->
  -    to_ascii(Labels, Options, lists:reverse(label_to_ascii(Label, Options)));
  -to_ascii([Label|Labels], Options, Acc) ->
  -    to_ascii(Labels, Options, lists:reverse(label_to_ascii(Label, Options), [$.|Acc])).
  +encode_1([Label|Labels], []) ->
  +    encode_1(Labels, lists:reverse(alabel(Label)));
  +encode_1([Label|Labels], Acc) ->
  +    encode_1(Labels, lists:reverse(alabel(Label), [$.|Acc])).
   
  -label_to_ascii(Label, Options) ->
  +alabel(Label) ->
       case lists:all(fun(C) -> idna_ucs:is_ascii(C) end, Label) of
           true ->
               Label;
           false ->
  -            ?ACE_PREFIX ++ punycode:encode(characters_to_nfkc_list(uts46_remap(Label, Options)))
  +            ?ACE_PREFIX ++ punycode:encode(Label)
       end.
   
   from_ascii([], Acc) ->
  
positive.code: append(GC, Str) when is_list(GC) -> GC ++ Str.
  
  
  characters_to_nfkc_list(CD) ->
      case unicode_util_compat:nfc(CD) of
          [CPs|Str] when is_list(CPs) -> CPs ++ characters_to_nfkc_list(Str);
          [CP|Str] -> [CP|characters_to_nfkc_list(Str)];
          [] -> []
      end.
  
  
  uts46_remap(Str, Options) ->
    Std3Rules = proplists:get_value(std3_rules, Options, true),
    Transitional = proplists:get_value(transitional, Options, false),
    uts46_remap(Str, Std3Rules, Transitional).
  
  uts46_remap([Cp|Rs], Std3Rules, Transitional) ->
    {Status, Replacement, _IStatus} =  idna_mapping:uts46_map(Cp),
    if
      ((Status =:= valid) orelse
       (Status =:= deviation andalso Transitional =:= false) orelse
       (Status =:= disallowed_STD3_mapped andalso Std3Rules =:= false andalso Replacement =:= undefined)) ->
        [Cp] ++ uts46_remap(Rs, Std3Rules, Transitional);
      ((Replacement =/= undefined) andalso
       ((Status =:= mapped) orelse
        (Status =:= disallowed_STD3_mapped andalso Std3Rules =:= false) orelse
        (Status =:= deviation andalso Transitional =:= true))) ->
        Replacement ++ uts46_remap(Rs, Std3Rules, Transitional);
      Status =:= ignored ->
         uts46_remap(Rs, Std3Rules, Transitional);
      true ->
        erlang:exit({invalid_codepoint, Cp})
    end;
  uts46_remap([], _, _) ->
    [].
  
negative.code: -module(idna).
  
  %% API
  -export([encode/1, encode/2]).
  
  %% compatibility API
  -export([to_ascii/1,
           utf8_to_ascii/1,
           from_ascii/1]).
  
  -define(ACE_PREFIX, "xn--").
  
  encode(Domain) ->
    encode(Domain, []).
  
  encode(Domain0, Options) ->
      ok = validate_options(Options),
  
      Domain = case proplists:get_value(uts46, Options, false) of
                 true ->
                   STD3Rules = proplists:get_value(std3_rules, Options, false),
                   Transitional = proplists:get_value(transitional, Options, false),
                   uts46_remap(Domain0, STD3Rules, Transitional);
                 false -> Domain0
               end,
  
      Labels = case proplists:get_value(strict, Options, false) of
                 false ->
                   re:split(lowercase(Domain), "[.。．｡]", [{return, list}, unicode]);
                true ->
                  string:tokens(lowercase(Domain), ".")
              end,
  
      case Labels of
        [] -> exit(empty_domain);
        _ ->
          encode_1(Labels, [])
      end.
  
  to_ascii(Domain) -> encode(Domain, [uts46]).
  
  
  utf8_to_ascii(Domain) ->
    to_ascii(idna_ucs:from_utf8(Domain)).
  
  -spec from_ascii(nonempty_string()) -> nonempty_string().
  from_ascii(Domain) ->
      from_ascii(string:tokens(Domain, "."), []).
  
  
  %% Helper functions
  %%
  
  validate_options([]) -> ok;
  validate_options([uts46|Rs]) -> validate_options(Rs);
  validate_options([{uts46, B}|Rs]) when is_boolean(B) -> validate_options(Rs);
  validate_options([strict|Rs]) -> validate_options(Rs);
  validate_options([{strict, B}|Rs]) when is_boolean(B) -> validate_options(Rs);
  validate_options([std3_rules|Rs]) -> validate_options(Rs);
  