<?xml version='1.0' encoding='utf-8' ?>
<!--  If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/  -->
<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:media='http://search.yahoo.com/mrss/'>
<channel>
  <title>LiveJournal ChangeLog</title>
  <link>http://community.livejournal.com/changelog/</link>
  <description>LiveJournal ChangeLog - LiveJournal.com</description>
  <lastBuildDate>Fri, 17 Jul 2009 15:00:25 GMT</lastBuildDate>
  <generator>LiveJournal / LiveJournal.com</generator>
  <lj:journal>changelog</lj:journal>
  <lj:journalid>29488</lj:journalid>
  <lj:journaltype>community</lj:journaltype>
  <image>
    <url>http://l-userpic.livejournal.com/32044/29488</url>
    <title>LiveJournal ChangeLog</title>
    <link>http://community.livejournal.com/changelog/</link>
    <width>96</width>
    <height>96</height>
  </image>

<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7439757.html</guid>
  <pubDate>Fri, 17 Jul 2009 15:00:25 GMT</pubDate>
  <title>[ljcom] r7463: LJSUP-4590: The Independent banner is sh...</title>
  <link>http://community.livejournal.com/changelog/7439757.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: gariev&lt;/div&gt;LJSUP-4590: The Independent banner is shown to Perm accounts&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/index.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/index.bml
===================================================================
--- trunk/htdocs/index.bml	2009-07-17 10:06:57 UTC (rev 7462)
+++ trunk/htdocs/index.bml	2009-07-17 10:11:52 UTC (rev 7463)
@@ -32,7 +32,7 @@
             ## viewer is from UK
             ($country eq &apos;UK&apos; || $country eq &apos;GB&apos;) &amp;&amp; 
             ## and viewer is either anonymous, or plus (non-paid/perm/sponsored and non-basic) account
-            !$remote || $remote-&amp;gt;in_class(&apos;force_ads&apos;) || !$remote-&amp;gt;get_cap(&apos;paid&apos;) &amp;&amp; $remote-&amp;gt;in_class(&apos;plus&apos;)
+            (!$remote || $remote-&amp;gt;in_class(&apos;force_ads&apos;) || !$remote-&amp;gt;get_cap(&apos;paid&apos;) &amp;&amp; $remote-&amp;gt;in_class(&apos;plus&apos;))
         ) ? 
         LJ::Widget::ExtBlock-&amp;gt;render(id=&amp;gt;&apos;homepage.uk&apos;) : &apos;&apos;;
  

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7439757.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>gariev</lj:poster>
  <lj:posterid>11233912</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7439488.html</guid>
  <pubDate>Fri, 17 Jul 2009 14:55:30 GMT</pubDate>
  <title>[ljcom] r7462: LJSUP-4590: The Independent banner is sh...</title>
  <link>http://community.livejournal.com/changelog/7439488.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: gariev&lt;/div&gt;LJSUP-4590: The Independent banner is shown to Perm accounts&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/index.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/index.bml
===================================================================
--- trunk/htdocs/index.bml	2009-07-17 10:01:23 UTC (rev 7461)
+++ trunk/htdocs/index.bml	2009-07-17 10:06:57 UTC (rev 7462)
@@ -27,9 +27,13 @@
     my $ret = &quot;&quot;;
 
     my $country = LJ::GeoLocation-&amp;gt;get_country_info_by_ip;
-    my $uk_block = (!$remote ||
-        ($remote &amp;&amp; ($remote-&amp;gt;in_class(&apos;plus&apos;) || $remote-&amp;gt;in_class(&apos;force_ads&apos;))
-         &amp;&amp; ($country eq &apos;UK&apos; || $country eq &apos;GB&apos;) )) ?
+    my $uk_block = 
+        (    
+            ## viewer is from UK
+            ($country eq &apos;UK&apos; || $country eq &apos;GB&apos;) &amp;&amp; 
+            ## and viewer is either anonymous, or plus (non-paid/perm/sponsored and non-basic) account
+            !$remote || $remote-&amp;gt;in_class(&apos;force_ads&apos;) || !$remote-&amp;gt;get_cap(&apos;paid&apos;) &amp;&amp; $remote-&amp;gt;in_class(&apos;plus&apos;)
+        ) ? 
         LJ::Widget::ExtBlock-&amp;gt;render(id=&amp;gt;&apos;homepage.uk&apos;) : &apos;&apos;;
  
     ### Logged-in Homepage ###

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7439488.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>gariev</lj:poster>
  <lj:posterid>11233912</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7439310.html</guid>
  <pubDate>Fri, 17 Jul 2009 14:49:57 GMT</pubDate>
  <title>[ljcom] r7461: LJSUP-4203: Userpic Add-on - LJSUP-4457:...</title>
  <link>http://community.livejournal.com/changelog/7439310.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: ssafronova&lt;/div&gt;LJSUP-4203: Userpic Add-on - LJSUP-4457: move bulk code to class structure - preliminary, incomplete version&lt;br /&gt;&lt;pre&gt;U   branches/shop/bin/maint/pay.pl
U   branches/shop/cgi-bin/LJ/Hooks/Caps.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Addon.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Clothes.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Coppa.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Coupon.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Interval.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/PaidAccount/
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/PaidAccount/Permanent.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/PaidAccount.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/RecBillAble.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Rename.pm
A   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/VGift.pm
U   branches/shop/cgi-bin/LJ/Pay/Payment/PayItem.pm
U   branches/shop/cgi-bin/LJ/Pay/Payment.pm
U   branches/shop/cgi-bin/LJ/Pay/ShopVGift.pm
U   branches/shop/cgi-bin/paylib.pl
A   branches/shop/cgi-bin/paylib_cart.pl
A   branches/shop/cgi-bin/paylib_cc.pl
A   branches/shop/cgi-bin/paylib_paypal.pl
A   branches/shop/cgi-bin/paylib_sms.pl
U   branches/shop/htdocs/admin/accounts/acctedit.bml
U   branches/shop/htdocs/manage/account/index.bml
U   branches/shop/htdocs/manage/account/modify.bml
U   branches/shop/htdocs/pay/modify.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: branches/shop/bin/maint/pay.pl
===================================================================
--- branches/shop/bin/maint/pay.pl	2009-07-17 03:49:11 UTC (rev 7460)
+++ branches/shop/bin/maint/pay.pl	2009-07-17 10:01:23 UTC (rev 7461)
@@ -337,7 +337,7 @@
 
         # if permanent account, ignore this legacy (non-cart) payment
         my $u = LJ::load_userid($userid);
-        next if $u-&amp;gt;{&apos;caps&apos;} &amp; (1 &amp;lt;&amp;lt; $LJ::Pay::capinf{&apos;perm&apos;}-&amp;gt;{&apos;bit&apos;});
+        next if $u-&amp;gt;in_class(&apos;perm&apos;);
 
         # if there is an error adding paid months, remove from used list
         # so we&apos;ll try again later
@@ -415,466 +415,8 @@
             next;
         }
 
-        next if $pi-&amp;gt;{&apos;giveafter&apos;} &amp;gt; $now; # delayed payment
-
         my $pp = $get_payment-&amp;gt;($pi-&amp;gt;{&apos;payid&apos;});
