code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010 StatusNet, Inc.
 *
 * 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/>.
 */

/**
 * Class for activity streams
 *
 * Includes objects like notices, subscriptions and from plugins.
 *
 * We extend atomusernoticefeed since it does some nice setup for us.
 *
 */
class UserActivityStream extends AtomUserNoticeFeed
{
    public $activities = array();
    public $after = null;

    const OUTPUT_STRING = 1;
    const OUTPUT_RAW = 2;
    public $outputMode = self::OUTPUT_STRING;

    /**
     *
     * @param User $user
     * @param boolean $indent
     * @param boolean $outputMode: UserActivityStream::OUTPUT_STRING to return a string,
     *                           or UserActivityStream::OUTPUT_RAW to go to raw output.
     *                           Raw output mode will attempt to stream, keeping less
     *                           data in memory but will leave $this->activities incomplete.
     */
    function __construct($user, $indent = true, $outputMode = UserActivityStream::OUTPUT_STRING, $after = null)
    {
        parent::__construct($user, null, $indent);

        $this->outputMode = $outputMode;

        if ($this->outputMode == self::OUTPUT_STRING) {
            // String buffering? Grab all the notices now.
            $notices = $this->getNotices();
        } elseif ($this->outputMode == self::OUTPUT_RAW) {
            // Raw output... need to restructure from the stringer init.
            $this->xw = new XMLWriter();
            $this->xw->openURI('php://output');
            if(is_null($indent)) {
                $indent = common_config('site', 'indent');
            }
            $this->xw->setIndent($indent);

            // We'll fetch notices later.
            $notices = array();
        } else {
            throw new Exception('Invalid outputMode provided to ' . __METHOD__);
        }

        $this->after = $after;

        // Assume that everything but notices is feasible
        // to pull at once and work with in memory...

        $subscriptions = $this->getSubscriptions();
        $subscribers   = $this->getSubscribers();
        $groups        = $this->getGroups();

        $objs = array_merge($subscriptions, $subscribers, $groups, $notices);

        Event::handle('AppendUserActivityStreamObjects', array($this, &$objs));

        $subscriptions = null;
        $subscribers   = null;
        $groups        = null;

        unset($subscriptions);
        unset($subscribers);
        unset($groups);

        // Sort by create date

        usort($objs, 'UserActivityStream::compareObject');

        // We'll keep these around for later, and interleave them into
        // the output stream with the user's notices.

        $this->objs = $objs;
    }

    /**
     * Interleave the pre-sorted objects with the user's
     * notices, all in reverse chron order.
     */
    function renderEntries($format=Feed::ATOM, $handle=null)
    {
        $haveOne = false;

        $end = time() + 1;
        foreach ($this->objs as $obj) {
            set_time_limit(10);

            try {
                $act = $obj->asActivity();
            } catch (Exception $e) {
                common_log(LOG_ERR, $e->getMessage());
                continue;
            }

            $start = $act->time;

            if ($this->outputMode == self::OUTPUT_RAW && $start != $end) {
                // In raw mode, we haven't pre-fetched notices.
                // Grab the chunks of notices between other activities.
                try {
                    $notices = $this->getNoticesBetween($start, $end);
                    foreach ($notices as $noticeAct) {
                        try {
                            $nact = $noticeAct->asActivity($this->user->getProfile());
                            if ($format == Feed::ATOM) {
                                $nact->outputTo($this, false, false);
                            } else {
                                if ($haveOne) {
                                    fwrite($handle, ",");
                                }
                                fwrite($handle, json_encode($nact->asArray()));
                                $haveOne = true;
                            }
                        } catch (Exception $e) {
                            common_log(LOG_ERR, $e->getMessage());
                            continue;
                        }
                        $nact = null;
                        unset($nact);
                    }
                } catch (Exception $e) {
                    common_log(LOG_ERR, $e->getMessage());
                }
            }

            $notices = null;
            unset($notices);

            try {
                if ($format == Feed::ATOM) {
                    // Only show the author sub-element if it's different from default user
                    $act->outputTo($this, false, ($act->actor->id != $this->user->getUri()));
                } else {
                    if ($haveOne) {
                        fwrite($handle, ",");
                    }
                    fwrite($handle, json_encode($act->asArray()));
                    $haveOne = true;
                }
            } catch (Exception $e) {
                common_log(LOG_ERR, $e->getMessage());
            }

            $act = null;
            unset($act);

            $end = $start;
        }

        if ($this->outputMode == self::OUTPUT_RAW) {
            // Grab anything after the last pre-sorted activity.
            try {
                if (!empty($this->after)) {
                    $notices = $this->getNoticesBetween($this->after, $end);
                } else {
                    $notices = $this->getNoticesBetween(0, $end);
                }
                foreach ($notices as $noticeAct) {
                    try {
                        $nact = $noticeAct->asActivity($this->user->getProfile());
                        if ($format == Feed::ATOM) {
                            $nact->outputTo($this, false, false);
                        } else {
                            if ($haveOne) {
                                fwrite($handle, ",");
                            }
                            fwrite($handle, json_encode($nact->asArray()));
                            $haveOne = true;
                        }
                    } catch (Exception $e) {
                        common_log(LOG_ERR, $e->getMessage());
                        continue;
                    }
                }
            } catch (Exception $e) {
                common_log(LOG_ERR, $e->getMessage());
            }
        }

        if (empty($this->after) || strtotime($this->user->created) > $this->after) {
            // We always add the registration activity at the end, even if
            // they have older activities (from restored backups) in their stream.

            try {
                $ract = $this->user->registrationActivity();
                if ($format == Feed::ATOM) {
                    $ract->outputTo($this, false, false);
                } else {
                    if ($haveOne) {
                        fwrite($handle, ",");
                    }
                    fwrite($handle, json_encode($ract->asArray()));
                    $haveOne = true;
                }
            } catch (Exception $e) {
                common_log(LOG_ERR, $e->getMessage());
                continue;
            }
        }
    }

    function compareObject($a, $b)
    {
        $ac = strtotime((empty($a->created)) ? $a->modified : $a->created);
        $bc = strtotime((empty($b->created)) ? $b->modified : $b->created);

        return (($ac == $bc) ? 0 : (($ac < $bc) ? 1 : -1));
    }

    function getSubscriptions()
    {
        $subs = array();

        $sub = new Subscription();

        $sub->subscriber = $this->user->id;

        if (!empty($this->after)) {
            $sub->whereAdd("created > '" . common_sql_date($this->after) . "'");
        }

        if ($sub->find()) {
            while ($sub->fetch()) {
                if ($sub->subscribed != $this->user->id) {
                    $subs[] = clone($sub);
                }
            }
        }

        return $subs;
    }

    function getSubscribers()
    {
        $subs = array();

        $sub = new Subscription();

        $sub->subscribed = $this->user->id;

        if (!empty($this->after)) {
            $sub->whereAdd("created > '" . common_sql_date($this->after) . "'");
        }

        if ($sub->find()) {
            while ($sub->fetch()) {
                if ($sub->subscriber != $this->user->id) {
                    $subs[] = clone($sub);
                }
            }
        }

        return $subs;
    }

    /**
     *
     * @param int $start unix timestamp for earliest
     * @param int $end unix timestamp for latest
     * @return array of Notice objects
     */
    function getNoticesBetween($start=0, $end=0)
    {
        $notices = array();

        $notice = new Notice();

        $notice->profile_id = $this->user->id;

        // Only stuff after $this->after

        if (!empty($this->after)) {
            if ($start) {
                $start = max($start, $this->after);
            }
            if ($end) {
                $end = max($end, $this->after);
            }
        }

        if ($start) {
            $tsstart = common_sql_date($start);
            $notice->whereAdd("created >= '$tsstart'");
        }
        if ($end) {
            $tsend = common_sql_date($end);
            $notice->whereAdd("created < '$tsend'");
        }

        $notice->orderBy('created DESC');

        if ($notice->find()) {
            while ($notice->fetch()) {
                $notices[] = clone($notice);
            }
        }

        return $notices;
    }

    function getNotices()
    {
        if (!empty($this->after)) {
            return $this->getNoticesBetween($this->after);
        } else {
            return $this->getNoticesBetween();
        }
    }

    function getGroups()
    {
        $groups = array();

        $gm = new Group_member();

        $gm->profile_id = $this->user->id;

        if (!empty($this->after)) {
            $gm->whereAdd("created > '" . common_sql_date($this->after) . "'");
        }

        if ($gm->find()) {
            while ($gm->fetch()) {
                $groups[] = clone($gm);
            }
        }

        return $groups;
    }

    function createdAfter($item) {
        $created = strtotime((empty($item->created)) ? $item->modified : $item->created);
        return ($created >= $this->after);
    }

