# [erlang-questions] LAST RESUME of Pytagoriam Numbers!!!

Edmond Begumisa <>
Mon Nov 15 21:53:30 CET 2010

```Below is a parallelised version of Richard/Håkan's blazing and yet
easy-to-read algo using a max of 2000 processes (find lpmap function on

On my dual-core it's about 20% faster for when N is small (300) and gets
up to 40% faster when N is large (3,000). Evens out from there. I'm
getting about 4.5s for N = 5,000!

I must say, I'm floored. I need to learn much, much, more about Erlang. I
just wasn't convinced it would be any good at this! And their algo retains
Garcia's original beauty too! It reads much like the high-school math
problems.

py3R_p(N)->
lists:flatten(lpmap(fun(A) ->
[{A, B, C} ||
B <- lists:seq(1, N - A),
C <- [trunc(math:sqrt(A * A + B * B))],
A + B + C =< N,
A*A + B*B =:= C*C]
end, lists:seq(1, N div 2), 2000, ordered)).

- Edmond -

Håkan Huss" <>

On Sun, 15 Jan 2006 15:11:42 +1100, Ivan Carmenates García
<> wrote:

>
> Compiled using c(py) normal in the shell.
>
> Feel free to make a new Resume on a DualCore CPU!!!
>
>
> Now we are re-talking about!!!
>
> Tested on Intel(R) Celeron CPU 2.13 GHz, 192 of Ram
>
> *** Pytagoriam's Numbers REPORT! ***
>
> Using N = 300
>
> *** THE ORIGINAL IMPLEMENTATIONS (ME!)****
> -py1:         14860000 mcs = 14.86 s
> -py2:         14843999 mcs = 14.843999 s
> -py3:         12749999 mcs = 12.749999 s
>
> *** Tony's implementations ****
> -pythag1:     11702999 mcs = 11.702999 s
> -pythag2:     1983999 mcs = 1.983999 s
>
> *** Hynek's implementation ****
> Simpler and about 5% faster version
> -pythag3:     1952999 mcs = 1.952999 s
>
> *** Edmond's implementation, using parallelism****
> -py2E:        14843999 mcs = 14.843999 s
>
> *** Willem's implementation****
> -wpythag2:    1749999 mcs = 1.749999 s
>
> *** Hynek's new implementation****
> -pythag4:     1140999 mcs = 1.140999 s
>
> *** Willem's new implementation in parallel by Edmond!!!****
> -wpythag2P:   1795999 mcs = 1.795999 s
>
> *** Morten's implementation****
> -pythag5:     46999 mcs = 0.046999 s
>
> *** Richard's improvement****
> -py3R:        46999 mcs = 0.046999 s   *** NEW ***
>
> *** Joe's improvement****
> -py3a:        1577999 mcs = 1.577999 s    *** NEW ***
>
> Comparisons in results agains 'pythag1' Tony's
> function
> py1 returns the same than 'pythag1'
> py2 returns the same than 'pythag1'
> py3 returns the same than 'pythag1'
> pythag1 returns the same than 'pythag1'
> pythag2 returns the same than 'pythag1'
> pythag3 returns the same than 'pythag1'
> py2E returns the same than 'pythag1'
> wpythag2 returns the same than 'pythag1'
> pythag4 returns the same than 'pythag1'
> wpythag2P returns the same than 'pythag1'
> pythag5 returns the same than 'pythag1'
> py3R returns the same than 'pythag1' <- now are we talking about!!! (is
> the best!!!)
> py3a returns the same than 'pythag1'
>
> NOTE: Time took using timer:tc/3 function.
>
>
> %*******************   START CODE *********************
>
> -module(py).
> -compile([export_all]).
>
>
> start(N)->
>      %% My implementations.
>      {T1,R1} = timer:tc(py,py1, [N]),
>      {T2,R2} = timer:tc(py,py2,[N]),
>      {T3,R3} = timer:tc(py,py3,[N]),
>
>      %% Tony's improvement of the original form 3.
>      {T4,R4} = timer:tc(py,pythag1,[N]),
>      %% Tony's implementation.
>      {T5,R5} = timer:tc(py,pythag2,[N]),
>
>      %% Hynek's implementation.
>      %% Simpler and about 5% faster version:
>      {T6,R6} = timer:tc(py,pythag3,[N]),
>
>      %% Edmond's implementation using parallelism.
>      {T7,R7} = timer:tc(py,py2E,[N]),
>
>      %% Willem's implementation.
>      {T8,R8} = timer:tc(py,wpythag2,[N]),
>
>      %% Hynek's new version
>      {T9,R9} = timer:tc(py,pythag4,[N]),
>
>      %% Willem's implementation in parallel by Edmond.
>      {T10,R10} = timer:tc(py,wpythag2P,[N]),
>
>      %% Morten's implementation.
>      {T11,R11} = timer:tc(py,pythag5,[N]),
>
>      %% Richard's improvement.
>      {T12,R12} = timer:tc(py,py3R,[N]),
>
>      %% Joe's improvement.
>      {T13,R13} = timer:tc(py,py3a,[N]),
>
>      io:format("~n *** Pytagoriam's Numbers REPORT! ***~n~n"),
>      io:format("Using N = ~p~n", [N]),
>
>      io:format("~n*** THE ORIGINAL IMPLEMENTATIONS (ME!)****~n"),
>      io:format("-py1:         ~p mcs = ~p s~n", [T1,T1/1000000]),
>      io:format("-py2:         ~p mcs = ~p s~n", [T2,T2/1000000]),
>      io:format("-py3:         ~p mcs = ~p s~n", [T3,T3/1000000]),
>
>      io:format("~n*** Tony's implementations ****~n"),
>      io:format("-pythag1:     ~p mcs = ~p s~n", [T4,T4/1000000]),
>      io:format("-pythag2:     ~p mcs = ~p s~n", [T5,T5/1000000]),
>
>      io:format("~n*** Hynek's implementation ****~n"),
>      io:format("Simpler and about 5% faster version~n"),
>      io:format("-pythag3:     ~p mcs = ~p s~n", [T6,T6/1000000]),
>
>      io:format("~n*** Edmond's implementation, using parallelism****~n"),
>      io:format("-py2E:        ~p mcs = ~p s~n", [T7,T7/1000000]),
>
>      io:format("~n*** Willem's implementation****~n"),
>      io:format("-wpythag2:    ~p mcs = ~p s~n", [T8,T8/1000000]),
>
>      io:format("~n*** Hynek's new implementation****~n"),
>      io:format("-pythag4:     ~p mcs = ~p s~n", [T9,T9/1000000]),
>
>      io:format("~n*** Willem's new implementation in parallel by
> Edmond!!!****~n"),
>      io:format("-wpythag2P:   ~p mcs = ~p s~n", [T10,T10/1000000]),
>
>      io:format("~n*** Morten's implementation****~n"),
>      io:format("-pythag5:     ~p mcs = ~p s~n", [T11,T11/1000000]),
>
>      io:format("~n*** Richard's improvement****~n"),
>      io:format("-py3R:        ~p mcs = ~p s~n", [T12,T12/1000000]),
>
>      io:format("~n*** Joe's improvement****~n"),
>      io:format("-py3a:        ~p mcs = ~p s~n", [T13,T13/1000000]),
>
>      io:format("~nComparisons in results agains 'pythag1' Tony's
> function~n"),
>      Rs = [{py1,R1}, {py2,R2}, {py3,R3}, {pythag1,R4}, {pythag2,R5},
> {pythag3,R6},
>            {py2E,R7}, {wpythag2,R8}, {pythag4,R9}, {wpythag2P,R10},
> {pythag5,R11}, {py3R,R12},
>            {py3a,R13}],
>      lists:foreach(fun({Name, R})->
>          if
>              (R=:=R4)->
>                  io:format("~p returns the same than 'pythag1'~n",
> [Name]);
>              true->
>                  io:format("~p NO returns the same than 'pythag1'~n",
> [Name])
>          end
>      end, Rs),
>      io:format("~nNOTE: Time took using timer:tc/3 function.~n").
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% The original form 1.
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> py1(Max)->
>      L = lists:seq(1, Max),
>      lists:foldr(
>          fun(A, Acc3)->
>              lists:foldr(
>                  fun(B, Acc2)->
>                      lists:foldr(
>                          fun(C, Acc)->
>                              case ((A*A + B*B =:= C*C) andalso (A+B+C =<
> Max)) of
>                                  true->
>                                      [{A,B,C}|Acc];
>                                  false->
>                                      Acc
>                              end
>                          end
>                      , Acc2, L)
>                  end
>              , Acc3, L)
>          end
>      , [], L).
>
>
>
> %% The original form 2.
> py2(Max)->
>      lists:reverse(fora(1, [], Max)).
>
> fora(A, Acc, Max)->
>      Acc1 = forb(A,1, Acc, Max),
>      case A<  Max of
>          true->
>              fora(A+1, Acc1, Max);
>          false->
>              Acc1
>      end.
>
> forb(A,B, Acc, Max)->
>      Acc1 = forc(A,B,1, Acc, Max),
>      case B<  Max of
>          true->
>              forb(A,B+1, Acc1, Max);
>          false->
>              Acc1
>      end.
>
> forc(A,B,C, Acc, Max)->
>      Acc1 = case (A*A + B*B =:= C*C) andalso (A+B+C =<  Max) of
>          true->
>              [{A,B,C}|Acc];
>          _->
>              Acc
>      end,
>      case C<  Max of
>          true->
>              forc(A,B,C+1, Acc1, Max);
>          false->
>              Acc1
>      end.
>
> %% The original form 3.
> py3(Max)->
>      [{A,B,C} ||
>          A<-lists:seq(1, Max),
>          B<-lists:seq(1, Max),
>          C<-lists:seq(1, Max),
>          A*A + B*B =:= C*C,
>          A+B+C =<  Max].
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Tony's improvement of the original form 3.
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> pythag1(N) ->
>      L = lists:seq(1,N),
>      [ {A,B,C} ||
>          A<- L,
>          B<- L,
>          C<- L,
>          A+B+C =<  N,
>          A*A+B*B =:= C*C].
>
> %% Tony's implementation.
> pythag2(N) ->
>      lists:reverse(pythan2_A(1, N, [])).
>
> pythan2_A(A, N, Acc) when A>  N ->  Acc;
> pythan2_A(A, N, Acc) ->  pythan2_A(A+1,N,pythan2_B(A, 1, N, Acc)).
>
> pythan2_B(A, B, N, Acc) when A+B>  N ->  Acc;
> pythan2_B(A, B, N, Acc) ->  pythan2_B(A,B+1,N,pythan2_C(A, B, 1, N,
> Acc)).
>
> pythan2_C(A, B, C, N, Acc) when A+B+C>  N ->  Acc;
> pythan2_C(A, B, C, N, Acc) ->
>      if A*A+B*B =:= C*C ->
>          pythan2_C(A, B, C+1, N, [{A,B,C}|Acc]);
>      true ->
>          pythan2_C(A, B, C+1, N, Acc)
>      end.
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Hynek's implementation.
> %% Simpler and about 5% faster version:
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> pythag3(N) when is_integer(N) ->  pythag3(N,1).
>
> pythag3(N, A) when A+2>  N ->  [];
> pythag3(N, A) ->  pythag3(N, A, 1).
>
> pythag3(N, A, B) when A+B+1>  N ->  pythag3(N, A+1);
> pythag3(N, A, B) ->  pythag3(N, A, B, 1).
>
> pythag3(N, A, B, C) when A+B+C>  N ->  pythag3(N, A, B+1);
> pythag3(N, A, B, C) when A*A + B*B =:= C*C ->  [{A, B, C}|pythag3(N, A,
> B, C+1)];
> pythag3(N, A, B, C) ->  pythag3(N, A, B, C+1).
>
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Edmond's implementation using parallelism.
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> %%---- START CODE ----
>
> py2E(Max)->
>      lists:flatten(lpmap(fun(A) ->
>                              forbE(A, 1, [], Max)
>                          end, lists:seq(1, Max), ordered)).
>
> forbE(A, B, Acc, Max) ->
>      Acc1 = forcE(A, B, 1, Acc, Max),
>      case B<  Max of
>          true ->  forbE(A, B+1, Acc1, Max);
>          false ->  Acc1
>      end.
>
> forcE(A, B, C, Acc, Max) ->
>      Acc1 = case (A*A + B*B =:= C*C) andalso (A+B+C =<  Max) of
>                  true ->  [{A,B,C}|Acc];
>                  _ ->  Acc
>             end,
>      case C<  Max of
>          true->  forcE(A, B, C+1, Acc1, Max);
>          false->  Acc1
>      end.
>
>
> pythag2E(N)->
>      lists:flatten(lpmap(fun(A) ->
>                              pythan2_BE(A, 1, N, [])
>                          end, lists:seq(1, N), ordered)).
>
> pythan2_AE(A, N, Acc) when A>  N ->  Acc;
> pythan2_AE(A, N, Acc) ->  pythan2_AE(A+1,N,pythan2_BE(A, 1, N, Acc)).
>
> pythan2_BE(A, B, N, Acc) when A+B>  N ->  Acc;
> pythan2_BE(A, B, N, Acc) ->  pythan2_BE(A,B+1,N,pythan2_CE(A, B, 1, N,
> Acc)).
>
> pythan2_CE(A, B, C, N, Acc) when A+B+C>  N ->  Acc;
> pythan2_CE(A, B, C, N, Acc) ->
>      if A*A+B*B =:= C*C ->
>          pythan2_CE(A, B, C+1, N, [{A,B,C}|Acc]);
>         true ->
>          pythan2_CE(A, B, C+1, N, Acc)
>      end.
>
> %% @spec    lpmap(fun(), list(), (atom() = ordered|unordered)) ->  list()
> %% @doc     Spawns a process for each element in list L, performs
> specified
> %%          function F against each in parallel and then returns results
> either
> %%          same order as L (ordered) or in any order (unordered).
>
> lpmap(F, L, ordered) ->
>      Ref = erlang:make_ref(),
>      Pids = [lpmap_spawn_link(self(), Ref, F, I) || I<- L],
>      lpmap_gather_ordered(Pids, Ref, [], 0, void);
> lpmap(F, L, unordered) ->
>      Ref = erlang:make_ref(),
>      lists:foreach(fun(I) ->
>                    end, L),
>      lpmap_gather_unordered(length(L), Ref, [], 0, void).
>
> %% @spec    lpmap(fun(), integer(), list(), (atom() =
> ordered|unordered)) ->
>   list()
> %% @doc     Same as lpmap/3 except ensures only a maximum of MaxPs
> parallel
> %%          processes execute function F at any one time (i.e. first
> takes
> MaxPs
> %%          items from list, executes F in parallel against each, then as
> each
> %%          process returns, spawns another process on next item in L as
> long as
> %%          active processes are less than MaxPs).
>
> lpmap(F, L, MaxPs, ordered) when MaxPs>0 ->
>      Ref = erlang:make_ref(),
>      {HPids, TPids} = if
>                          length(L)>  MaxPs ->  lists:split(MaxPs, L);
>                          true ->  {L, []}
>                       end,
>      Pids = [lpmap_spawn_link(self(), Ref, F, I) || I<- HPids],
>      lpmap_gather_ordered(Pids, Ref, TPids, MaxPs, F);
> lpmap(F, L, MaxPs, unordered) when MaxPs>0 ->
>      Ref = erlang:make_ref(),
>      {HPids, TPids} = if
>                          length(L)>  MaxPs ->  lists:split(MaxPs, L);
>                          true ->  {L, []}
>                       end,
>      lists:foreach(fun(I) ->
>                    end, HPids),
>      lpmap_gather_unordered(length(HPids), Ref, TPids, MaxPs, F).
>
> %% lpmap internal functions
>
> lpmap_spawn_link(Parent, Ref, F, I) ->
>                      Parent ! {self(), Ref, F(I)}
>                 end).
>
> lpmap_gather_ordered([], _Ref, [], _MaxPs, _F) ->
>      [];
> lpmap_gather_ordered([HPid|TPids], Ref, L, MaxPs, F) ->
>          {HPid, Ref, Ret} when length(TPids)<MaxPs, L=/=[] ->
>              [H | T] = L,
>              [Ret | lpmap_gather_ordered(
> H)]),
>                  Ref, T, MaxPs, F)];
>          {HPid, Ref, Ret} ->
>              [Ret | lpmap_gather_ordered(TPids, Ref, L, MaxPs, F)]
>      end.
>
> lpmap_gather_unordered(0, _Ref, [], _MaxPs, _F) ->
>      [];
> lpmap_gather_unordered(NPs, Ref, L, MaxPs, F) ->
>          {_Pid, Ref, Ret} when NPs-1<MaxPs, L=/=[] ->
>              [H | T] = L,
>              [Ret | lpmap_gather_unordered(NPs, Ref, T, MaxPs, F)];
>          {_Pid, Ref, Ret} ->
>              [Ret | lpmap_gather_unordered(NPs-1, Ref, L, MaxPs, F)]
>      end.
>
>
> %%---- END CODE -----
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Willem's implementation.
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> wpythag2(N) ->
>     L = [{A, A*A} || A<- lists:seq(1,N)],
>     lists:flatten([forAllBs(A, A2, L, N) || {A, A2}<- L]).
>
> forAllBs(A, A2, L, N) ->
>    [forAllCs(A, B, A + B, A2 + B2, L, N) || {B, B2}<- L, A + B<  N].
>
> forAllCs(A, B, AB, A2B2, L, N) ->
>    [{A, B, C} || {C, C2}<- L, A2B2 =:= C2, AB + C =<  N].
>
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Hynek's new version
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> pythag4(N) when is_integer(N) ->  pythag4(N,1).
>
> pythag4(N, A) when A+2>  N ->  [];
> pythag4(N, A) ->  pythag4(N, A, A*A, 1).
>
> pythag4(N, A, _A2, B) when A+B+1>  N ->  pythag4(N, A+1);
> pythag4(N, A, A2, B) ->  pythag4(N, A, A2, B, B*B, 1).
>
> pythag4(N, A, A2, B, _B2, C) when A+B+C>  N ->  pythag4(N, A, A2, B+1);
> pythag4(N, A, A2, B, B2, C) when A2 + B2 =:= C*C ->
>    [{A, B, C}|pythag4(N, A, A2, B, B2, C+1)];
> pythag4(N, A, A2, B, B2, C) ->  pythag4(N, A, A2, B, B2, C+1).
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Willem's implementation in parallel by Hynek
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> wpythag2P(N) ->
>      L = [{A, A*A} || A<- lists:seq(1,N)], % For all A's
>      lists:flatten(lpmap(fun({A, A2}) ->     % For all B's in parallel
>                              [forAllCsWH(A, B, A + B, A2 + B2, L, N)
>                                          || {B, B2}<- L, A + B<  N]
>                          end, L, 2000, ordered)).
>
> forAllCsWH(A, B, AB, A2B2, L, N) ->
>      [{A, B, C} || {C, C2}<- L, A2B2 =:= C2, AB + C =<  N].
>
>
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Morten's implementation.
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> pythag5(N) when is_integer(N) ->
>    Primes = sieve(N div 2),
>    M1M2s = incorporate_primes([{1,1}], N, Primes),
>    lists:usort(lists:flatten([ [{A,B,C}, {B,A,C}] || {M1, M2}<- M1M2s,
> M1>  M2, A<- [M1-M2], B<- [2*round(math:sqrt(M1*M2))], C<- [M1+M2],
> A+B+C =<  N])).
>
> sieve(N) when is_integer(N) ->
>    erase(),
>    sieve(N,2).
>
> sieve(N, K) when K>= N ->
>   [X || X<- lists:seq(2, N), erase(X) == undefined];
> sieve(N, K) ->
>    cross_off(K, K, N div K - 1),
>    sieve(N, find_next_in_sieve(K + 1)).
>
> cross_off(_K, _Current, 0) ->
>    ok;
> cross_off(K, Current, Left) ->
>    Next = Current + K,
>    put(Next, out),
>    cross_off(K, Next, Left - 1).
>
> find_next_in_sieve(K) ->
>    case get(K) of
>      undefined ->
>        K;
>      _ ->
>        find_next_in_sieve(K+1)
>    end.
>
> incorporate_prime(M1M2s, N, P) ->
>    lists:flatten([incorporate_prime_single({M1,M2}, N, P)|| {M1, M2}<-
> M1M2s]).
>
> incorporate_prime_single({M1,M2}, N, P) ->
>    Evens = [{X, Y} || X<- incorporate_prime_even(M1, N, P), Y<-
> incorporate_prime_even(M2, N, P)],
>    Odds = [{X, Y} || X<- incorporate_prime_odd(M1, N, P), Y<-
> incorporate_prime_odd(M2, N, P)],
>    Evens ++ Odds.
>
> incorporate_prime_even(M, N, P) ->
>    incorporate_prime(M, N, P, []).
>
> incorporate_prime_odd(M, N, P) ->
>    incorporate_prime(M * P, N, P, []).
>
> incorporate_prime(M, N, _P, Acc) when M>  N/2 ->
>    Acc;
> incorporate_prime(M, N, P, Acc) ->
>    incorporate_prime(M * P * P, N, P, [M|Acc]).
>
> incorporate_primes(M1M2s, _N, []) ->
>    M1M2s;
> incorporate_primes(M1M2s, N, [P|Rest]) ->
>    M1M2s_new = incorporate_prime(M1M2s, N, P),
>    incorporate_primes(M1M2s_new, N, Rest).
>
>
>   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>   %% Richard's improvement.
>   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
>   py3R(N)->
>      [{A,B,C} ||
>          A <- lists:seq(1, N div 2),
>          B <- lists:seq(1, N - A),
>          C <- [trunc(math:sqrt(A * A + B * B))],
>          A + B + C =< N,
>          A*A + B*B =:= C*C].
>
>   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>   %% Joe's improvement.
>   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> py3a(Max) ->
>      N = Max div 2,
>      [{A,B,C} ||
>     A <- lists:seq(1,N+1),
>     B <- lists:seq(1,Max-A),
>     C <- lists:seq(1,Max-A-B),
>     A*A + B*B =:= C*C].
>
> %************************* END CODE*************************
>
> Cheers,
>
> Ivan.
>
>
> =======================================================================
> Este mensaje ha sido enviado mediante el servicio de correo electronico
> que ofrece la Federacion de Radioaficionados de Cuba a sus miembros para
> respaldar el cumplimiento de los objetivos de la organizacion y su
> politica informativa. La persona que envia este correo asume el
> compromiso de  usar el servicio a tales fines y cumplir con las
> regulaciones establecidas.
>
>
> =======================================================================
> Este mensaje ha sido enviado mediante el servicio de correo electronico
> que ofrece la Federacion de Radioaficionados de Cuba a sus miembros para
> respaldar el cumplimiento de los objetivos de la organizacion y su
> politica informativa. La persona que envia este correo asume el
> compromiso de  usar el servicio a tales fines y cumplir con las
> regulaciones establecidas.
>

--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
```