-        my $bu = LJ::load_userid($pp-&amp;gt;{&apos;userid&apos;}); # buying user, no force needed
-
-        my $email = $pi-&amp;gt;{&apos;rcptemail&apos;};
-        my $ru;  # rcpt user
-        if ($pi-&amp;gt;{&apos;rcptid&apos;}) {
-            $ru = LJ::load_userid($pi-&amp;gt;{&apos;rcptid&apos;}, &quot;force&quot;);
-            warn &quot;Unable to load userid $pi-&amp;gt;{rcptid} for payid $pi-&amp;gt;{payid}&quot; unless $ru;
-            $email = $ru-&amp;gt;email_raw;
-        }
-
-        # does $ru have a perm account?  this affects things from time to time
-        my $has_perm = $ru &amp;&amp; $ru-&amp;gt;{&apos;caps&apos;} &amp; (1 &amp;lt;&amp;lt; $LJ::Pay::capinf{&apos;perm&apos;}-&amp;gt;{&apos;bit&apos;});
-
-        # optional gift header
-        my $msg;
-        if ($bu &amp;&amp; $bu-&amp;gt;{&apos;userid&apos;} != $pi-&amp;gt;{&apos;rcptid&apos;}) {
-            if ($pi-&amp;gt;{&apos;anon&apos;}) {
-                $msg .= &quot;(the following is an anonymous gift)\n\n&quot;
-            } else {
-                $msg .= &quot;(the following is a gift from $LJ::SITENAMESHORT user \&quot;$bu-&amp;gt;{&apos;user&apos;}\&quot;)\n\n&quot;;
-            }
-        }
-
-        my ($token, $tokenid);
-        my $close = sub {
-            $dbh-&amp;gt;do(&quot;UPDATE payitems SET status=&apos;done&apos;, token=?, tokenid=? &quot;.
-                     &quot;WHERE piid=? AND status=&apos;pend&apos;&quot;, undef, $token,
-                     $tokenid, $pi-&amp;gt;{&apos;piid&apos;});
-        };
-
-        # paid/perm accounts
-        if ($pi-&amp;gt;{&apos;item&apos;} eq &quot;paidacct&quot; || $pi-&amp;gt;{&apos;item&apos;} eq &quot;perm&quot;) {
-            my $isacct = $pi-&amp;gt;{&apos;item&apos;} eq &quot;paidacct&quot;;
-
-            # send &apos;em a token
-            if ($pi-&amp;gt;{&apos;rcptid&apos;} == 0 || $has_perm) { # rcpt is an email address, or perm acct
-                $token = LJ::acct_code_generate($bu ? $bu-&amp;gt;{userid} : 0);
-                my ($acid, $auth) = LJ::acct_code_decode($token);
-                $dbh-&amp;gt;do(&quot;INSERT INTO acctpayitem (piid, acid) VALUES (?,?)&quot;,
-                         undef, $pi-&amp;gt;{&apos;piid&apos;}, $acid);
-
-                $tokenid = $acid;
-
-                my $what;
-                if ($isacct) {
-                    $what = &quot;$pi-&amp;gt;{&apos;qty&apos;} month(s) of paid account time&quot;;
-                } else {
-                    $what = &quot;a permanent account&quot;;
-                }
-
-                $msg .= &quot;The following code will give $what to any $LJ::SITENAMESHORT account:\n\n&quot;;
-                $msg .= &quot;   $token\n\n&quot;;
-                $msg .= &quot;To apply it to an existing account, visit:\n\n&quot;;
-                $msg .= &quot;   $LJ::SITEROOT/paidaccounts/apply.bml?code=$token\n\n&quot;;
-
-                LJ::send_mail({
-                    &apos;to&apos; =&amp;gt; $email,
-                    &apos;from&apos; =&amp;gt; $LJ::ACCOUNTS_EMAIL,
-                    &apos;fromname&apos; =&amp;gt; $LJ::SITENAMESHORT,
-                    &apos;wrap&apos; =&amp;gt; 1,
-                    &apos;charset&apos; =&amp;gt; &apos;utf-8&apos;,
-                    &apos;subject&apos; =&amp;gt; $isacct ? &quot;Paid account&quot; : &quot;Permanent account&quot;,
-                    &apos;body&apos; =&amp;gt; $msg,
-                });
-
-                # nothing to do here for loyalty userpics since we have rcptid==0
-                # and therefore no $ru
-
-                $close-&amp;gt;();
-                # don&apos;t need to release lock, no rcptid
-                next;
-            }
-
-            # just set it up now, and tell them it&apos;s done.
-            # no need to release lock since no $ru anyway
-            next unless $ru;
-
-            my $mo;
-            $mo = $pi-&amp;gt;{&apos;qty&apos;} if $isacct;
-            $mo = 99 if $pi-&amp;gt;{&apos;item&apos;} eq &quot;perm&quot;;
-            my $bonus_ref = [];
-
-            # modifying paid account status, need to get a lock on the account,
-            # try again later if we fail to get a lock
-            next unless LJ::Pay::get_lock($ru);
-
-            my $res = LJ::Pay::add_paid_months($ru, $mo, $bonus_ref);
-
-            # finished modifying account, can unconditionally release lock and finish payitem now
-            LJ::Pay::release_lock($ru);
-
-            # some sort of error occurred, log to payvars and try again later
-            unless ($res) {
-                LJ::Pay::payvar_append($pp, &quot;error&quot;,
-                                       &quot;[&quot; . LJ::mysql_time() . &quot;] unable to apply: item=$pi-&amp;gt;{&apos;item&apos;}, qty=$pi-&amp;gt;{&apos;qty&apos;}.&quot;);
-                next;
-            }
-
-            # account changes were successful: close transaction, only need to send email now
-            $close-&amp;gt;();
-
-            # note that this user&apos;s bill changed
-            $note_rec_change-&amp;gt;($ru, $pp) if $ru;
-
-            # harvest this payitem for loyalty userpics
-            LJ::Pay::LoyaltyUserpic-&amp;gt;harvest_payitem($pi) if $ru;
-
-            # finish composing email to send to user
-            my $bonus_added;
-            if (@$bonus_ref) {
-                $bonus_added = &quot;Additionally, the following previously deactivated bonus features\n&quot; .
-                               &quot;have been reactivated so you can use the time remaining on them:\n\n&quot; .
-                               join(&quot;\n&quot;, map { &quot;   - &quot; . LJ::Pay::product_name($_-&amp;gt;{&apos;item&apos;}, $_-&amp;gt;{&apos;size&apos;}, undef, &quot;short&quot;) .
-                                                &quot;: $_-&amp;gt;{&apos;daysleft&apos;} days applied&quot; }
-                                    sort { $a-&amp;gt;{&apos;item&apos;} cmp $b-&amp;gt;{&apos;item&apos;} } @$bonus_ref) .
-                               &quot;\n\n&quot;;
-            }
-
-            if ($isacct) {
-                $msg .= &quot;$mo months of paid account time have been added to your $LJ::SITENAMESHORT &quot;;
-                $msg .= &quot;account \&quot;$ru-&amp;gt;{&apos;user&apos;}\&quot;.\n\n&quot;;
-            } else {
-                $msg .= &quot;Your $LJ::SITENAMESHORT account \&quot;$ru-&amp;gt;{&apos;user&apos;}\&quot; has been upgraded to a &quot;;
-                $msg .= &quot;permanent account.\n\n&quot;;
-
-                if (! LJ::conf_test($LJ::DISABLED{dec2008_permsale})) {
-                    my $area;
-                    my $charity = 0.00;
-                    if (LJ::SUP-&amp;gt;is_sup_enabled($bu)) {
-                        $area = &quot;SUP&quot;;
-                        $charity = $LJ::PERM_SALE_CHARITY_AMT
-                            if LJ::conf_test($LJ::PERM_SALE_CHARITY_SUP);
-                    } else {
-                        $charity = $LJ::PERM_SALE_CHARITY_AMT
-                            if LJ::conf_test($LJ::PERM_SALE_CHARITY_NONSUP);
-                    }
-                    # insert into the perm_sale table
-                    my $dbh = LJ::get_db_writer() or die &quot;Could not get db writer&quot;;
-                    $dbh-&amp;gt;do(&quot;INSERT INTO perm_sale(payid, journalid, area, name, price, charity, extra) VALUES (?, ?, ?, ?, ?, ?, ?)&quot;, undef, $pi-&amp;gt;{payid}, $bu-&amp;gt;{&apos;userid&apos;}, $area, &apos;dec2008&apos;, $pi-&amp;gt;{&apos;amt&apos;}, $charity, undef);
-
-                    $msg .= &quot;LiveJournal will donate \$$charity from this purchase to charity.\n\n&quot;
-                        if $charity &amp;gt; 0;
-                }
-            }
-
-            if ($ru) {
-                $msg .= &quot;Take advantage of some of your paid account features:\n\n&quot;;
-                $msg .= LJ::Pay::usage_summary_text($ru);
-            }
-
-            $msg .= $bonus_added;
-
-            $msg .= &quot;Thank you for supporting the site!\n\n&quot;;
-            $msg .= &quot;--\n$LJ::SITENAME Team\n$LJ::SITEROOT&quot;;
-
-            # send notification email
-            my $subject = $isacct ? &quot;$LJ::SITENAMEABBREV Paid Account Extension&quot;
-                                  : &quot;$LJ::SITENAMEABBREV Permanent Account Upgrade&quot;;
-
-            LJ::send_mail({
-                &apos;to&apos; =&amp;gt; $email,
-                &apos;from&apos; =&amp;gt; $LJ::ACCOUNTS_EMAIL,
-                &apos;fromname&apos; =&amp;gt; $LJ::SITENAMESHORT,
-                &apos;wrap&apos; =&amp;gt; 1,
-                &apos;charset&apos; =&amp;gt; &apos;utf-8&apos;,
-                &apos;subject&apos; =&amp;gt; $subject,
-                &apos;body&apos; =&amp;gt; $msg,
-            });
-
-            next;
-        }
-
-        # rename tokens
-        elsif ($pi-&amp;gt;{&apos;item&apos;} eq &quot;rename&quot;) {
-            next unless ($token, $tokenid) = LJ::Pay::new_rename_token($dbh, $pp-&amp;gt;{&apos;payid&apos;});
-
-            # send email notification
-            LJ::send_mail({
-                &apos;to&apos; =&amp;gt; $email,
-                &apos;from&apos; =&amp;gt; $LJ::ACCOUNTS_EMAIL,
-                &apos;fromname&apos; =&amp;gt; $LJ::SITENAMESHORT,
-                &apos;wrap&apos; =&amp;gt; 1,
-                &apos;charset&apos; =&amp;gt; &apos;utf-8&apos;,
-                &apos;subject&apos; =&amp;gt; &quot;You&apos;ve Received a Rename Token&quot;,
-                &apos;body&apos; =&amp;gt; &quot;${msg}$LJ::SITENAMESHORT username rename token:\n\n&quot;.
-                    &quot;   $token\n\n&quot;.
-                    &quot;You can use it here:\n\n&quot;.
-                    &quot;   $LJ::SITEROOT/rename/use.bml?token=$token\n\n&quot;.
-                    &quot;For more information regarding account renames, read:\n\n&quot;.
-                    &quot;   $LJ::SITEROOT/rename/\n\n&quot;.
-                    &quot;Thank you for supporting the site!\n\n&quot;.
-                    &quot;--\n$LJ::SITENAMESHORT Team\n$LJ::SITEROOT&quot;
-                });
-
-            $close-&amp;gt;();
-            next;
-        }
-
-        # clothing items
-        elsif ($pi-&amp;gt;{&apos;item&apos;} eq &quot;clothes&quot;) {
-            $dbh-&amp;gt;do(&quot;INSERT IGNORE INTO shipping (payid, status, dateready) VALUES (?, &apos;needs&apos;, NOW())&quot;,
-                     undef, $pp-&amp;gt;{&apos;payid&apos;}) and $close-&amp;gt;();
-            next;
-        }
-
-        # coupons
-        elsif ($pi-&amp;gt;{&apos;item&apos;} eq &quot;coupon&quot;) {
-
-            # subitem used to be type-dollaramount, but that was redundant
-            my $type = (split(&apos;-&apos;, $pi-&amp;gt;{&apos;subitem&apos;}))[0];
-
-            # If amt &amp;lt; 0, this item is a previously purchased coupon being applied
-            # to this cart.  So we shouldn&apos;t generate a new tokenid for it, especially
-            # since it will have rcptid=0, so we wouldn&apos;t know where to mail it anyway.
-            if ($type =~  /^dollaroff(int|tan)?$/ &amp;&amp; $pi-&amp;gt;{&apos;amt&apos;} &amp;gt; 0) {
-
-                ($tokenid, $token) =
-                    LJ::Pay::new_coupon($type, $pi-&amp;gt;{&apos;amt&apos;}, $pi-&amp;gt;{&apos;rcptid&apos;}, $pp-&amp;gt;{&apos;payid&apos;});
-
-                # if there was an error, try again later
-                next unless $tokenid;
-
-                LJ::Pay::send_coupon_email($email, $token, $pi-&amp;gt;{&apos;amt&apos;}, $1);
-
-            # close, but preserve token info
-            } else {
-                ($token, $tokenid) = ($pi-&amp;gt;{&apos;token&apos;}, $pi-&amp;gt;{&apos;tokenid&apos;});
-            }
-            $close-&amp;gt;();
-            next;
-        }
-
-        # vgifts
-        elsif (LJ::Pay::is_vgift($pi)) {
-
-            # we&apos;ll see if there is already a giftid, which means
-            # that a vgift has already been generated for this
-            # payitem but the status wasn&apos;t marked as &apos;done&apos;
-            # via $close-&amp;gt;(), presumably because of an error checking
-            # or applying vgift bonus paid time
-            my $exist_giftid = $pi-&amp;gt;get_prop(&apos;vgift_giftid&apos;);
-
-            unless ($exist_giftid) {
-                my $note  = $pi-&amp;gt;get_prop(&apos;vgift_note&apos;);
-                my $vg = LJ::Pay::ShopVGift-&amp;gt;new($pi-&amp;gt;{subitem});
-
-                ##
-                ## vgift_10 has id 249
-                ## User can buy no more than 5 free such vgifts
-                ## We store the number of purchased vgifts in user property &apos;vgifts_restrict&apos;
-                ## format is &quot;vgift_id:number_of_vgifts,vgift_id2:number_of_vgifts2&quot;
-                ##
-                if ($pi-&amp;gt;{subitem} eq &apos;vgift_10&apos; &amp;&amp; $pi-&amp;gt;{amt} == 0.00) {
-                    my $vgift = LJ::Pay::ShopVGift-&amp;gt;new(name =&amp;gt; &apos;vgift_10&apos;);
-                    my $vgifts_restrict = $bu ? $bu-&amp;gt;prop(&apos;vgifts_restrict&apos;) : &apos;&apos;;
-                    my %vgifts_restrict = map {split &apos;:&apos;, $_} split &apos;,&apos;, $vgifts_restrict;
-                    $vgifts_restrict{ $vgift-&amp;gt;id }++;
-                    $bu-&amp;gt;set_prop(&apos;vgifts_restrict&apos;, join(&quot;,&quot;, map {&quot;$_:$vgifts_restrict{$_}&quot;} keys %vgifts_restrict));
-                }
-                
-                my $vgift = LJ::VGift-&amp;gt;create
-                    ( to   =&amp;gt; $ru,
-                      from =&amp;gt; $bu,
-                      type =&amp;gt; $pi-&amp;gt;{subitem},
-                      note =&amp;gt; $note,
-                      anon =&amp;gt; $pi-&amp;gt;{anon},
-                      expires =&amp;gt; $vg-&amp;gt;expire_time,
-                      );
-
-                # if there was an error we&apos;ll start mentioning it every time
-                # we try to process this payitem so it will be noticed but
-                # not stop payment processing altogether
-                unless ($vgift) {
-                    print STDERR &quot;unable to create VGift for piid: $pi-&amp;gt;{piid}\n&quot;;
-                    next;
-                }
-
-                # save the giftid we created for revokes later
-                $pi-&amp;gt;set_prop(&apos;vgift_giftid&apos; =&amp;gt; $vgift-&amp;gt;{giftid});
-
-                my $extra = &quot;&quot;;
-                my $html_extra = &quot;&quot;;
-                if ($vgift-&amp;gt;is_charity) {
-                    $extra = LJ::Lang::ml(&apos;esn.vgift.extra_charity.text&apos;, { siteroot =&amp;gt; $LJ::SITEROOT, });
-                    $html_extra = LJ::Lang::ml(&apos;esn.vgift.extra_charity.html&apos;, { siteroot =&amp;gt; $LJ::SITEROOT, });
-                }
-
-                my $promo = &quot;&quot;;
-                my $html_promo = &quot;&quot;;
-                if (LJ::Pay::ShopVGiftSponsored-&amp;gt;show_promo({viewer =&amp;gt; $ru})) {
-                    my $sponsor = $LJ::SPONSORED_VGIFTS{&apos;free&apos;}{&apos;name&apos;};
-                    my $link = $LJ::SPONSORED_VGIFTS{&apos;free&apos;}{&apos;tracking_link_email&apos;};
-                    my $vars = {
-                            siteroot =&amp;gt; $LJ::SITEROOT,
-                            sponsor  =&amp;gt; $sponsor,
-                            link     =&amp;gt; $link,
-                        };
-                    $promo = LJ::Lang::ml(&apos;esn.vgift.promo.text&apos;,      $vars);
-                    $html_promo = LJ::Lang::ml(&apos;esn.vgift.promo.html&apos;, $vars);
-                }
-
-                my $vars = {
-                    siteroot        =&amp;gt; $LJ::SITEROOT,
-                    sitenameshort   =&amp;gt; $LJ::SITENAMESHORT,
-                    user            =&amp;gt; $ru-&amp;gt;{user},
-                    sender          =&amp;gt; ((! $bu || $pi-&amp;gt;{anon}) ? LJ::Lang::ml(&apos;esn.vgift.anon_sender&apos;) : $bu-&amp;gt;{user}),
-                    note            =&amp;gt; ($note ? LJ::Lang::ml(&apos;esn.vgift.note&apos;, { note =&amp;gt; $note }) : &quot;&quot;),
-                    extra           =&amp;gt; $extra,
-                    profile         =&amp;gt; $ru-&amp;gt;profile_url,
-                    promo           =&amp;gt; $promo,
-                };
-
-                my $body = LJ::Lang::ml(&apos;esn.vgift.body.text&apos;, $vars);
-
-                my $html_body = undef;
-                unless ($ru-&amp;gt;{opt_htmlemail} eq &apos;N&apos;) {
-                    $vars-&amp;gt;{extra} = $html_extra;
-                    $vars-&amp;gt;{promo} = $html_promo;
-                    $vars-&amp;gt;{note}  = $note ? LJ::Lang::ml(&apos;esn.vgift.note&apos;, { note =&amp;gt; $note }) : &apos;&apos;;
-                    $vars-&amp;gt;{user}  = LJ::load_user($ru-&amp;gt;{user})-&amp;gt;ljuser_display;
-                    $vars-&amp;gt;{sender} = LJ::load_user($bu-&amp;gt;{user})-&amp;gt;ljuser_display if ($bu &amp;&amp; !$pi-&amp;gt;{anon});
-
-                    $html_body = LJ::Lang::ml(&apos;esn.vgift.body.html&apos;, $vars);
-                }
-
-                # send email notification
-                LJ::send_mail({
-                    to       =&amp;gt; $email,
-                    from     =&amp;gt; $LJ::ACCOUNTS_EMAIL,
-                    fromname =&amp;gt; $LJ::SITENAMESHORT,
-                    wrap     =&amp;gt; 1,
-                    charset  =&amp;gt; &apos;utf-8&apos;,
-                    subject  =&amp;gt; LJ::Lang::ml(&apos;esn.vgift.to_you.subject&apos;, { sitenameshort =&amp;gt; $LJ::SITENAMESHORT}),
-                    body     =&amp;gt; $body,
-                    html     =&amp;gt; $html_body,
-                });
-            }
-
-            # now if the user has passed a certain threshold of
-            # vgifts received, then they will receive a bonus!
-            LJ::VGift-&amp;gt;check_gifts_for_paid_bonus
-                ( $ru, sub {
-                    my %args = @_;
-                    # u=$ru, sum=$amt
-
-                    my $sum = sprintf(&quot;\$%.02f&quot;, $args{sum});
-
-                    my $pmt = LJ::Pay::Payment-&amp;gt;new
-                        (
-                         anum      =&amp;gt; int(rand()*65535), # unused for recbill payments
-                         userid    =&amp;gt; $ru-&amp;gt;{userid},
-                         datesent  =&amp;gt; undef,             # use NOW()
-                         daterecv  =&amp;gt; undef,             # use NOW()
-                         amount    =&amp;gt; 0.00,
-                         used      =&amp;gt; &apos;N&apos;,               # &apos;C&apos; until payment has gone through
-                         mailed    =&amp;gt; &apos;N&apos;,               # &apos;C&apos; until payment has gone through
-                         method    =&amp;gt; &apos;free&apos;,
-                         forwhat   =&amp;gt; &apos;cart&apos;,
-                         ) or return undef;
-
-                    my $it = $pmt-&amp;gt;add_item
-                        (
-                         item      =&amp;gt; &apos;paidacct&apos;,
-                         subitem   =&amp;gt; undef,         # no subitem for paidacct
-                         qty       =&amp;gt; 2,             # 2 months free
-                         rcptid    =&amp;gt; $ru-&amp;gt;{userid}, # virtual gift recipient
-                         amt       =&amp;gt; 0.00,
-                         status    =&amp;gt; &apos;cart&apos;,        # not finished processing
-                         ) or return undef;
-
-                    # add a payvar to preserve history
-                    $pmt-&amp;gt;payvar_add(&apos;vgift_bonus&apos;,
-                                     &quot;2 month paidacct bonus for $sum received vgifts&quot;);
-
-                    # and statushistory never hurts...
-                    my $sys_u = LJ::load_user(&quot;system&quot;);
-                    LJ::statushistory_add($ru, $sys_u, &quot;vgift_bonus&quot;,
-                                          &quot;generated 2 month paidacct bonus payment &quot; .
-                                          &quot;[payid=$pmt-&amp;gt;{payid}]&quot;);
-                }) unless $has_perm;
-
-            # vgift has been applied and bonus given, we can close this payitem
-            $close-&amp;gt;();
-
-            next;
-        }
-
-        # bonus features
-        elsif (LJ::Pay::is_bonus($pi)) {
-
-            # if a bonus item of this type failed to apply, don&apos;t try to apply any more
-            next if exists $bonus_failure{&quot;$pi-&amp;gt;{&apos;payid&apos;}-$pi-&amp;gt;{&apos;item&apos;}-$pi-&amp;gt;{&apos;subitem&apos;}&quot;};
-
-            # get a lock since we&apos;re about to modify their account,
-            # try again later if we can&apos;t get a lock
-            next unless LJ::Pay::get_lock($ru);
-
-            # apply the bonus item to the recipient user&apos;s account
-            my $res = LJ::Pay::apply_bonus_item($ru, $pi);
-
-            # release lock and close regardless of results of operation
-            LJ::Pay::release_lock($ru);
-
-            # if an error, log to payvars (call above also logged to statushistory) and skip the email
-            unless ($res) {
-                LJ::Pay::payvar_append($pp, &quot;error&quot;,
-                                       &quot;[&quot; . LJ::mysql_time() . &quot;] unable to apply: item=$pi-&amp;gt;{&apos;item&apos;},  size=&quot; .
-                                       (split(&quot;-&quot;, $pi-&amp;gt;{&apos;subitem&apos;}))[0] . &quot;, qty=$pi-&amp;gt;{&apos;qty&apos;}. invalid cart?&quot;);
-
-                # if there was a failure, all bonus items of this type were marked
-                # as failed, so we shouldn&apos;t try to process any more of them
-                $bonus_failure{&quot;$pi-&amp;gt;{&apos;payid&apos;}-$pi-&amp;gt;{&apos;item&apos;}-$pi-&amp;gt;{&apos;subitem&apos;}&quot;}++;
-
-                next;
-            }
-
-            # at this point time is applied, just need to send mail.  so close.
-            $close-&amp;gt;();
-
-            # note that this user&apos;s bill changed
-            $note_rec_change-&amp;gt;($ru, $pp) if $ru;
-
-            # send notification email to user
-            my $name = LJ::Pay::product_name($pi);
-
-            $msg .= &quot;Your $LJ::SITENAMESHORT account for user \&quot;$ru-&amp;gt;{&apos;user&apos;}\&quot; has been &quot;;
-            $msg .= &quot;credited with the following add-on:\n\n&quot;;
-
-            $msg .= &quot;   - $name\n\n&quot;;
-
-            $msg .= &quot;Your account has been updated so you can use your new feature immediately.\n\n&quot;;
-
-            if ($ru) {
-                $msg .= &quot;Take advantage of some of your paid account features:\n\n&quot;;
-                $msg .= LJ::Pay::usage_summary_text($ru);
-            }
-
-            $msg .= &quot;Thank you for supporting the site,\n&quot;;
-            $msg .= &quot;$LJ::SITENAMESHORT Team\n&quot;;
-
-            LJ::send_mail({
-                &apos;to&apos; =&amp;gt; $email,
-                &apos;from&apos; =&amp;gt; $LJ::ACCOUNTS_EMAIL,
-                &apos;fromname&apos; =&amp;gt; $LJ::SITENAMESHORT,
-                &apos;wrap&apos; =&amp;gt; 1,
-                &apos;charset&apos; =&amp;gt; &apos;utf-8&apos;,
-                &apos;subject&apos; =&amp;gt; $name,
-                &apos;body&apos; =&amp;gt; $msg,
-            });
-
-            next;
-
-        # just close -- shipping, coppa, etc
-        } else {
-            $close-&amp;gt;();
-            next;
-        }
+        $pi-&amp;gt;pay_updateaccounts($pp, $now, $note_rec_change);
     }
 
     # respect biller_disable flag