    function writeJSON($handle)
    {
        require_once INSTALLDIR.'/lib/activitystreamjsondocument.php';
        fwrite($handle, '{"items": [');
        $this->renderEntries(Feed::JSON, $handle);
        fwrite($handle, ']}');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Class for an exception when the user profile is missing
 *
 * 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  Exception
 * @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('GNUSOCIAL')) { exit(1); }

/**
 * Class for an exception when the user profile is missing
 *
 * @category Exception
 * @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 UserNoProfileException extends NoProfileException
{
    protected $user = null;

    /**
     * constructor
     *
     * @param User $user User that's missing a profile
     */

    public function __construct(User $user)
    {
        $this->user = $user;

        // TRANS: Exception text shown when no profile can be found for a user.
        // TRANS: %1$s is a user nickname, $2$d is a user ID (number).
        $message = sprintf(_('User %1$s (%2$d) has no profile record.'),
                           $user->nickname, $user->id);

        parent::__construct($user->id, $message);
    }

    /**
     * Accessor for user
     *
     * @return User the user that triggered this exception
     */

    public function getUser()
    {
        return $this->user;
    }
}

repo_name: dansup/gnu

license: mit


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * UUID generation
 *
 * 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  UUID
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 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);
}

/**
 * UUID generation
 *
 * @category  General
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class UUID
{
    const REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
    protected $str = null;

    /**
     * Constructor for a UUID
     *
     * Uses gen() to create a new UUID
     */

    function __construct()
    {
        $this->str = self::gen();
    }

    /**
     * For serializing to a string
     *
     * @return string version of self
     */

    function __toString()
    {
        return $this->str;
    }

    /**
     * For serializing to a string
     *
     * @return string version of self
     */

    function getString()
    {
        return $this->str;
    }

    /**
     * Generate a new UUID
     *
     * @return 36-char v4 (random-ish) UUID
     */

    static function gen()
    {
        return sprintf('%s-%s-%04x-%04x-%s',
                       // 32 bits for "time_low"
                       common_random_hexstr(4),
                       // 16 bits for "time_mid"
                       common_random_hexstr(2),
                       // 16 bits for "time_hi_and_version",
                       // four most significant bits holds version number 4
                       (hexdec(common_random_hexstr(2)) & 0x0fff) | 0x4000,
                       // 16 bits, 8 bits for "clk_seq_hi_res",
                       // 8 bits for "clk_seq_low",
                       // two most significant bits holds zero and one
                       // for variant DCE1.1
                       (hexdec(common_random_hexstr(2)) & 0x3fff) | 0x8000,
                       // 48 bits for "node"
                       common_random_hexstr(6));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for deleting things
 *
 * 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  Personal
 * @package   StatusNet
 * @author    Zach Copley <zach@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);
}

class WebColor {
    // XXX: Maybe make getters and setters for r,g,b values and tuples,
    // e.g.: to support this kinda CSS representation: rgb(255,0,0)
    // http://www.w3.org/TR/CSS21/syndata.html#color-units

    var $red   = 0;
    var $green = 0;
    var $blue  = 0;

    /**
     * Constructor
     *
     * @return nothing
     */
    function __construct($color = null)
    {
        if (isset($color)) {
            $this->parseColor($color);
        }
    }

    /**
     * Parses input to and tries to determine whether the color
     * is being specified via an integer or hex tuple and sets
     * the RGB instance variables accordingly.
     *
     * XXX: Maybe support (r,g,b) style, and array?
     *
     * @param mixed $color
     *
     * @return nothing
     */
    function parseColor($color) {

        if (is_numeric($color)) {
            $this->setIntColor($color);
        } else {

            // XXX named colors

            // XXX: probably should do even more validation

            if (preg_match('/(#([0-9A-Fa-f]{3,6})\b)/u', $color) > 0) {
                $this->setHexColor($color);
            } else {
                // TRANS: Web color exception thrown when a hexadecimal color code does not validate.
                // TRANS: %s is the provided (invalid) color code.
                $errmsg = _('%s is not a valid color! Use 3 or 6 hex characters.');
                throw new WebColorException(sprintf($errmsg, $color));
            }
        }
    }

    /**
     * @param string $name
     *
     * @return nothing
     */
    function setNamedColor($name)
    {
        // XXX Implement this
    }

