Skip to content

Instantly share code, notes, and snippets.

@ngerakines
Created July 22, 2009 06:13
Show Gist options
  • Select an option

  • Save ngerakines/151842 to your computer and use it in GitHub Desktop.

Select an option

Save ngerakines/151842 to your computer and use it in GitHub Desktop.
<%@ draw(Year, Month, Dates) %>
<html>
<head>
<style>
/* calendar */
table.calendar { border-left:1px solid #999; }
tr.calendar-row { }
td.calendar-day { min-height:80px; font-size:11px; position:relative; } * html div.calendar-day { height:80px; }
td.calendar-day:hover { background:#eceff5; }
td.calendar-day-np { background:#eee; min-height:80px; } * html div.calendar-day-np { height:80px; }
td.calendar-day-head { background:#ccc; font-weight:bold; text-align:center; width:120px; padding:5px; border-bottom:1px solid #999; border-top:1px solid #999; border-right:1px solid #999; }
div.day-number { background:#999; padding:5px; color:#fff; font-weight:bold; float:right; margin:-5px -5px 0 0; width:20px; text-align:center; }
/* shared */
td.calendar-day, td.calendar-day-np { width:120px; padding:5px; border-bottom:1px solid #999; border-right:1px solid #999; }
</style>
</head>
<body>
<h2><% Month %> <% Year %></h2>
<table cellpadding="0" cellspacing="0" class="calendar">
<tr class="calendar-row">
<td class="calendar-day-head">Sunday</td>
<td class="calendar-day-head">Monday</td>
<td class="calendar-day-head">Tuesday</td>
<td class="calendar-day-head">Wednesday</td>
<td class="calendar-day-head">Thursday</td>
<td class="calendar-day-head">Friday</td>
<td class="calendar-day-head">Saturday</td>
</tr>
<% draw_cal(Dates) %>
</table>
</body>
</html>
<%@ draw_cal([]) %>
<%@ draw_cal([Week | Weeks]) %>
<% draw_week(Week) %>
<% draw_cal(Weeks) %>
<%@ draw_week(Week) %>
<tr class="calendar-row">
<% draw_days(Week) %>
</tr>
<%@ draw_days([]) %>
<%@ draw_days([new | Days]) %>
<td class="calendar-day-np">&nbsp;</td>
<% draw_days(Days) %>
<%@ draw_days([old | Days]) %>
<td class="calendar-day-np">&nbsp;</td>
<% draw_days(Days) %>
<%@ draw_days([{N, ok} | Days]) %>
<td class="calendar-day"><div class="day-number"><% integer_to_list(N) %></div><p>Commits!</p><p>&nbsp;</p></td>
<% draw_days(Days) %>
<%@ draw_days([{N, _} | Days]) %>
<td class="calendar-day"><div class="day-number"><% integer_to_list(N) %></div><p>&nbsp;</p><p>&nbsp;</p></td>
<% draw_days(Days) %>
-module(gh).
-compile(export_all).
-include_lib("stdlib/include/qlc.hrl").
-record(stats, {user, date}).
%% erlc gh.erl
%% erl
%% 1> erltl:compile("draw.et", [report_errors, report_warnings, nowarn_unused_vars]).
%% 2> gh:bootstrap().
%% 3> gh:process("ngerakines").
%% 4> gh:write("ngerakines", 2009, 7).
write(Username, Year, Month) ->
Dates = gh:fetch(Username, {Year, Month}),
Data = erlang:iolist_to_binary(draw:draw(integer_to_list(Month), integer_to_list(Year), lists:reverse(gh:gen_cal(Dates)))),
{ok, Fd} = file:open(Username ++ ".html", [write, binary]),
io:format(Fd, "~s", [Data]),
file:close(Fd),
ok.
bootstrap() ->
inets:start(),
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(stats, [{attributes, record_info(fields, stats)}, {disc_copies, [node()]}, {type, bag}]),
ok.
process(Username) ->
Url = "http://github.com/" ++ Username ++ ".atom",
{ok,{{_, 200, _}, _Headers , Body}} = http:request(get, {Url, []}, [], []),
%% fun(State) -> {<<>>, NewState} end
{ok, Timestamps} = xmerl_sax_parser:stream(list_to_binary(Body), [
{event_fun, fun parser/3},
{event_state, []},
{continuation_fun, fun(State) -> {<<>>, State} end},
{continuation_state, []}
]),
process_dates(Username, Timestamps).
process_dates(_Username, []) -> ok;
process_dates(Username, [{_, Timestamp} | Timestamps]) ->
{atomic, ok} = mnesia:transaction(fun() ->
Stats = #stats{
user = Username,
date = parse_Date(Timestamp)
},
ok = mnesia:write(Stats),
ok
end),
process_dates(Username, Timestamps).
parse_Date(Timestamp) ->
[DateRaw | _] = string:tokens(Timestamp, "T"),
erlang:list_to_tuple([list_to_integer(X) || X <- string:tokens(DateRaw, "-")]).
parser({startElement, _NS, "published", _, _}, _, State) ->
[{"published"} | State];
parser({startElement, _NS, "updated", _, _}, _, State) ->
[{"updated"} | State];
parser({characters, MoreData}, _, [{Elem} | State]) ->
[{Elem, MoreData} | State];
parser(_Other, _, State) ->
%% io:format("'~p' Other ~p~n", [State#state.depth, Other]),
State.
fetch(Username, {Year, Month}) ->
F = fun() ->
Q = qlc:q([
{stats, RUsername, {RYear, RMonth, RDay}}
|| {stats, RUsername, {RYear, RMonth, RDay}} <- mnesia:table(stats), RUsername == Username, RYear == Year, RMonth == Month]),
qlc:e(Q)
end,
{atomic, Dates} = mnesia:transaction(F),
Dates.
gen_cal(Dates) ->
[First | _ ] = Dates,
{Y, M, _} = First#stats.date,
FirstDayOfTheMonth = calendar:day_of_the_week({Y, M, 1}),
TotalDays = calendar:last_day_of_the_month(Y, M),
Vals = gen_cal_range(1, Dates, []),
FinalVals = case length(Vals) of
TotalDays -> Vals;
X ->
Vals ++ [{N, nok} || N <- lists:seq(length(Vals) + 1, TotalDays)]
end,
split_range(
1,
lists:duplicate(FirstDayOfTheMonth, old) ++ FinalVals,
[[]]
).
gen_cal_range(_, [], Acc) -> lists:reverse(Acc);
gen_cal_range(Day, [Stat | Stats] = StatsAll, Acc) ->
{Year, Month, _} = Stat#stats.date,
{Value, NewStats} = case Stat#stats.date of
{_Y, _M, Day} -> {ok, Stats};
_ -> {nok, StatsAll}
end,
gen_cal_range(Day + 1, NewStats, [{Day, Value}| Acc]).
split_range(_, [], [X | Y]) ->
case length(X) of
7 -> [X | Y];
N -> [lists:sort(X) ++ lists:duplicate(7 - N, new) | Y]
end;
split_range(8, Vals, [X | Y]) ->
split_range(1, Vals, [[], lists:sort(X) | Y]);
split_range(N, [Val | Vals], [X | Y]) ->
split_range(N + 1, Vals, [[Val | X] | Y]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment