anchor.diff:      Date = {
         {
           list_to_integer(binary_to_list(Year)) + 2000,
  -        list_to_integer(binary_to_list(Month)), 
  +        list_to_integer(binary_to_list(Month)),
           list_to_integer(binary_to_list(Day))
         },
         {
  -        list_to_integer(binary_to_list(Hour)), 
  +        list_to_integer(binary_to_list(Hour)),
           list_to_integer(binary_to_list(Minute)),
  -        list_to_integer(binary_to_list(Second)) 
  +        list_to_integer(binary_to_list(Second))
         }
        },
  -  em_helper_time:datetime_to_utc(Date).
  +    em_helper_time:datetime_to_utc(Date).
   
   data_match(Data, Pattern) ->
  -  {match, List} = re:run(Data, Pattern),
  -  lists:reverse(lists:foldl(fun(Param, Res) ->
  -                                    [read_param(Param, Data) | Res]
  -                            end, [], List)).
  +    {match, List} = re:run(Data, Pattern),
  +    lists:reverse(lists:foldl(fun(Param, Res) ->
  +                                      [read_param(Param, Data) | Res]
  +                              end, [], List)).
   
   read_param({-1, 0}, _) ->
       void;
  
positive.code: -define(Millage, <<"(?:L([0-9a-fA-F]+))?">>).       % Millage
  
  -define(PATTERN,
    <<
    ?DeviceID/binary,
    ?Command/binary,
    ?IMEI/binary,
    ?Date/binary,
    ?Validity/binary,
    ?Latitude/binary,
    ?LatitudeType/binary,
    ?Longitude/binary,
    ?LongitudeType/binary,
    ?Speed/binary,
    ?Time/binary,
    ?Course/binary,
    ?State/binary,
    ?Millage/binary
    >>
  ).
  
  
  -record(state, {protocol, transport, socket, timeout, device, pattern}).
  
  start_link(Ref, Socket, Transport, Opts) ->
    Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]),
    {ok, Pid}.
  
  init(Ref, Socket, Transport, Opts) ->
    ok = ranch:accept_ack(Ref),
    Protocol = proplists:get_value(protocol, Opts),
    {ok, Pattern} = re:compile(?PATTERN),
    loop(#state{protocol = Protocol, socket = Socket, transport = Transport, pattern = Pattern}).
  
  
  loop(State = #state{protocol = Protocol, socket = Socket, transport = Transport, pattern = Pattern}) ->
    case Transport:recv(Socket, 0, 5000) of
      {ok, Data} ->
        em_logger:info("[packet] unit: ip = '~s' data: ~s", [em_hardware:resolve(Socket), Data]),
        {Imei, Message} = parse(Data, Pattern),
        case em_data_manager:get_device_by_uid(Imei) of
          null ->
            em_logger:info("[packet] unit: ip = '~s' unknown device with imei = '~s'", [em_hardware:resolve(Socket), Imei]),
            Transport:close(Socket);
          Object ->
            em_logger:info("save message => unit: ip = '~s' id = '~w' imei = '~s' message: ~s", [em_hardware:resolve(Socket), maps:get(<<"id">>, Object), Imei, em_json:encode(Message)]),
            em_data_manager:create_message(maps:get(<<"id">>, Object), Protocol, maps:merge(#{imei => maps:get(<<"uniqueId">>, Object)}, Message)),
            loop(State#state{device = Object})
        end;
      _ ->
        Transport:close(Socket)
    end.
  
  % echo "2. tk103"
  % (echo -n -e "(123456789012BP05123456789012345120101A6000.0000N13000.0000E000.0120200000.0000000000L000946BB)";) | nc -v localhost 5002
  parse(Data, Pattern) ->
      case data_match(Data, Pattern) of
          [_, DeviceId, Command, Imei, Year, Month, Day, Validity, LatDD, LatMM_MMMM, LatType, LonDD, LonMM_MMMM, LonType, Speed, Hour, Minute, Second, Course, State, Millage] ->
              Message = #{
                <<"deviceTime">> => parse_date(Year, Month, Day, Hour, Minute, Second),
                <<"latitude">> => parse_coord(LatDD, LatMM_MMMM, LatType),
                <<"longitude">> => parse_coord(LonDD, LonMM_MMMM, LonType),
                <<"speed">> => parse_speed(Speed),
                <<"course">> => parse_course(Course),
                <<"deviceId">> => parse_device_id(DeviceId),
                <<"valid">> => parse_validity(Validity)
               },
              {Imei, Message};
          _ ->
              #{}
      end.
  
negative.code: 
  %% (123456789012 BP05 123456789012345 120101 A 6000.0000N 13000.0000E 000.0 120200 000.00 00000000 L000946BB)
  test() ->
      Packet = <<"(123456789012BP05123456789012345120101A6000.0000N13000.0000E000.0120200000.0000000000L000946BB)">>,
      {ok, Pattern} = re:compile(?PATTERN),
      parse(Packet, Pattern).
  