Implementations/Libraries/Erlang

From Geohashing

Erlang Implementation

This implementation IS FULLY 30W-compliant.

Carl-Johan made a reference Erlang implementation. It should be fully 30W compliant even for retro hashes. Don't forget to run geohash:init() befor your first lookup.

-module(geohash).
-export([init/0
	 , lookup/1
	]).

-record(meetup,
	{lat
	 , lon
	 , date
	 , djiadate
	 , latdec
	 , londec
	 , latcoord
	 , loncoord
	 , djia
	}).

url() ->
    "http://carabiner.peeron.com/xkcd/map/data/~4.10.0b/~2.10.0b/~2.10.0b".

int_to_dec() ->
    5.421010862427522e-20. %math:pow(2,-64).

init() ->
    application:start(inets),
    application:start(crypto).

lookup(Meetup = #meetup{lat=Lat, lon=Lon, date = {_Y, _M, _D}}) when
      Lat > -90,
      Lat < 90,
      Lon > -180,
      Lon < 180 ->
    Meetup1 = w30(Meetup),
    get_djia(Meetup1).

w30(Meetup = #meetup{lat=Lat, date = {Y, M, D}}) ->
    case (Lat > -30) and
	(calendar:date_to_gregorian_days(Y, M, D) >
	     calendar:date_to_gregorian_days(2008, 5, 26)) of
	true  -> Meetup#meetup{
		   djiadate =
		       calendar:gregorian_days_to_date(
			 calendar:date_to_gregorian_days(Y,M,D)-1)
		  };
	false -> Meetup#meetup{
		   djiadate={Y, M, D}
		  }
    end.
	    
get_djia(Meetup = #meetup{djiadate = {Y, M, D}}) ->
    Url = io_lib:format(url(), [Y, M, D]),
    case httpc:request(Url) of
	{ok, {{"HTTP/1.1",200,"OK"},
	      _,
	      Djia}} -> coords(Meetup#meetup{djia=Djia});
	{ok, {{"HTTP/1.1",404,"Not Found"},
	      _,_}}  -> Meetup
    end.

coords(Meetup = #meetup{lat = Lat
			, lon = Lon
			, date = {Y, M, D}
			, djia = Djia}) ->
    Str = io_lib:format("~4.10.0b-~2.10.0b-~2.10.0b-~s",
			[Y, M, D, Djia]),
    <<LatInt:64,
      LonInt:64>> = crypto:md5(Str),
    LatDec = LatInt * int_to_dec(),
    LonDec = LonInt * int_to_dec(),
    Meetup#meetup{latdec = LatDec
		  , londec = LonDec
		  , latcoord = Lat + LatDec
		  , loncoord = Lon + LonDec
		 }.