code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Local navigation for subscriptions group of pages
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Subs
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/widget.php';

/**
 * Local nav menu for subscriptions, subscribers
 *
 * @category Subs
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubGroupNav extends Menu
{
    var $user = null;

    /**
     * Construction
     *
     * @param Action $action current action, used for output
     * @param User   $user   Current user or NULL if "guest"
     */
    function __construct(Action $action=null, User $user=null)
    {
        parent::__construct($action);
        $this->user = $user;
    }

    /**
     * Show the menu
     *
     * @return void
     */
    function show()
    {
        $cur = common_current_user();
        $action = $this->action->trimmed('action');

        $this->out->elementStart('ul', array('class' => 'nav'));

        if (Event::handle('StartSubGroupNav', array($this))) {

            $this->out->menuItem(common_local_url('showstream', array('nickname' =>
                                                                      $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Profile'),
                                 (empty($profile)) ? $this->user->nickname : $profile->getBestName(),
                                 $action == 'showstream',
                                 'nav_profile');
            $this->out->menuItem(common_local_url('subscriptions',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Subscriptions'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('People %s subscribes to.'),
                                         $this->user->nickname),
                                 $action == 'subscriptions',
                                 'nav_subscriptions');
            $this->out->menuItem(common_local_url('subscribers',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Subscribers'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('People subscribed to %s.'),
                                         $this->user->nickname),
                                 $action == 'subscribers',
                                 'nav_subscribers');
            if ($cur && $cur->id == $this->user->id) {
                // Possibly site admins should be able to get in here too
                $pending = $this->countPendingSubs();
                if ($pending || $cur->subscribe_policy == User::SUBSCRIBE_POLICY_MODERATE) {
                    $this->out->menuItem(common_local_url('subqueue',
                                                          array('nickname' =>
                                                                $this->user->nickname)),
                                         // TRANS: Menu item in local navigation menu.
                                         // TRANS: %d is the number of pending subscription requests.
                                         sprintf(_m('MENU','Pending (%d)'), $pending),
                                         // TRANS: Menu item title in local navigation menu.
                                         sprintf(_('Approve pending subscription requests.'),
                                                 $this->user->nickname),
                                         $action == 'subqueueaction',
                                         'nav_subscribers');
                }
            }
            $this->out->menuItem(common_local_url('usergroups',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item in local navigation menu.
                                 _m('MENU','Groups'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('Groups %s is a member of.'),
                                         $this->user->nickname),
                                 $action == 'usergroups',
                                 'nav_usergroups');
            $this->out->menuItem(common_local_url('peopletagsubscriptions',
                                                  array('nickname' =>
                                                        $this->user->nickname)),
                                 // TRANS: Menu item title in local navigation menu.
                                 _m('MENU','Lists'),
                                 // TRANS: Menu item title in local navigation menu.
                                 // TRANS: %s is a user nickname.
                                 sprintf(_('List subscriptions by %s.'),
                                         $this->user->nickname),
                                 in_array($action, array('peopletagsbyuser', 'peopletagsubscriptions', 'peopletagsforuser')),
                                 'nav_timeline_peopletags');

            if (common_config('invite', 'enabled') && !is_null($cur) && $this->user->id === $cur->id) {
                $this->out->menuItem(common_local_url('invite'),
                                     // TRANS: Menu item in local navigation menu.
                                     _m('MENU','Invite'),
                                     // TRANS: Menu item title in local navigation menu.
                                     // TRANS: %s is the StatusNet sitename.
                                     sprintf(_('Invite friends and colleagues to join you on %s.'),
                                             common_config('site', 'name')),
                                     $action == 'invite',
                                     'nav_invite');
            }

            Event::handle('EndSubGroupNav', array($this));
        }

        $this->out->elementEnd('ul');
    }

    function countPendingSubs()
    {
        $req = new Subscription_queue();
        $req->subscribed = $this->user->id;
        return $req->count();
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */

class SubPeopleTagCloudSection extends TagCloudSection
{
    function getTags()
    {
        $qry = $this->query();
        $limit = TAGS_PER_SECTION;
        $offset = 0;

        if (common_config('db','type') == 'pgsql') {
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
        } else {
            $qry .= ' LIMIT ' . $offset . ', ' . $limit;
        }

        $profile_tag = Memcached_DataObject::cachedQuery('Profile_tag',
                                                 sprintf($qry,
                                                         $this->out->user->id));
        return $profile_tag;
    }

    function tagUrl($tag) {
        return common_local_url('peopletag', array('tag' => $tag));
    }

    function showTag($tag, $weight, $relative) {
        $rel = 'tag-cloud-';
        $rel .= 1+intval(7 * $relative * $weight - 0.01);

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)), $tag);
        $this->out->elementEnd('li');
    }
}

repo_name: piratas/tortuga

license: mit


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for subscribing to a user
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Form
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/form.php';

/**
 * Form for subscribing to a user
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class SubscribeForm extends Form
{
    /**
     * Profile of user to subscribe to
     */
    var $profile = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out     output channel
     * @param Profile       $profile profile of user to subscribe to
     */
    function __construct($out=null, $profile=null)
    {
        parent::__construct($out);

        $this->profile = $profile;
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    function id()
    {
        return 'subscribe-' . $this->profile->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_user_subscribe ajax';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('subscribe');
    }

    /**
     * Legend of the Form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form of form to subscribe to a user.
        $this->out->element('legend', null, _('Subscribe to this user'));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->hidden('subscribeto-' . $this->profile->id,
                           $this->profile->id,
                           'subscribeto');
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text to subscribe to a user.
        $this->out->submit('submit', _m('BUTTON','Subscribe'), 'submit', null,
                           // TRANS: Button title to subscribe to a user.
                           _('Subscribe to this user.'));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for subscribing to a peopletag
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Form
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/form.php';

/**
 * Form for subscribing to a peopletag
 *
 * @category Form
 * @package  StatusNet
 * @author   Shashi Gowda <connect2shashi@gmail.com>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      UnsubscribeForm
 */
class SubscribePeopletagForm extends Form
{
    /**
     * peopletag for the user to join
     */
    var $peopletag = null;

    /**
     * Constructor
     *
     * @param HTMLOutputter $out   output channel
     * @param peopletag     $peopletag peopletag to subscribe to
     */
    function __construct($out=null, $peopletag=null)
    {
        parent::__construct($out);

        $this->peopletag = $peopletag;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        return 'peopletag-subscribe-' . $this->peopletag->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_peopletag_subscribe';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('subscribepeopletag',
                                array('id' => $this->peopletag->id));
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text for subscribing to a list.
        $this->out->submit('submit', _m('BUTTON', 'Subscribe'));

    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscribersPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as self-tagged');
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged group by tag order by weight desc';

        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on  profile_list.tag =  profile_tag.tag and profile_list.tagger =  profile_tag.tagger and profile_tag.tagger = subscriber where subscribed=%d and subscribed != subscriber and profile_tag.tagger = tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';

//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscribersPeopleTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as tagged');
    }

    function tagUrl($tag) {
        $nickname = $this->out->profile->nickname;
        return common_local_url('subscribers', array('nickname' => $nickname, 'tag' => $tag));
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed group by tag order by weight desc';
        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagged and subscribed=profile_tag.tagger and profile_tag.tagger = profile_list.tagger and profile_tag.tag = profile_list.tag where subscribed=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Widget to show a list of profiles
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Public
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Widget to show a list of subscriptions
 *
 * @category Public
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscriptionList extends ProfileList
{
    /** Owner of this list */
    var $owner = null;

    function __construct($profile, $owner=null, $action=null)
    {
        parent::__construct($profile, $action);

        $this->owner = $owner;
    }

    function newListItem($profile)
    {
        return new SubscriptionListItem($profile, $this->owner, $this->action);
    }
}

class SubscriptionListItem extends ProfileListItem
{
    /** Owner of this list */
    var $owner = null;

    function __construct($profile, $owner, $action)
    {
        parent::__construct($profile, $action);

        $this->owner = $owner;
    }

    function showProfile()
    {
        $this->startProfile();
        $this->showAvatar($this->profile);
        $this->showNickname();
        $this->showFullName();
        $this->showLocation();
        $this->showHomepage();
        $this->showBio();
        // Relevant portion!
        $this->showTags();
        if ($this->isOwn()) {
            $this->showOwnerControls();
        }
        $this->endProfile();
    }

    function showOwnerControls()
    {
        // pass
    }

    function isOwn()
    {
        $user = common_current_user();
        return (!empty($user) && ($this->owner->id == $user->id));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscriptionsPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as self-tagged');
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscriber != subscribed and tagger = tagged group by tag order by weight desc';

        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on profile_tag.tagger = subscribed and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_tag.tagger where subscriber=%d and subscribed != subscriber and profile_tag.tagger = profile_tag.tagged and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';

//        return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Personal tag cloud section
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Personal tag cloud section
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class SubscriptionsPeopleTagCloudSection extends SubPeopleTagCloudSection
{
    function title()
    {
        // TRANS: Title of personal tag cloud section.
        return _('People Tagcloud as tagged');
    }

    function tagUrl($tag) {
        $nickname = $this->out->profile->nickname;
        return common_local_url('subscriptions', array('nickname' => $nickname, 'tag' => $tag));
    }

    function query() {
//        return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed group by tag order by weight desc';
        return 'select profile_tag.tag, count(profile_tag.tag) as weight from subscription left join (profile_tag, profile_list) on subscriber=profile_tag.tagger and subscribed=tagged and profile_tag.tag = profile_list.tag and profile_tag.tagger = profile_list.tagger where subscriber=%d and subscriber != subscribed and profile_list.private = false and profile_tag.tag is not null group by profile_tag.tag order by weight desc';
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Database schema utilities
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Database
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * A class encapsulating the structure of a table.
 *
 * @category Database
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */

class TableDef
{
    /** name of the table */
    public $name;
    /** array of ColumnDef objects for the columns. */
    public $columns;

    /**
     * Constructor.
     *
     * @param string  $name     name of the table
     * @param array   $columns  columns in the table
     */

    function __construct($name=null,$columns=null)
    {
        $this->name = $name;
        $this->columns = $columns;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for sections showing tag clouds
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

define('TAGS_PER_SECTION', 10);

/**
 * Base class for sections
 *
 * These are the widgets that show interesting data about a person
 * group, or site.
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class TagCloudSection extends Section
{
    function showContent()
    {
        $tags = $this->getTags();

        if (!$tags) {
            // TRANS: Content displayed in a tag cloud section if there are no tags.
            $this->out->element('p', null, _m('NOTAGS','None'));
            return false;
        }

        $cnt = 0;

        $tw = array();
        $sum = 0;

        while ($tags->fetch() && ++$cnt <= TAGS_PER_SECTION) {
            $tw[$tags->tag] = $tags->weight;
            $sum += $tags->weight;
        }

        if ($cnt == 0) {
            // TRANS: Content displayed in a tag cloud section if there are no tags.
            $this->out->element('p', null, _m('NOTAGS','None'));
            return false;
        }

        ksort($tw);

        $this->out->elementStart('ul', 'tags xoxo tag-cloud');
        foreach ($tw as $tag => $weight) {
            $this->showTag($tag, $weight, ($sum == 0) ? 0 : $weight/$sum);
        }
        $this->out->elementEnd('ul');

        return ($cnt > TAGS_PER_SECTION);
    }

    function getTags()
    {
        return null;
    }

    function showTag($tag, $weight, $relative)
    {
        if ($relative > 0.1) {
            $rel =  'tag-cloud-7';
        } else if ($relative > 0.05) {
            $rel = 'tag-cloud-6';
        } else if ($relative > 0.02) {
            $rel = 'tag-cloud-5';
        } else if ($relative > 0.01) {
            $rel = 'tag-cloud-4';
        } else if ($relative > 0.005) {
            $rel = 'tag-cloud-3';
        } else if ($relative > 0.002) {
            $rel = 'tag-cloud-2';
        } else {
            $rel = 'tag-cloud-1';
        }

        $this->out->elementStart('li', $rel);
        $this->out->element('a', array('href' => $this->tagUrl($tag)),
                       $tag);
        $this->out->elementEnd('li');
    }

    function tagUrl($tag)
    {
        if ('showstream' === $this->out->trimmed('action')) {
            return common_local_url('showstream', array('nickname' => $this->out->profile->nickname, 'tag' => $tag));
        } else {
            return common_local_url('tag', array('tag' => $tag));
        }
    }

    function divId()
    {
        return 'tagcloud';
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Stream of notices by a profile with a given tag
 *
 * PHP version 5
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * Stream of notices with a given profile and tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class TaggedProfileNoticeStream extends ScopingNoticeStream
{
    function __construct($profile, $tag, $userProfile=-1)
    {
        if (is_int($userProfile) && $userProfile == -1) {
            $userProfile = Profile::current();
        }
        parent::__construct(new CachingNoticeStream(new RawTaggedProfileNoticeStream($profile, $tag),
                                                    'profile:notice_ids_tagged:'.$profile->id.':'.Cache::keyize($tag)),
                            $userProfile);
    }
}

/**
 * Raw stream of notices with a given profile and tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class RawTaggedProfileNoticeStream extends NoticeStream
{
    protected $profile;
    protected $tag;

    function __construct($profile, $tag)
    {
        $this->profile = $profile;
        $this->tag     = $tag;
    }

    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        // XXX It would be nice to do this without a join
        // (necessary to do it efficiently on accounts with long history)

        $notice = new Notice();

        $query =
          "select id from notice join notice_tag on id=notice_id where tag='".
          $notice->escape($this->tag) .
          "' and profile_id=" . intval($this->profile->id);

        $since = Notice::whereSinceId($since_id, 'id', 'notice.created');
        if ($since) {
            $query .= " and ($since)";
        }

        $max = Notice::whereMaxId($max_id, 'id', 'notice.created');
        if ($max) {
            $query .= " and ($max)";
        }

        $query .= ' order by notice.created DESC, id DESC';

        if (!is_null($offset)) {
            $query .= " LIMIT " . intval($limit) . " OFFSET " . intval($offset);
        }

        $notice->query($query);

        $ids = array();

        while ($notice->fetch()) {
            $ids[] = $notice->id;
        }

        return $ids;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Stream of notices with a given tag
 *
 * PHP version 5
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * Stream of notices with a given tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class TagNoticeStream extends ScopingNoticeStream
{
    function __construct($tag, $profile = -1)
    {
        if (is_int($profile) && $profile == -1) {
            $profile = Profile::current();
        }
        parent::__construct(new CachingNoticeStream(new RawTagNoticeStream($tag),
                                                    'notice_tag:notice_ids:' . Cache::keyize($tag)));
    }
}

/**
 * Raw stream of notices with a given tag
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class RawTagNoticeStream extends NoticeStream
{
    protected $tag;

    function __construct($tag)
    {
        $this->tag = $tag;
    }

    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        $nt = new Notice_tag();

        $nt->tag = $this->tag;

        $nt->selectAdd();
        $nt->selectAdd('notice_id');

        Notice::addWhereSinceId($nt, $since_id, 'notice_id');
        Notice::addWhereMaxId($nt, $max_id, 'notice_id');

        $nt->orderBy('created DESC, notice_id DESC');

        if (!is_null($offset)) {
            $nt->limit($offset, $limit);
        }

        $ids = array();

        if ($nt->find()) {
            while ($nt->fetch()) {
                $ids[] = $nt->notice_id;
            }
        }

        return $ids;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for tagging a profile with a peopletag
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Form
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Form for tagging a profile with a peopletag
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      HTMLOutputter
 */
class TagProfileForm extends Form
{
    protected $target = null;

    /**
     * Constructor
     *
     * @param Action $action  Action we're being embedded into
     * @param array  $options Array of optional parameters
     *                        'user' a user instead of current
     *                        'content' notice content
     *                        'inreplyto' ID of notice to reply to
     *                        'lat' Latitude
     *                        'lon' Longitude
     *                        'location_id' ID of location
     *                        'location_ns' Namespace of location
     */
    function __construct(Action $action, Profile $target)
    {
        parent::__construct($action);

        $this->target = $target;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */

    function id()
    {
        return 'form_tagprofile_'.$target->id;
    }

   /**
     * Class of the form
     *
     * @return string class of the form
     */

    function formClass()
    {
        return 'form_tagprofile form_settings';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url('tagprofile', array('id' => $this->target->id));
    }

    /**
     * Legend of the Form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend for notice form.
        $this->out->element('legend', null, sprintf(_m('ADDTOLIST', 'List %s'), $this->target->getNickname()));

    }

    /**
     * Data elements
     *
     * @return void
     */
    function formData()
    {
        if (Event::handle('StartShowTagProfileFormData', array($this))) {
            $this->hidden('token', common_session_token());
            $this->hidden('id', $this->target->id);

            $this->elementStart('ul', 'form_data');
            $this->elementStart('li');

            $tags = Profile_tag::getTagsArray($this->out->getScoped()->id, $this->target->id, $this->out->getScoped()->id);
            // TRANS: Field label on list form.
            $this->input('tags', _m('LABEL','Lists'),
                         ($this->arg('tags')) ? $this->arg('tags') : implode(' ', $tags),
                         // TRANS: Field title on list form.
                         _('Lists for this user (letters, numbers, -, ., and _), comma- or space- separated.'));
            $this->elementEnd('li');
            $this->elementEnd('ul');
            Event::handle('EndShowTagProfileFormData', array($this));
        }
    }

    function formActions()
    {
        // TRANS: Button text to save lists.
        $this->out->submit('save', _m('BUTTON', 'Save'));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Utility for creating new tag: URIs
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  URI
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Mint tag: URIs
 *
 * tag: URIs are unique identifiers according to http://tools.ietf.org/html/rfc4151.
 *
 * We use them for creating URIs for things that can't be HTTP retrieved.
 *
 * @category URI
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */

class TagURI
{
    /**
     * Return the base part of a tag URI
     *
     * Note: use mint() instead.
     *
     * @return string Tag URI base to use
     */

    static function base()
    {
        $base = common_config('integration', 'taguri');

        if (empty($base)) {

            $base = common_config('site', 'server').','.date('Y-m-d');

            $pathPart = trim(common_config('site', 'path'), '/');

            if (!empty($pathPart)) {
                $base .= ':'.str_replace('/', ':', $pathPart);
            }
        }

        return $base;
    }

    /**
     * Make a new tag URI
     *
     * Builds the proper base and creates all the parts
     *
     * @return string minted URI
     */

    static function mint()
    {
        $base = self::base();

        $args = func_get_args();

        $format = array_shift($args);

        $extra = vsprintf($format, $args);

        return 'tag:'.$base.':'.$extra;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Utilities for theme files and paths
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Paths
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Class for querying and manipulating a theme
 *
 * Themes are directories with some expected sub-directories and files
 * in them. They're found in either local/theme (for locally-installed themes)
 * or theme/ subdir of installation dir.
 *
 * Note that the 'local' directory can be overridden as $config['local']['path']
 * and $config['local']['dir'] etc.
 *
 * This used to be a couple of functions, but for various reasons it's nice
 * to have a class instead.
 *
 * @category Output
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class Theme
{
    const FALLBACK = 'neo';

    var $name = null;
    var $dir  = null;
    var $path = null;
    protected $metadata = null; // access via getMetadata() lazy-loader
    protected $externals = null;
    protected $deps = null;

    /**
     * Constructor
     *
     * Determines the proper directory and path for this theme.
     *
     * @param string $name Name of the theme; defaults to config value
     */
    function __construct($name=null)
    {
        if (empty($name)) {
            $name = common_config('site', 'theme');
        }
        if (!self::validName($name)) {
            // TRANS: Server exception displayed if a theme name was invalid.
            throw new ServerException(_('Invalid theme name.'));
        }
        $this->name = $name;

        // Check to see if it's in the local dir

        $localroot = self::localRoot();

        $fulldir = $localroot.'/'.$name;

        if (file_exists($fulldir) && is_dir($fulldir)) {
            $this->dir  = $fulldir;
            $this->path = $this->relativeThemePath('local', 'local', 'theme/' . $name);
            return;
        }

        // Check to see if it's in the distribution dir

        $instroot = self::installRoot();

        $fulldir = $instroot.'/'.$name;

        if (file_exists($fulldir) && is_dir($fulldir)) {
            $this->dir = $fulldir;
            $this->path = $this->relativeThemePath('theme', 'theme', $name);
            return;
        }

        // Ruh roh. Fall back to default, then.

        common_log(LOG_WARNING, sprintf("Unable to find theme '%s', falling back to default theme '%s'",
                                        $name,
                                        Theme::FALLBACK));

        $this->name = Theme::FALLBACK;
        $this->dir  = $instroot.'/'.Theme::FALLBACK;
        $this->path = $this->relativeThemePath('theme', 'theme', Theme::FALLBACK);

    }

    /**
     * Build a full URL to the given theme's base directory, possibly
     * using an offsite theme server path.
     *
     * @param string $group configuration section name to pull paths from
     * @param string $fallbackSubdir default subdirectory under INSTALLDIR
     * @param string $name theme name
     *
     * @return string URL
     *
     * @todo consolidate code with that for other customizable paths
     */
    protected function relativeThemePath($group, $fallbackSubdir, $name)
    {
        if (GNUsocial::isHTTPS()) {
            $sslserver = common_config($group, 'sslserver');

            if (empty($sslserver)) {
                if (is_string(common_config('site', 'sslserver')) &&
                    mb_strlen(common_config('site', 'sslserver')) > 0) {
                    $server = common_config('site', 'sslserver');
                } else if (common_config('site', 'server')) {
                    $server = common_config('site', 'server');
                }
                $path   = common_config('site', 'path') . '/';
                if ($fallbackSubdir) {
                    $path .= $fallbackSubdir . '/';
                }
            } else {
                $server = $sslserver;
                $path   = common_config($group, 'sslpath');
                if (empty($path)) {
                    $path = common_config($group, 'path');
                }
            }

            $protocol = 'https';
        } else {
            $path = common_config($group, 'path');

            if (empty($path)) {
                $path = common_config('site', 'path') . '/';
                if ($fallbackSubdir) {
                    $path .= $fallbackSubdir . '/';
                }
            }

            $server = common_config($group, 'server');

            if (empty($server)) {
                $server = common_config('site', 'server');
            }

            $protocol = 'http';
        }

        if ($path[strlen($path)-1] != '/') {
            $path .= '/';
        }

        if ($path[0] != '/') {
            $path = '/'.$path;
        }

        return $protocol.'://'.$server.$path.$name;
    }

    /**
     * Gets the full local filename of a file in this theme.
     *
     * @param string $relative relative name, like 'logo.png'
     *
     * @return string full pathname, like /var/www/mublog/theme/default/logo.png
     */
    function getFile($relative)
    {
        return $this->dir.'/'.$relative;
    }

    /**
     * Gets the full HTTP url of a file in this theme
     *
     * @param string $relative relative name, like 'logo.png'
     *
     * @return string full URL, like 'http://example.com/theme/default/logo.png'
     */
    function getPath($relative)
    {
        return $this->path.'/'.$relative;
    }

    /**
     * Fetch a list of other themes whose CSS needs to be pulled in before
     * this theme's, based on following the theme.ini 'include' settings.
     * (May be empty if this theme has no include dependencies.)
     *
     * @return array of strings with theme names
     */
    function getDeps()
    {
        if ($this->deps === null) {
            $chain = $this->doGetDeps(array($this->name));
            array_pop($chain); // Drop us back off
            $this->deps = $chain;
        }
        return $this->deps;
    }

    protected function doGetDeps($chain)
    {
        $data = $this->getMetadata();
        if (!empty($data['include'])) {
            $include = $data['include'];

            // Protect against cycles!
            if (!in_array($include, $chain)) {
                try {
                    $theme = new Theme($include);
                    array_unshift($chain, $include);
                    return $theme->doGetDeps($chain);
                } catch (Exception $e) {
                    common_log(LOG_ERR,
                            "Exception while fetching theme dependencies " .
                            "for $this->name: " . $e->getMessage());
                }
            }
        }
        return $chain;
    }

    /**
     * Pull data from the theme's theme.ini file.
     * @fixme calling getFile will fall back to default theme, this may be unsafe.
     *
     * @return associative array of strings
     */
    function getMetadata()
    {
        if ($this->metadata == null) {
            $this->metadata = $this->doGetMetadata();
        }
        return $this->metadata;
    }

    /**
     * Pull data from the theme's theme.ini file.
     * @fixme calling getFile will fall back to default theme, this may be unsafe.
     *
     * @return associative array of strings
     */
    private function doGetMetadata()
    {
        $iniFile = $this->getFile('theme.ini');
        if (file_exists($iniFile)) {
            return parse_ini_file($iniFile);
        } else {
            return array();
        }
    }

    /**
     * Get list of any external URLs required by this theme and any
     * dependencies. These are lazy-loaded from theme.ini.
     *
     * @return array of URL strings
     */
    function getExternals()
    {
        if ($this->externals == null) {
            $data = $this->getMetadata();
            if (!empty($data['external'])) {
                $ext = (array)$data['external'];
            } else {
                $ext = array();
            }

            if (!empty($data['include'])) {
                $theme = new Theme($data['include']);
                $ext = array_merge($ext, $theme->getExternals());
            }

            $this->externals = array_unique($ext);
        }
        return $this->externals;
    }

    /**
     * Gets the full path of a file in a theme dir based on its relative name
     *
     * @param string $relative relative path within the theme directory
     * @param string $name     name of the theme; defaults to current theme
     *
     * @return string File path to the theme file
     */
    static function file($relative, $name=null)
    {
        $theme = new Theme($name);
        return $theme->getFile($relative);
    }

    /**
     * Gets the full URL of a file in a theme dir based on its relative name
     *
     * @param string $relative relative path within the theme directory
     * @param string $name     name of the theme; defaults to current theme
     *
     * @return string URL of the file
     */
    static function path($relative, $name=null)
    {
        $theme = new Theme($name);
        return $theme->getPath($relative);
    }

    /**
     * list available theme names
     *
     * @return array list of available theme names
     */
    static function listAvailable()
    {
        $local   = self::subdirsOf(self::localRoot());
        $install = self::subdirsOf(self::installRoot());

        $i = array_search('base', $install);

        unset($install[$i]);

        return array_merge($local, $install);
    }

    /**
     * Utility for getting subdirs of a directory
     *
     * @param string $dir full path to directory to check
     *
     * @return array relative filenames of subdirs, or empty array
     */
    protected static function subdirsOf($dir)
    {
        $subdirs = array();

        if (is_dir($dir)) {
            if ($dh = opendir($dir)) {
                while (($filename = readdir($dh)) !== false) {
                    if ($filename != '..' && $filename !== '.' &&
                        is_dir($dir.'/'.$filename)) {
                        $subdirs[] = $filename;
                    }
                }
                closedir($dh);
            }
        }

        return $subdirs;
    }

    /**
     * Local root dir for themes
     *
     * @return string local root dir for themes
     */
    protected static function localRoot()
    {
        $basedir = common_config('local', 'dir');

        if (empty($basedir)) {
            $basedir = INSTALLDIR . '/local';
        }

        return $basedir . '/theme';
    }

    /**
     * Root dir for themes that are shipped with StatusNet
     *
     * @return string root dir for StatusNet themes
     */
    protected static function installRoot()
    {
        $instroot = common_config('theme', 'dir');

        if (empty($instroot)) {
            $instroot = INSTALLDIR.'/theme';
        }

        return $instroot;
    }

    static function validName($name)
    {
        return preg_match('/^[a-z0-9][a-z0-9_-]*$/i', $name);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Utilities for theme files and paths
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Paths
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Encapsulation of the validation-and-save process when dealing with
 * a user-uploaded StatusNet theme archive...
 *
 * @todo extract theme metadata from css/display.css
 * @todo allow saving multiple themes
 */
class ThemeUploader
{
    protected $sourceFile;
    protected $isUpload;
    private $prevErrorReporting;

    public function __construct($filename)
    {
        if (!class_exists('ZipArchive')) {
            // TRANS: Exception thrown when a compressed theme is uploaded while no support present in PHP configuration.
            throw new Exception(_('This server cannot handle theme uploads without ZIP support.'));
        }
        $this->sourceFile = $filename;
    }

    public static function fromUpload($name)
    {
        if (!isset($_FILES[$name]['error'])) {
            // TRANS: Server exception thrown when uploading a theme fails.
            throw new ServerException(_('The theme file is missing or the upload failed.'));
        }
        if ($_FILES[$name]['error'] != UPLOAD_ERR_OK) {
            // TRANS: Server exception thrown when uploading a theme fails.
            throw new ServerException(_('The theme file is missing or the upload failed.'));
        }
        return new ThemeUploader($_FILES[$name]['tmp_name']);
    }

    /**
     * @param string $destDir
     * @throws Exception on bogus files
     */
    public function extract($destDir)
    {
        $zip = $this->openArchive();

        // First pass: validate but don't save anything to disk.
        // Any errors will trip an exception.
        $this->traverseArchive($zip);

        // Second pass: now that we know we're good, actually extract!
        $tmpDir = $destDir . '.tmp' . getmypid();
        $this->traverseArchive($zip, $tmpDir);

        $zip->close();

        if (file_exists($destDir)) {
            $killDir = $tmpDir . '.old';
            $this->quiet();
            $ok = rename($destDir, $killDir);
            $this->loud();
            if (!$ok) {
                common_log(LOG_ERR, "Could not move old custom theme from $destDir to $killDir");
                // TRANS: Server exception thrown when saving an uploaded theme after decompressing it fails.
                throw new ServerException(_('Failed saving theme.'));
            }
        } else {
            $killDir = false;
        }

        $this->quiet();
        $ok = rename($tmpDir, $destDir);
        $this->loud();
        if (!$ok) {
            common_log(LOG_ERR, "Could not move saved theme from $tmpDir to $destDir");
            // TRANS: Server exception thrown when saving an uploaded theme after decompressing it fails.
            throw new ServerException(_('Failed saving theme.'));
        }

        if ($killDir) {
            $this->recursiveRmdir($killDir);
        }
    }

    /**
     *
     */
    protected function traverseArchive($zip, $outdir=false)
    {
        $sizeLimit = 2 * 1024 * 1024; // 2 megabyte space limit?
        $blockSize = 4096; // estimated; any entry probably takes this much space

        $totalSize = 0;
        $hasMain = false;
        $commonBaseDir = false;

        for ($i = 0; $i < $zip->numFiles; $i++) {
            $data = $zip->statIndex($i);
            $name = str_replace('\\', '/', $data['name']);

            if (substr($name, -1) == '/') {
                // A raw directory... skip!
                continue;
            }

            // Is this a safe or skippable file?
            $path = pathinfo($name);
            if ($this->skippable($path['filename'], $path['extension'])) {
                // Documentation and such... booooring
                continue;
            } else {
                $this->validateFile($path['filename'], $path['extension']);
            }

            // Check the directory structure...
            $dirs = explode('/', $path['dirname']);
            $baseDir = array_shift($dirs);
            if ($commonBaseDir === false) {
                $commonBaseDir = $baseDir;
            } else {
                if ($commonBaseDir != $baseDir) {
                    // TRANS: Server exception thrown when an uploaded theme has an incorrect structure.
                    throw new ClientException(_('Invalid theme: Bad directory structure.'));
                }
            }

            foreach ($dirs as $dir) {
                $this->validateFileOrFolder($dir);
            }

            $fullPath = $dirs;
            $fullPath[] = $path['basename'];
            $localFile = implode('/', $fullPath);
            if ($localFile == 'css/display.css') {
                $hasMain = true;
            }

            $size = $data['size'];
            $estSize = $blockSize * max(1, intval(ceil($size / $blockSize)));
            $totalSize += $estSize;
            if ($totalSize > $sizeLimit) {
                // TRANS: Client exception thrown when an uploaded theme is larger than the limit.
                // TRANS: %d is the number of bytes of the uncompressed theme.
                $msg = sprintf(_m('Uploaded theme is too large; must be less than %d byte uncompressed.',
                                  'Uploaded theme is too large; must be less than %d bytes uncompressed.',
                                  $sizeLimit),
                               $sizeLimit);
                throw new ClientException($msg);
            }

            if ($outdir) {
                $this->extractFile($zip, $data['name'], "$outdir/$localFile");
            }
        }

        if (!$hasMain) {
            // TRANS: Server exception thrown when an uploaded theme is incomplete.
            throw new ClientException(_('Invalid theme archive: ' .
                                        "Missing file css/display.css"));
        }
    }

    /**
     * @fixme Probably most unrecognized files should just be skipped...
     */
    protected function skippable($filename, $ext)
    {
        $skip = array('txt', 'html', 'rtf', 'doc', 'docx', 'odt', 'xcf');
        if (strtolower($filename) == 'readme') {
            return true;
        }
        if (in_array(strtolower($ext), $skip)) {
            return true;
        }
        if ($filename == '' || substr($filename, 0, 1) == '.') {
            // Skip Unix-style hidden files
            return true;
        }
        if ($filename == '__MACOSX') {
            // Skip awful metadata files Mac OS X slips in for you.
            // Thanks Apple!
            return true;
        }
        return false;
    }

    protected function validateFile($filename, $ext)
    {
        $this->validateFileOrFolder($filename);
        $this->validateExtension($filename, $ext);
        // @fixme validate content
    }

    protected function validateFileOrFolder($name)
    {
        if (!preg_match('/^[a-z0-9_\.-]+$/i', $name)) {
            common_log(LOG_ERR, "Bad theme filename: $name");
            // TRANS: Server exception thrown when an uploaded theme has an incorrect file or folder name.
            $msg = _("Theme contains invalid file or folder name. " .
                     'Stick with ASCII letters, digits, underscore, and minus sign.');
            throw new ClientException($msg);
        }
        if (preg_match('/\.(php|cgi|asp|aspx|js|vb)\w/i', $name)) {
            common_log(LOG_ERR, "Unsafe theme filename: $name");
            // TRANS: Server exception thrown when an uploaded theme contains files with unsafe file extensions.
            $msg = _('Theme contains unsafe file extension names; may be unsafe.');
            throw new ClientException($msg);
        }
        return true;
    }

    protected function validateExtension($base, $ext)
    {
        $allowed = array('css', // CSS may need validation
                         'png', 'gif', 'jpg', 'jpeg',
                         'svg', // SVG images/fonts may need validation
                         'ttf', 'eot', 'woff');
        if (!in_array(strtolower($ext), $allowed)) {
            if ($ext == 'ini' && $base == 'theme') {
                // theme.ini exception
                return true;
            }
            // TRANS: Server exception thrown when an uploaded theme contains a file type that is not allowed.
            // TRANS: %s is the file type that is not allowed.
            $msg = sprintf(_('Theme contains file of type ".%s", which is not allowed.'),
                           $ext);
            throw new ClientException($msg);
        }
        return true;
    }

    /**
     * @return ZipArchive
     */
    protected function openArchive()
    {
        $zip = new ZipArchive;
        $ok = $zip->open($this->sourceFile);
        if ($ok !== true) {
            common_log(LOG_ERR, "Error opening theme zip archive: " .
                                "{$this->sourceFile} code: {$ok}");
            // TRANS: Server exception thrown when an uploaded compressed theme cannot be opened.
            throw new Exception(_('Error opening theme archive.'));
        }
        return $zip;
    }

    /**
     * @param ZipArchive $zip
     * @param string $from original path inside ZIP archive
     * @param string $to final destination path in filesystem
     */
    protected function extractFile($zip, $from, $to)
    {
        $dir = dirname($to);
        if (!file_exists($dir)) {
            $this->quiet();
            $ok = mkdir($dir, 0755, true);
            $this->loud();
            if (!$ok) {
                common_log(LOG_ERR, "Failed to mkdir $dir while uploading theme");
                // TRANS: Server exception thrown when an uploaded theme cannot be saved during extraction.
                throw new ServerException(_('Failed saving theme.'));
            }
        } else if (!is_dir($dir)) {
            common_log(LOG_ERR, "Output directory $dir not a directory while uploading theme");
            // TRANS: Server exception thrown when an uploaded theme cannot be saved during extraction.
            throw new ServerException(_('Failed saving theme.'));
        }

        // ZipArchive::extractTo would be easier, but won't let us alter
        // the directory structure.
        $in = $zip->getStream($from);
        if (!$in) {
            common_log(LOG_ERR, "Couldn't open archived file $from while uploading theme");
            // TRANS: Server exception thrown when an uploaded theme cannot be saved during extraction.
            throw new ServerException(_('Failed saving theme.'));
        }
        $this->quiet();
        $out = fopen($to, "wb");
        $this->loud();
        if (!$out) {
            common_log(LOG_ERR, "Couldn't open output file $to while uploading theme");
            // TRANS: Server exception thrown when an uploaded theme cannot be saved during extraction.
            throw new ServerException(_('Failed saving theme.'));
        }
        while (!feof($in)) {
            $buffer = fread($in, 65536);
            fwrite($out, $buffer);
        }
        fclose($in);
        fclose($out);
    }

    private function quiet()
    {
        $this->prevErrorReporting = error_reporting();
        error_reporting($this->prevErrorReporting & ~E_WARNING);
    }

    private function loud()
    {
        error_reporting($this->prevErrorReporting);
    }

    private function recursiveRmdir($dir)
    {
        $list = dir($dir);
        while (($file = $list->read()) !== false) {
            if ($file == '.' || $file == '..') {
                continue;
            }
            $full = "$dir/$file";
            if (is_dir($full)) {
                $this->recursiveRmdir($full);
            } else {
                unlink($full);
            }
        }
        $list->close();
        rmdir($dir);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * widget for displaying a list of notices
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  UI
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * widget for displaying a list of notices
 *
 * There are a number of actions that display a list of notices, in
 * reverse chronological order. This widget abstracts out most of the
 * code for UI for notice lists. It's overridden to hide some
 * data for e.g. the profile page.
 *
 * @category UI
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 * @see      Notice
 * @see      NoticeListItem
 * @see      ProfileNoticeList
 */
class ThreadedNoticeList extends NoticeList
{
    protected $userProfile;

    function __construct(Notice $notice, Action $out=null, $profile=-1)
    {
        parent::__construct($notice, $out);
        if (is_int($profile) && $profile == -1) {
            $profile = Profile::current();
        }
        $this->userProfile = $profile;
    }

    /**
     * show the list of notices
     *
     * "Uses up" the stream by looping through it. So, probably can't
     * be called twice on the same list.
     *
     * @return int count of notices listed.
     */
    function show()
    {
        $this->out->elementStart('div', array('id' =>'notices_primary'));
        // TRANS: Header for Notices section.
        $this->out->element('h2', null, _m('HEADER','Notices'));
        $this->out->elementStart('ol', array('class' => 'notices threaded-notices xoxo'));

		$notices = $this->notice->fetchAll();
		$total = count($notices);
		$notices = array_slice($notices, 0, NOTICES_PER_PAGE);

        $allnotices = self::_allNotices($notices);
    	self::prefill($allnotices);

        $conversations = array();

        foreach ($notices as $notice) {

            // Collapse repeats into their originals...

            if ($notice->repeat_of) {
                $orig = Notice::getKV('id', $notice->repeat_of);
                if ($orig instanceof Notice) {
                    $notice = $orig;
                }
            }
            $convo = $notice->conversation;
            if (!empty($conversations[$convo])) {
                // Seen this convo already -- skip!
                continue;
            }
            $conversations[$convo] = true;

            // Get the convo's root notice
            $root = $notice->conversationRoot($this->userProfile);
            if ($root instanceof Notice) {
                $notice = $root;
            }

            try {
                $item = $this->newListItem($notice);
                $item->show();
            } catch (Exception $e) {
                // we log exceptions and continue
                common_log(LOG_ERR, $e->getMessage());
                continue;
            }
        }

        $this->out->elementEnd('ol');
        $this->out->elementEnd('div');

        return $total;
    }

    function _allNotices($notices)
    {
        $convId = array();
        foreach ($notices as $notice) {
            $convId[] = $notice->conversation;
        }
        $convId = array_unique($convId);
        $allMap = Notice::listGet('conversation', $convId);
        $allArray = array();
        foreach ($allMap as $convId => $convNotices) {
            $allArray = array_merge($allArray, $convNotices);
        }
        return $allArray;
    }

    /**
     * returns a new list item for the current notice
     *
     * Recipe (factory?) method; overridden by sub-classes to give
     * a different list item class.
     *
     * @param Notice $notice the current notice
     *
     * @return NoticeListItem a list item for displaying the notice
     */
    function newListItem(Notice $notice)
    {
        return new ThreadedNoticeListItem($notice, $this->out, $this->userProfile);
    }
}

/**
 * widget for displaying a single notice
 *
 * This widget has the core smarts for showing a single notice: what to display,
 * where, and under which circumstances. Its key method is show(); this is a recipe
 * that calls all the other show*() methods to build up a single notice. The
 * ProfileNoticeListItem subclass, for example, overrides showAuthor() to skip
 * author info (since that's implicit by the data in the page).
 *
 * @category UI
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 * @see      NoticeList
 * @see      ProfileNoticeListItem
 */
class ThreadedNoticeListItem extends NoticeListItem
{
    protected $userProfile = null;

    function __construct(Notice $notice, Action $out=null, $profile=null)
    {
        parent::__construct($notice, $out);
        $this->userProfile = $profile;
    }

    function initialItems()
    {
        return 3;
    }

    /**
     * finish the notice
     *
     * Close the last elements in the notice list item
     *
     * @return void
     */
    function showEnd()
    {
        $max = $this->initialItems();
        if (!$this->repeat) {
            $stream = new ConversationNoticeStream($this->notice->conversation, $this->userProfile);
            $notice = $stream->getNotices(0, $max + 2);
            $notices = array();
            $cnt = 0;
            $moreCutoff = null;
            while ($notice->fetch()) {
                if (Event::handle('StartAddNoticeReply', array($this, $this->notice, $notice))) {
                    // Don't list repeats as separate notices in a conversation
                    if (!empty($notice->repeat_of)) {
                        continue;
                    }

                    if ($notice->id == $this->notice->id) {
                        // Skip!
                        continue;
                    }
                    $cnt++;
                    if ($cnt > $max) {
                        // boo-yah
                        $moreCutoff = clone($notice);
                        break;
                    }
                    $notices[] = clone($notice); // *grumble* inefficient as hell
                    Event::handle('EndAddNoticeReply', array($this, $this->notice, $notice));
                }
            }

            if (Event::handle('StartShowThreadedNoticeTail', array($this, $this->notice, &$notices))) {
                $threadActive = count($notices) > 0; // has this thread had any activity?

                $this->out->elementStart('ul', 'notices threaded-replies xoxo');

                if (Event::handle('StartShowThreadedNoticeTailItems', array($this, $this->notice, &$threadActive))) {
                    // Repeats and Faves/Likes are handled in plugins.
                    Event::handle('EndShowThreadedNoticeTailItems', array($this, $this->notice, &$threadActive));
                }

                if (count($notices)>0) {
                    if ($moreCutoff) {
                        $item = new ThreadedNoticeListMoreItem($moreCutoff, $this->out, count($notices));
                        $item->show();
                    }
                    foreach (array_reverse($notices) as $notice) {
                        if (Event::handle('StartShowThreadedNoticeSub', array($this, $this->notice, $notice))) {
                            $item = new ThreadedNoticeListSubItem($notice, $this->notice, $this->out);
                            $item->show();
                            Event::handle('EndShowThreadedNoticeSub', array($this, $this->notice, $notice));
                        }
                    }
                }

                Event::handle('EndShowThreadedNoticeTail', array($this, $this->notice, $notices));
                $this->out->elementEnd('ul');
            }
        }

        parent::showEnd();
    }
}

// @todo FIXME: needs documentation.
class ThreadedNoticeListSubItem extends NoticeListItem
{
    protected $root = null;

    function __construct(Notice $notice, $root, $out)
    {
        $this->root = $root;
        parent::__construct($notice, $out);
    }

    function avatarSize()
    {
        return AVATAR_STREAM_SIZE; // @fixme would like something in between
    }

    function showNoticeLocation()
    {
        //
    }

    function showNoticeSource()
    {
        //
    }

    function getReplyProfiles()
    {
        $all = parent::getReplyProfiles();

        $profiles = array();

        $rootAuthor = $this->root->getProfile();

        foreach ($all as $profile) {
            if ($profile->id != $rootAuthor->id) {
                $profiles[] = $profile;
            }
        }

        return $profiles;
    }

    function showEnd()
    {
        $threadActive = null;   // unused here for now, but maybe in the future?
        if (Event::handle('StartShowThreadedNoticeTailItems', array($this, $this->notice, &$threadActive))) {
            // Repeats and Faves/Likes are handled in plugins.
            Event::handle('EndShowThreadedNoticeTailItems', array($this, $this->notice, &$threadActive));
        }
        parent::showEnd();
    }
}

/**
 * Placeholder for loading more replies...
 */
class ThreadedNoticeListMoreItem extends NoticeListItem
{
    protected $cnt;

    function __construct(Notice $notice, Action $out, $cnt)
    {
        parent::__construct($notice, $out);
        $this->cnt = $cnt;
    }

    /**
     * recipe function for displaying a single notice.
     *
     * This uses all the other methods to correctly display a notice. Override
     * it or one of the others to fine-tune the output.
     *
     * @return void
     */
    function show()
    {
        $this->showStart();
        $this->showMiniForm();
        $this->showEnd();
    }

    /**
     * start a single notice.
     *
     * @return void
     */
    function showStart()
    {
        $this->out->elementStart('li', array('class' => 'notice-reply-comments'));
    }

    function showEnd()
    {
        $this->out->elementEnd('li');
    }

    function showMiniForm()
    {
        $id = $this->notice->conversation;
        $url = common_local_url('conversation', array('id' => $id));

        $n = Conversation::noticeCount($id) - 1;

        // TRANS: Link to show replies for a notice.
        // TRANS: %d is the number of replies to a notice and used for plural.
        $msg = sprintf(_m('Show reply', 'Show all %d replies', $n), $n);

        $this->out->element('a', array('href' => $url), $msg);
    }
}


code:
<?php

if (!defined('GNUSOCIAL')) { exit(1); }

class ThreadingNetworkPublicNoticeStream extends ThreadingNoticeStream
{
    public function __construct(Profile $scoped=null)
    {
        parent::__construct(new NetworkPublicNoticeStream($scoped));
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Notice stream that's good for threading lists
 *
 * PHP version 5
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Notice stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * This notice stream filters notices by whether their conversation
 * has been seen before. It's a good (well, OK) way to get streams
 * for a ThreadedNoticeList display.
 *
 * @category  Notice stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class ThreadingNoticeStream extends FilteringNoticeStream
{
    protected $seen = array();

    function getNotices($offset, $limit, $sinceId=null, $maxId=null)
    {
        // Clear this each time we're called
        $this->seen = array();
        return parent::getNotices($offset, $limit, $sinceId, $maxId);
    }

    function filter($notice)
    {
        if (!array_key_exists($notice->conversation, $this->seen)) {
            $this->seen[$notice->conversation] = true;
            return true;
        } else {
            return false;
        }
    }
}


code:
<?php

if (!defined('GNUSOCIAL')) { exit(1); }

class ThreadingPublicNoticeStream extends ThreadingNoticeStream
{
    function __construct($scoped)
    {
        parent::__construct(new PublicNoticeStream($scoped));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for editing a peopletag
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Form
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/form.php';

/**
 * Form for editing a peopletag
 *
 * @category Form
 * @package  StatusNet
 * @author   Shashi Gowda <connect2shashi@gmail.com>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      GroupEditForm
 */
class SearchProfileForm extends Form
{
    var $peopletag;

    function __construct($out, Profile_list $peopletag)
    {
        parent::__construct($out);
        $this->peopletag = $peopletag;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        return 'form_peopletag-add-' . $this->peopletag->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_peopletag_edit_user_search';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('profilecompletion');
    }

    /**
     * Name of the form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend.
        $this->out->element('legend', null, sprintf(_('Search and list people')));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        // TRANS: Dropdown option for searching in profiles.
        $fields = array('fulltext'    => _('Everything'),
                        // TRANS: Dropdown option for searching in profiles.
                        'nickname'    => _('Nickname'),
                        // TRANS: Dropdown option for searching in profiles.
                        'fullname'    => _('Fullname'),
                        // TRANS: Dropdown option for searching in profiles.
                        'description' => _('Description'),
                        // TRANS: Dropdown option for searching in profiles.
                        'location'    => _('Location'),
                        // TRANS: Dropdown option for searching in profiles.
                        'uri'         => _('URI (Remote users)'));

        $this->out->hidden('peopletag_id', $this->peopletag->id);
        $this->out->input('q', null);
        // TRANS: Dropdown field label.
        $this->out->dropdown('field', _m('LABEL','Search in'), $fields,
                        // TRANS: Dropdown field title.
                        _('Choose a field to search.'), false, 'fulltext');
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text to search profiles.
        $this->out->submit('submit', _m('BUTTON','Search'));
    }
}

class UntagButton extends Form
{
    var $profile;
    var $peopletag;

    function __construct($out, Profile $profile, Profile_list $peopletag)
    {
        parent::__construct($out);
        $this->profile = $profile;
        $this->peopletag = $peopletag;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        return 'form_peopletag-' . $this->peopletag->id . '-remove-' . $this->profile->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_user_remove_peopletag';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url('removepeopletag');
    }

    /**
     * Name of the form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend.
        // TRANS: %1$s is a nickname, $2$s is a list.
        $this->out->element('legend', null, sprintf(_('Remove %1$s from list %2$s'),
            $this->profile->nickname, $this->peopletag->tag));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->hidden('peopletag_id', $this->peopletag->id);
        $this->out->hidden('tagged', $this->profile->id);
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text to untag a profile.
        $this->out->submit('submit', _m('BUTTON','Remove'));
    }
}

class TagButton extends Form
{
    var $profile;
    var $peopletag;

    function __construct($out, Profile $profile, Profile_list $peopletag)
    {
        parent::__construct($out);
        $this->profile = $profile;
        $this->peopletag = $peopletag;
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */
    function id()
    {
        return 'form_peopletag-' . $this->peopletag->id . '-add-' . $this->profile->id;
    }

    /**
     * class of the form
     *
     * @return string of the form class
     */
    function formClass()
    {
        return 'form_user_add_peopletag';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('addpeopletag');
    }

    /**
     * Name of the form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Legend on form to add a profile to a list.
        // TRANS: %1$s is a nickname, %2$s is a list.
        $this->out->element('legend', null, sprintf(_('Add %1$s to list %2$s'),
            $this->profile->nickname, $this->peopletag->tag));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        UntagButton::formData();
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button text to tag a profile.
        $this->out->submit('submit', _m('BUTTON','Add'));
    }
}

class TaggedProfileItem extends Widget
{
    var $profile=null;

    function __construct($out=null, $profile)
    {
        parent::__construct($out);
        $this->profile = $profile;
    }

    function show()
    {
        $this->out->elementStart('a', array('class' => 'url',
                                            'href' => $this->profile->profileurl,
                                            'title' => $this->profile->getBestName()));
        $avatarUrl = $this->profile->avatarUrl(AVATAR_MINI_SIZE);
        $this->out->element('img', array('src' => $avatarUrl,
                                         'width' => AVATAR_MINI_SIZE,
                                         'height' => AVATAR_MINI_SIZE,
                                         'class' => 'avatar photo',
                                         'alt' => $this->profile->getBestName()));
        $this->out->element('span', 'fn nickname', $this->profile->nickname);
        $this->out->elementEnd('a');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for sections showing lists of people
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Base class for sections
 *
 * These are the widgets that show interesting data about a person
 * group, or site.
 *
 * @category Widget
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class TopPostersSection extends ProfileSection
{
    function getProfiles()
    {
        $qry = 'SELECT profile.*, count(*) as value ' .
          'FROM profile JOIN notice ON profile.id = notice.profile_id ' .
          (common_config('public', 'localonly') ? 'WHERE is_local = 1 ' : '') .
          'GROUP BY profile.id,nickname,fullname,profileurl,homepage,bio,location,profile.created,profile.modified,textsearch ' .
          'ORDER BY value DESC ';

        $limit = PROFILES_PER_SECTION;
        $offset = 0;

        if (common_config('db','type') == 'pgsql') {
            $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
        } else {
            $qry .= ' LIMIT ' . $offset . ', ' . $limit;
        }

        $profile = Memcached_DataObject::cachedQuery('Profile',
                                                     $qry,
                                                     6 * 3600);
        return $profile;
    }

    function title()
    {
        // TRANS: Title for top posters section.
        return _('Top posters');
    }

    function divId()
    {
        return 'top_posters';
    }
}