Modified: branches/shop/cgi-bin/LJ/Hooks/Caps.pm
===================================================================
--- branches/shop/cgi-bin/LJ/Hooks/Caps.pm	2009-07-17 03:49:11 UTC (rev 7460)
+++ branches/shop/cgi-bin/LJ/Hooks/Caps.pm	2009-07-17 10:01:23 UTC (rev 7461)
@@ -25,8 +25,7 @@
 LJ::register_hook(&quot;get_cap_bit&quot;, sub {
     my $name = shift;
     return undef unless $name;
-
-    return $LJ::Pay::capinf{$name}-&amp;gt;{&apos;bit&apos;};
+    return LJ::class_bit($name);
 });
 
 # Register hooks for turning on/off certain cap bits
@@ -106,13 +105,6 @@
     return $size || undef;
 });
 
-LJ::register_hook(&quot;check_cap_perm&quot;, sub {
-    my $u = shift;
-    return undef unless $u;
-
-    return $u-&amp;gt;{&apos;caps&apos;} &amp; (1 &amp;lt;&amp;lt; $LJ::Pay::capinf{&apos;perm&apos;}-&amp;gt;{&apos;bit&apos;}) ? 1 : 0;
-});
-
 LJ::register_hook(&quot;check_cap_userpics&quot;, sub {
     my $u = shift;
     return undef unless $u;

Added: branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Addon.pm
===================================================================
--- branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Addon.pm	                        (rev 0)
+++ branches/shop/cgi-bin/LJ/Pay/Payment/PayItem/Addon.pm	2009-07-17 10:01:23 UTC (rev 7461)
@@ -0,0 +1,1009 @@
+package LJ::Pay::Payment::PayItem::Addon;
+
+use base LJ::Pay::Payment::PayItem::RecBillAble;
+
+# bonus features are of 2 types:
+# - &quot;bool&quot; are either on or off (userpics), &apos;cap&apos; key is required
+# - &quot;sized&quot; have a magnitude associated with them (how much disk quota)
+%bonus = (
+           # userpics are a &apos;bool&apos; item
+           &apos;userpic&apos; =&amp;gt; {
+               &apos;name&apos; =&amp;gt; &apos;pay.product.extrauserpics&apos;,
+               &apos;type&apos; =&amp;gt; &apos;bool&apos;,
+               &apos;cap&apos; =&amp;gt; 9, # cap bit to activate for user
+               &apos;items&apos; =&amp;gt; {
+                   # quantities
+                   # * undef amount means recurring only
+                   1  =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;1 month&apos;,   &apos;amount&apos; =&amp;gt; undef, &apos;amount_rec&apos; =&amp;gt;  1, },
+                   2  =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;2 months&apos;,  &apos;amount&apos; =&amp;gt; 2,     &apos;amount_rec&apos; =&amp;gt;  2, },
+                   6  =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;6 months&apos;,  &apos;amount&apos; =&amp;gt; 6,     &apos;amount_rec&apos; =&amp;gt;  6, },
+                   12 =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;12 months&apos;, &apos;amount&apos; =&amp;gt; 10,    &apos;amount_rec&apos; =&amp;gt; 10, }
+               }
+           },
+
+           # disk quota is a &apos;sized&apos; item
+           &apos;diskquota&apos; =&amp;gt; {
+               &apos;name&apos; =&amp;gt; &apos;pay.product.extrastorage&apos;,
+               &apos;type&apos; =&amp;gt; &apos;sized&apos;,
+               &apos;cap&apos; =&amp;gt; undef, # optional
+               &apos;apply_hook&apos; =&amp;gt; \&amp;LJ::Pay::Payment::PayItem::Addon::diskquota_apply_hook,
+               &apos;items&apos; =&amp;gt; {
+                   # 1024*10 = 10240 = 10GB
+                   10240 =&amp;gt; {
+                       &apos;name&apos; =&amp;gt; &apos;10 GB&apos;,
+                       &apos;qty&apos; =&amp;gt; {
+                           1  =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;1 months&apos;,  &apos;amount&apos; =&amp;gt; undef, &apos;amount_rec&apos; =&amp;gt;  3, },
+                           2  =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;2 months&apos;,  &apos;amount&apos; =&amp;gt; 5,     &apos;amount_rec&apos; =&amp;gt;  5, },
+                           6  =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;6 months&apos;,  &apos;amount&apos; =&amp;gt; 14,    &apos;amount_rec&apos; =&amp;gt; 14, },
+                           12 =&amp;gt; { &apos;name&apos; =&amp;gt; &apos;12 months&apos;, &apos;amount&apos; =&amp;gt; 24,    &apos;amount_rec&apos; =&amp;gt; 24, },
+                       }
+                   },
+
+               }
+           }
+          );
+
+# now allow a mechanism for individual bonus items to be disabled
+foreach my $itemname (keys %bonus) {
+    next unless $LJ::DISABLED{&quot;bonus-$itemname&quot;};
+
+    delete $bonus{$itemname};
+}
+
+sub diskquota_apply_hook
+{
+    my ($u, $item) = @_;
+
+    # RIP old business model: this is where used to enqueue a
+    # white-labeled-parent-site ping to update what a user&apos;s quota
+    # should be.  for instance: deadjournal pinging LJ where LJ was
+    # hosting all of DJ&apos;s photo hosting under DJ&apos;s style.  DJ ran this
+    # on their beta site for a bit, but we never went into business
+    # with it.  (around time of SixApart acquistion, and 6a wasn&apos;t
+    # interested in FotoBilder code/services).  now this code is
+    # removed because we&apos;re killing cmdbuffer usage now that all
+    # cmdbuffer is moving to using our new job queue system.
+}
+
+sub get_bonus_exp {
+    my ($u, @items) = @_;
+    return undef unless @items &amp;&amp; ! grep { ! LJ::Pay::is_bonus($_) } @items;
+    my $userid = LJ::want_userid($u);
+    return undef unless $userid;
+
+    my $dbh = LJ::get_db_writer()
+        or return undef;
+
+    my $bind = join(&apos;,&apos;, map { &quot;?&quot; } @items);
+    my $sth = $dbh-&amp;gt;prepare
+        (&quot;SELECT item, UNIX_TIMESTAMP(expdate) FROM paidexp WHERE userid=? AND item IN ($bind)&quot;);
+    $sth-&amp;gt;execute($userid, @items);
+
+    my %ret = ();
+    while (my ($it, $exp) = $sth-&amp;gt;fetchrow_array) {
+        $ret{$it} = $exp;
+    }
+
+    return \%ret;
+}
+
+# get dimensions of current sized bonus block
+sub get_bonus_dim {
+    my ($u, $itemname) = @_;
+    my $userid = LJ::want_userid($u);
+    return undef unless $userid;
+
+    my $dbh = LJ::get_db_writer();
+    my ($exptime, $size) = $dbh-&amp;gt;selectrow_array(&quot;SELECT UNIX_TIMESTAMP(expdate), size &quot; .
+                                                 &quot;FROM paidexp WHERE userid=? AND item=?&quot;,
+                                                 undef, $userid, $itemname);
+    return wantarray ? ($exptime || 0, $size || 0) : $exptime;
+}
+
+# given a cart can we add a given item?
+sub can_apply_sized_bonus {
+    my ($u, $cartobj, $item, $size, $qty, $opts) = @_;
+    $u = LJ::want_user($u);
+
+    my $userid = $u-&amp;gt;{userid};
+
+    # easy/obvious checks
+    return undef unless $userid &amp;&amp; item_is_bonus($item, &apos;sized&apos;);
+
+    # if the caller doesn&apos;t specify a qty they are trying to add, just
+    # validate items already in the cart
+    $qty ||= 0;
+
+    # is there immediately applying paid time in the cart?
+    my $cart_paid_immed = undef;
+
+    # now go through the current cart and see what they have already
+    if ($cartobj) {
+
+        # will be used for checks later on &quot;dimension signature&quot;
+        my ($prev_exp, $prev_size) = get_bonus_dim($userid, $item);
+
+        foreach my $it (@{$cartobj-&amp;gt;{&apos;items&apos;}}) {
+            next unless $it-&amp;gt;{&apos;rcptid&apos;} == $userid;
+
+            # collect information on when paid account starts in this cart
+            $cart_paid_immed = 1
+                if $it-&amp;gt;{&apos;item&apos;} eq &apos;paidacct&apos; &amp;&amp; ! $it-&amp;gt;{&apos;giveafter&apos;};
+
+            next unless $it-&amp;gt;{&apos;item&apos;} eq $item;
+
+            # can&apos;t have a giveafter date on sized items
+            return undef if $it-&amp;gt;{&apos;giveafter&apos;};
+
+            # subitem field contains a few useful bits of info
+            my ($itsize, $curr_exp, $curr_size) = split(&quot;-&quot;, $it-&amp;gt;{&apos;subitem&apos;});
+
+            # if no size specified, then just verify that all sizes in the cart are equal
+            $size ||= $itsize;
+
+            # can buy multiple items, but only of the same size
+            return undef if $itsize != $size;
+
+            # when applying sized bonus, we have to make sure that no other sized bonus features have been
+            # applied since this one was added to the cart, so check the previous &quot;dimension signature&quot;
+            # to decide if this item can be legally applied
+            return undef unless $prev_exp == $curr_exp &amp;&amp; $prev_size == $curr_size;
+
+            # this is an extension to something already in the cart
+            $qty += $it-&amp;gt;{&apos;qty&apos;};
+
+            # can&apos;t have more than 12 months in cart
+            return undef if $qty &amp;gt; 12;
+        }
+    }
+
+    # now time to run some checks on the database
+    my $dbh = LJ::get_db_writer();
+
+    # if no paid account in cart starting immediately, check in the database
+    # to see if there is currently paid time there
+    unless ($cart_paid_immed) {
+
+        # sometimes users have the paid cap with no paiduser row in the database, eg when
+        # they have a permanent account ... assume if they have a perm account then
+        # they are paid forever
+        unless ($dbh-&amp;gt;selectrow_array(&quot;SELECT COUNT(*) FROM paiduser WHERE userid=? AND paiduntil&amp;gt;NOW()&quot;, undef, $userid)) {
+
+            # if the query above failed, check to see if they have the paid cap
+            return undef unless $u &amp;&amp; $u-&amp;gt;in_class(&apos;perm&apos;);
+        }
+    }
+
+    # now let&apos;s see what&apos;s in the database, with regards to this bonus item
+    my $row = $dbh-&amp;gt;selectrow_hashref(&quot;SELECT *, &quot; .
+                                      &quot;(NOW() + INTERVAL ? MONTH &amp;lt;= expdate) AS &apos;is_short&apos;, &quot; .
+                                      &quot;(IF(size=?, expdate, NOW()) + INTERVAL ? MONTH &amp;gt; NOW() + INTERVAL 12 MONTH) AS &apos;is_long&apos; &quot; .
+                                      &quot;FROM paidexp WHERE userid=? AND item=?&quot;, undef, $qty, $size, $qty, $userid, $item);
+
+    # if nothing in database, the checks we&apos;ve already done are sufficient
+    return 1 unless $row;
+
+    # now we know there was a $row in the db
+
+    # if we are checking for the addition of a recurring item, there is no need to do
+    # short/long checks.  allow a flag to disable them.
+    unless ($opts-&amp;gt;{recurring}) {
+        # can&apos;t apply if they already have stored, therefore presumably no paid account?
+        return undef if $row-&amp;gt;{&apos;daysleft&apos;};
+
+        # can&apos;t apply if expiration date won&apos;t extend past that of their current time
+        # unless the size is the same as their current size
+        return undef if $row-&amp;gt;{&apos;is_short&apos;} &amp;&amp; $row-&amp;gt;{&apos;size&apos;} != $size;
+
+        # can&apos;t apply more than one year in the future
+        return undef if $row-&amp;gt;{&apos;is_long&apos;};
+    }
+
+    # can&apos;t downgrade to a lower size
+    return undef if $size &amp;lt; $row-&amp;gt;{&apos;size&apos;};
+
+    return 1;
+}
+
+sub can_apply_bool_bonus {
+    my ($u, $cartobj, $item) = @_;
+    my $userid = LJ::want_userid($u);
+
+    # easy/obvious checks
+    return undef unless $userid &amp;&amp; item_is_bonus($item, &apos;bool&apos;);
+
+    # when does paid time in the cart begin?
+    my $cart_paid_start = undef;
+    my $cart_bonus_start = undef;
+
+    if ($cartobj) {
+
+        # check the cart to see if we can immediately exonerate this bonus feature
+        # without even looking in the database.
+        foreach my $it (@{$cartobj-&amp;gt;{&apos;items&apos;}}) {
+            next unless $it-&amp;gt;{&apos;rcptid&apos;} == $userid;
+
+            # can&apos;t buy bool bonus features for permanent accounts
+            return undef if $it-&amp;gt;{&apos;item&apos;} eq &apos;perm&apos;;
+
+            # calculate starting time of first applying amount of paid time in the cart
+            if ($it-&amp;gt;{&apos;item&apos;} eq &apos;paidacct&apos;) {
+
+                if ($it-&amp;gt;{&apos;giveafter&apos;}) {
+                    $cart_paid_start = $it-&amp;gt;{&apos;giveafter&apos;} if ! defined $cart_paid_start || $it-&amp;gt;{&apos;giveafter&apos;} &amp;lt; $cart_paid_start;
+                    next;
+                }
+
+                # no giveafter time, applies immediately
+                $cart_paid_start = 0;
+                next;
+            }
+
+            # calculate starting time of this bonus item
+            if ($it-&amp;gt;{&apos;item&apos;} eq $item) {
+
+                if ($it-&amp;gt;{&apos;giveafter&apos;}) {
+                    $cart_bonus_start = $it-&amp;gt;{&apos;giveafter&apos;} if ! defined $cart_bonus_start || $it-&amp;gt;{&apos;giveafter&apos;} &amp;lt; $cart_bonus_start;
+                    next;
+                }
+
+                # no giveafter time, applies immediately
+                $cart_bonus_start = 0;
+                next;
+            }
+        }
+
+        # immediately applying paid account == we&apos;re in the clear
+        # - note that undef == 0 returns true since undef gets converted to numeric
+        #   context (0) before the comparison is done, blah perl
+        return 1 if defined $cart_paid_start &amp;&amp; $cart_paid_start == 0;
+        return 1 if defined $cart_bonus_start &amp;&amp; defined $cart_paid_start &amp;&amp;
+                    $cart_bonus_start &amp;gt;= $cart_paid_start;
+    }
+
+    # is the specified userid a permanent account?  if so there&apos;s a problem
+    $u = LJ::load_userid($userid, &quot;force&quot;);
+    return undef if !$u || $u-&amp;gt;in_class(&apos;perm&apos;);
+
+    # can be applied if they have a currently unexpired paid account
+    my $dbh = LJ::get_db_writer();
+    my $paiduntil = $dbh-&amp;gt;selectrow_array(&quot;SELECT UNIX_TIMESTAMP(paiduntil) FROM paiduser WHERE userid=? AND paiduntil&amp;gt;NOW()&quot;,
+                                          undef, $userid);
+
+    # at this point we know that paid time in the cart doesn&apos;t immediately
+    # exonerate the bonus feature, because we would have returned already
+    return undef if !$paiduntil || $paiduntil &amp;lt; $cart_bonus_start;
+
+    # everything checked out
+    return 1;
+}
+
+# upgrade or extend the length of a bonus item
+# qty - 0..98: number of months to add
+#       99:    permanent account (historically)
+#       100+:  exact unixtime when item should expire
+sub apply_bonus_item {
+    my ($u, $item, $subitem, $qty, $payid) = @_;
+
+    # allow u/payitem objects passed optionally
+    my $userid = LJ::want_userid($u);
+    if (ref $item) {
+        $subitem = $item-&amp;gt;{&apos;subitem&apos;};
+        $qty = $item-&amp;gt;{&apos;qty&apos;};
+        $payid = $item-&amp;gt;{&apos;payid&apos;};
+        $item = $item-&amp;gt;{&apos;item&apos;};
+    }
+
+    # if $qty is &amp;gt; 100, then we assume it is a unixtime of when
+    # their bonus item should expire
+    my $now = time();
+    return undef if $qty &amp;gt;= 100 &amp;&amp; $qty &amp;lt; $now;
+
+    my ($months, $exact_time);
+    $months     = $qty if $qty &amp;lt; 100;
+    $exact_time = $qty if $qty &amp;gt;= $now;
+
+    # userid and item are required regardless of bonus feature type
+    return undef unless $userid &amp;&amp; $item;
+
+    my $dbh = LJ::get_db_writer()
+        or return undef;
+
+    # does an existing paidexp row exist?
+    my $exp = $dbh-&amp;gt;selectrow_hashref(&quot;SELECT userid, item, size, expdate, daysleft, &quot; .
+                                      &quot;UNIX_TIMESTAMP(expdate) AS &apos;exptime&apos;, &quot; .
+                                      &quot;(expdate &amp;gt; NOW()) AS &apos;unexpired&apos; &quot; .
+                                      &quot;FROM paidexp WHERE userid=? AND item=?&quot;,
+                                      undef, $userid, $item);
+
+    # if no row in database, fill in $exp with good values
+    $exp ||= {
+        &apos;userid&apos; =&amp;gt; $userid,
+        &apos;item&apos; =&amp;gt; $item,
+        &apos;size&apos; =&amp;gt; 0,
+        &apos;expdate&apos; =&amp;gt; undef,
+        &apos;daysleft&apos; =&amp;gt; 0,
+        &apos;exptime&apos; =&amp;gt; 0,
+        &apos;unexpired&apos; =&amp;gt; 0,
+    };
+
+    my $new_size = $exp-&amp;gt;{&apos;size&apos;};
+
+    # activate cap if necessary
+    if (my $cap = $LJ::Pay::bonus{$item}-&amp;gt;{&apos;cap&apos;}) {
+        $u = LJ::modify_caps($userid, [$cap], [])
+            or return undef;
+    }
+
+    # actions for &apos;sized&apos; bonus feature type
+    # -- need to check that account is still in size/exp state it was in
+    #    when this item was purchased so people can&apos;t be comp&apos;d more than
+    #    once for existing paid time on upgrades
+
+    my $sized_upgrade = 0;
+
+    if (LJ::Pay::is_bonus($item, &apos;sized&apos;)) {
+        return undef unless $subitem;
+
+        # make sure exp/size signature in subitem still matches
+        my ($it_size, $old_exptime, $old_size) = split(&quot;-&quot;, $subitem);
+
+        # only do extra checks if old_exptime and old_size were provided for our pleasure
+        if (defined $old_exptime &amp;&amp; defined $old_size) {
+
+            # if a payid is passed, then first check to make sure that no other payitems
+            # in this cart have been applied, altering the exp/size signature and making
+            # this check return false-positives
+
+            unless ($payid &amp;&amp;
+                    $dbh-&amp;gt;selectrow_array(&quot;SELECT COUNT(*) FROM payitems &quot; .
+                                          &quot;WHERE payid=? AND item=? AND subitem=? AND status=&apos;done&apos;&quot;,
+                                          undef, $payid, $item, $subitem))
+            {
+
+                # zero-fill
+                $old_exptime ||= 0;
+                $old_size ||= 0;
+
+                # check for exptime/size mismatch, now that we know it&apos;s necessary
+                unless ($old_exptime == $exp-&amp;gt;{&apos;exptime&apos;} &amp;&amp; $old_size == $exp-&amp;gt;{&apos;size&apos;}) {
+
+                    # all bonus items of this type have the same size and exptime/oldsize signature
+                    # by the rules applied to them when they entered the cart.
+                    #
+                    # so if one item fails, we go ahead and mark them all as having failed.
+                    # the caller (pay.pl) will have to be smart enough to know to not try to process
+                    # subsequent items of the failed bonus type
+
+                    LJ::statushistory_add($userid, undef, &apos;pay_modify&apos;,
+                                          &quot;ERROR: cannot apply bonus feature: $item, &quot; .
+                                          &quot;${old_exptime}x${old_size} != $exp-&amp;gt;{&apos;exptime&apos;}x$exp-&amp;gt;{&apos;size&apos;}&quot;);
+
+                      $dbh-&amp;gt;do(&quot;UPDATE payitems SET status=&apos;done&apos; WHERE payid=? AND item=? AND subitem=?&quot;,
+                               undef, $payid, $item, $subitem);
+
+                      return undef;
+                  }
+            }
+
+            # means that we are upgrading a sized bonus item, so the time added should start
+            # from now, not the current expdate
+            $sized_upgrade = 1 unless $old_size == $it_size;
+
+        # no old_exptime or old_size passed -- recbill case, etc
+        } else {
+
+            # it is a sized upgrade if the amount currently applied account (new_size, from $exp)
+            # is not equal to the size being passed from the caller (it_size)
+            $sized_upgrade = 1 unless $new_size == $it_size;
+        }
+
+        # could either be upgrade or extension, but either way we adopt the item&apos;s size
+        $new_size = $it_size;
+    }
+
+    # insert a new row, or add time to old one
+    # - this code somewhat duplicates functionality from LJ::Pay::activate_frozen_bonus
+    #   but we need to extend the expdate by $months months anyway, so we&apos;ll just do the
+    #   daysleft activation here as well, avoiding some queries
+    {
+        # expdate calculation is tricky
+        # [(expdate || NOW()) + INTERVAL $months MONTH] + INTERVAL $daysleft DAY
+
+        # expiration extends off current expdate if there&apos;s a currently unexpired item of
+        # the same size.  otherwise it&apos;s an upgrade and starts from NOW()
+        my $expdate;
+
+        # month interval was specified
+        if ($months) {
+            $expdate = $exp-&amp;gt;{&apos;unexpired&apos;} &amp;&amp; ! $sized_upgrade
+                ? $dbh-&amp;gt;quote($exp-&amp;gt;{&apos;expdate&apos;}) : &quot;NOW()&quot;;
+
+            my $qqty = $dbh-&amp;gt;quote($months || 0);
+            $expdate = &quot;($expdate + INTERVAL $qqty MONTH)&quot;;
+
+        # exact unix timestamp of expiration was specified
+        } elsif ($exact_time) {
+            $expdate = &quot;FROM_UNIXTIME($exact_time)&quot;;
+
+        # shouldn&apos;t get here
+        } else {
+            return undef;
+        }
+
+        if ($exp-&amp;gt;{&apos;daysleft&apos;}) {
+            my $qdaysleft = $dbh-&amp;gt;quote($exp-&amp;gt;{&apos;daysleft&apos;});
+            $expdate = &quot;($expdate + INTERVAL $qdaysleft DAY)&quot;;
+        }
+
+        # update / insert paidexp row
+        $dbh-&amp;gt;do(&quot;REPLACE INTO paidexp (userid, item, size, expdate, daysleft) &quot; .
+                 &quot;VALUES (?, ?, ?, $expdate, 0)&quot;, undef, $userid, $item, $new_size);
+        return undef if $dbh-&amp;gt;err;
+    }
+
+    # call any application hooks for this bonus feature
+    my $apply_hook = $LJ::Pay::bonus{$item}-&amp;gt;{&apos;apply_hook&apos;};
+    if ($apply_hook &amp;&amp; ref $apply_hook eq &apos;CODE&apos;) {
+        # apply_hook needs a real $u object
+        $u = ref $u ? $u : LJ::load_userid($u);
+        $apply_hook-&amp;gt;($u, $item);
+    }
+
+    # log this bonus feature activation
+    {
+        my $msg = &quot;adding bonus feature: item=$item; &quot;;
+        if (LJ::Pay::is_bonus($item, &apos;sized&apos;)) {
+            $msg .= &quot;size=$exp-&amp;gt;{&apos;size&apos;}&quot;;
+            $msg .= &quot;=&amp;gt;$new_size&quot; if $exp-&amp;gt;{&apos;size&apos;} != $new_size;
+            $msg .= &quot;; &quot;;
+        }
+        $msg .= &quot;old_expdate=$exp-&amp;gt;{&apos;expdate&apos;}; &quot;;
+        $msg .= &quot;applying $months months&quot; if $months;
+        $msg .= &quot;extending to &quot; . LJ::mysql_time($exact_time) if $exact_time;
+        $msg .= &quot;, $exp-&amp;gt;{&apos;daysleft&apos;} existing days&quot;;
+
+        LJ::statushistory_add($userid, undef, &apos;pay_modify&apos;, $msg);
+    }
+
+    return 1;
+}
+
+sub expire_bonus {
+    my ($u, $item, $force) = @_;
+
+    # allow u/payitem objects passed optionally
+    my $userid = LJ::want_userid($u);
+    $item = $item-&amp;gt;{&apos;item&apos;} if ref $item;
+    return undef unless $userid;
+
+    my $dbh = LJ::get_db_writer();
+    my $sql = &quot;SELECT item FROM paidexp WHERE userid=?&quot;;
+
+    # we can either operate on one given item or all items for a user
+    $sql .= (&quot; AND item=&quot; . $dbh-&amp;gt;quote($item)) if $item;
+
+    # hard-validate constraints on the paidexp table in here
+    # - this is probably done by the caller too, but outside of a lock
+
+    unless ($force) {
+        $sql .= &quot;AND (daysleft=0 OR daysleft IS NULL) &quot;;
+        $sql .= &quot;AND expdate &amp;lt; NOW() AND expdate &amp;gt; &apos;0000-00-00&apos;&quot;;
+    }
+
+    my $sth = $dbh-&amp;gt;prepare($sql);
+    $sth-&amp;gt;execute($userid);
+
+    my @activated = ();
+    while (my ($item) = $sth-&amp;gt;fetchrow_array) {
+        next unless LJ::Pay::is_bonus($item);
+
+        # remove cap if there&apos;s one associated with this bonus item
+        if (my $cap = $LJ::Pay::bonus{$item}-&amp;gt;{&apos;cap&apos;}) {
+            LJ::modify_caps($userid, [], [$cap])
+                or return undef;
+        }
+
+        # remove paidexp row
+        $dbh-&amp;gt;do(&quot;DELETE FROM paidexp WHERE userid=? AND item=?&quot;, undef, $userid, $item);
+
+        # log this bonus feature expiration
+        LJ::statushistory_add($u, undef, &apos;pay_modify&apos;, &quot;expiring bonus feature: $item&quot;);
+    }
+
+    return 1;
+}
+
+sub transfer_bonus {
+    my ($from, $to, $item) = @_;
+
+    # add on any frozen time to the current expiration date
+    activate_frozen_bonus($from, $item);
+
+    my $from_exp = get_bonus_dim($from, $item);
+    my $to_exp = get_bonus_dim($to, $item) || time();
+
+    my $add_secs = $from_exp - time();
+    return 0 unless $add_secs &amp;gt; 0;
+
+    my $new_exp = $to_exp + $add_secs;
+
+    apply_bonus_item($to, $item, &apos;&apos;, $new_exp);
+    expire_bonus($from, $item, &quot;force&quot;);
+
+    return $add_secs;
+}
+
+# activates frozen bonus features
+# - returns array of hashrefs: { item =&amp;gt; { itemname, size, days_activated }
+sub activate_frozen_bonus {
+    my ($u, $item) = @_; # item is optional
+
+    # allow u/payitem objects passed optionally
+    my $userid = LJ::want_userid($u);
+    $item = $item-&amp;gt;{&apos;item&apos;} if ref $item;
+    return undef unless $userid;
+
+    my $dbh = LJ::get_db_writer();
+
+    # we can either operate on one given item or all items for a user
+    my $itemand = $item ? (&quot; AND item=&quot; . $dbh-&amp;gt;quote($item)) : &apos;&apos;;
+
+    # see if there is existing time
+    my $sth = $dbh-&amp;gt;prepare(&quot;SELECT item, size, expdate, daysleft, (expdate &amp;gt; NOW()) AS &apos;unexpired&apos; &quot; .
+                            &quot;FROM paidexp WHERE daysleft&amp;gt;0 AND userid=?$itemand&quot;);
+    $sth-&amp;gt;execute($userid);
+    my @activated = ();
+    while (my ($item, $size, $expdate, $daysleft, $unexpired) = $sth-&amp;gt;fetchrow_array) {
+        next unless LJ::Pay::is_bonus($item);
+
+        # it would generally suffice to set expdate to NOW() + INTERVAL daysleft DAY, but to be more
+        # robust we want to handle the case where there are daysleft in the db, but the item isn&apos;t
+        # expired yet
+        my $base = $unexpired ? $dbh-&amp;gt;quote($expdate) : &quot;NOW()&quot;;
+
+        # update database if we found some (need select above to fetch daysleft)
+        $dbh-&amp;gt;do(&quot;UPDATE paidexp SET expdate=($base + INTERVAL ? DAY), daysleft=0 &quot; .
+                 &quot;WHERE userid=? AND item=?&quot;, undef, $daysleft, $userid, $item);
+        return undef if $dbh-&amp;gt;err;
+
+        # reactivate caps if necessary
+        if (my $cap = $LJ::Pay::bonus{$item}-&amp;gt;{&apos;cap&apos;}) {
+            LJ::modify_caps($userid, [$cap], [])
+                or return undef;
+        }
+
+        # log this bonus feature activation
+        LJ::statushistory_add($userid, undef, &apos;pay_modify&apos;,
+                              &quot;adding bonus feature: item=$item; old_expdate=$expdate; &quot; .
+                              &quot;applying $daysleft existing days&quot;);
+
+        push @activated, { &apos;item&apos; =&amp;gt; $item, &apos;size&apos; =&amp;gt; $size, &apos;daysleft&apos; =&amp;gt; $daysleft };
+    }
+
+    return @activated;
+}
+
+# deactivates frozen bonus features
+# - returns array of hashrefs: { item, size, daysleft frozen }
+sub freeze_bonus {
+    my ($u, $item) = @_; # item is optional
+
+    # allow u/payitem objects passed optionally
+    my $userid = LJ::want_userid($u);
+    $item = $item-&amp;gt;{&apos;item&apos;} if ref $item;
+    return undef unless $userid;
+
+    my $dbh = LJ::get_db_writer();
+
+    # we can either operate on one given item or all items for a user
+    my $itemand = $item ? (&quot; AND item=&quot; . $dbh-&amp;gt;quote($item)) : &quot;&quot;;
+
+    # see if there is existing time
+    my $sth = $dbh-&amp;gt;prepare(&quot;SELECT item, size, (TO_DAYS(expdate)-TO_DAYS(NOW())+daysleft) AS &apos;new_daysleft&apos; &quot; .
+                            &quot;FROM paidexp WHERE expdate&amp;gt;NOW() AND userid=?$itemand&quot;);
+    $sth-&amp;gt;execute($userid);
+    my @deactivated = ();
+    while (my ($item, $size, $new_daysleft) = $sth-&amp;gt;fetchrow_array) {
+
+        # this shouldn&apos;t ever get triggered
+        next unless LJ::Pay::is_bonus($item);
+
+        # remove cap (if necessary) and run applicable hooks
+        if (my $cap = $LJ::Pay::bonus{$item}-&amp;gt;{&apos;cap&apos;}) {
+            LJ::modify_caps($userid, [], [$cap])
+                or return 0;
+        }
+
+        # set expdate to now and save current time in daysleft
+        # - to be robust, handle the case where there are currently daysleft but the expdate&amp;gt;NOW(),
+        #   even though it technically shouldn&apos;t happen.
+        if ($new_daysleft) {
+            $dbh-&amp;gt;do(&quot;UPDATE paidexp SET daysleft=?, expdate=NOW() &quot; .
+                     &quot;WHERE userid=? AND item=?&quot;, undef, $new_daysleft, $userid, $item);
+
+        # if daysleft ended up being 0 above, delete the row
+        } else {
+            $dbh-&amp;gt;do(&quot;DELETE FROM paidexp WHERE userid=? AND item=? AND (daysleft=0 OR daysleft IS NULL)&quot;,
+                     undef, $userid, $item);
+        }
+
+        # log this bonus feature expiration
+        LJ::statushistory_add($u, undef, &apos;pay_modify&apos;,
+                              &quot;deactivating bonus feature due to paid account expiration: item=$item; &quot;.
+                              &quot;saving $new_daysleft extra days&quot;);
+
+        # return a list of deactivated rows
+        push @deactivated, { &apos;item&apos; =&amp;gt; $item, &apos;size&apos; =&amp;gt; $size, &apos;daysleft&apos; =&amp;gt; $new_daysleft };
+    }
+
+    return @deactivated;
+}
+
+sub get_bool_bonus_price {
+    my ($item, $qty, $is_rec) = @_;
+
+    # allow passing of an $it hash
+    if (ref $item) {
+        $qty = $item-&amp;gt;{&apos;qty&apos;};
+        $item = $item-&amp;gt;{&apos;item&apos;};
+    }
+
+    return undef unless
+        is_valid_bool_bonus($item, $qty, $is_rec);
+
+    return $LJ::Pay::Payment::PayItem::Addon::bonus{$item}-&amp;gt;{items}-&amp;gt;{$qty}-&amp;gt;{$is_rec ? &apos;amount_rec&apos; : &apos;amount&apos;};
+}
+
+sub is_valid_bool_bonus {
+    my ($item, $qty, $is_rec) = @_;
+
+    # allow passing of an $it hash
+    if (ref $item) {
+        $qty  = $item-&amp;gt;{qty};
+        $item = $item-&amp;gt;{item};
+    }
+
+    my $itrec = $LJ::Pay::Payment::PayItem::Addon::bonus{$item};
+    return 0 unless ref $itrec;
+    return 0 unless $itrec-&amp;gt;{type} eq &apos;bool&apos;;
+    return 0 unless ref $itrec-&amp;gt;{items}-&amp;gt;{$qty};
+    return 0 unless defined $itrec-&amp;gt;{items}-&amp;gt;{$qty}-&amp;gt;{$is_rec ? &apos;amount_rec&apos; : &apos;amount&apos;};
+    return 1;
+}
+
+sub is_valid_sized_bonus {
+    my ($item, $size, $qty, $is_rec) = @_;
+
+    # allow passing of an $it hash
+    if (ref $item) {
+        $qty  = $item-&amp;gt;{qty};
+        $item = $item-&amp;gt;{item};
+        $size = $item-&amp;gt;{size};
+    }
+
+    my $itrec = $LJ::Pay::Payment::PayItem::Addon::bonus{$item};
+    return 0 unless ref $itrec; # should be hash
+    return 0 unless $itrec-&amp;gt;{type} eq &apos;sized&apos;;
+    return 0 unless ref $itrec-&amp;gt;{items}-&amp;gt;{$size};
+    return 0 unless ref $itrec-&amp;gt;{items}-&amp;gt;{$size}-&amp;gt;{qty}-&amp;gt;{$qty};
+    return 0 unless defined $itrec-&amp;gt;{items}-&amp;gt;{$size}-&amp;gt;{qty}-&amp;gt;{$qty}-&amp;gt;{$is_rec ? &apos;amount_rec&apos; : &apos;amount&apos;};
+    return 1;
+}
+
+sub get_sized_bonus_price {
+    my ($u, $cartobj, $item, $size, $qty, $is_rec) = @_;
+
+    my $userid = LJ::want_userid($u);
+
+    # allow passing of an $it hash
+    if (ref $item) {
+        # get size from subitem
+        $size = (split(&quot;-&quot;, $item-&amp;gt;{&apos;subitem&apos;}))[0];
+        $qty = $item-&amp;gt;{&apos;qty&apos;};
+        $item = $item-&amp;gt;{&apos;item&apos;};
+    }
+
+    # easy/obvious checks
+    return undef unless $userid &amp;&amp; $size &amp;gt; 0 &amp;&amp;
+        is_valid_sized_bonus($item, $size, $qty, $is_rec);
+
+    # total price of this item with no comp
+    my $total_price = $LJ::Pay::Payment::PayItem::Addon::bonus{$item}-&amp;gt;{&apos;items&apos;}-&amp;gt;{$size}-&amp;gt;{&apos;qty&apos;}-&amp;gt;{$qty}-&amp;gt;{&apos;amount&apos;};
+
+    # no negative prices allowed
+    $total_price = 0 if $total_price &amp;lt; 0;
+
+    # if there is already an item of this size in the cart, it already received a comp, so don&apos;t do it again
+    return $total_price
+        if grep { $_-&amp;gt;{&apos;rcptid&apos;} == $userid &amp;&amp; $_-&amp;gt;{&apos;item&apos;} eq $item &amp;&amp;
+                  (split(&quot;-&quot;, $_-&amp;gt;{&apos;subitem&apos;}))[0] == $size } @{$cartobj-&amp;gt;{&apos;items&apos;}};
+
+    my $dbh = LJ::get_db_writer();
+    my $row = $dbh-&amp;gt;selectrow_hashref(&quot;SELECT TO_DAYS(expdate)-TO_DAYS(NOW()) AS &apos;curr_days&apos;, &quot; .
+                                      &quot;TO_DAYS(NOW() + INTERVAL ? MONTH)-TO_DAYS(NOW()) AS &apos;new_days&apos;, &quot; .
+                                      &quot;size AS &apos;curr_size&apos; FROM paidexp WHERE userid=? AND item=?&quot;,
+                                      undef, $qty, $userid, $item);
+    $row-&amp;gt;{&apos;new_size&apos;} = $size;
+    $row-&amp;gt;{&apos;curr_days&apos;} = 0 if $row-&amp;gt;{&apos;curr_days&apos;} &amp;lt; 0;
+
+    # if current size is what they&apos;re trying to buy or there are no current days, there is no comp&apos;ing to be done
+    return $total_price if $row-&amp;gt;{&apos;curr_size&apos;} == $row-&amp;gt;{&apos;new_size&apos;} || $row-&amp;gt;{&apos;curr_days&apos;} == 0;
+
+    # find areas of new/existing rectangles to be bought
+    my $old_area = $row-&amp;gt;{&apos;curr_size&apos;} * $row-&amp;gt;{&apos;curr_days&apos;};
+    my $new_area = $row-&amp;gt;{&apos;new_size&apos;} * $row-&amp;gt;{&apos;new_days&apos;};
+    my $rate = $old_area / ($new_area || 1);
+
+    # calculate comp&apos;d price to subtract from the total
+    my $comp_amt = $total_price * $rate;
+
+    # return final price to user.
+    my $final_price = sprintf(&quot;%.02f&quot;, $total_price - $comp_amt);
+
+    # don&apos;t let final price be &amp;lt; 0
+    $final_price = 0 if $final_price &amp;lt; 0;
+
+    return $final_price;
+}
+
+# return list of bonus items available for purchase,
+# to be plugged into LJ::html_select()
+sub bonus_item_list {
+    my ($u, $cartobj) = @_; # purchasing user
+
+    my @bool;
+    my @sized;
+    foreach my $itemname (keys %LJ::Pay::Payment::PayItem::Addon::bonus) {
+        my $bitem = $LJ::Pay::Payment::PayItem::Addon::bonus{$itemname};
+        next unless ref $bitem &amp;&amp; ref $bitem-&amp;gt;{&apos;items&apos;}; # eh?
+
+        # bool type
+        if ($bitem-&amp;gt;{&apos;type&apos;} eq &apos;bool&apos;) {
+            foreach my $qty (sort { $b &amp;lt;=&amp;gt; $a } keys %{$bitem-&amp;gt;{&apos;items&apos;}}) {
+                my $amt = $bitem-&amp;gt;{&apos;items&apos;}-&amp;gt;{$qty}-&amp;gt;{&apos;amount&apos;};
+                push @bool, (&quot;$itemname-$qty&quot;,
+                             LJ::Pay::Payment::PayItem::Addon-&amp;gt;get_product_name($itemname, undef, $qty) . &quot; (\$$amt.00 USD)&quot;);
+            }
+
+            next;
+        }
+
+        # sized type
+        if ($u &amp;&amp; $bitem-&amp;gt;{&apos;type&apos;} eq &apos;sized&apos;) {
+            foreach my $size (reverse sort { $a &amp;lt;=&amp;gt; $b } keys %{$bitem-&amp;gt;{&apos;items&apos;}}) {
+                my $sizeit = $bitem-&amp;gt;{&apos;items&apos;}-&amp;gt;{$size};
+                foreach my $qty (sort { $b &amp;lt;=&amp;gt; $a } keys %{$sizeit-&amp;gt;{&apos;qty&apos;}}) {
+
+                    # do a bunch of checks, $u probably is $remote since gifts aren&apos;t allowed
+                    next unless can_apply_sized_bonus($u, $cartobj, $itemname, $size, $qty);
+
+                    # will be interpretted as item-subitem-qty
+                    my $amt = $sizeit-&amp;gt;{&apos;qty&apos;}-&amp;gt;{$qty}-&amp;gt;{&apos;amount&apos;};
+                    my $amt_comp = get_sized_bonus_price($u, $cartobj, $itemname, $size, $qty);
+                    push @sized, (&quot;$itemname-$size-$qty&quot;,
+                                  LJ::Pay::Payment::PayItem::Addon-&amp;gt;get_product_name($itemname, $size, $qty) . &quot; (\$$amt.00 USD&quot; .
+                                  ($amt == $amt_comp ? &quot;&quot; : &quot;; to upgrade: \$$amt_comp&quot;) . &quot;)&quot;);
+                }
+            }
+
+            next;
+        }
+    }
+
+    return (@bool, @sized);
+}
+
+sub remove_bonus_item {
+    my ($it, $time) = @_;
+    return undef unless ref $it;
+    return undef unless LJ::Pay::is_bonus($it);
+
+    # infer timeqty from passed item if possible
+    $time ||= $it-&amp;gt;{qty};
+
+    # figure out the amount of time, as well
+    # as what type of units it is measured in
+    $time = ref $time ? $time : [ $time, &apos;month&apos; ];
+
+    my ($timeval, $units) = @$time;
+    return undef unless $timeval &amp;gt; 0;
+    $units = lc($units);
+    $units ||= &quot;month&quot;;
+    return undef unless $units =~ /^(?:month|day|second|epoch)$/;
+
+    my $dbh = LJ::get_db_writer()
+        or return undef;
+
+    my $sub_sql;
+    my $qtv = $dbh-&amp;gt;quote($timeval);
+    if ($units eq &apos;epoch&apos;) { # explicit expiration time
+        $sub_sql = &quot;FROM_UNIXTIME($qtv)&quot;;
+    } else {
+        $sub_sql = &quot;DATE_SUB(expdate, INTERVAL $qtv $units)&quot;;
+    }
+
+    # update paidexp
+    $dbh-&amp;gt;do(&quot;UPDATE paidexp SET expdate=$sub_sql &quot; .
+             &quot;WHERE userid=? AND item=?&quot;,
+             undef, $it-&amp;gt;{rcptid}, $it-&amp;gt;{item});
+
+    # if they&apos;re now totally out of time for this bonus feature, we need to
+    # delete their paidexp row altogether and possibly remove their cap
+
+    my $newrow = $dbh-&amp;gt;selectrow_hashref(&quot;SELECT *, (expdate&amp;gt;NOW()) AS &apos;timeleft&apos; &quot; .
+                                         &quot;FROM paidexp WHERE userid=? AND item=?&quot;,
+                                         undef, $it-&amp;gt;{rcptid}, $it-&amp;gt;{item});
+
+    unless ($newrow-&amp;gt;{timeleft}) {
+
+        # handle recurring billing modifications
+        if (LJ::Pay::RecBill-&amp;gt;is_active_recbill_user($it-&amp;gt;{rcptid})) {
+
+            # need a $u object to pass to RecBill-&amp;gt;load
+            my $rcptu = LJ::load_userid($it-&amp;gt;{rcptid})
+                or return undef;
+
+            my $rec = LJ::Pay::RecBill-&amp;gt;load( u =&amp;gt; $rcptu )
+                or return undef;
+
+            # set recflag to off, revoke any necessary promos, all
+            # those things that we&apos;d otherwise forget
+            $rec-&amp;gt;deactivate_item($it-&amp;gt;{item})
+                or return undef;
+        }
+
+        # delete empty row
+        $dbh-&amp;gt;do(&quot;DELETE FROM paidexp WHERE userid=? AND item=? AND expdate&amp;lt;NOW()&quot;,
+                 undef, $it-&amp;gt;{&apos;rcptid&apos;}, $it-&amp;gt;{&apos;item&apos;});
+
+        # update user&apos;s cap if necessary
+        my $cap = $LJ::Pay::Payment::PayItem::Addon::bonus{$it-&amp;gt;{&apos;item&apos;}}-&amp;gt;{&apos;cap&apos;};
+        LJ::modify_caps($it-&amp;gt;{&apos;rcptid&apos;}, [], [$cap]) if $cap;
+    }
+
+    # log to statushistory
+    LJ::statushistory_add($it-&amp;gt;{rcptid}, undef, &apos;revoke&apos;,
+                          LJ::Pay::product_name($it, &quot;short&quot;) . &quot;; $timeval ${units}s&quot;);
+
+    return 1;
+}
+
+
+sub get_product_name {
+    my ($class, $subitem, $qty, $short) = @_;
+    my $item = $class-&amp;gt;item;
+
+    if (item_is_bonus($item, &apos;bool&apos;)) {
+        my $bitem = $LJ::Pay::Payment::PayItem::Addon::bonus{$item};
+        return LJ::Lang::ml($bitem-&amp;gt;{&apos;name&apos;}) . ($short ? &quot;&quot; : (&quot; - &quot; . ($bitem-&amp;gt;{&apos;items&apos;}-&amp;gt;{$qty}-&amp;gt;{&apos;name&apos;} || $qty)));
+    }
+
+    if (item_is_bonus($item, &apos;sized&apos;)) {
+        my $bitem = $LJ::Pay::Payment::PayItem::Addon::bonus{$item};
+
+        my $size = (split(&quot;-&quot;, $subitem))[0];
+        my $sizeit = $bitem-&amp;gt;{&apos;items&apos;}-&amp;gt;{$size};
+        my $qtyit = $sizeit-&amp;gt;{&apos;qty&apos;}-&amp;gt;{$qty};
+
+        return ($sizeit-&amp;gt;{&apos;name&apos;} || $size) . &quot; &quot; . LJ::Lang::ml($bitem-&amp;gt;{&apos;name&apos;}) .
+            ($short ? &quot;&quot; : (&quot; - &quot; . ($sizeit-&amp;gt;{&apos;qty&apos;}-&amp;gt;{$qty}-&amp;gt;{&apos;name&apos;} || $qty)));
+    }
+
+}
+
+sub item_is_bonus { 
+    my ($item, $type) = @_;
+
+    return undef unless defined $LJ::Pay::Payment::PayItem::Addon::bonus{$item};
+    return 1 unless $type; # check was made for any type
+    return undef unless $LJ::Pay::Payment::PayItem::Addon::bonus{$item}-&amp;gt;{&apos;type&apos;} eq $type;
+    return 1; 
+}
+
+sub is_bonus { 
+    my ($self, $type) = @_;
+
+    return 1 unless $type; # check was made for any type
+    return undef unless $LJ::Pay::Payment::PayItem::Addon::bonus{$self-&amp;gt;{&apos;item&apos;}}-&amp;gt;{&apos;type&apos;} eq $type;
+    return 1; 
+}
+
+sub is_valid_cart_item {
+    my $self = shift;
+    my $cartobj = shift;
+
+    if ($self-&amp;gt;is_bonus(&apos;sized&apos;)) {
+        return undef unless can_apply_sized_bonus($self-&amp;gt;{&apos;rcptid&apos;}, $cartobj, $self-&amp;gt;{&apos;item&apos;});
+        return 1;
+    }
+
+    if ($self-&amp;gt;is_bonus(&apos;bool&apos;)) {
+        return undef unless can_apply_bool_bonus($self-&amp;gt;{&apos;rcptid&apos;}, $cartobj, $self-&amp;gt;{&apos;item&apos;});
+        return 1;
+    }
+
+    return undef; # unknown type? wrong!
+}
+
+sub render_cart_item {
+    my $self = shift;
+    my $opts = shift;
+
+    my %result; # keys in hash = columns in page: name(item), type, recipient
+
+    $result{name} = $self-&amp;gt;product_name(&apos;short&apos;);
+    $result{type} = LJ::Lang::ml(&apos;pay.account.xmonths&apos;, {&apos;num&apos; =&amp;gt; $self-&amp;gt;{&apos;qty&apos;}});
+
+    return \%result;
+}
+
+sub pay_updateaccounts_item {
+    my ($self, $payment, $buyer_u, $rcpt_u, $note_rec_change) = @_;
+
+    return (0, undef, undef) unless $rcpt_u;
+
+    # get a lock since we&apos;re about to modify their account,
+    # try again later if we can&apos;t get a lock
+    return (0, undef, undef) unless LJ::Pay::get_lock($rcpt_u);
+
+    # apply the bonus item to the recipient user&apos;s account
+    my $res = apply_bonus_item($rcpt_u, $self);
+
+    # release lock and close regardless of results of operation
+    LJ::Pay::release_lock($rcpt_u);
+
+    # if an error, log to payvars (call above also logged to statushistory) and skip the email
+    unless ($res) {
+        LJ::Pay::payvar_append($pp, &quot;error&quot;,
+                               &quot;[&quot; . LJ::mysql_time() . &quot;] unable to apply: item=$pi-&amp;gt;{&apos;item&apos;},  size=&quot; .
+                               (split(&quot;-&quot;, $pi-&amp;gt;{&apos;subitem&apos;}))[0] . &quot;, qty=$pi-&amp;gt;{&apos;qty&apos;}. invalid cart?&quot;);
+
+        # if there was a failure, all bonus items of this type were marked
+        # as failed, so we shouldn&apos;t try to process any more of them
+        #$bonus_failure{&quot;$pi-&amp;gt;{&apos;payid&apos;}-$pi-&amp;gt;{&apos;item&apos;}-$pi-&amp;gt;{&apos;subitem&apos;}&quot;}++;
+
+        return (0, undef, undef);
+    }
+
+    # note that this user&apos;s bill changed
+    $note_rec_change-&amp;gt;($rcpt_u, $payment);
+
+    # send notification email to user
+    my $name = $self-&amp;gt;product_name;
+
+    my $msg = &quot;Your $LJ::SITENAMESHORT account for user \&quot;$rcpt_u-&amp;gt;{&apos;user&apos;}\&quot; has been &quot;;
+    $msg .= &quot;credited with the following add-on:\n\n&quot;;
+    $msg .= &quot;   - $name\n\n&quot;;
+    $msg .= &quot;Your account has been updated so you can use your new feature immediately.\n\n&quot;;
+    $msg .= &quot;Take advantage of some of your paid account features:\n\n&quot;;
+    $msg .= LJ::Pay::usage_summary_text($rcpt_u);
+    $msg .= &quot;Thank you for supporting the site,\n&quot;;
+    $msg .= &quot;$LJ::SITENAMESHORT Team\n&quot;;
+
+    return (1, $name, $msg); 
+}
+
+sub get_item_base_price {
+    my ($item, $qty, $size, $is_rec, %opts) = @_;
+
+    if (LJ::Pay::is_bonus($item, &apos;bool&apos;)) {
+
+        return undef unless LJ::Pay::is_valid_bool_bonus
+            ($item, $qty, $is_rec);
+
+        return $LJ::Pay::Payment::PayItem::Addon::bonus{$item}-&amp;gt;{items}-&amp;gt;{$qty}-&amp;gt;{$is_rec ? &apos;amount_rec&apos; : &apos;amount&apos;};
+
+    } elsif (LJ::Pay::is_bonus($item, &apos;sized&apos;)) {
+        return undef unless LJ::Pay::is_valid_sized_bonus
+            ($item, $size, $qty, $is_rec);
+
+        return $LJ::Pay::Payment::PayItem::Addon::bonus{$item}-&amp;gt;{&apos;items&apos;}-&amp;gt;{$size}-&amp;gt;...
 (truncated)&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7439310.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>ssafronova</lj:poster>
  <lj:posterid>14234266</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7438403.html</guid>
  <pubDate>Fri, 17 Jul 2009 14:02:32 GMT</pubDate>
  <title>[livejournal] r15511: Pass &quot;dev server&quot; flag to JS </title>
  <link>http://community.livejournal.com/changelog/7438403.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: gariev&lt;/div&gt;Pass &quot;dev server&quot; flag to JS&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/cgi-bin/weblib.pl
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/cgi-bin/weblib.pl
===================================================================
--- trunk/cgi-bin/weblib.pl	2009-07-17 03:54:15 UTC (rev 15510)
+++ trunk/cgi-bin/weblib.pl	2009-07-17 09:13:58 UTC (rev 15511)
@@ -2109,6 +2109,7 @@
                 esn_async =&amp;gt; $esn_async,
                 );
     $site{default_copyright} = $default_copyright if LJ::is_enabled(&apos;default_copyright&apos;, $remote);
+    $site{is_dev_server} = 1 if $LJ::IS_DEV_SERVER;
 
     my $site_params = LJ::js_dumper(\%site);
     my $site_param_keys = LJ::js_dumper([keys %site]);

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7438403.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>gariev</lj:poster>
  <lj:posterid>11233912</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7435333.html</guid>
  <pubDate>Fri, 17 Jul 2009 08:28:25 GMT</pubDate>
  <title>[ljcom] r7459: refactoring shop code</title>
  <link>http://community.livejournal.com/changelog/7435333.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: ssafronova&lt;/div&gt;refactoring shop code&lt;br /&gt;&lt;pre&gt;A   branches/shop/
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7435333.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>ssafronova</lj:poster>
  <lj:posterid>14234266</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7435079.html</guid>
  <pubDate>Fri, 17 Jul 2009 08:28:09 GMT</pubDate>
  <title>[livejournal] r15509: refactoring shop code</title>
  <link>http://community.livejournal.com/changelog/7435079.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: ssafronova&lt;/div&gt;refactoring shop code&lt;br /&gt;&lt;pre&gt;A   branches/shop/
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7435079.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>ssafronova</lj:poster>
  <lj:posterid>14234266</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7433237.html</guid>
  <pubDate>Fri, 17 Jul 2009 07:51:14 GMT</pubDate>
  <title>[ljcom] r7458: New release: r51.1</title>
  <link>http://community.livejournal.com/changelog/7433237.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: jirasup&lt;/div&gt;New release: r51.1&lt;br /&gt;&lt;pre&gt;A   branches/r51.1/
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7433237.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>changelog_bot</lj:poster>
  <lj:posterid>9986173</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7433213.html</guid>
  <pubDate>Fri, 17 Jul 2009 07:51:03 GMT</pubDate>
  <title>[livejournal] r15507: New release: r51.1</title>
  <link>http://community.livejournal.com/changelog/7433213.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: jirasup&lt;/div&gt;New release: r51.1&lt;br /&gt;&lt;pre&gt;A   branches/r51.1/
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7433213.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>changelog_bot</lj:poster>
  <lj:posterid>9986173</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7432597.html</guid>
  <pubDate>Thu, 16 Jul 2009 21:23:30 GMT</pubDate>
  <title>[livejournal] r15505: updated to work properly with memcache 1...</title>
  <link>http://community.livejournal.com/changelog/7432597.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: tupshin&lt;/div&gt;updated to work properly with memcache 1.4&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/admin/memcache.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/admin/memcache.bml
===================================================================
--- trunk/htdocs/admin/memcache.bml	2009-07-16 16:05:58 UTC (rev 15504)
+++ trunk/htdocs/admin/memcache.bml	2009-07-16 16:34:51 UTC (rev 15505)
@@ -103,7 +103,7 @@
 	    }
             $ret .= sprintf(&quot; %0.02f&quot;, $t2-$t1);
 	    $ret .= &quot;&amp;lt;/td&amp;gt;&quot;;
