<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>elib/rfc4627/rfc4627.erl</filename>
    </added>
    <added>
      <filename>elib/twitter_client/twitter_client.erl</filename>
    </added>
    <added>
      <filename>elib/twitter_client/twitter_client.hrl</filename>
    </added>
    <added>
      <filename>migrations/8.sql</filename>
    </added>
    <added>
      <filename>migrations/9.sql</filename>
    </added>
    <added>
      <filename>src/bundles/twoorl_deu.erl</filename>
    </added>
    <added>
      <filename>src/bundles/twoorl_fra.erl</filename>
    </added>
    <added>
      <filename>src/bundles/twoorl_kor.erl</filename>
    </added>
    <added>
      <filename>src/bundles/twoorl_pol.erl</filename>
    </added>
    <added>
      <filename>src/bundles/twoorl_por_br.erl</filename>
    </added>
    <added>
      <filename>src/bundles/twoorl_spa.erl</filename>
    </added>
    <added>
      <filename>src/components/language_select_controller.erl</filename>
    </added>
    <added>
      <filename>src/components/language_select_view.et</filename>
    </added>
    <added>
      <filename>src/components/stats_controller.erl</filename>
    </added>
    <added>
      <filename>src/components/stats_view.et</filename>
    </added>
    <added>
      <filename>src/twoorl_stats.erl</filename>
    </added>
    <added>
      <filename>src/twoorl_twitter.erl</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,6 @@
 {&quot;src/twoorl.erl&quot;, [{outdir, &quot;./ebin&quot;}]}.
