anchor.diff:  %% Geographic IP Informatin Server
   %%================================
   
  -%% TODO: erlang:decode_packet
  -%% TODO: inet:parse_ipv4strict_address
  -
   -module(geoip).
   -author('wuhualiang@meituan.com').
   
   -mode(compile).
  -
  --export([start/2]).
  +-export([init/1, start/2, worker/2]).
   
   -define(DEV, _).
   -ifdef(DEV).
   -export([http_response/2]).
   -export([special_ip/1]).
   -export([multicast_ip/1]).
  +-export([invalid_ip/0]).
  +-export([normal_ip/0]).
  +-export([format/1]).
   -endif.
   
  +-define(LOG_FILE, "logs").
   -define(IPS_FILE, "ips.dump").
   -define(GEO_FILE, "geo.meta").
   -define(IPS_TABLE, mt_ips).
   -define(GEO_TABLE, mt_geo).
   -define(GEO_MANAGER, geoman).
  +-define(SNAPSHOT_INTV, 86400000).
  +-define(WRITEBACK_THR, 100000).
   -define(HIGH_WATER_MARK, 1000).
  --define(SNAPSHOT_INTV, 86400*1000).
  --define(WRITEBACK_THR, 100000).
  -
  -start(Port, Threads) ->
  +
  +init(careful) ->
  +    ets:new(?IPS_TABLE, [set, public, named_table]),
  +    ets:new(?GEO_TABLE, [set, public, named_table]),
  +    ets:insert(?IPS_TABLE, {count, 0}),
  +    ets:insert(?GEO_TABLE, {{ips,      count}, 0}),
  +    ets:insert(?GEO_TABLE, {{country,  count}, 0}),
  +    ets:insert(?GEO_TABLE, {{province, count}, 0}),
  +    ets:insert(?GEO_TABLE, {{city,     count}, 0}),
  +    ets:insert(?GEO_TABLE, {{county,   count}, 0}),
  +    ets:tab2file(?IPS_TABLE, ?IPS_FILE),
  +    ets:tab2file(?GEO_TABLE, ?GEO_FILE),
  +    ets:delete(?IPS_TABLE),
  +    ets:delete(?GEO_TABLE),
  +    ok.
  +
  +start(Port, Procs) ->
       inets:start(),
  -    % ets:new(?IPS_TABLE, [set, public, named_table])
  -    % ets:new(?GEO_TABLE, [set, public, named_table])
  +    error_logger:logfile({open, ?LOG_FILE}),
       {ok, ?IPS_TABLE} = ets:file2tab(?IPS_FILE),
       {ok, ?GEO_TABLE} = ets:file2tab(?GEO_FILE),
       GeoMan = spawn(geoman),
       register(?GEO_MANAGER, GeoMan),
  -    lists:map(fun worker_init/1, [0, Threads-1]),
  -    {ok, LSock} = gen_tcp:listen(Port, []),
  -    listen(Port).
  +    lists:map(fun worker_init/1, [0, Procs-1]),
  +    {ok, LSock} = gen_tcp:listen(Port, [{active, false}, {packet, http}]),
  +    loop(LSock, Procs).
   
   %% ======== Internal Functions ======== %%
   
  -listen(Port) ->
  -   ok. 
  +worker_init(X) when is_integer(X) ->
  +    Tid = ets:new(taskqueue, [set, public]),
  +    put({worker, X}, Tid),
  +    put({latest_task, X}, 0),
  +    spawn(?MODULE, worker, [Tid, 1]).
  +
  +worker(Tid, Todo) ->
  +    case ets:lookup(Tid, Todo) of
  +        [{_, Sock}] ->
  +            case gen_tcp:recv(Sock, 0, 4000) of
  +                {ok, {http_request, 'GET', {abs_path, Path}, _}} ->
  +                    case Path of
  +                        "/api/ip/get/" ++ IP ->
  +                            {Code, Json} = lookup(IP),
  +                            Response = http_response(Code, Json),
  +                            inet:setopts(Sock, {send_timeout, 4000}),
  +                            gen_tcp:send(Sock, Response);
  +                        _ -> pass
  +                    end;
  +                _ -> pass
  +            end,
  +            gen_tcp:close(Sock),
  +            worker(Tid, Todo + 1);
  +        [] ->
  +            timer:sleep(1),
  +            worker(Tid, Todo)
  +    end.
  +
  +loop(LSock, Procs) ->
  +    {ok, Sock} = gen_tcp:accept(LSock),
  +    {X, Tid} = free_proc(Procs),
  +    Task = get({latest_task, X}) + 1,
  +    put({latest_task, X}, Task),
  +    ets:insert(Tid, {Task, Sock}),
  +    loop(LSock, Procs).
  +
  +free_proc(Procs) -> free_proc(Procs, 1).
  +free_proc(Procs, Tried) ->
  +    {_, _, Y} = erlang:now(),
  +    X = Y rem Procs,
  +    Tid = get({worker, X}),
  +    Size = ets:info(Tid, size),
  +    if Size < ?HIGH_WATER_MARK ->
  +        {X, Tid};
  +    true ->
  +        if Procs == Tried ->
  +            {X, Tid};
  +        true ->
  +            free_proc(Procs, Tried + 1)
  +        end
  +    end.
  +
  +geoman() ->
  +    receive
  +        {Type, Name, Pid} when is_pid(Pid) ->
  +            case ets:lookup(?GEO_TABLE, {Type, Name}) of
  +                [{_, Id}] ->
  +                    Pid ! Id;
  +                [] ->
  +                    [{_, Count}] = ets:lookup(?GEO_TABLE, {Type, count}),
  +                    Id = Count + 1,
  +                    ets:insert({{Type, Id}, Name}),
  +                    ets:insert({{Type, Name}, Id}),
  +                    ets:insert({{Type, count}, Id}),
  +                    Pid ! Id
  +            end;
  +        _ -> pass
  +    end,
  +    geoman().
   
   snapshot() ->
       timer:sleep(?SNAPSHOT_INTV),
  
positive.code:         _ -> invalid_ip()
      end.
  
  lookup_ets(IP) ->
      ok.
  
  special_ip(IP) ->
      Json = "{\"province\":\"https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml\"," ++
  
negative.code:     {200, Json}.
  
  invalid_ip() ->
      {400, "{\"message\":\"Invalid IP\"}"}.
  
  months() ->
      ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
  