-	    my $gb_used = ($stat{&apos;malloc&apos;}{&apos;mmapped_space&apos;} + $stat{&apos;malloc&apos;}{&apos;arena_size&apos;}) / (1024*1024*1024);
+	    my $gb_used = $stat{&apos;&apos;}{&apos;bytes&apos;} / (1024*1024*1024);
 	    my $gb_max = $stat{&apos;&apos;}{&apos;limit_maxbytes&apos;} / (1024*1024*1024);
 	    if ($gb_used &amp;gt;= $gb_max) {
 		$ret .= sprintf(&quot;&amp;lt;td align=&apos;center&apos;&amp;gt;%0.01fG&amp;lt;/td&amp;gt;&quot;, $gb_max);
@@ -111,9 +111,8 @@
 		$ret .= sprintf(&quot;&amp;lt;td&amp;gt;%0.02f/%0.01fG (%0.02f%%)&amp;lt;/td&amp;gt;&quot;, $gb_used, $gb_max, $gb_used*100/($gb_max||1));
 	    }
 
-	    my $utiliz = $stat{&apos;&apos;}{&apos;bytes&apos;} /
-		(($stat{&apos;malloc&apos;}{&apos;mmapped_space&apos;} + $stat{&apos;malloc&apos;}{&apos;arena_size&apos;}) || 1);
-	    $ret .= sprintf(&quot;&amp;lt;td&amp;gt;%0.02f%%&amp;lt;/td&amp;gt;&quot;, $utiliz*100);
+	    my $utiliz = $gb_used/$gb_max;
+    $ret .= sprintf(&quot;&amp;lt;td&amp;gt;%0.02f%%&amp;lt;/td&amp;gt;&quot;, $utiliz*100);
 	    
 	    my $up = $stat{&apos;&apos;}{&apos;uptime&apos;};
 	    my $upstring;

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7432597.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>tupshin</lj:poster>
  <lj:posterid>15287167</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7432222.html</guid>
  <pubDate>Thu, 16 Jul 2009 20:54:37 GMT</pubDate>
  <title>[livejournal] r15504: Display custom message if reports were c...</title>
  <link>http://community.livejournal.com/changelog/7432222.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: henrylyne&lt;/div&gt;Display custom message if reports were closed already.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href=&quot;http://bugs.dwscoalition.org/show_bug.cgi?id=1228&quot;&gt;http://bugs.dwscoalition.org/show_bug.cgi?id=1228&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/admin/spamreports.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/admin/spamreports.bml