    /**
     * Sets the RGB color values from a a hex tuple
     *
     * @param string $hexcolor
     *
     * @return nothing
     */
    function setHexColor($hexcolor) {

        if ($hexcolor[0] == '#') {
            $hexcolor = substr($hexcolor, 1);
        }

        if (strlen($hexcolor) == 6) {
            list($r, $g, $b) = array($hexcolor[0].$hexcolor[1],
                                     $hexcolor[2].$hexcolor[3],
                                     $hexcolor[4].$hexcolor[5]);
        } elseif (strlen($hexcolor) == 3) {
            list($r, $g, $b) = array($hexcolor[0].$hexcolor[0],
                                     $hexcolor[1].$hexcolor[1],
                                     $hexcolor[2].$hexcolor[2]);
        } else {
            // TRANS: Web color exception thrown when a hexadecimal color code does not validate.
            // TRANS: %s is the provided (invalid) color code.
            $errmsg = _('%s is not a valid color! Use 3 or 6 hex characters.');
            throw new WebColorException(sprintf($errmsg, $hexcolor));
        }

        $this->red   = hexdec($r);
        $this->green = hexdec($g);
        $this->blue  = hexdec($b);

    }

    /**
     * Sets the RGB color values from a 24-bit integer
     *
     * @param int $intcolor
     *
     * @return nothing
     */
    function setIntColor($intcolor)
    {
        // We could do 32 bit and have an alpha channel because
        // Sarven wants one real bad, but nah.

        $this->red   = $intcolor >> 16;
        $this->green = $intcolor >> 8 & 0xFF;
        $this->blue  = $intcolor & 0xFF;

    }

    /**
     * Returns a hex tuple of the RGB color useful for output in HTML
     *
     * @return string
     */
    function hexValue() {

        $hexcolor  = (strlen(dechex($this->red)) < 2 ? '0' : '' ) .
            dechex($this->red);
        $hexcolor .= (strlen(dechex($this->green)) < 2 ? '0' : '') .
            dechex($this->green);
        $hexcolor .= (strlen(dechex($this->blue)) < 2 ? '0' : '') .
            dechex($this->blue);

        return strtoupper($hexcolor);
    }

    /**
     * Returns a 24-bit packed integer representation of the RGB color
     * for convenient storage in the DB
     *
     * XXX: probably could just use hexdec() instead
     *
     * @return int
     */
    function intValue()
    {
        $intcolor = 256 * 256 * $this->red + 256 * $this->green + $this->blue;
        return $intcolor;
    }

}

class WebColorException extends Exception
{
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for UI widgets
 *
 * 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>
 * @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); }

/**
 * Base class for UI widgets
 *
 * A widget is a cluster of HTML elements that provide some functionality
 * that's used on different parts of the site. Examples would be profile
 * lists, notice lists, navigation menus (tabsets) and common forms.
 *
 * @category Widget
 * @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 Widget
{
    protected $avatarSize = AVATAR_STREAM_SIZE;

    /**
     * Action (HTMLOutputter) to use for output
     */

    var $out = null;

    /**
     * Prepare the widget for use
     *
     * @param Action $out output helper, defaults to null
     */

    function __construct(Action $out=null, array $widgetOpts=array())
    {
        $this->out = $out;
        if (!array_key_exists('scoped', $widgetOpts)) {
            $this->widgetOpts['scoped'] = Profile::current();
        }
        $this->scoped = $this->widgetOpts['scoped'];
    }

    /**
     * Show the widget
     *
     * Emit the HTML for the widget, using the configured outputter.
     *
     * @return void
     */

    function show()
    {
    }

    /**
     * Get HTMLOutputter
     *
     * Return the HTMLOutputter for the widget.
     *
     * @return HTMLOutputter the output helper
     */

    function getOut()
    {
        return $this->out;
    }

    /**
     * Delegate output methods to the outputter attribute.
     *
     * @param string $name      Name of the method
     * @param array  $arguments Arguments called
     *
     * @return mixed Return value of the method.
     */
    function __call($name, $arguments)
    {
        return call_user_func_array(array($this->out, $name), $arguments);
    }

    /**
     * Default avatar size for this widget.
     */
    public function avatarSize()
    {
        return $this->avatarSize;
    }

    protected function showAvatar(Profile $profile, $size=null)
    {
        $avatar_url = $profile->avatarUrl($size ?: $this->avatarSize());
        $this->out->element('img', array('src' => $avatar_url,
                                         'class' => 'avatar u-photo',
                                         'width' => $this->avatarSize(),
                                         'height' => $this->avatarSize(),
                                         'alt' => $profile->getBestName()));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Low-level generator for XML
 *
 * 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  Output
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008 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);
}

/**
 * Low-level generator for XML
 *
 * This is a thin wrapper around PHP's XMLWriter. The main
 * advantage is the element() method, which simplifies outputting
 * an element.
 *
 * @category Output
 * @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      Action
 * @see      HTMLOutputter
 */

