anchor.diff:  
   -endif. %% NO_HAVE_MAPS
   
  +is_major_version_at_least(VsnMin) when VsnMin >= 17 ->
  +    case erlang:system_info(otp_release) of
  +        "R"++_ -> % R16 or ealier
  +            false;
  +        RelStr ->
  +            %% In Erlang 17 the leading "R" was dropped
  +            %% The exact format isn't super documented,
  +            %% so be prepared for some (future?) alternatives.
  +            try list_to_integer(RelStr) of
  +                N when is_integer(N) -> N >= VsnMin
  +            catch error:badarg ->
  +                    [NStr | _] = string:tokens(RelStr, ".-"),
  +                    try list_to_integer(NStr) of
  +                        N when is_integer(N) -> N >= VsnMin
  +                    catch error:badarg ->
  +                            false
  +                    end
  +            end
  +    end.
  +
   find_translation(ElemPath, Op, AnRes) ->
       find_translation(ElemPath, Op, AnRes, undefined).
   find_translation(ElemPath, Op, #anres{map_translations=Ts}, Default) ->
  
positive.code:                            "."))
                 end)
       end].
  
  %% -- translators ------------------------------------------------------
  
  
negative.code:               unsigned -> 1 bsl NumBits - 1;
                signed   -> 1 bsl (NumBits-1) - 1
            end,
      FnName = mk_fn(v_type_, IntType),
      [nowarn_dialyzer_attr(FnName, 2),
       gpb_codegen:format_fn(
         FnName,
         fun(N, _Path) when '<Min>' =< N, N =< '<Max>' ->
                 ok;
            (N, Path) when is_integer(N) ->
                 mk_type_error({value_out_of_range, '<details>'}, N, Path);
            (X, Path) ->
                 mk_type_error({bad_integer, '<details>'}, X, Path)
         end,
         [replace_term('<Min>', Min),
          replace_term('<Max>', Max),
          splice_trees('<details>', [erl_syntax:atom(IntType),
                                     erl_syntax:atom(Signedness),
                                     erl_syntax:integer(NumBits)])])].
  
  format_bool_verifier() ->
      FnName = mk_fn(v_type_, bool),
      [nowarn_dialyzer_attr(FnName, 2),
       gpb_codegen:format_fn(
         FnName,
         fun(false, _Path) -> ok;
            (true, _Path)  -> ok;
            (X, Path) -> mk_type_error(bad_boolean_value, X, Path)
         end)].
  
  format_float_verifier(FlType) ->
      BadTypeOfValue = list_to_atom(lists:concat(["bad_", FlType, "_value"])),
      FnName = mk_fn(v_type_, FlType),
      [nowarn_dialyzer_attr(FnName, 2),
       gpb_codegen:format_fn(
         FnName,
         fun(N, _Path) when is_float(N) -> ok;
            %% It seems a float for the corresponding integer value is
            %% indeed packed when doing <<Integer:32/little-float>>.
            %% So let verify accept integers too.
            %% When such a value is unpacked, we get a float.
            (N, _Path) when is_integer(N) -> ok;
            (X, Path) -> mk_type_error('<bad_x_value>', X, Path)
         end,
         [replace_term('<bad_x_value>', BadTypeOfValue)])].
  
  format_string_verifier() ->
      FnName = mk_fn(v_type_, string),
      [nowarn_dialyzer_attr(FnName, 2),
       gpb_codegen:format_fn(
         FnName,
         fun(S, Path) when is_list(S); is_binary(S) ->
                 try unicode:characters_to_binary(S) of
                     B when is_binary(B) ->
                         ok;
                     {error, _, _} -> %% a non-UTF-8 binary
                         mk_type_error(bad_unicode_string, S, Path)
                 catch error:badarg ->
                         mk_type_error(bad_unicode_string, S, Path)
                 end;
            (X, Path) ->
                 mk_type_error(bad_unicode_string, X, Path)
         end)].
  
  format_bytes_verifier() ->
      FnName = mk_fn(v_type_, bytes),
      [nowarn_dialyzer_attr(FnName, 2),
       gpb_codegen:format_fn(
         FnName,
         fun(B, _Path) when is_binary(B) ->
                 ok;
            (X, Path) ->
                 mk_type_error(bad_binary_value, X, Path)
         end)].
  
  format_map_verifiers(#anres{map_types=MapTypes}, Opts) ->
      RecordsOrMaps = get_records_or_maps_by_opts(Opts),
  