===================================================================
--- trunk/htdocs/admin/spamreports.bml	2009-07-16 14:05:39 UTC (rev 15503)
+++ trunk/htdocs/admin/spamreports.bml	2009-07-16 16:05:58 UTC (rev 15504)
@@ -241,7 +241,7 @@
         $title = &quot;Close Reports&quot;;
         $body .= &quot;&amp;lt;?p [ &amp;lt;a href=\&quot;spamreports.bml\&quot;&amp;gt;&amp;lt;&amp;lt; Front Page&amp;lt;/a&amp;gt; ] $backlink p?&amp;gt;\n&quot;;
         my $s = $count == 1 ? &apos;&apos; : &apos;s&apos;;
-        $body .= &quot;Closed $count report$s.\n&quot;;
+        $body .= $count &amp;gt; 0 ? &quot;Closed $count report$s.\n&quot; : &quot;Reports were already closed.&quot;;
 
     } else {
         # standard

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7432222.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>henrylyne</lj:poster>
  <lj:posterid>8852209</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7432165.html</guid>
  <pubDate>Thu, 16 Jul 2009 18:54:19 GMT</pubDate>
  <title>[livejournal] r15503: Keep the comment text even if an error i...</title>
  <link>http://community.livejournal.com/changelog/7432165.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: henrylyne&lt;/div&gt;Keep the comment text even if an error is returned.&lt;br /&gt;Don&apos;t just return on error right away, push error on to error list.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href=&quot;http://bugs.dwscoalition.org/show_bug.cgi?id=126&quot;&gt;http://bugs.dwscoalition.org/show_bug.cgi?id=126&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/talkpost_do.bml
U   trunk/htdocs/talkpost_do.bml.text
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/talkpost_do.bml
===================================================================
--- trunk/htdocs/talkpost_do.bml	2009-07-16 13:48:18 UTC (rev 15502)
+++ trunk/htdocs/talkpost_do.bml	2009-07-16 14:05:39 UTC (rev 15503)
@@ -111,7 +111,7 @@
 
     # FIXME: this isn&apos;t entirely correct, if ecphash is present but ignored/incorrect
     # that fix would need to be done in talklib.pl
-    return &quot;&amp;lt;?h1 $ML{&apos;Error&apos;} h1?&amp;gt; $ML{&apos;error.invalidform&apos;}&quot;
+    push @errors, $ML{&apos;.error.invalidform&apos;}
         if $remote &amp;&amp; ! ($skip_form_auth || $POST{&apos;ecphash&apos;} || LJ::check_form_auth());
 
     ## preview

Modified: trunk/htdocs/talkpost_do.bml.text
===================================================================
--- trunk/htdocs/talkpost_do.bml.text	2009-07-16 13:48:18 UTC (rev 15502)
+++ trunk/htdocs/talkpost_do.bml.text	2009-07-16 14:05:39 UTC (rev 15503)
@@ -14,6 +14,8 @@
 
 .error.friendsonly=Only friends of [[user]] may post in this journal.
 
+.error.invalidform=Invalid form submission. You may have left the reply form open too long, or logged out since you opened the page. Please try posting again.
+
 .error.membersonly=Only members of [[user]] can post in this community.
 
 .error.lostcookie=Your login cookie seems to have disappeared?

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7432165.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>henrylyne</lj:poster>
  <lj:posterid>8852209</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7431834.html</guid>
  <pubDate>Thu, 16 Jul 2009 18:36:58 GMT</pubDate>
  <title>[livejournal] r15502: Fix display of tags and &apos;track this&apos; in ...</title>
  <link>http://community.livejournal.com/changelog/7431834.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: henrylyne&lt;/div&gt;Fix display of tags and &apos;track this&apos; in previews.&lt;br /&gt;&lt;br /&gt;Much thanks to &lt;a href=&quot;http://bugs.dwscoalition.org/show_bug.cgi?id=1310&quot;&gt;http://bugs.dwscoalition.org/show_bug.cgi?id=1310&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/preview/entry.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/preview/entry.bml
===================================================================
--- trunk/htdocs/preview/entry.bml	2009-07-16 13:32:10 UTC (rev 15501)
+++ trunk/htdocs/preview/entry.bml	2009-07-16 13:48:18 UTC (rev 15502)
@@ -233,11 +233,11 @@
                 &apos;screened&apos; =&amp;gt; 0,
             });
 