class XMLOutputter
{
    /**
     * Wrapped XMLWriter object, which does most of the heavy lifting
     * for output.
     */

    var $xw = null;

    /**
     * Constructor
     *
     * Initializes the wrapped XMLWriter.
     *
     * @param string  $output URL for outputting, if null it defaults to stdout ('php://output')
     * @param boolean $indent Whether to indent output, default true
     */

    function __construct($output=null, $indent=null)
    {
        if (is_null($output)) {
            $output = 'php://output';
        }
        $this->xw = new XMLWriter();
        $this->xw->openURI($output);
        if(is_null($indent)) {
            $indent = common_config('site', 'indent');
        }
        $this->xw->setIndent($indent);
    }

    /**
     * Start a new XML document
     *
     * @param string $doc    document element
     * @param string $public public identifier
     * @param string $system system identifier
     *
     * @return void
     */

    function startXML($doc=null, $public=null, $system=null)
    {
        $this->xw->startDocument('1.0', 'UTF-8');
        if ($doc) {
            $this->xw->writeDTD($doc, $public, $system);
        }
    }

    /**
     * finish an XML document
     *
     * It's probably a bad idea to continue to use this object
     * after calling endXML().
     *
     * @return void
     */

    function endXML()
    {
        $this->xw->endDocument();
        $this->xw->flush();
    }

    /**
     * output an XML element
     *
     * Utility for outputting an XML element. A convenient wrapper
     * for a bunch of longer XMLWriter calls. This is best for
     * when an element doesn't have any sub-elements; if that's the
     * case, use elementStart() and elementEnd() instead.
     *
     * The $content element will be escaped for XML. If you need
     * raw output, use elementStart() and elementEnd() with a call
     * to raw() in the middle.
     *
     * If $attrs is a string instead of an array, it will be treated
     * as the class attribute of the element.
     *
     * @param string $tag     Element type or tagname
     * @param array  $attrs   Array of element attributes, as
     *                        key-value pairs
     * @param string $content string content of the element
     *
     * @return void
     */

    function element($tag, $attrs=null, $content=null)
    {
        $this->elementStart($tag, $attrs);
        if (!is_null($content)) {
            $this->xw->text($content);
        }
        $this->elementEnd($tag);
    }

    function elementNS(array $ns, $tag, $attrs=null, $content=null)
    {
        $this->elementStartNS($ns, $tag, $attrs);
        if (!is_null($content)) {
            $this->xw->text($content);
        }
        $this->elementEnd($tag);
    }

    /**
     * output a start tag for an element
     *
     * Mostly used for when an element has content that's
     * not a simple string.
     *
     * If $attrs is a string instead of an array, it will be treated
     * as the class attribute of the element.
     *
     * @param string $tag   Element type or tagname
     * @param array  $attrs Array of element attributes
     *
     * @return void
     */

    function elementStart($tag, $attrs=null)
    {
        $this->xw->startElement($tag);
        if (is_array($attrs)) {
            foreach ($attrs as $name => $value) {
                $this->xw->writeAttribute($name, $value);
            }
        } else if (is_string($attrs)) {
            $this->xw->writeAttribute('class', $attrs);
        }
    }

    function elementStartNS(array $ns, $tag, $attrs=null)
    {
        reset($ns); // array pointer to 0
        $uri = key($ns);
        $this->xw->startElementNS($ns[$uri], $tag, $uri);
        if (is_array($attrs)) {
            foreach ($attrs as $name => $value) {
                $this->xw->writeAttribute($name, $value);
            }
        } else if (is_string($attrs)) {
            $this->xw->writeAttribute('class', $attrs);
        }
    }

    /**
     * output an end tag for an element
     *
     * Used in conjunction with elementStart(). $tag param
     * should match the elementStart() param.
     *
     * For HTML 4 compatibility, this method will force
     * a full end element (</tag>) even if the element is
     * empty, except for a handful of exception tagnames.
     * This is a hack.
     *
     * @param string $tag Element type or tagname.
     *
     * @return void
     */

    function elementEnd($tag)
    {
        static $empty_tag = array('base', 'meta', 'link', 'hr',
                                  'br', 'param', 'img', 'area',
                                  'input', 'col', 'source');
        // XXX: check namespace
        if (in_array($tag, $empty_tag)) {
            $this->xw->endElement();
        } else {
            $this->xw->fullEndElement();
        }
    }

