anchor.diff:             true -> throw({badarg,K})
           end,
       [T|List];
  -validate({default_character_set=K,Value}, List) -> % integer()
  -    T = if is_integer(Value)                 -> {K, Value};
  +validate({default_character_set=K,Value}, List) -> % non_neg_integer()
  +    T = if is_integer(Value), 0 =< Value     -> {K, Value};
              true -> throw({badarg,K})
           end,
       [T|List];
  
positive.code:             {reply, {ok,Term1,Term2,Term3}, S#state{handle = Handle}};
          {error, Reason, Handle} ->
              {reply, {error,Reason}, S#state{handle = Handle}}
      end;
  handle_call(Request, From, State) ->
      io:format("~p [~p:handle_call] req=~p,~p~n", [self(),?MODULE,Request,From]),
      {reply, {error,badarg}, State}.
  
  handle_cast(stop, State) ->
      {stop, normal, State};
  handle_cast(Request, State) ->
      io:format("~p [~p:handle_cast] req=~p~n", [self(),?MODULE,Request]),
      {noreply, State}.
  
  handle_info({'EXIT',_Pid,Reason}, State) ->
      {stop, Reason, State};
  handle_info(Info, State) ->
      io:format("~p [~p:handle_info] info=~p~n", [self(),?MODULE,Info]),
      {noreply, State}.
  
  %% == private: state ==
  
  cleanup(#state{handle=H}=S)
    when undefined =/= H ->
      _ = myer_protocol:close(H),
      cleanup(S#state{handle = undefined, auth = false});
  cleanup(#state{}) ->
      %%io:format("~p [~p:cleanup]~n",[self(),?MODULE]),
      flush().
  
  setup([]) ->
      %%io:format("~p [~p:setup]~n",[self(),?MODULE]),
      process_flag(trap_exit, true),
      {ok, #state{}}.
  
  setup(Args, #state{handle=undefined}=S) ->
      L = [
           proplists:get_value(address, Args, "localhost"),
           proplists:get_value(port, Args, 3306),
           proplists:get_value(default_character_set, Args, ?CHARSET_utf8_general_ci),
           proplists:get_value(compress, Args, false),
           proplists:get_value(max_allowed_packet, Args, 4194304),
           timer:seconds(proplists:get_value(timeout, Args, 10))
          ],
      case apply(myer_protocol, connect, [L]) of
          {ok, Handle} ->
              setup(Args, S#state{handle = Handle, auth = false});
          {error, Reason} ->
              {error, Reason, S};
          {error, Reason, Handle} ->
              {error, Reason, S#state{handle = Handle}}
      end;
  setup(Args, #state{handle=H,auth=false}=S) ->
      L = [
           proplists:get_value(user, Args, <<"root">>),
           proplists:get_value(password, Args, <<"">>),
           proplists:get_value(database, Args, <<"">>)
          ],
      case apply(myer_protocol, auth, [H|L]) of
          {ok, _Result, Handle} ->
              setup(Args, S#state{handle = Handle, auth = true});
          {error, Reason, Handle} ->
              {error, Reason, S#state{handle = Handle}}
      end;
  setup(_Args, #state{}=S) ->
      {ok, S}.
  
  %% == private ==
  
  flush() ->
      receive _ -> flush() after 0 -> ok end.
  
  validate({address=K,Value}, List) -> % inet:ip_address()|inet:hostname()
      T = if is_atom(Value)                    -> {K, Value};
             is_list(Value), 0 < length(Value) -> {K, Value};
             is_binary(Value), 0 < size(Value) -> {K, binary_to_list(Value)};
             true -> throw({badarg,K})
          end,
      [T|List];
  validate({port=K,Value}, List) -> % inet:port_number()
      T = if is_integer(Value)                 -> {K, Value};
             true -> throw({badarg,K})
          end,
  
negative.code:          handle_call/3, handle_cast/2, handle_info/2]).
  
  %% -- private --
  -record(state, {
            args :: [property()],
            handle :: tuple()
           }).
  
  -define(SOCKET(Handle), element(2,Handle)).     % !CAUTION!
  
  %% == public ==
  
  -spec start_link([property()]) -> {ok,pid()}|ignore|{error,_}.
  start_link(Args) ->
      start_link(Args, false).
  
  -spec start_link([property()],boolean()) -> {ok,pid()}|ignore|{error,_}.
  start_link(Args, false)
  