-{&quot;src/twoorl_util.erl&quot;, [{outdir, &quot;./ebin&quot;}]}.
-{&quot;elib/*.erl&quot;, [{outdir, &quot;./ebin&quot;}]}.
\ No newline at end of file
+{&quot;src/twoorl_sup.erl&quot;, [{outdir, &quot;./ebin&quot;}]}.
+{&quot;src/twoorl_server.erl&quot;, [{outdir, &quot;./ebin&quot;},
+	{i, &quot;/Users/yariv/yaws/include&quot;}]}.
+{&quot;elib/rfc4627/*&quot;, [{outdir, &quot;./ebin&quot;}]}.
+{&quot;elib/twitter_client/*&quot;, [{outdir, &quot;./ebin&quot;}]}.
\ No newline at end of file</diff>
      <filename>Emakefile</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 all: code
 
 code: clean
-	erl -s make all load -run twoorl init_mysql -run twoorl compile -s init stop
+	erl -s make all load -s init stop
 
 clean:
 	rm -fv ebin/*.beam twoorl.rel twoorl.script twoorl.boot erl_crash.dump *.log *.access</diff>
      <filename>Makefile</filename>
    </modified>
    <modified>
      <diff>@@ -10,3 +10,12 @@ To run Twoorl follow the following steps:
 
 Cheers!
 Yariv
+
+To run in embedded mode:
+
+$ make clean &amp;&amp; make
+$ erl -sname twoorlapp -setcookie twoorl -mnesia dir &quot;'twoorl.mnesia'&quot; -yaws embedded true -pa ebin -boot start_sasl
+1&gt; [application:start(X) || X &lt;- [inets, crypto, mnesia, twoorl]].
+[ok, ok, ok, ok]
+
+# Nick Gerakines</diff>
      <filename>README.txt</filename>
    </modified>
    <modified>
      <diff>@@ -1,14 +1,19 @@
 {application, twoorl, [
   {description, &quot;Twoorl is an open-source Twitter clone.&quot;},
   {vsn, &quot;0.3&quot;},
-  {modules, [
-    twoorl,
-    twoorl_server,
-    twoorl_sup
-  ]},
+  {modules, [twoorl, twoorl_server, twoorl_sup]},
   {registered, [twoorl]},
-  {env, []},
   {applications, [kernel, stdlib, sasl, crypto, inets, mnesia]},
   {mod, {twoorl, []}},
-  {start_phases, []}
+  {env, [
+    {dbconns, [
+        {&quot;localhost&quot;, &quot;root&quot;, &quot;password&quot;, &quot;twoorl&quot;, 3}
+    ]},
+    {tables, [session]}
+  ]},
+  {start_phases, [
+    {mysql, []},
+    {mnesia, []},
+    {compile, []}
+  ]}
 ]}.</diff>
      <filename>ebin/twoorl.app</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,26 @@
+%% This file is part of Twoorl.
+%% 
+%% Twoorl is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% (at your option) any later version.
+%% 
+%% Twoorl is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%% 
+%% You should have received a copy of the GNU General Public License
+%% along with Twoorl.  If not, see &lt;http://www.gnu.org/licenses/&gt;.
+
 -module(twoorl_eng).
 -export([bundle/1]).
 
 bundle(Tag) -&gt;
     case Tag of
+	
+	language -&gt; &lt;&lt;&quot;english&quot;&gt;&gt;;
+	
 	%% layout
 	login -&gt; &lt;&lt;&quot;login&quot;&gt;&gt;;
 	register -&gt; &lt;&lt;&quot;register&quot;&gt;&gt;;
@@ -12,7 +30,7 @@ bundle(Tag) -&gt;
 	get_source -&gt;
 	    &lt;&lt;&quot;Get the &lt;a href=\&quot;http://code.google.com/p/twoorl\&quot;&gt;&quot;
 	     &quot;source code&lt;/a&gt;&quot;&gt;&gt;;
-
+	
 	%% navbar
 	home -&gt; &lt;&lt;&quot;home&quot;&gt;&gt;;
 	replies -&gt; &lt;&lt;&quot;replies&quot;&gt;&gt;;
@@ -27,25 +45,25 @@ bundle(Tag) -&gt;
 	login_submit -&gt; &lt;&lt;&quot;login&quot;&gt;&gt;;
 
 	%% register page
+	% note: 'username', 'password' and 'Login_cap' are taken from
+	% login page section
 	register_cap -&gt; &lt;&lt;&quot;Register&quot;&gt;&gt;;
-	username -&gt; &lt;&lt;&quot;username&quot;&gt;&gt;;
 	email -&gt; &lt;&lt;&quot;email&quot;&gt;&gt;;
-	password -&gt; &lt;&lt;&quot;password&quot;&gt;&gt;;
 	password2 -&gt; &lt;&lt;&quot;re-enter password&quot;&gt;&gt;;
 	already_member -&gt; &lt;&lt;&quot;Already a member?&quot;&gt;&gt;;
-	login_cap -&gt; &lt;&lt;&quot;Login&quot;&gt;&gt;;
 
 	%% home page
 	upto -&gt; &lt;&lt;&quot;What are you up to?&quot;&gt;&gt;;
 	twitter_msg -&gt; &lt;&lt;&quot;Automatic posting to Twitter enabled for &quot;
 			&quot;non-replies&quot;&gt;&gt;;
+	send -&gt; &lt;&lt;&quot;send&quot;&gt;&gt;;
 
 	%% main page
 	public_timeline -&gt; &lt;&lt;&quot;Public timeline&quot;&gt;&gt;;
 
 	%% users page
 	{no_user, Username} -&gt;
-	    [&lt;&lt;&quot;The user '&quot;&gt;&gt;, Username, &lt;&lt;&quot; doesn't exist&quot;&gt;&gt;];
+	    [&lt;&lt;&quot;The user '&quot;&gt;&gt;, Username, &lt;&lt;&quot;' doesn't exist&quot;&gt;&gt;];
 	{timeline_of, Username} -&gt;
 	    [Username, &lt;&lt;&quot;'s timeline&quot;&gt;&gt;];
 	following -&gt; &lt;&lt;&quot;following&quot;&gt;&gt;;
@@ -85,7 +103,7 @@ bundle(Tag) -&gt;
 	%% error messages
 	{missing_field, Field} -&gt;
 	    [&lt;&lt;&quot;The &quot;&gt;&gt;, Field, &lt;&lt;&quot; field is required&quot;&gt;&gt;];
-	{username, Val} -&gt;
+	{username_taken, Val} -&gt;
 	    [&lt;&lt;&quot;The username '&quot;&gt;&gt;, Val, &lt;&lt;&quot;' is taken&quot;&gt;&gt;];
 	{invalid_username, Val} -&gt;
 	    [&lt;&lt;&quot;The username '&quot;&gt;&gt;, Val,
@@ -108,5 +126,11 @@ bundle(Tag) -&gt;
 	
 	%% confirmation messages
 	settings_updated -&gt;
-	    [&lt;&lt;&quot;Your settings have been updated successfully&quot;&gt;&gt;]
+	    [&lt;&lt;&quot;Your settings have been updated successfully&quot;&gt;&gt;];
+
+	%% miscellaneous
+	{seconds_ago, Val} -&gt; [Val, &lt;&lt;&quot; seconds ago&quot;&gt;&gt;];
+	{minutes_ago, Val} -&gt; [Val, &lt;&lt;&quot; minutes ago&quot;&gt;&gt;];
+	{hours_ago, Val} -&gt; [Val, &lt;&lt;&quot; hours ago&quot;&gt;&gt;];
+	{days_ago, Val} -&gt; [Val, &lt;&lt;&quot; days ago&quot;&gt;&gt;]
     end.</diff>
      <filename>src/bundles/twoorl_eng.erl</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,18 @@
+%% This file is part of Twoorl.
+%% 
+%% Twoorl is free software: you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% (at your option) any later version.
+%% 
+%% Twoorl is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%% 
+%% You should have received a copy of the GNU General Public License
+%% along with Twoorl.  If not, see &lt;http://www.gnu.org/licenses/&gt;.
+
 -module(twoorl_rus).
 -export([bundle/1]).
 
@@ -28,15 +43,12 @@ bundle(Tag) -&gt;
 
 	%% register page
 	register_cap -&gt; &lt;&lt;&quot;&#1056;&#1077;&#1075;&#1080;&#1089;&#1090;&#1088;&#1072;&#1094;&#1080;&#1103;&quot;&gt;&gt;;
-	username -&gt; &lt;&lt;&quot;&#1080;&#1084;&#1103;&quot;&gt;&gt;;
 	email -&gt; &lt;&lt;&quot;email&quot;&gt;&gt;;
-	password -&gt; &lt;&lt;&quot;&#1087;&#1072;&#1088;&#1086;&#1083;&#1100;&quot;&gt;&gt;;
 	password2 -&gt; &lt;&lt;&quot;&#1087;&#1072;&#1088;&#1086;&#1083;&#1100; (&#1087;&#1086;&#1076;&#1090;&#1074;&#1077;&#1088;&#1078;&#1076;&#1077;&#1085;&#1080;&#1077;)&quot;&gt;&gt;;
 	already_member -&gt; &lt;&lt;&quot;&#1059;&#1078;&#1077; &#1079;&#1072;&#1088;&#1077;&#1075;&#1080;&#1089;&#1090;&#1088;&#1080;&#1088;&#1086;&#1074;&#1072;&#1083;&#1080;&#1089;&#1100;?&quot;&gt;&gt;;
-	login_cap -&gt; &lt;&lt;&quot;&#1042;&#1093;&#1086;&#1076;&quot;&gt;&gt;;
 
 	%% home page
-	upto -&gt; &lt;&lt;&quot;&#1063;&#1077;&#1084; &#1079;&#1072;&#1085;&#1080;&#1084;&#1072;&#1077;&#1096;&#1089;&#1103;?&quot;&gt;&gt;;
+	upto -&gt; &lt;&lt;&quot;&#1063;&#1077;&#1084; &#1079;&#1072;&#1085;&#1080;&#1084;&#1072;&#1077;&#1096;&#1100;&#1089;&#1103;?&quot;&gt;&gt;;
 	twitter_msg -&gt; &lt;&lt;&quot;&#1040;&#1074;&#1090;&#1086;&#1084;&#1072;&#1090;&#1080;&#1095;&#1077;&#1089;&#1082;&#1086;&#1077; &#1082;&#1086;&#1087;&#1080;&#1088;&#1086;&#1074;&#1072;&#1085;&#1080;&#1077; &#1085;&#1072; Twitter &#1088;&#1072;&#1073;&#1086;&#1090;&#1072;&#1077;&#1090; &#1076;&#1083;&#1103; &#1086;&#1073;&#1099;&#1095;&#1085;&#1099;&#1093; &#1089;&#1086;&#1086;&#1073;&#1097;&#1077;&#1085;&#1080;&#1081;,&quot;
 			&quot; &#1085;&#1077; &#1086;&#1090;&#1074;&#1077;&#1090;&#1086;&#1074;&quot;&gt;&gt;;
 
@@ -45,7 +57,7 @@ bundle(Tag) -&gt;
 
 	%% users page
 	{no_user, Username} -&gt;
-	    [&lt;&lt;&quot;&#1055;&#1086;&#1083;&#1100;&#1079;&#1086;&#1074;&#1072;&#1090;&#1077;&#1083;&#1100; '&quot;&gt;&gt;, Username, &lt;&lt;&quot; &#1085;&#1077; &#1089;&#1091;&#1097;&#1077;&#1089;&#1090;&#1074;&#1091;&#1077;&#1090;&quot;&gt;&gt;];
+	    [&lt;&lt;&quot;&#1055;&#1086;&#1083;&#1100;&#1079;&#1086;&#1074;&#1072;&#1090;&#1077;&#1083;&#1100; '&quot;&gt;&gt;, Username, &lt;&lt;&quot;' &#1085;&#1077; &#1089;&#1091;&#1097;&#1077;&#1089;&#1090;&#1074;&#1091;&#1077;&#1090;&quot;&gt;&gt;];
 	{timeline_of, Username} -&gt;
 	    [&lt;&lt;&quot;&#1051;&#1077;&#1085;&#1090;&#1072; &quot;&gt;&gt;, Username];
 	following -&gt; &lt;&lt;&quot;&#1076;&#1088;&#1091;&#1079;&#1077;&#1081;&quot;&gt;&gt;;
@@ -85,7 +97,7 @@ bundle(Tag) -&gt;
 	%% error messages
 	{missing_field, Field} -&gt;
 	    [Field, &lt;&lt;&quot; &#1086;&#1073;&#1103;&#1079;&#1072;&#1090;&#1077;&#1083;&#1100;&#1085;&#1086;&#1077; &#1087;&#1086;&#1083;&#1077;&quot;&gt;&gt;];
-	{username, Val} -&gt;
+	{username_taken, Val} -&gt;
 	    [&lt;&lt;&quot;&#1048;&#1084;&#1103; '&quot;&gt;&gt;, Val, &lt;&lt;&quot;' &#1091;&#1078;&#1077; &#1079;&#1072;&#1085;&#1103;&#1090;&#1086;&quot;&gt;&gt;];
 	{invalid_username, Val} -&gt;
 	    [&lt;&lt;&quot;&#1048;&#1084;&#1103; '&quot;&gt;&gt;, Val,</diff>
      <filename>src/bundles/twoorl_rus.erl</filename>
    </modified>
    <modified>
      <diff>@@ -19,7 +19,7 @@
 %% @copyright Yariv Sadan, 2008
 
 -module(api_controller).
--export([send/1, follow/1]).
+-export([send/1, follow/1, toggle_twitter/1]).
 -include(&quot;twoorl.hrl&quot;).
 
 send(A) -&gt;
@@ -61,23 +61,26 @@ send(A) -&gt;
 					     Usr:email())},
 					  {usr_gravatar_enabled,
 					   Usr:gravatar_enabled()},
-					  {twitter_status, TwitterStatus}]),
+					  {twitter_status, TwitterStatus},
+					  {spam, Usr:spammer()}]),
 		      Msg1 = Msg:save(),
 
+%%		      twoorl_stats:cast({record, twoorl}),
+
 		      if TwitterEnabled andalso RecipientNames == [] -&gt;
-			      %% yey concurrency
-			      spawn(
-				fun() -&gt;
-					send_tweet(Usr, Msg1)
-				end);
+			      spawn(twoorl_twitter, send_tweet, [Usr, Msg1]);
 			 true -&gt;
 			      ok
 		      end,
 
-		      %% yey concurrency
 		      spawn(
 			fun() -&gt;
-				save_replies(Msg1:id(), RecipientNames)
+				RecipientIds = 
+				    usr:find(
+				      {username, in,
+				       lists:usort(
+					 [Name || Name &lt;- RecipientNames])}),
+				reply:save_replies(Msg1:id(), RecipientIds)
 			end),
 		      
 		      case proplists:get_value(&quot;get_html&quot;, Params) of
@@ -95,14 +98,6 @@ send(A) -&gt;
 	      end
       end).
 
-save_replies(MsgId, RecipientNames) -&gt;
-    RecipientNames1 = [Name || Name &lt;- RecipientNames],
-    Recipients = 
-	usr:find({username, in, lists:usort(RecipientNames1)}),
-    RecipientIds =
-	[Recipient:id() || Recipient &lt;- Recipients],
-    reply:save_replies(MsgId, RecipientIds).
-
 follow(A) -&gt;
     twoorl_util:auth(
       A,
@@ -163,23 +158,21 @@ follow(A) -&gt;
 	      end
       end).
 
+toggle_twitter(A) -&gt;
+    twoorl_util:auth(
+      A,
+      fun(Usr) -&gt;
+	      Params = yaws_api:parse_post(A),
+	      Enabled =
+		  case proplists:get_value(&quot;value&quot;, Params) of
+		      &quot;true&quot; -&gt; 1;
+		      &quot;false&quot; -&gt; 0;
+		      %% TODO need better error handling
+		      Val -&gt; exit({unexpected_value, Val})
+		  end,
+	      Usr1 = usr:twitter_enabled(Usr, Enabled),
+	      twoorl_util:update_session(A, Usr1),
+	      usr:update([{twitter_enabled, Enabled}], {id,'=',Usr:id()}),
+	      {response, [{html, &lt;&lt;&quot;ok&quot;&gt;&gt;}]}
+      end).
 	      
-send_tweet(Usr, Msg) -&gt;
-    Username = Usr:twitter_username(),
-    Password = Usr:twitter_password(),
-    
-    Res = twitter:update(Username, Password, Msg:body_raw()),
-
-    UpdateFun = fun(Status) -&gt;
-			msg:update([{twitter_status, Status}],
-				   {id,'=',Msg:id()})
-		end,
-    case Res of
-	{ok, {{_Protocol, 200, _},_Headers, _Body}} -&gt;
-	    UpdateFun(?TWITTER_SENT_OK);
-	_ -&gt;
-	    ?Warn(&quot;error sending tweet ~p ~p&quot;, [Msg:id(), Res]),
-	    UpdateFun(?TWITTER_SENT_ERR)
-    end.
-
-    </diff>
      <filename>src/components/api_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
 &lt;%@ send(Data) %&gt;&lt;% Data %&gt;
-
 &lt;%@ follow(Data) %&gt;&lt;% Data %&gt;
+&lt;%@ toggle_twitter(Data) %&gt;&lt;% Data %&gt;</diff>
      <filename>src/components/api_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -27,6 +27,10 @@ index(A) -&gt;
       A,
       fun(Usr) -&gt;
 	      Ids = usr:get_timeline_usr_ids(Usr),
-	      [?Data(A, {Usr:username(), Usr:twitter_enabled() == 1}),
+	      HasTwitter = (
+		Usr:twitter_username() =/= undefined andalso
+		Usr:twitter_password() =/= undefined),
+	      [?Data(A, {Usr:username(), HasTwitter,
+			 Usr:twitter_enabled() == 1}),
 	       {ewc, timeline, show, [A, Ids]}]
       end).</diff>
      <filename>src/components/home_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -1,18 +1,18 @@
-&lt;%@ index([{B, {Username,TwitterEnabled}}, Timeline]) %&gt;
+&lt;%@ index([{B, {Username, HasTwitter, TwitterEnabled}}, Timeline]) %&gt;
 &lt;table id=&quot;txt_table&quot;&gt;
   &lt;tr&gt;
-    &lt;td width=&quot;100%&quot;&gt;&lt;div class=&quot;t1&quot;&gt;&lt;% B(upto) %&gt;&lt;/div&gt;&lt;/td&gt;
-    &lt;td align=&quot;right&quot;&gt;&lt;div id=&quot;chars&quot;&gt;140&lt;div&gt;&lt;/td&gt;
+    &lt;td&gt;&lt;div class=&quot;t1&quot;&gt;&lt;% B(upto) %&gt;&lt;/div&gt;&lt;/td&gt;
+    &lt;td align=&quot;right&quot;&gt;&lt;div id=&quot;chars&quot;&gt;140&lt;/div&gt;&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
     &lt;td colspan=&quot;2&quot; align=&quot;center&quot;&gt;
       &lt;form action=&quot;/api/send&quot; method=&quot;post&quot; id=&quot;txt_form&quot;&gt;
 	&lt;fieldset&gt;
 	  &lt;textarea rows=&quot;3&quot; cols=&quot;70&quot; id=&quot;txt&quot; name=&quot;msg&quot;&gt;&lt;/textarea&gt;
-	  &lt;% if TwitterEnabled -&gt; twitter_msg(B); true -&gt;[] end %&gt;
+	  &lt;% if HasTwitter -&gt; twitter_msg(B, TwitterEnabled); true -&gt;[] end %&gt;
 	&lt;/fieldset&gt;
       &lt;/form&gt;
-      &lt;input type=&quot;button&quot; id=&quot;submit&quot; value=&quot;send&quot; onclick=&quot;send()&quot;/&gt;
+      &lt;input type=&quot;button&quot; id=&quot;submit&quot; value=&quot;&lt;% B(send) %&gt;&quot; onclick=&quot;send()&quot;/&gt;
     &lt;/td&gt;
   &lt;/tr&gt;
 &lt;/table&gt;
@@ -20,5 +20,7 @@
 
 &lt;% Timeline %&gt;
 
-&lt;%@ twitter_msg(B) %&gt;&lt;div id=&quot;twitter_msg&quot;&gt;&lt;% B(twitter_msg) %&gt;&lt;/div&gt;
+&lt;%@ twitter_msg(B, TwitterEnabled) %&gt;
+&lt;div id=&quot;twitter_msg&quot;&gt;&lt;input onchange=&quot;toggle_twitter(this);&quot; type=&quot;checkbox&quot; &lt;% if TwitterEnabled -&gt; &lt;&lt;&quot;checked=\&quot;checked\&quot;&quot;&gt;&gt;;
+       true -&gt; [] end %&gt;/&gt;&lt;% B(twitter_msg) %&gt;&lt;/div&gt;
 </diff>
      <filename>src/components/home_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,13 @@
 &lt;%@ index([{Background, HeaderItems}, Data]) %&gt;
-&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
+&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; 
+ &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
+
 &lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
 &lt;head&gt;
   &lt;title&gt;Twoorl&lt;/title&gt;
   &lt;link rel=&quot;stylesheet&quot; href=&quot;/static/style.css&quot; type=&quot;text/css&quot;/&gt;
   &lt;meta http-equiv=&quot;Content-type&quot; content=&quot;text/html; charset=utf-8&quot;/&gt;
-  &lt;style&gt;
+  &lt;style type=&quot;text/css&quot;&gt;
     body {
       background-image: url('&lt;% Background %&gt;');
     }</diff>
      <filename>src/components/html_container_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -33,4 +33,4 @@ index(A, Ewc) -&gt;
 	     true -&gt;
 		{undefined, {data, []}}
 	end,
-    [?Data(A, Username), Navbar, Ewc].
+    [?Data(A, Username), Navbar, Ewc, {ewc, language_select, [A]}].</diff>
      <filename>src/components/layout_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;%@ index([{B, Username}, Navbar, Ewc]) %&gt;
+&lt;%@ index([{B, Username}, Navbar, Ewc, LanguageSelect]) %&gt;
 &lt;table id=&quot;top&quot; class=&quot;section1&quot;&gt;
   &lt;tr&gt;
     &lt;td id=&quot;logo&quot;&gt;&lt;a href=&quot;/&quot;&gt;Twoorl&lt;/a&gt;&lt;/td&gt;
@@ -7,6 +7,7 @@
 &lt;/table&gt;
 &lt;% Navbar %&gt;
 &lt;% Ewc %&gt;
+&lt;% LanguageSelect %&gt;
 &lt;div id=&quot;footer&quot;&gt;&lt;% B(get_source) %&gt;&lt;/div&gt;
 
 &lt;%@ header(B, undefined) %&gt;&lt;a href=&quot;/login&quot;&gt;&lt;% B(login) %&gt;&lt;/a&gt; | &lt;a href=&quot;/register&quot;&gt;&lt;% B(register) %&gt;&lt;/a&gt;</diff>
      <filename>src/components/layout_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -43,6 +43,7 @@ index(A) -&gt;
 		  end),
 	    Errs1 = 
 		if Errs == [] -&gt;
+%%			twoorl_stats:cast({record, site_login}),
 			Hash = crypto:sha([usr:username(Usr), Password]),
 			case usr:password(Usr) of
 			    Hash -&gt;
@@ -54,7 +55,7 @@ index(A) -&gt;
 			Errs
 		end,
 	    if Errs1 == [] -&gt;
-		    do_login(Usr);
+		    do_login(A, Usr);
 	       true -&gt;
 		    [?Data(A, undefined),
 		     {ewc, ui_msgs, [A, Errs1]}]
@@ -71,8 +72,42 @@ get_usr(Username) -&gt;
 	    {ok, Usr}
     end.
 
-do_login(Usr) -&gt;
+do_login(A, Usr) -&gt;
     Key = twoorl_util:gen_key(),
-    twoorl_util:update_session_by_key(Usr, Key),
-    usr:update([{session_key, Key}], {id,'=',usr:id(Usr)}),
-    {response, [yaws_api:setcookie(&quot;key&quot;, Key), ewr]}.
+    LangCookie = erlyweb_util:get_cookie(&quot;lang&quot;, A),
+    Usr1 = case LangCookie of
+	       undefined -&gt;
+		   Usr;
+	       Lang -&gt;
+		   LangBin = list_to_binary(Lang),
+		   case Usr:language() of
+		       LangBin -&gt;
+			   Usr;
+		       _ -&gt;
+			   spawn(fun() -&gt; 
+					 usr:update([{language, Lang}],
+						    {id,'=',Usr:id()})
+				 end),
+			   usr:language(Usr, Lang)
+		   end
+	   end,
+
+    twoorl_util:update_session(A, Usr1, Key),
+    spawn(fun() -&gt;
+		  usr:update([{session_key, Key}], {id,'=',usr:id(Usr1)})
+	  end),
+    Response = [twoorl_util:cookie(&quot;key&quot;, Key)],
+    
+    %% set the language cookie for the session if it's not defined
+    Response1 = if LangCookie == undefined -&gt;
+			case Usr1:language() of
+			    undefined -&gt;
+				Response;
+			    Other -&gt;
+				[twoorl_util:cookie(&quot;lang&quot;, Other) | Response]
+			end;
+		   true -&gt;
+			Response
+		end,
+    {response, [{ewr, home} | Response1]}.
+</diff>
      <filename>src/components/login_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -26,7 +26,7 @@ index(A) -&gt;
     FeedUrl = &lt;&lt;&quot;/feeds/main/rss&quot;&gt;&gt;,
     {response,
      [{body, [?Data(A, twoorl_util:get_feed_link(FeedUrl, &lt;&lt;&quot;RSS&quot;&gt;&gt;)),
-	       {ewc, timeline, show, [A]}]},
+	       {ewc, timeline, show, [A, undefined, [{filter_spam, true}]]}]},
        {phased_vars,
 	[{header_items,
 	  [{feed_link, &lt;&lt;&quot;rss+xml&quot;&gt;&gt;,</diff>
      <filename>src/components/main_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ get_gravatar_id(Msg) -&gt;
 		Other -&gt;
 		    Other
 	    end;
-	0 -&gt;
+	_ -&gt;
 	    ?DEFAULT_GRAVATAR_ID
     end.
 </diff>
      <filename>src/components/msg.erl</filename>
    </modified>
    <modified>
      <diff>@@ -107,7 +107,15 @@ get_links(A, NumPages, Page, Params) -&gt;
     Page1 = lists:max([lists:min([Page, NumPages]), 1]),
     Params1 = proplists:delete(&quot;page&quot;, Params),
 
-    BaseUrl1 = erlyweb_util:get_url_prefix(A),
+    %% ugly hack ahead to get around appmod rewriting for the 'users'
+    %% component
+    A1 = case yaws_arg:get_opaque_val(A, paging_path) of
+	     undefined -&gt;
+		 A;
+	     Val -&gt;
+		 yaws_arg:appmoddata(A, Val)
+	 end,
+    BaseUrl1 = erlyweb_util:get_url_prefix(A1),
 
     BaseUrl2 = 
 	[BaseUrl1, &quot;?&quot;, lists:map(fun({Key, Val}) -&gt; [Key,$=,Val,$&amp;] end,</diff>
      <filename>src/components/paging_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -40,9 +40,8 @@ index(A) -&gt;
 		    [?Data(A, {Username, Email}),
 		     {ewc, ui_msgs, [A, Errs1]}];
 	       true -&gt;
-		    %% todo set cookie
 		    Usr = register_usr(Username, Email, Password),
-		    login_controller:do_login(Usr)
+		    login_controller:do_login(A, Usr)
 	    end;
 	_ -&gt;
 	    [?Data(A, {[], []}), {data, []}]</diff>
      <filename>src/components/register_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -12,5 +12,5 @@
   &lt;div&gt;&lt;input name=&quot;password2&quot; type=&quot;password&quot;/&gt;&lt;/div&gt;
   &lt;div style=&quot;margin-top:5px;&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot;/&gt;&lt;/div&gt;
 &lt;/form&gt;
-&lt;% B(already_member) %&gt; &lt;a href=&quot;/register&quot;&gt;&lt;% B(login_cap) %&gt;&lt;/a&gt;
+&lt;% B(already_member) %&gt; &lt;a href=&quot;/login&quot;&gt;&lt;% B(login_cap) %&gt;&lt;/a&gt;
 </diff>
      <filename>src/components/register_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -21,11 +21,7 @@
 -module(reply).
 -compile(export_all).
 
-
-save_replies(MsgId, RecipientIds) -&gt;    
-    Replies =
-	[reply:new_with(
-	   [{usr_id, RecipientId},
-	    {msg_id, MsgId}]) || RecipientId &lt;-
-				     RecipientIds],
+save_replies(MsgId, Recipients) -&gt;
+    Replies = [reply:new_with([{usr_id, Recipient:id()}, {msg_id, MsgId}])
+	       || Recipient &lt;- Recipients],
     reply:insert(Replies).</diff>
      <filename>src/components/reply.erl</filename>
    </modified>
    <modified>
      <diff>@@ -15,6 +15,7 @@ process_request(A, Usr) -&gt;
 	    ValidationFun = get_validation_fun(TwitterEnabled),
 	    Background = proplists:get_value(&quot;background&quot;, Params),
 	    
+	    
 	    {[TwitterUsername, TwitterPassword], Errs} =
 		erlyweb_forms:validate(
 		  Params,
@@ -28,34 +29,44 @@ process_request(A, Usr) -&gt;
 			_ -&gt; [{invalid_url, &lt;&lt;&quot;background image&quot;&gt;&gt;} | Errs1]
 		    end,
 	    Errs3 = Errs ++ Errs2,
-	    Messages =
-		case Errs3 of
-		    [] -&gt;
-			Usr2 =
-			    update_settings(
-			      Usr, TwitterUsername, TwitterPassword,
-			      TwitterEnabled, GravatarEnabled, Background),
-			twoorl_util:update_session(A,Usr2),
-			[settings_updated];
-		    _ -&gt;
-			[]
-		end,
-	    [?Data(
-		A,
-		{TwitterUsername, TwitterPassword,
-		 checked(TwitterEnabled), checked(GravatarEnabled),
-		 str(Background)}),
-	     {ewc, ui_msgs, [A, Errs3, Messages]}];
+	    case Errs3 of
+		[] -&gt;
+		    Usr2 =
+			update_settings(
+			  Usr, TwitterUsername, TwitterPassword,
+			  TwitterEnabled, GravatarEnabled, Background),
+		    twoorl_util:update_session(A,Usr2),
+		    {ewr, settings, [&quot;?success=true&quot;]};
+		_ -&gt;
+		    [result_data(
+		       A,
+		       TwitterUsername, TwitterPassword,
+		       checked(TwitterEnabled), checked(GravatarEnabled),
+		       str(Background)),
+		     {ewc, ui_msgs, [A, Errs3, []]}]
+	    end;
 	_ -&gt;
-	    [?Data(
-		A, {str(usr:twitter_username(Usr)),
-		    str(usr:twitter_password(Usr)),
-		    checked(usr:twitter_enabled(Usr)),
-		    checked(usr:gravatar_enabled(Usr)),
-		    str(usr:background(Usr))}),
-	     {data, []}]
+	    UiMessages = case lists:member({&quot;success&quot;, &quot;true&quot;},
+					yaws_api:parse_query(A)) of
+			     true -&gt;
+			       [settings_updated];
+			     false -&gt;
+				 []
+			 end,
+	    [result_data(A, str(usr:twitter_username(Usr)),
+			 str(usr:twitter_password(Usr)),
+			 checked(usr:twitter_enabled(Usr)),
+			 checked(usr:gravatar_enabled(Usr)),
+			 str(usr:background(Usr))),
+	     {ewc, ui_msgs, [A, [], UiMessages]}]
     end.
 
+result_data(A, TwitterUsername, TwitterPassword, TwitterEnabled,
+	    GravatarEnabled, Background) -&gt;
+    ?Data(A, {TwitterUsername, TwitterPassword, TwitterEnabled,
+	      GravatarEnabled, Background}).
+
+
 get_validation_fun(true) -&gt;
     fun(Field, Val) -&gt;
 	    case Val of
@@ -63,7 +74,7 @@ get_validation_fun(true) -&gt;
 		    FName = case Field of
 				&quot;twitter_username&quot; -&gt;
 				    &quot;Twitter username&quot;;
-					&quot;twitter_password&quot; -&gt;
+				&quot;twitter_password&quot; -&gt;
 				    &quot;Twitter password&quot;
 			    end,
 		    {error, {missing_field, FName}};
@@ -76,24 +87,14 @@ get_validation_fun(_) -&gt;
 	    ok
     end.
 
-verify_twitter_credentials(TwitterEnabled, TwitterUsername, TwitterPassword) -&gt;
-    if (TwitterEnabled andalso not (TwitterUsername == [])
-	andalso not (TwitterPassword == [])) -&gt;
-	    case twitter:verify_credentials(
-		   TwitterUsername, TwitterPassword) of
-		ok -&gt;
-		    [];
-		{error, unauthorized} -&gt;
-		    [twitter_unauthorized];
-		{error, Err} -&gt;
-		    ?Error(&quot;twitter authorization error: ~p ~p ~p&quot;,
-			   [TwitterUsername, TwitterPassword,
-			    Err]),
-		    [twitter_authorization_error]
-	    end;
-       true -&gt;
-	    []
-    end.
+verify_twitter_credentials(_, [], _) -&gt; [];
+verify_twitter_credentials(_, _, []) -&gt; [];
+verify_twitter_credentials(true, Username, Password) -&gt;
+    case twitter_client:account_verify_credentials(Username, Password, []) of
+        true -&gt; [];
+        false -&gt; [twitter_unauthorized]
+    end;
+verify_twitter_credentials(_, _, _) -&gt; [].
 
 update_settings(Usr, TwitterUsername, TwitterPassword, TwitterEnabled,
 	  GravatarEnabled, Background) -&gt;
@@ -119,13 +120,17 @@ update_settings(Usr, TwitterUsername, TwitterPassword, TwitterEnabled,
 
 
 str(undefined) -&gt; [];
+str(Val) when is_list(Val) -&gt; list_to_binary(Val);
 str(Val) -&gt; Val.
 
 checked(0) -&gt; [];
 checked(false) -&gt; [];
-checked(1) -&gt; &lt;&lt;&quot;checked&quot;&gt;&gt;;
-checked(true) -&gt; &lt;&lt;&quot;checked&quot;&gt;&gt;.
-    
+checked(1) -&gt; checked1();
+checked(true) -&gt; checked1();
+checked(undefined) -&gt; [].   
+
+checked1() -&gt; 
+    &lt;&lt;&quot;checked=\&quot;checked\&quot;&quot;&gt;&gt;.
     
 is_checked(Param, Params) -&gt;
     proplists:get_value(Param, Params)  == &quot;on&quot;.</diff>
      <filename>src/components/settings_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 &lt;%@ index([{B, {TwitterUsername, TwitterPassword, TwitterEnabledChecked,
-    GravatarEnabledChecked, Background}}, UiMsgs]) %&gt;
+    GravatarEnabledChecked, Background}},
+    UiMsgs]) %&gt;
 &lt;div class=&quot;t2&quot;&gt;&lt;% B(settings_cap) %&gt;&lt;/div&gt;
 &lt;% UiMsgs %&gt;
 &lt;form action=&quot;/settings&quot; method=&quot;post&quot;&gt;
@@ -23,6 +24,5 @@
     &lt;/div&gt;
     &lt;div&gt;&lt;br/&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot;/&gt;&lt;/div&gt;
   &lt;/div&gt;
-
 &lt;/form&gt;
 </diff>
      <filename>src/components/settings_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -40,20 +40,29 @@ show(A, UserIds) -&gt;
 show(A, UserIds, Opts) -&gt;
     OrderBy = {order_by, {created_on, desc}},
     
+    Where = case proplists:get_value(filter_spam, Opts) of
+		true -&gt;
+		    {'not', {spam,'=',1}};
+		_ -&gt;
+		    true
+	    end,
     %% this function is a prime optimization candidate
-    Total = 
+    Where1 = 
 	if UserIds =/= undefined -&gt;
-		msg:count('*', {usr_id, in, UserIds});
+		{'and', [{usr_id, in, UserIds}, Where]};
 	   true -&gt;
-		msg:count('*')
+		Where
 	end,
+    Total = msg:count('*', Where1),
+
     {replace, 
      {ewc, paging,
       [A, fun(Limit) -&gt;
-		  if UserIds =/= undefined -&gt;
-			  msg:find({usr_id,in,UserIds}, [OrderBy, Limit]);
-		     true -&gt;
-			  msg:find_with([OrderBy, Limit])
+		  case Where1 of
+		      undefined -&gt;
+			  msg:find_with([OrderBy, Limit]);
+		      _ -&gt;
+			  msg:find(Where1, [OrderBy, Limit])
 		  end
 	  end,
        fun(Msgs) -&gt;
@@ -94,7 +103,8 @@ show_msg(A, Msg, Opts) -&gt;
 		{usr:get_icon_link(Username, GravatarId),
 		 usr:get_link(Username)}
 	end,
-    CreatedOn = msg:get_time_since(Msg),
+    CreatedOn = twoorl_util:i18n(A, msg:get_time_since(Msg)),
+
     IsBig = proplists:get_value(is_big, Opts) == true,
     
     {data, {Username, Icon, Userlink,</diff>
      <filename>src/components/timeline_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -24,6 +24,6 @@
 private() -&gt;
     true.
 
-index(A, Usr) -&gt;
+index(_A, Usr) -&gt;
     {data, {usr:get_link(Usr),
 	    usr:get_icon(Usr, true)}}.</diff>
      <filename>src/components/user_icon_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,7 @@
 catch_all(A, [Username]) -&gt;
     case usr:find_first({username,'=',Username}) of
 	undefined -&gt;
-	    ?Data(A, {no_such_user, Username});
+	    ?Data(A, {no_user, Username});
 	Usr -&gt;
 	    ToFollow =
 		case twoorl_util:get_usr(A) of</diff>
      <filename>src/components/users_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
-&lt;%@ catch_all({no_such_user, Username, RssLink})%&gt;
-The user '&lt;% Username %&gt;' doesn't exist.
+&lt;%@ catch_all({B, Err}) %&gt;
+&lt;% B(Err) %&gt;
 
 &lt;%@ catch_all([{B, {Username, ToFollow, Gravatar, FeedLink}}, Data]) %&gt;
 &lt;div class=&quot;header1&quot;&gt;</diff>
      <filename>src/components/users_view.et</filename>
    </modified>
    <modified>
      <diff>@@ -26,13 +26,51 @@
 start(_Type, _Args) -&gt;
     twoorl_sup:start_link([]).
 
-start() -&gt;
-    application:start(inets),
-    init_mnesia(),
-    TablesInfo = [{session, [{attributes, record_info(fields, session)}]}],
-    create_mnesia_tables(TablesInfo),
-    init_mysql(),
-    compile().
+start_phase(mysql, _, _) -&gt;
+    {ok, DBConfig} = application:get_env(twoorl, dbconns),
+    [mysql_connect(PoolSize, Hostname, User, Password, Database)
+     || {Hostname, User, Password, Database, PoolSize} &lt;- DBConfig],
+    ok;
+
+start_phase(compile, _, _) -&gt;
+    twoorl:compile(),
+    ok;
+
+%% Having the mnesia store on a separate but connected node with a module
+%% to handle its maintenance would move a lot of this foo out of the
+%% application stack. Eventually that really needs to happen. -- nkg
+start_phase(mnesia, _, _) -&gt;
+    %% Mnesia should have been started already, because of that the schema
+    %% is in memory if the schema doesn't already exist on disc. If so we
+    %% change the type so that it writes to the mnesia dir we set. -- nkg
+    case mnesia:table_info(schema, storage_type) of
+        ram_copies -&gt; 
+            mnesia:change_table_copy_type(schema, node(), disc_copies);
+        _ -&gt;
+            ok
+    end,
+    ExistingTables = mnesia:system_info(tables) -- [schema],
+    {ok, Tables} = application:get_env(twoorl, tables),
+    [create_table(Table) ||
+	Table &lt;- Tables, not lists:member(Table, ExistingTables)],
+    ok.
+
+create_table(session) -&gt;
+    mnesia:create_table(session, [{attributes, record_info(fields, session)}]),
+    ok.
+
+mysql_connect(PoolSize, Hostname, User, Password, Database) -&gt;
+    erlydb:start(
+      mysql, [{hostname, Hostname},
+	      {username, User},
+	      {password, Password},
+	      {database, Database},
+	      {logfun, fun twoorl_util:log/4}]),
+    lists:foreach(
+      fun() -&gt;
+	      mysql:connect(erlydb_mysql, Hostname, undefined, User, Password,
+			    Database, true)
+      end, lists:seq(1, PoolSize - 1)).
 
 compile() -&gt;
     compile([]).
@@ -47,12 +85,25 @@ compile(Opts) -&gt;
     erlyweb:compile(compile_dir(default),
 		    [{erlydb_driver, mysql}, {erlydb_timeout, 20000} | Opts]).
 
+compile_dir(auto) -&gt;
+    {ok, CWD} = file:get_cwd(), CWD;
+compile_dir(default) -&gt;
+    ?APP_PATH;
+compile_dir(appconfig) -&gt;
+    {ok, CDir} = application:get_env(twoorl, compile_dir),
+    CDir;
 compile_dir(Dir) -&gt;
-    case Dir of
-        auto -&gt; {ok, CWD} = file:get_cwd(), CWD;
-        default -&gt; ?APP_PATH;
-        _ -&gt; Dir
-    end.
+    Dir.
+
+%% --- The rest of these functions will be deprecated --- %%
+
+start() -&gt;
+    application:start(inets),
+    init_mnesia(),
+    TablesInfo = [{session, [{attributes, record_info(fields, session)}]}],
+    create_mnesia_tables(TablesInfo),
+    init_mysql(),
+    compile().
 
 init_mnesia() -&gt;
     ?L(&quot;creating schema&quot;),
@@ -98,16 +149,17 @@ create_table(Table, Def) -&gt;
             exit(Err2)
     end.
 
-
 init_mysql() -&gt;
     erlydb:start(mysql,
 		 [{hostname, ?DB_HOSTNAME},
 		  {username, ?DB_USERNAME}, {password, ?DB_PASSWORD},
 		  {database, ?DB_DATABASE},
-		  {logfun, fun twoorl_util:log/4}]),
+		  {logfun, fun log/4}]),
     lists:foreach(
       fun(_) -&gt;
 	      mysql:connect(erlydb_mysql, ?DB_HOSTNAME, undefined,
 			    ?DB_USERNAME, ?DB_PASSWORD, ?DB_DATABASE, true)
       end, lists:seq(1, ?DB_POOL_SIZE)).
 
+log(Module, Line, Level, FormatFun) -&gt;
+    twoorl_util:log(Module, Line, Level, FormatFun).</diff>
      <filename>src/twoorl.erl</filename>
    </modified>
    <modified>
      <diff>@@ -27,16 +27,17 @@ hook(A) -&gt;
     case erlyweb:get_initial_ewc({ewc, A1}) of
 	{page, &quot;/&quot;} -&gt; start(A1);
 	{page, &quot;/static&quot; ++ _} = Ewc -&gt; Ewc;
-	{page, &quot;/favicon.ico&quot;} = Ewc -&gt; {page, &quot;/static/favicon.ico&quot;};
-	{page, [$/ | Username]} -&gt;
+	{page, &quot;/favicon.ico&quot;} -&gt; {page, &quot;/static/favicon.ico&quot;};
+	{page, [$/ | Username] = Path} -&gt;
 	    A2 = yaws_arg:appmoddata(A1, &quot;/users/&quot; ++ Username),
-	    start(A2);
+	    A3 = yaws_arg:add_to_opaque(A2, {paging_path, Path}),
+	    start(A3);
 
 	%% redirect user urls from &quot;/users/[Username]&quot; to &quot;/[Username]&quot;
 	{ewc, users_controller, users_view, catch_all,
 	 [_, [Username]]} -&gt;
 	    {response, [{redirect_local, {any_path, [$/|Username]}, 301}]};
-	Ewc -&gt;
+	_Ewc -&gt;
 	    start(A1)
     end.
 </diff>
      <filename>src/twoorl_app_controller.erl</filename>
    </modified>
    <modified>
      <diff>@@ -37,3 +37,12 @@ m8() -&gt;
 	      msg:update([{body, Body1}], {id,'=',Msg:id()})
       end, Msgs).
     
+
+m9() -&gt;
+    Users = usr:find({spammer,'=',1}),
+    lists:foreach(
+      fun(Usr) -&gt;
+	      msg:update([{spam, 1}], {usr_id,'=',Usr:id()})
+      end, Users).
+	      
+    </diff>
      <filename>src/twoorl_migrations.erl</filename>
    </modified>
    <modified>
      <diff>@@ -27,6 +27,7 @@ start_link(Args) -&gt;
     supervisor:start_link({local, ?MODULE}, ?MODULE, Args).
 
 init(Args) -&gt;
-    {ok, {{one_for_one, 10, 10}, [
-        {twoorl_yaws, {twoorl_server, start_link, [Args]}, permanent, 2000, worker, [twoorl_server]}
-    ]}}.
+    {ok, {{one_for_one, 10, 10},
+	  [{twoorl_yaws,
+	    {twoorl_server, start_link, [Args]},
+	    permanent, 20000, worker, [twoorl_server]}]}}.</diff>
      <filename>src/twoorl_sup.erl</filename>
    </modified>
    <modified>
      <diff>@@ -22,6 +22,9 @@
 -compile(export_all).
 -include(&quot;twoorl.hrl&quot;).
 
+cookie(Key, Val) -&gt;
+    yaws_api:setcookie(Key, Val, &quot;/&quot;, &quot;Wed 01-01-2020 00:00:00 GMT&quot;).
+
 gen_key() -&gt;
     gen_key(?DEFAULT_KEY_SIZE).
 
@@ -50,30 +53,28 @@ join(List, Delim) -&gt;
 	 (Elem, Acc) -&gt;
 	      [Elem, Delim | Acc]
       end, [], lists:reverse(List)).
-	      
-    
-get_seconds_since({datetime, Val}) -&gt;
+
+get_seconds_since({datetime, Val}) -&gt;	      
     get_seconds_since(Val);
 get_seconds_since(Val) -&gt;
     calendar:datetime_to_gregorian_seconds(
       calendar:local_time()) -
-	calendar:datetime_to_gregorian_seconds(Val).
+       calendar:datetime_to_gregorian_seconds(Val).
 
 get_time_since(DateTime) -&gt;
     Diff = 
 	get_seconds_since(DateTime),
-    {Val1, UnitStr} =
+    {Type, Val} =
 	if Diff &lt; 60 -&gt;
-		{Diff, &lt;&lt;&quot;seconds&quot;&gt;&gt;};
+		{seconds_ago, Diff};
 	   Diff &lt; 3600 -&gt;
-		{round(Diff / 60), &lt;&lt;&quot;minutes&quot;&gt;&gt;};
+		{minutes_ago, round(Diff/60)};
 	   Diff &lt; 86400 -&gt;
-		{round(Diff / 3600), &lt;&lt;&quot;hours&quot;&gt;&gt;};
+		{hours_ago, round(Diff/3600)};
 	   true -&gt;
-		{round(Diff / 86400), &lt;&lt;&quot;days&quot;&gt;&gt;}
+		{days_ago, round(Diff/86400)}
 	end,
-    [integer_to_list(Val1), 32, UnitStr, &lt;&lt;&quot; ago&quot;&gt;&gt;].
-
+    {Type, integer_to_list(Val)}.
 
 auth(A, Fun) -&gt;
     auth(A, Fun, fun() -&gt; {ewr, login} end).
@@ -131,7 +132,7 @@ htmlize_l([X|Tail], Ack) when is_list(X) -&gt;
 log(Module, Line, Level, FormatFun) -&gt;
     Func = case Level of
 	       debug -&gt;
-		   undefined;
+		   info_msg;
 	       info -&gt;
 		   info_msg;
 	       normal -&gt;
@@ -261,15 +262,24 @@ get_session_key(A) -&gt;
     yaws_arg:get_opaque_val(A, key).
 
 update_session(A, Usr) -&gt;
-    update_session_by_key(twoorl_util:get_session_key(A), Usr).
+    Key = twoorl_util:get_session_key(A),
+    update_session(A, Usr, Key).
 
-update_session_by_key(Key, Usr) -&gt;
-    mnesia:dirty_write(#session{key=Key,
-				value=Usr}).
+update_session(A, Usr, Key) -&gt;
+    NewSession = #session{key=Key,
+			  value=Usr},
+    mnesia:dirty_write(NewSession),
+    Opaque1 = 
+	lists:map(fun({session, _}) -&gt; {session, NewSession};
+		     (Other) -&gt; Other
+		  end, yaws_arg:opaque(A)),
+    yaws_arg:opaque(A, Opaque1).
 
 
 gravatar_icon(GravatarId) -&gt;
-    [&lt;&lt;&quot;&lt;img border=\&quot;0\&quot; src=\&quot;http://www.gravatar.com/avatar.php?size=32&amp;gravatar_id=&quot;&gt;&gt;,
+    [&lt;&lt;&quot;&lt;img alt=\&quot;gravatar\&quot; class=\&quot;gravatar\&quot; &quot;
+      &quot;src=\&quot;http://www.gravatar.com/avatar.php?&quot;
+      &quot;size=32&amp;amp;gravatar_id=&quot;&gt;&gt;,
      GravatarId, &lt;&lt;&quot;\&quot;/&gt;&quot;&gt;&gt;].
 
 gravatar_id(Email) -&gt;
@@ -303,6 +313,7 @@ iolist_fun(Rec, Fun) -&gt;
 
 
 
+%% Used for RSS formatting
 %% Reference: http://cyber.law.harvard.edu/rss/rss.html
 format_datetime({Date = {Year, Month, Day}, {Hour, Minute, Second}}) -&gt;
     Daynum = calendar:day_of_the_week(Date),
@@ -351,5 +362,54 @@ get_feed_link(Url, Format) -&gt;
 with_bundle(A, Data) -&gt;
     {data, {get_bundle(A), Data}}.
 
+%% codes taken from http://www.loc.gov/standards/iso639-2/php/code_list.php
+bundles() -&gt;
+    [{&lt;&lt;&quot;eng&quot;&gt;&gt;, &lt;&lt;&quot;English&quot;&gt;&gt;, twoorl_eng},
+     {&lt;&lt;&quot;spa&quot;&gt;&gt;, &lt;&lt;&quot;Espa&#241;ol&quot;&gt;&gt;, twoorl_spa},
+     {&lt;&lt;&quot;deu&quot;&gt;&gt;, &lt;&lt;&quot;Deutsch&quot;&gt;&gt;, twoorl_deu},
+     {&lt;&lt;&quot;fra&quot;&gt;&gt;, &lt;&lt;&quot;Fran&#231;ais&quot;&gt;&gt;, twoorl_fra},
+     {&lt;&lt;&quot;kor&quot;&gt;&gt;, &lt;&lt;&quot;&#54620;&#44397;&#50612;&quot;&gt;&gt;, twoorl_kor},
+     {&lt;&lt;&quot;pol&quot;&gt;&gt;, &lt;&lt;&quot;Polski&quot;&gt;&gt;, twoorl_pol},
+     {&lt;&lt;&quot;por&quot;&gt;&gt;, &lt;&lt;&quot;Portugu&#234;s Brasileiro&quot;&gt;&gt;, twoorl_por_br},
+     {&lt;&lt;&quot;ru&quot;&gt;&gt;, &lt;&lt;&quot;&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;&quot;&gt;&gt;, twoorl_rus}].
+
 get_bundle(A) -&gt;
-    fun twoorl_eng:bundle/1.
+    Module1 =
+	case erlyweb_util:get_cookie(&quot;lang&quot;, A) of
+	    undefined -&gt;
+		twoorl_eng;
+	    Lang -&gt;
+		Lang1 = list_to_binary(Lang),
+		case lists:keysearch(Lang1, 1, bundles()) of
+		    false -&gt;
+			?Warn(&quot;undefined language: ~p ~p&quot;, 
+			      [get_usr(A), Lang1]),
+			twoorl_eng;
+		    {value, {_, _, Module}} -&gt; Module
+		end
+	end,
+    fun(StrId) -&gt;
+	    %% Some values may not have been translated from English.
+	    %% We catch such exceptions and fall back on the english
+	    %% translation.
+	    case catch Module1:bundle(StrId) of
+		{'EXIT', Err} -&gt;
+		    case Module1 of
+			twoorl_eng -&gt;
+			    %% this is not supposed to happen
+			    exit(Err);
+			_ -&gt;
+			    twoorl_eng:bundle(StrId)
+		    end;
+		Other -&gt;
+		    Other
+	    end
+    end.
+
+i18n(A, Val) -&gt;
+    F = get_bundle(A), F(Val).
+	    
+
+delete_sessions() -&gt;
+    Sessions = mnesia:dirty_match_object(#session{_ = '_'}),
+    lists:foreach(fun mnesia:dirty_delete_object/1, Sessions).</diff>
      <filename>src/twoorl_util.erl</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ form input {
   margin-bottom: 5px;
 }
 
-.section1, .paging_content {
+.section1, .paging_content, #txt_form {
   margin-bottom: 10px;
 }
 
@@ -150,4 +150,11 @@ fieldset {
 .user_icon {
   text-align: center;
   padding: 3px;
-}
\ No newline at end of file
+}
+
+#language_select_box {
+  margin: 10px 0px 10px 0px;
+  text-align: center
+}
+
+.gravatar { border:0px; }
\ No newline at end of file</diff>
      <filename>www/static/style.css</filename>
    </modified>
    <modified>
      <diff>@@ -11,6 +11,14 @@ $(function() {
 	$(&quot;#chars&quot;).text(&quot;&quot; + (maxChars - length));
 	
     });
+    $(&quot;#language_select&quot;).change(function(e) {
+	var select = $(&quot;#language_select&quot;)[0];
+	var lang = select.options[select.selectedIndex].value;
+	document.cookie =
+	    'lang=' + lang + '; expires=Wed, 1 Jan 2020 00:00:00 UTC; path=/';
+	location.href = location.href;
+    });
+	
 });
 
 function val() {
@@ -34,7 +42,7 @@ function follow(username, val) {
     $.post(&quot;/api/follow&quot;,
 	   {&quot;username&quot;: username,
 	    &quot;value&quot;: val},
-	   function(Res) {
+	   function(res) {
 	       if (val == &quot;1&quot;) {
 		   $(&quot;#follow&quot;).hide();
 		   $(&quot;#unfollow&quot;).show();
@@ -45,3 +53,14 @@ function follow(username, val) {
 	   });
 	   
 }
+
+function toggle_twitter(input) {
+    $.post(&quot;/api/toggle_twitter&quot;,
+	   {&quot;value&quot;: input.value == &quot;on&quot;},
+	   function(res) {
+	       if (res != &quot;ok&quot;) {
+		   alert(&quot;Toggle Twitter failed&quot;);
+	       }
+	   });
+}
+</diff>
      <filename>www/static/twoorl.js</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>README</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>e8e58757d4cdd890717d82c16ecf0a9877781a35</id>
    </parent>
    <parent>
      <id>947592174633a687a30167ce1e32811cc7379a88</id>
    </parent>
  </parents>
  <author>
    <name>Eduard Bondarenko</name>
    <email>edbond@gmail.com</email>
  </author>
  <url>http://github.com/yariv/twoorl/commit/1fa9b885b6b8e5dcbb8919aeb26a2b1ba23bf654</url>
  <id>1fa9b885b6b8e5dcbb8919aeb26a2b1ba23bf654</id>
  <committed-date>2008-07-21T04:21:28-07:00</committed-date>
  <authored-date>2008-07-21T04:21:28-07:00</authored-date>
  <message>Merge branch 'master' of git@github.com:edbond/twoorl

Conflicts:

	.gitignore
	Emakefile
	elib/twitter_client/twitter_client.erl
	elib/twitter_client/twitter_client.hrl
	src/components/api_controller.erl
	src/components/login_controller.erl
	src/components/register_controller.erl
	src/components/reply.erl
	src/components/settings_controller.erl
	src/components/stats_controller.erl
	src/components/stats_view.et
	src/twoorl.erl
	src/twoorl_stats.erl
	src/twoorl_sup.erl
	src/twoorl_twitter.erl</message>
  <tree>d67f5ff29ec2f57740a38d84d9c466dcb130da54</tree>
  <committer>
    <name>Eduard Bondarenko</name>
    <email>edbond@gmail.com</email>
  </committer>
</commit>