    /**
     * output plain text
     *
     * Text will be escaped. If you need it not to be,
     * use raw() instead.
     *
     * @param string $txt Text to output.
     *
     * @return void
     */

    function text($txt)
    {
        $this->xw->text($txt);
    }

    /**
     * output raw xml
     *
     * This will spit out its argument verbatim -- no escaping is
     * done.
     *
     * @param string $xml XML to output.
     *
     * @return void
     */

    function raw($xml)
    {
        $this->xw->writeRaw($xml);
    }

    /**
     * output a comment
     *
     * @param string $txt text of the comment
     *
     * @return void
     */

    function comment($txt)
    {
        $this->xw->writeComment($txt);
    }

    /**
     * Flush output buffers
     *
     * @return void
     */

    function flush()
    {
        $this->xw->flush();
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Generator for in-memory XML
 *
 * 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  Output
 * @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);
}

/**
 * Create in-memory XML
 *
 * @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/
 * @see      Action
 * @see      HTMLOutputter
 */

class XMLStringer extends XMLOutputter
{
    function __construct($indent=false)
    {
        $this->xw = new XMLWriter();
        $this->xw->openMemory();
        $this->xw->setIndent($indent);
    }

    function getString()
    {
        return $this->xw->outputMemory();
    }

    // utility for quickly creating XML-strings

    static function estring($tag, $attrs=null, $content=null)
    {
        $xs = new XMLStringer();
        $xs->element($tag, $attrs, $content);
        return $xs->getString();
    }
}


code:
# This is completely optional, but if you're running a site with
# ssl="always" configured, then you might as well redirect any of
# your stray HTTP visitors to HTTPS.
#
#$HTTP["scheme"] == "http" {
#  $HTTP["host"] =~ "^(social\.example\.com)$" {
#    url.redirect = ( "^\/?(.*)" => "https://%1/$1" )
#    server.name                 = "%1"
#  }
#}

# If you're using vhosts, you should have per-vhost server.document-root
#   settings too! Read how in the respective alternative vhost modules.
#$HTTP["host"] =~ "^social\.example\.com$" {

#    NOTE: configure fastcgi/cgi/fpm here if you're using per-user cgi/fpm
#    fastcgi.server += ( ".php" =>
#      ( "localhost" => (
#        "host" => "127.0.0.1",
#        "port" => "9000"
#      ))
#    )

    dir-listing.activate = "disable"

# Make sure "mod_rewrite" is enabled in server.modules
    url.rewrite-if-not-file = ( "^/(.*)$" => "/index.php/$1" )
#}


code:
# Warning: do not transform tabs to spaces in this file.

all : translations

trans = $(patsubst %.po,%.mo,$(wildcard */LC_MESSAGES/statusnet.po))

translations : $(trans)

clean :
	rm -f $(trans)

%.mo : %.po
	msgfmt -o $@ $<

path: locale/Makefile


code:
Localizations for StatusNet are being maintained through TranslateWiki:
http://translatewiki.net/wiki/Translating:StatusNet

Ongoing translation work should be done there to ensure updates are
integrated into future versions of StatusNet.

== Building runtime translations ==

If you are working with a direct git checkout or have customized any
message files, you will need to build binary .mo files from the .po
source files for translations to work in the web app.

If gettext and GNU make are installed, you can simply run 'make' in the
main StatusNet directory, and all core and plugin localizations will be
recompiled.

== Customization ==

User interface texts in any language can be customized by editing the
texts in the .po source files, then rebuilding the binary .mo files
used at runtime.

The default/US English texts can be overridden by adding "translations"
to en/LC_MESSAGES/statusnet.po.

Note that texts you change in one language will not affect other
languages, which are selected based on visitors' browser preferences.
If you customizations include important information or links,
you may wish to disable languages that you haven't customized so that
visitors always get your text.

To disable all non-English languages add this to your config.php (you
will need to edit both the en and en_GB files):

$config['site']['languages'] = array(
        'en-us'   => array('q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'),
        'en-gb'   => array('q' => 1, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'),
        'en'      => array('q' => 1, 'lang' => 'en',    'name' => 'English (US)', 'direction' => 'ltr'),
);

To disable everything including British English variant:

$config['site']['languages'] = array(
        'en'      => array('q' => 1, 'lang' => 'en',    'name' => 'English', 'direction' => 'ltr'),
);

== Plugins ==

This locale directory contains translations for the core StatusNet
software only. Plugins may have their own locale subdirectories and
their own .po and .mo files as well, so if customizing you may need
to poke at those as well.

path: locale/README