-        # build tag objects, faking kwid as &apos;0&apos;
+        # build tag objects, faking kwid as &apos;-1&apos;
         # * invalid tags will be stripped by is_valid_tagstring()
         my @taglist = ();
         LJ::Tags::is_valid_tagstring($POST{prop_taglist}, \@taglist);
-        @taglist = map { LJ::S2::Tag($u, 0, $_) } @taglist;
+        @taglist = map { LJ::S2::Tag($u, -1, $_) } @taglist;
 
         # format it
         my $raw_subj = $req{&apos;subject&apos;};
@@ -249,7 +249,7 @@
             &apos;security&apos; =&amp;gt; $req{&apos;security&apos;},
             &apos;allowmask&apos; =&amp;gt; $req{&apos;allowmask&apos;},
             &apos;props&apos; =&amp;gt; $req{&apos;props&apos;},
-            &apos;itemid&apos; =&amp;gt; 0,
+            &apos;itemid&apos; =&amp;gt; -1,
             &apos;comments&apos; =&amp;gt; $comments,
             &apos;journal&apos; =&amp;gt; $userlite_journal,
             &apos;poster&apos; =&amp;gt; $userlite_poster,

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7431834.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>henrylyne</lj:poster>
  <lj:posterid>8852209</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7431565.html</guid>
  <pubDate>Thu, 16 Jul 2009 18:20:49 GMT</pubDate>
  <title>[livejournal] r15501: Expire syndication memcache after 2 hour...</title>
  <link>http://community.livejournal.com/changelog/7431565.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: henrylyne&lt;/div&gt;Expire syndication memcache after 2 hours.&lt;br /&gt;Thanks to &lt;a href=&quot;http://bugs.dwscoalition.org/show_bug.cgi?id=1288&quot;&gt;http://bugs.dwscoalition.org/show_bug.cgi?id=1288&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/cgi-bin/LJ/User.pm
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/cgi-bin/LJ/User.pm
===================================================================
--- trunk/cgi-bin/LJ/User.pm	2009-07-16 10:47:33 UTC (rev 15500)
+++ trunk/cgi-bin/LJ/User.pm	2009-07-16 13:32:10 UTC (rev 15501)
@@ -242,7 +242,7 @@
         my $dbr = LJ::get_db_reader();
         return unless $dbr;
         $synd = $dbr-&amp;gt;selectrow_hashref(&quot;SELECT * FROM syndicated WHERE userid=$u-&amp;gt;{&apos;userid&apos;}&quot;);
-        LJ::MemCache::set($memkey, $synd) if $synd;
+        LJ::MemCache::set($memkey, $synd, 60 * 120) if $synd;
     }
 
     return $synd;

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7431565.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>henrylyne</lj:poster>
  <lj:posterid>8852209</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7431168.html</guid>
  <pubDate>Thu, 16 Jul 2009 15:36:14 GMT</pubDate>
  <title>[livejournal] r15500: LJLMI-93: Display messenger status in us...</title>
  <link>http://community.livejournal.com/changelog/7431168.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: pkornilov&lt;/div&gt;LJLMI-93: Display messenger status in user&apos;s profile&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/userinfo.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/userinfo.bml
===================================================================
--- trunk/htdocs/userinfo.bml	2009-07-16 09:33:20 UTC (rev 15499)
+++ trunk/htdocs/userinfo.bml	2009-07-16 10:47:33 UTC (rev 15500)
@@ -1005,7 +1005,7 @@
             my $msnname = $mangleaddress-&amp;gt;(LJ::ehtml($u-&amp;gt;{&apos;msn&apos;}));
             my $msn_alt = $ML{&apos;.im.msn&apos;};
             my $msn_status = $ML{&apos;.im.msn.status&apos;};
-            $instant_message .= &quot;&amp;lt;tr class=&apos;im_msn&apos;&amp;gt;&amp;lt;td class=&apos;im_icon&apos;&amp;gt;&amp;lt;img src=&apos;$LJ::IMGPREFIX/profile_icons/wlm.gif&apos; alt=\&quot;$msn_alt\&quot; title=\&quot;$msn_alt\&quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$msnname&amp;lt;/td&amp;gt;&amp;lt;td class=&apos;msn_status&apos;&amp;gt;&amp;lt;span class=&apos;offline&apos; title=&apos;$msn_status offline&apos;&amp;gt;$msn_status offline&amp;lt;/span&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&quot;;
+            $instant_message .= &quot;&amp;lt;tr class=&apos;im_msn&apos;&amp;gt;&amp;lt;td class=&apos;im_icon&apos;&amp;gt;&amp;lt;img src=&apos;$LJ::IMGPREFIX/profile_icons/wlm.gif&apos; alt=\&quot;$msn_alt\&quot; title=\&quot;$msn_alt\&quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$msnname&amp;lt;/td&amp;gt;&amp;lt;td class=&apos;msn_status&apos;&amp;gt;&amp;lt;span id=&apos;mlm-status&apos; class=&apos;offline&apos; title=&apos;$msn_status offline&apos;&amp;gt;$msn_status offline&amp;lt;/span&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&quot;;
         }
         if ($u-&amp;gt;{&apos;jabber&apos;}) {
             my $jabber = $mangleaddress-&amp;gt;(LJ::ehtml($u-&amp;gt;{&apos;jabber&apos;}));

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7431168.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>lusever</lj:poster>
  <lj:posterid>10627869</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7430555.html</guid>
  <pubDate>Thu, 16 Jul 2009 14:22:01 GMT</pubDate>
  <title>[livejournal] r15499: LJSUP-4584: java script error when user ...</title>
  <link>http://community.livejournal.com/changelog/7430555.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: sebua&lt;/div&gt;LJSUP-4584: java script error when user click button &quot;Login&quot;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/cgi-bin/weblib.pl
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/cgi-bin/weblib.pl
===================================================================
--- trunk/cgi-bin/weblib.pl	2009-07-16 08:50:02 UTC (rev 15498)
+++ trunk/cgi-bin/weblib.pl	2009-07-16 09:33:20 UTC (rev 15499)
@@ -3818,8 +3818,9 @@
     if (! document.getElementById) return true;
     var loginform = document.getElementById(formid);
     if (! loginform) return true;
-    if(document.getElementById(&apos;prop_current_location&apos;).value==&apos;detecting...&apos;) document.getElementById(&apos;prop_current_location&apos;).value=&apos;&apos;;
-
+    if(document.getElementById(&apos;prop_current_location&apos;)){
+        if(document.getElementById(&apos;prop_current_location&apos;).value==&apos;detecting...&apos;) document.getElementById(&apos;prop_current_location&apos;).value=&apos;&apos;;
+    }
     // Avoid accessing the password field if there is no username.
     // This works around Opera &amp;lt; 7 complaints when commenting.
     if (checkuser) {

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7430555.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>barnhouse</lj:poster>
  <lj:posterid>6890374</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7429460.html</guid>
  <pubDate>Thu, 16 Jul 2009 13:36:49 GMT</pubDate>
  <title>[livejournal] r15497: LJSUP-4580: Security bug in Notes/Alias </title>
  <link>http://community.livejournal.com/changelog/7429460.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: gariev&lt;/div&gt;LJSUP-4580: Security bug in Notes/Alias&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/cgi-bin/LJ/User.pm
U   trunk/cgi-bin/talklib.pl
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/cgi-bin/LJ/User.pm
===================================================================
--- trunk/cgi-bin/LJ/User.pm	2009-07-16 08:21:44 UTC (rev 15496)
+++ trunk/cgi-bin/LJ/User.pm	2009-07-16 08:48:07 UTC (rev 15497)
@@ -1315,8 +1315,7 @@
 
 
         my $remote = LJ::get_remote();
-        my $alias_enable = $remote &amp;&amp; $remote-&amp;gt;get_cap(&apos;paid&apos;);
-        my $alias = $alias_enable ? LJ::ehtml(LJ::ljuser_alias($u-&amp;gt;{user})) : &apos;&apos;;
+        my $alias = LJ::ehtml(LJ::ljuser_alias($u-&amp;gt;{user}) || &apos;&apos;);
   
         my $profile = $profile_url ne &apos;&apos; ? $profile_url : &quot;$LJ::SITEROOT/userinfo.bml?userid=$u-&amp;gt;{userid}&amp;amp;t=I$andfull&quot;;
         
@@ -6404,11 +6403,14 @@
 sub ljuser_alias {
     my $user = shift;
 
+    return if $LJ::DISABLED{&apos;aliases&apos;};
+
     my $remote = LJ::get_remote();
-    return undef unless $remote;
+    return unless $remote;
+    return unless $remote-&amp;gt;get_cap(&apos;aliases&apos;);
 
     my $u = LJ::load_user($user);
-    return undef unless $u;
+    return unless $u;
     
     my $prop_aliases = $remote-&amp;gt;prop(&apos;aliases&apos;);
     my $aliases = JSON::jsonToObj($prop_aliases);
@@ -6467,8 +6469,7 @@
         $url = $journal_url ne &apos;&apos; ? $journal_url : $url;
          
         my $u = LJ::get_remote();
-        my $alias_enable = $u &amp;&amp; $u-&amp;gt;get_cap(&apos;aliases&apos;);
-        my $alias = $alias_enable ? LJ::ehtml(LJ::ljuser_alias($user)) : &apos;&apos;;
+        my $alias = LJ::ehtml(LJ::ljuser_alias($user) || &apos;&apos;);
         
         my $user_html = &apos;&apos;;
         $user_html .= &quot;&amp;lt;span class=&apos;ljuser &quot;;

Modified: trunk/cgi-bin/talklib.pl
===================================================================
--- trunk/cgi-bin/talklib.pl	2009-07-16 08:21:44 UTC (rev 15496)
+++ trunk/cgi-bin/talklib.pl	2009-07-16 08:48:07 UTC (rev 15497)
@@ -2381,6 +2381,11 @@
                                  )
                 )
             {
+                ## security bug: if aliases are enabled, then e-mail recipient
+                ## may get e-mail with aliases of current remote user.
+                ## TODO: all e-mails should be sent from workers tier, not Apache
+                local $LJ::DISABLED{&apos;aliases&apos;} = 1;
+
                 $parentmailed = $paru-&amp;gt;email_raw;
                 $encoding = $paru-&amp;gt;mailencoding || &quot;UTF-8&quot;;
                 my $part;
@@ -2445,6 +2450,8 @@
         !$entryu-&amp;gt;gets_notified(journal =&amp;gt; $journalu, arg1 =&amp;gt; $ditemid, arg2 =&amp;gt; $comment-&amp;gt;{talkid})
         )
     {
+        local $LJ::DISABLED{&apos;aliases&apos;} = 1;
+        
         LJ::load_user_props($entryu, &apos;mailencoding&apos;);
         my $part;
 
@@ -2519,6 +2526,8 @@
         &amp;&amp; !$u-&amp;gt;gets_notified(journal =&amp;gt; $journalu, arg1 =&amp;gt; $ditemid, arg2 =&amp;gt; $comment-&amp;gt;{talkid})) {
         my $part;
 
+        local $LJ::DISABLED{&apos;aliases&apos;} = 1;
+
         # Now we going to send email to &apos;$u&apos;.
         $lang = $u-&amp;gt;prop(&apos;browselang&apos;);
         $encoding = $u-&amp;gt;mailencoding || &quot;UTF-8&quot;;

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7429460.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>gariev</lj:poster>
  <lj:posterid>11233912</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7428865.html</guid>
  <pubDate>Thu, 16 Jul 2009 13:10:26 GMT</pubDate>
  <title>[livejournal] r15496: LJLMI-93 Display messenger status in use...</title>
  <link>http://community.livejournal.com/changelog/7428865.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: nefimenko&lt;/div&gt;LJLMI-93 Display messenger status in user&apos;s profile&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/stc/profile.css
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/stc/profile.css
===================================================================
--- trunk/htdocs/stc/profile.css	2009-07-16 03:58:27 UTC (rev 15495)
+++ trunk/htdocs/stc/profile.css	2009-07-16 08:21:44 UTC (rev 15496)
@@ -262,6 +262,7 @@
 		width: 16px;
 		height: 16px;
 		text-indent: -2000px;
+		margin: 0 auto;
     }
 	* HTML .external_services td.msn_status SPAN {
 		background: url(&apos;/img/profile_icons/mlm-icons.gif&apos;) no-repeat 0 -6px;

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7428865.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>rithm_of_samba</lj:poster>
  <lj:posterid>12052678</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7428440.html</guid>
  <pubDate>Thu, 16 Jul 2009 08:47:12 GMT</pubDate>
  <title>[livejournal] r15495: LJSUP-4581 rename column &quot;User alias&quot; to...</title>
  <link>http://community.livejournal.com/changelog/7428440.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: nefimenko&lt;/div&gt;LJSUP-4581 rename column &quot;User alias&quot; to &quot;Notes&quot;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/manage/banusers.bml.text
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/manage/banusers.bml.text
===================================================================
--- trunk/htdocs/manage/banusers.bml.text	2009-07-15 16:02:24 UTC (rev 15494)
+++ trunk/htdocs/manage/banusers.bml.text	2009-07-16 03:58:27 UTC (rev 15495)
@@ -12,7 +12,7 @@
 
 .intro.ban.self=To ban users from commenting in your journal, type in their usernames below. Separate multiple usernames with commas.
 
-.intro.unban.alias=User alias
+.intro.unban.alias=Notes
 
 .intro.unban.comm=You have the following users banned from commenting in your community. Select which ones you&apos;d like to unban.
 

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7428440.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>rithm_of_samba</lj:poster>
  <lj:posterid>12052678</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7427922.html</guid>
  <pubDate>Thu, 16 Jul 2009 00:48:49 GMT</pubDate>
  <title>[ljcom] r7456: Fix display of UK Block.</title>
  <link>http://community.livejournal.com/changelog/7427922.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: henrylyne&lt;/div&gt;Fix display of UK Block.&lt;br /&gt;Note: Will ask someone to remove this logic from index.bml.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/index.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/index.bml
===================================================================
--- trunk/htdocs/index.bml	2009-07-15 09:42:12 UTC (rev 7455)
+++ trunk/htdocs/index.bml	2009-07-15 20:00:04 UTC (rev 7456)
@@ -27,7 +27,9 @@
     my $ret = &quot;&quot;;
 
     my $country = LJ::GeoLocation-&amp;gt;get_country_info_by_ip;
-    my $uk_block = ($country eq &apos;UK&apos; || $country eq &apos;GB&apos;) ? 
+    my $uk_block = (!$remote ||
+        ($remote &amp;&amp; ($remote-&amp;gt;in_class(&apos;plus&apos;) || $remote-&amp;gt;in_class(&apos;force_ads&apos;))
+         &amp;&amp; ($country eq &apos;UK&apos; || $country eq &apos;GB&apos;) )) ?
         LJ::Widget::ExtBlock-&amp;gt;render(id=&amp;gt;&apos;homepage.uk&apos;) : &apos;&apos;;
  
     ### Logged-in Homepage ###

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7427922.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>henrylyne</lj:poster>
  <lj:posterid>8852209</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7427745.html</guid>
  <pubDate>Wed, 15 Jul 2009 20:51:11 GMT</pubDate>
  <title>[livejournal] r15494: Add link to Moderation page. </title>
  <link>http://community.livejournal.com/changelog/7427745.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: henrylyne&lt;/div&gt;Add link to Moderation page.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/admin/browse/index.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/admin/browse/index.bml
===================================================================
--- trunk/htdocs/admin/browse/index.bml	2009-07-15 09:39:42 UTC (rev 15493)
+++ trunk/htdocs/admin/browse/index.bml	2009-07-15 16:02:24 UTC (rev 15494)
@@ -18,6 +18,8 @@
     my $ret = &quot;&quot;;
 
     $ret .= &quot;&amp;lt;h2&amp;gt;Manage Communities&amp;lt;/h2&amp;gt;&amp;lt;blockquote&amp;gt;&quot;;
+    $ret .= &quot;&amp;lt;p&amp;gt;&amp;lt;a href=&apos;./add_community.bml&apos;&amp;gt;Moderate Community Submissions&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&quot;;
+
     $ret .= &quot;&amp;lt;p&amp;gt;&amp;lt;a href=&apos;./add_community.bml&apos;&amp;gt;Add Community to Category&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&quot;;
     $ret .= &quot;&amp;lt;p&amp;gt;&amp;lt;a href=&apos;./remove_community.bml&apos;&amp;gt;Remove Community from Category&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&quot;;
     $ret .= &quot;&amp;lt;/blockquote&amp;gt;&quot;;

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7427745.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>henrylyne</lj:poster>
  <lj:posterid>8852209</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7425852.html</guid>
  <pubDate>Wed, 15 Jul 2009 12:25:32 GMT</pubDate>
  <title>[livejournal] r15492: LJLMI-93 Display messenger status in use...</title>
  <link>http://community.livejournal.com/changelog/7425852.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: nefimenko&lt;/div&gt;LJLMI-93 Display messenger status in user&apos;s profile&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/userinfo.bml
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/userinfo.bml
===================================================================
--- trunk/htdocs/userinfo.bml	2009-07-15 07:10:50 UTC (rev 15491)
+++ trunk/htdocs/userinfo.bml	2009-07-15 07:36:43 UTC (rev 15492)
@@ -1005,8 +1005,7 @@
             my $msnname = $mangleaddress-&amp;gt;(LJ::ehtml($u-&amp;gt;{&apos;msn&apos;}));
             my $msn_alt = $ML{&apos;.im.msn&apos;};
             my $msn_status = $ML{&apos;.im.msn.status&apos;};
-            $instant_message .= &quot;&amp;lt;tr class=&apos;im_msn&apos;&amp;gt;&amp;lt;td class=&apos;im_icon&apos;&amp;gt;&amp;lt;img src=&apos;$LJ::IMGPREFIX/profile_icons/wlm.gif&apos; alt=\&quot;$msn_alt\&quot; title=\&quot;$msn_alt\&quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td colspan=&apos;2&apos;&amp;gt;$msnname&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&quot;;
-        ### $instant_message .= &quot;&amp;lt;tr class=&apos;im_msn&apos;&amp;gt;&amp;lt;td class=&apos;im_icon&apos;&amp;gt;&amp;lt;img src=&apos;$LJ::IMGPREFIX/profile_icons/wlm.gif&apos; alt=\&quot;$msn_alt\&quot; title=\&quot;$msn_alt\&quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$msnname&amp;lt;/td&amp;gt;&amp;lt;td class=&apos;msn_status&apos;&amp;gt;&amp;lt;span class=&apos;offline&apos; title=&apos;$msn_status offline&apos;&amp;gt;$msn_status offline&amp;lt;/span&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&quot;;
+            $instant_message .= &quot;&amp;lt;tr class=&apos;im_msn&apos;&amp;gt;&amp;lt;td class=&apos;im_icon&apos;&amp;gt;&amp;lt;img src=&apos;$LJ::IMGPREFIX/profile_icons/wlm.gif&apos; alt=\&quot;$msn_alt\&quot; title=\&quot;$msn_alt\&quot; /&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$msnname&amp;lt;/td&amp;gt;&amp;lt;td class=&apos;msn_status&apos;&amp;gt;&amp;lt;span class=&apos;offline&apos; title=&apos;$msn_status offline&apos;&amp;gt;$msn_status offline&amp;lt;/span&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;\n&quot;;
         }
         if ($u-&amp;gt;{&apos;jabber&apos;}) {
             my $jabber = $mangleaddress-&amp;gt;(LJ::ehtml($u-&amp;gt;{&apos;jabber&apos;}));

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7425852.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>rithm_of_samba</lj:poster>
  <lj:posterid>12052678</lj:posterid>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7425758.html</guid>
  <pubDate>Wed, 15 Jul 2009 12:00:02 GMT</pubDate>
  <title>[ljcom] r7454: LJSUP-4577 Minor text changes </title>
  <link>http://community.livejournal.com/changelog/7425758.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: nefimenko&lt;/div&gt;LJSUP-4577 Minor text changes&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/bin/upgrading/en_LJ.dat
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/bin/upgrading/en_LJ.dat
===================================================================
--- trunk/bin/upgrading/en_LJ.dat	2009-07-15 06:13:38 UTC (rev 7453)
+++ trunk/bin/upgrading/en_LJ.dat	2009-07-15 07:11:13 UTC (rev 7454)
@@ -5303,7 +5303,7 @@
 
 widget.addalias.too.long=You&apos;ve reached the maximum number of the notes.
 
-widget.addalias.display.helper=Visit the &amp;lt;a [[aopts]]&amp;gt;Manage notes&amp;lt;/a&amp;gt; page to manage all your user notes
+widget.addalias.display.helper=Visit the &amp;lt;a [[aopts]]&amp;gt;Manage Notes&amp;lt;/a&amp;gt; page to manage all your user notes.
 
 widget.alias.setalias=Set note for
 

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7425758.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>rithm_of_samba</lj:poster>
  <lj:posterid>12052678</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7425341.html</guid>
  <pubDate>Wed, 15 Jul 2009 11:59:40 GMT</pubDate>
  <title>[livejournal] r15491: LJSUP-4577 Minor text changes </title>
  <link>http://community.livejournal.com/changelog/7425341.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: nefimenko&lt;/div&gt;LJSUP-4577 Minor text changes&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/htdocs/manage/notes.bml.text
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/htdocs/manage/notes.bml.text
===================================================================
--- trunk/htdocs/manage/notes.bml.text	2009-07-15 05:34:16 UTC (rev 15490)
+++ trunk/htdocs/manage/notes.bml.text	2009-07-15 07:10:50 UTC (rev 15491)
@@ -6,7 +6,7 @@
 
 .alias.header.username=Username
 
-.alias.header.alias=Note
+.alias.header.alias=Notes
 
 .alias.header.newalias=New note:
 

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7425341.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>rithm_of_samba</lj:poster>
  <lj:posterid>12052678</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7424554.html</guid>
  <pubDate>Wed, 15 Jul 2009 11:02:28 GMT</pubDate>
  <title>[ljcom] r7453: LJLMI-98: WL problem&apos;s alert</title>
  <link>http://community.livejournal.com/changelog/7424554.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: mchernyshev&lt;/div&gt;LJLMI-98: WL problem&apos;s alert&lt;br /&gt; added multilanguage vars about and signin_error.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/bin/upgrading/en_LJ.dat
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/bin/upgrading/en_LJ.dat
===================================================================
--- trunk/bin/upgrading/en_LJ.dat	2009-07-15 05:34:40 UTC (rev 7452)
+++ trunk/bin/upgrading/en_LJ.dat	2009-07-15 06:13:38 UTC (rev 7453)
@@ -2771,12 +2771,16 @@
 
 msn.webiface.context.remove=Delete
 
+msn.webiface.about=About
+
 msn.webiface.add_contact=Add [[start_link]]contact[[end_link]]
 
 msn.webiface.add=Add
 
 msn.webiface.signin=Sign in to LJ Messenger
 
+msn.webiface.signin_error=Error ([[code]]). Try again.
+
 msn.webiface.loading=Loading
 
 msn.webiface.min_title=LJ Messenger

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7424554.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>slartyblartfast</lj:poster>
  <lj:posterid>10808924</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://community.livejournal.com/changelog/7424215.html</guid>
  <pubDate>Wed, 15 Jul 2009 10:23:30 GMT</pubDate>
  <title>[ljcom] r7452: LJSUP-4577 Minor text changes </title>
  <link>http://community.livejournal.com/changelog/7424215.html</link>
  <description>&lt;div style=&quot;font-size: 9pt; margin-bottom: 1em&quot;&gt;Committer: nefimenko&lt;/div&gt;LJSUP-4577 Minor text changes&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;U   trunk/bin/upgrading/en_LJ.dat
&lt;/pre&gt;&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;&lt;pre&gt;Modified: trunk/bin/upgrading/en_LJ.dat
===================================================================
--- trunk/bin/upgrading/en_LJ.dat	2009-07-13 10:16:32 UTC (rev 7451)
+++ trunk/bin/upgrading/en_LJ.dat	2009-07-15 05:34:40 UTC (rev 7452)
@@ -5299,7 +5299,7 @@
 
 widget.addalias.too.long=You&apos;ve reached the maximum number of the notes.
 
-widget.addalias.display.helper=Visit &amp;lt;a [[aopts]]&amp;gt;&quot;Manage notes&quot;&amp;lt;/a&amp;gt; page to manage all your user&apos;s notes
+widget.addalias.display.helper=Visit the &amp;lt;a [[aopts]]&amp;gt;Manage notes&amp;lt;/a&amp;gt; page to manage all your user notes
 
 widget.alias.setalias=Set note for
 

&lt;/pre&gt;</description>
  <comments>http://community.livejournal.com/changelog/7424215.html</comments>
  <lj:security>public</lj:security>
  <lj:poster>rithm_of_samba</lj:poster>
  <lj:posterid>12052678</lj:posterid>
  <lj:reply-count>0</lj:reply-count>
</item>
</channel>
</rss>
