code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Extra level of caching, in memory
 *
 * 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  Cache
 * @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);
}

/**
 * Extra level of caching
 *
 * This plugin adds an extra level of in-process caching to any regular
 * cache system like APC, XCache, or Memcache.
 *
 * Note that since most caching plugins return false for StartCache*
 * methods, you should add this plugin before them, i.e.
 *
 *     addPlugin('InProcessCache');
 *     addPlugin('XCache');
 *
 * @category  Cache
 * @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 InProcessCachePlugin extends Plugin
{
    private $_items = array();
    private $_hits  = array();
    private $active;

    /**
     * Constructor checks if it's safe to use the in-process cache.
     * On CLI scripts, we'll disable ourselves to avoid data corruption
     * due to keeping stale data around.
     *
     * On web requests we'll roll the dice; they're short-lived so have
     * less chance of stale data. Race conditions are still possible,
     * so beware!
     */
    function __construct()
    {
        parent::__construct();
        $this->active = (PHP_SAPI != 'cli');
    }

    /**
     * Get an item from the cache
     *
     * Called before other cache systems are called (iif this
     * plugin was loaded correctly, see class comment). If we
     * have the data, return it, and don't hit the other cache
     * systems.
     *
     * @param string &$key   Key to fetch
     * @param mixed  &$value Resulting value or false for miss
     *
     * @return boolean false if found, else true
     */
    function onStartCacheGet(&$key, &$value)
    {
        if ($this->active && array_key_exists($key, $this->_items)) {
            $value = $this->_items[$key];
            if (array_key_exists($key, $this->_hits)) {
                $this->_hits[$key]++;
            } else {
                $this->_hits[$key] = 1;
            }
            Event::handle('EndCacheGet', array($key, &$value));
            return false;
        }
        return true;
    }

    /**
     * Called at the end of a cache get
     *
     * If we don't already have the data, we cache it. This
     * keeps us from having to call the external cache if the
     * key is requested again.
     *
     * @param string $key    Key to fetch
     * @param mixed  &$value Resulting value or false for miss
     *
     * @return boolean hook value, true
     */
    function onEndCacheGet($key, &$value)
    {
        if ($this->active && (!array_key_exists($key, $this->_items) ||
            $this->_items[$key] != $value)) {
            $this->_items[$key] = $value;
        }
        return true;
    }

    /**
     * Called at the end of setting a cache element
     *
     * Always set the cache element; may overwrite existing
     * data.
     *
     * @param string  $key    Key to fetch
     * @param mixed   $value  Resulting value or false for miss
     * @param integer $flag   ignored
     * @param integer $expiry ignored
     *
     * @return boolean true
     */
    function onEndCacheSet($key, $value, $flag, $expiry)
    {
        if ($this->active) {
            $this->_items[$key] = $value;
        }
        return true;
    }

    /**
     * Called at the end of deleting a cache element
     *
     * If stuff's deleted from the other cache, we
     * delete it too.
     *
     * @param string  &$key     Key to delete
     * @param boolean &$success Success flag; ignored
     *
     * @return boolean true
     */
    function onStartCacheDelete(&$key, &$success)
    {
        if ($this->active && array_key_exists($key, $this->_items)) {
            unset($this->_items[$key]);
        }
        return true;
    }

    /**
     * Version info
     *
     * @param array &$versions Array of version blocks
     *
     * @return boolean true
     */
    function onPluginVersion(&$versions)
    {
        $url = 'http://status.net/wiki/Plugin:InProcessCache';

        $versions[] = array('name' => 'InProcessCache',
                            'version' => GNUSOCIAL_VERSION,
                            'author' => 'Evan Prodromou',
                            'homepage' => $url,
                            'description' =>
                            // TRANS: Plugin dscription.
                            _m('Additional in-process cache for plugins.'));
        return true;
    }

    /**
     * Cleanup function; called at end of process
     *
     * If the inprocess/stats config value is true, we dump
     * stats to the log file
     *
     * @return boolean true
     */
    function cleanup()
    {
        if ($this->active && common_config('inprocess', 'stats')) {
            $this->log(LOG_INFO, "cache size: " .
                       count($this->_items));
            $sum = 0;
            foreach ($this->_hits as $hitcount) {
                $sum += $hitcount;
            }
            $this->log(LOG_INFO, $sum . " hits on " .
                       count($this->_hits) . " keys");
        }
        return true;
    }
}


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Plugin dscription.
#: InProcessCachePlugin.php:183
msgid "Additional in-process cache for plugins."
msgstr ""

license: mit


code:
# Translation of StatusNet - InProcessCache to German (Deutsch)
# Exported from translatewiki.net
#
# Author: Fujnky
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: German <https://translatewiki.net/wiki/Portal:de>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: de\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Zusätzlicher in-Prozess-Cache für Plugins."


code:
# Translation of StatusNet - InProcessCache to Spanish (español)
# Exported from translatewiki.net
#
# Author: Armando-Martin
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Memoria caché adicional para los complementos (plugins)."


code:
# Translation of StatusNet - InProcessCache to Basque (euskara)
# Exported from translatewiki.net
#
# Author: Artsuaga
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Pluginentzako katxe memoria gehigarria."


code:
# Translation of StatusNet - InProcessCache to French (français)
# Exported from translatewiki.net
#
# Author: Sherbrooke
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: French <https://translatewiki.net/wiki/Portal:fr>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: fr\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Ajout de cache servant au traitement interne pour les plugins"


code:
# Translation of StatusNet - InProcessCache to Galician (galego)
# Exported from translatewiki.net
#
# Author: Toliño
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Galician <https://translatewiki.net/wiki/Portal:gl>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: gl\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Memoria caché adicional para os complementos."


code:
# Translation of StatusNet - InProcessCache to Hebrew (עברית)
# Exported from translatewiki.net
#
# Author: Amire80
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Hebrew <https://translatewiki.net/wiki/Portal:he>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: he\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "מטמון תוך־תהליכי נוסף לתוספים."


code:
# Translation of StatusNet - InProcessCache to Interlingua (interlingua)
# Exported from translatewiki.net
#
# Author: McDutchie
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Interlingua <https://translatewiki.net/wiki/Portal:ia>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: ia\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Un cache in-processo additional pro plug-ins."


code:
# Translation of StatusNet - InProcessCache to Italian (italiano)
# Exported from translatewiki.net
#
# Author: Ximo17
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Ulteriore cache in-process per i plugin."


code:
# Translation of StatusNet - InProcessCache to Macedonian (македонски)
# Exported from translatewiki.net
#
# Author: Bjankuloski06
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Macedonian <https://translatewiki.net/wiki/Portal:mk>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: mk\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n == 1 || n%10 == 1) ? 0 : 1;\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Дополнителни приклучоци за кеш во текот на работата."


code:
# Translation of StatusNet - InProcessCache to Dutch (Nederlands)
# Exported from translatewiki.net
#
# Author: Siebrand
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Dutch <https://translatewiki.net/wiki/Portal:nl>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: nl\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Extra in-procescache voor plug-ins."


code:
# Translation of StatusNet - InProcessCache to Portuguese (português)
# Exported from translatewiki.net
#
# Author: Waldir
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Portuguese <https://translatewiki.net/wiki/Portal:pt>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: pt\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Cache de processo adicional para plug-ins."


code:
# Translation of StatusNet - InProcessCache to Russian (русский)
# Exported from translatewiki.net
#
# Author: Александр Сигачёв
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Russian <https://translatewiki.net/wiki/Portal:ru>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: ru\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=3; plural=(n%10 == 1 && n%100 != 11) ? 0 : ( (n%10 >= "
"2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)) ? 1 : 2 );\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Дополнительный внутрипроцессный кэш для плагинов."


code:
# Translation of StatusNet - InProcessCache to Tagalog (Tagalog)
# Exported from translatewiki.net
#
# Author: AnakngAraw
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:53+0000\n"
"Language-Team: Tagalog <https://translatewiki.net/wiki/Portal:tl>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: tl\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Karagdagang taguang isinisagawa para sa mga pampasak."


code:
# Translation of StatusNet - InProcessCache to Ukrainian (українська)
# Exported from translatewiki.net
#
# Author: Boogie
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:54+0000\n"
"Language-Team: Ukrainian <https://translatewiki.net/wiki/Portal:uk>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: uk\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=3; plural=(n%10 == 1 && n%100 != 11) ? 0 : ( (n%10 >= "
"2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)) ? 1 : 2 );\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "Додатковий «кеш-в-процесі» для додатків."


code:
# Translation of StatusNet - InProcessCache to Simplified Chinese (中文（简体）)
# Exported from translatewiki.net
#
# Author: Hydra
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InProcessCache\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:54+0000\n"
"Language-Team: Simplified Chinese <https://translatewiki.net/wiki/Portal:zh-"
"hans>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:22+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: zh-hans\n"
"X-Message-Group: #out-statusnet-plugin-inprocesscache\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin dscription.
msgid "Additional in-process cache for plugins."
msgstr "其他过程中缓存的插件。"


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Plugin to enable Infinite Scrolling
 *
 * 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  Plugin
 * @package   StatusNet
 * @author    Craig Andrews <candrews@integralblue.com>
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @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 InfiniteScrollPlugin extends Plugin
{

    public $on_next_only = false;

    function __construct()
    {
        parent::__construct();
    }

    function onEndShowScripts($action)
    {
        $action->inlineScript('var infinite_scroll_on_next_only = ' . ($this->on_next_only?'true':'false') . ';');
        $action->inlineScript('var ajax_loader_url = "' . ($this->path('ajax-loader.gif')) . '";');
        $action->script($this->path('jquery.infinitescroll.js'));
        $action->script($this->path('infinitescroll.js'));
    }

    function onPluginVersion(&$versions)
    {
        $versions[] = array('name' => 'InfiniteScroll',
                            'version' => GNUSOCIAL_VERSION,
                            'author' => 'Craig Andrews',
                            'homepage' => 'http://status.net/wiki/Plugin:InfiniteScroll',
                            'rawdescription' =>
                            // TRANS: Plugin dscription.
                            _m('Infinite Scroll adds the following functionality to your StatusNet installation: When a user scrolls towards the bottom of the page, the next page of notices is automatically retrieved and appended. This means they never need to click "Next Page", which dramatically increases stickiness.'));
        return true;
    }
}


code:
Infinite Scroll adds the following functionality to your StatusNet installation:
When a user scrolls towards the bottom of the page, the next page of notices is
automatically retrieved and appended. This means they never need to click "Next
Page", which dramatically increases stickiness.

Note that there is a configuration option to make it so that the plugin doesn't
trigger when the user approaches the bottom of the page, but instead triggers
when the "next" button is clicked.

Installation
============
Add "addPlugin('InfiniteScroll',
    array('setting'=>'value', 'setting2'=>'value2', ...);"
to the bottom of your config.php

Settings
========
on_next_only (false): trigger infinite scroll when the next button is clicked.
Note that this means you really don't have "infinite scrolling" as the trigger
is clicking, not scrolling.

Example
=======
addPlugin('InfiniteScroll', array(
    'on_next_only'=>false
));

path: plugins/InfiniteScroll/README


code:
// notices
jQuery(document).ready(function($){
  $('notices_primary').infinitescroll({
    debug: false,
    infiniteScroll  : !infinite_scroll_on_next_only,
    nextSelector    : 'body#public li.nav_next a,'+
                      'body#all li.nav_next a,'+
                      'body#showstream li.nav_next a,'+
                      'body#replies li.nav_next a,'+
                      'body#showfavorites li.nav_next a,'+
                      'body#showgroup li.nav_next a,'+
                      'body#favorited li.nav_next a',
    loadingImg      : ajax_loader_url,
    text            : "Loading the next set of posts...",
    donetext        : "Congratulations, you\'ve reached the end of the Internet.",
    navSelector     : "#pagination",
    contentSelector : "#notices_primary ol.notices",
    itemSelector    : "#notices_primary ol.notices > li"
    },function(){
        // Reply button and attachment magic need to be set up
        // for each new notice.
        // DO NOT run SN.Init.Notices() which will duplicate stuff.
        $(this).find('.notice').each(function() {
            SN.U.NoticeReplyTo($(this));
            SN.U.NoticeWithAttachment($(this));
        });

        // moving the loaded notices out of their container
		$('#infscr-loading').remove();
		var ids_to_append = Array(); var i=0;
		$.each($('.infscr-pages').children('.notice'),function(){

			// remove dupes
			if($('.threaded-notices > #' + $(this).attr('id')).length > 0) {
				$(this).remove();
				}

			// keep new unique notices
			else {
				ids_to_append[i] = $(this).attr('id');
				i++;
				}
			});
		var loaded_html = $('.infscr-pages').html();
		$('.infscr-pages').remove();

		// no results
		if(loaded_html == '') {
			}
		// append
		else {
			$('#notices_primary ol.notices').append(loaded_html);
			}

    });
});

// users
jQuery(document).ready(function($){
  $('profile_list').infinitescroll({
    debug: false,
    infiniteScroll  : !infinite_scroll_on_next_only,
    nextSelector    : 'body#subscribers li.nav_next a, body#subscriptions li.nav_next a',
    loadingImg      : ajax_loader_url,
    text            : "Loading the next set of users...",
    donetext        : "Congratulations, you\'ve reached the end of the Internet.",
    navSelector     : "#pagination",
    contentSelector : "#content_inner ul.profile_list",
    itemSelector    : "#content_inner ul.profile_list > li"
    },function(){
        // Reply button and attachment magic need to be set up
        // for each new notice.
        // DO NOT run SN.Init.Notices() which will duplicate stuff.
        $(this).find('.profile').each(function() {
            SN.U.NoticeReplyTo($(this));
            SN.U.NoticeWithAttachment($(this));
        });

        // moving the loaded notices out of their container
		$('#infscr-loading').remove();
		var ids_to_append = Array(); var i=0;
		$.each($('.infscr-pages').children('.profile'),function(){

			// remove dupes
			if($('.profile_list > #' + $(this).attr('id')).length > 0) {
				$(this).remove();
				}

			// keep new unique notices
			else {
				ids_to_append[i] = $(this).attr('id');
				i++;
				}
			});
		var loaded_html = $('.infscr-pages').html();
		$('.infscr-pages').remove();

		// no results
		if(loaded_html == '') {
			}
		// append
		else {
			$('#content_inner ul.profile_list').append(loaded_html);
			}

    });
});

// user directory
jQuery(document).ready(function($){
  $('profile_list').infinitescroll({
    debug: false,
    infiniteScroll  : !infinite_scroll_on_next_only,
    nextSelector    : 'body#userdirectory li.nav_next a',
    loadingImg      : ajax_loader_url,
    text            : "Loading the next set of users...",
    donetext        : "Congratulations, you\'ve reached the end of the Internet.",
    navSelector     : "#pagination",
    contentSelector : "#profile_directory table.profile_list tbody",
    itemSelector    : "#profile_directory table.profile_list tbody tr"
    },function(){
        // Reply button and attachment magic need to be set up
        // for each new notice.
        // DO NOT run SN.Init.Notices() which will duplicate stuff.
        $(this).find('.profile').each(function() {
            SN.U.NoticeReplyTo($(this));
            SN.U.NoticeWithAttachment($(this));
        });

        // moving the loaded notices out of their container
		$('#infscr-loading').remove();
		var ids_to_append = Array(); var i=0;
		$.each($('.infscr-pages').children('.profile'),function(){

			// remove dupes
			if($('.profile_list > #' + $(this).attr('id')).length > 0) {
				$(this).remove();
				}

			// keep new unique notices
			else {
				ids_to_append[i] = $(this).attr('id');
				i++;
				}
			});
		var loaded_html = $('.infscr-pages').html();
		$('.infscr-pages').remove();

		// no results
		if(loaded_html == '') {
			}
		// append
		else {
			$('#profile_directory table.profile_list tbody').append(loaded_html);
			}

    });
});


code:
/*!
// Infinite Scroll jQuery plugin
// copyright Paul Irish, licensed GPL & MIT
// version 1.2.090804

// home and docs: http://www.infinite-scroll.com
*/

// todo: add preloading option.

;(function($){

  $.fn.infinitescroll = function(options,callback){

    // console log wrapper.
    function debug(){
      if (opts.debug) { window.console && console.log.call(console,arguments)}
    }

    // grab each selector option and see if any fail.
    function areSelectorsValid(opts){
      for (var key in opts){
        if (key.indexOf && (key.indexOf('Selector') != -1) && $(opts[key]).length === 0){
            debug('Your ' + key + ' found no elements.');
            return false;
        }
        return true;
      }
    }

    // find the number to increment in the path.
    function determinePath(path){

      path.match(relurl) ? path.match(relurl)[2] : path;

      // there is a 2 in the url surrounded by slashes, e.g. /page/2/
      if ( path.match(/^(.*?)\b2\b(.*?$)/) ){
          path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
      } else
        // if there is any 2 in the url at all.
        if (path.match(/^(.*?)2(.*?$)/)){
          debug('Trying backup next selector parse technique. Treacherous waters here, matey.');
          path = path.match(/^(.*?)2(.*?$)/).slice(1);
      } else {
        debug('Sorry, we couldn\'t parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.');
        props.isInvalidPage = true;  //prevent it from running on this page.
      }

      return path;
    }

    // 'document' means the full document usually, but sometimes the content of the overflow'd div in local mode
    function getDocumentHeight(){
      // weird doubletouch of scrollheight because http://soulpass.com/2006/07/24/ie-and-scrollheight/
      return opts.localMode ? ($(props.container)[0].scrollHeight && $(props.container)[0].scrollHeight)
                                // needs to be document's height. (not props.container's) html's height is wrong in IE.
                                : $(document).height()
    }

    function isNearBottom(opts,props){

      // distance remaining in the scroll
      // computed as: document height - distance already scroll - viewport height - buffer
      var pixelsFromWindowBottomToBottom = getDocumentHeight()  -
                                            (opts.localMode ? $(props.container).scrollTop() :
                                              // have to do this bs because safari doesnt report a scrollTop on the html element
                                              ($(props.container).scrollTop() || $(props.container.ownerDocument.body).scrollTop())) -
                                            $(opts.localMode ? props.container : window).height();

      debug('math:',pixelsFromWindowBottomToBottom, props.pixelsFromNavToBottom);

      // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
      return (pixelsFromWindowBottomToBottom  - opts.bufferPx < props.pixelsFromNavToBottom);
    }

    function showDoneMsg(){
      props.loadingMsg
        .find('img').hide()
        .parent()
          .find('div').html(opts.donetext).animate({opacity: 1},2000).fadeOut('normal');

      // user provided callback when done
      opts.errorCallback();
    }

    function infscrSetup(path,opts,props,callback){

        if (props.isDuringAjax || props.isInvalidPage || props.isDone) return;

    		if ( opts.infiniteScroll && !isNearBottom(opts,props) ) return;

    		// we dont want to fire the ajax multiple times
    		props.isDuringAjax = true;

    		// show the loading message and hide the previous/next links
    		props.loadingMsg.appendTo( opts.contentSelector ).show();
    		if(opts.infiniteScroll) $( opts.navSelector ).hide();

    		// increment the URL bit. e.g. /page/3/
    		props.currPage++;

    		debug('heading into ajax',path);

    		// if we're dealing with a table we can't use DIVs
    		var box = $(opts.contentSelector).is('table') ? $('
') : $('
');

    		box
    		  .attr('id','infscr-page-'+props.currPage)
    		  .addClass('infscr-pages')
    		  .appendTo( opts.contentSelector )
    		  .load( path.join( props.currPage ) + ' ' + opts.itemSelector,null,function(){

    		        // if we've hit the last page...
    		        if (props.isDone){
                    showDoneMsg();
        			      return false;

  	            } else {

  	                // if it didn't return anything
  	                if (box.children().length == 0){
  	                  // fake an ajaxError so we can quit.
  	                  $.event.trigger( "ajaxError", [{status:404}] );
  	                }

  	                // fadeout currently makes the 'd text ugly in IE6
    		            props.loadingMsg.fadeOut('normal' );

    		            // smooth scroll to ease in the new content
    		            if (opts.animate){
      		            var scrollTo = $(window).scrollTop() + $('#infscr-loading').height() + opts.extraScrollPx + 'px';
                      $('html,body').animate({scrollTop: scrollTo}, 800,function(){ props.isDuringAjax = false; });
    		            }

                    // pass in the new DOM element as context for the callback
                    callback.call( box[0] );

    		            if (!opts.animate) props.isDuringAjax = false; // once the call is done, we can allow it again.
  	            }
    		    }); // end of load()

      }  // end of infscrSetup()

    // lets get started.

    var opts    = $.extend({}, $.infinitescroll.defaults, options);
    var props   = $.infinitescroll; // shorthand
    callback    = callback || function(){};

    if (!areSelectorsValid(opts)){ return false;  }

     // we doing this on an overflow:auto div?
    props.container   =  opts.localMode ? this : document.documentElement;

    // contentSelector we'll use for our .load()
    opts.contentSelector = opts.contentSelector || this;

    // get the relative URL - everything past the domain name.
    var relurl        = /(.*?\/\/).*?(\/.*)/;
    var path          = $(opts.nextSelector).attr('href');

    if (!path) { debug('Navigation selector not found'); return; }

    // set the path to be a relative URL from root.
    path          = determinePath(path);

    // reset scrollTop in case of page refresh:
    if (opts.localMode) $(props.container)[0].scrollTop = 0;

    // distance from nav links to bottom
    // computed as: height of the document + top offset of container - top offset of nav link
    props.pixelsFromNavToBottom =  getDocumentHeight()  +
                                     $(props.container).offset().top -
                                     $(opts.navSelector).offset().top;

    // define loading msg
    props.loadingMsg = $('

'+opts.loadingText+'

');
     // preload the image
    (new Image()).src    = opts.loadingImg;

    // set up our bindings
    $(document).ajaxError(function(e,xhr,opt){
      debug('Page not found. Self-destructing...');

      // die if we're out of pages.
      if (xhr.status == 404){
        showDoneMsg();
        props.isDone = true;
        $(opts.localMode ? this : window).unbind('scroll.infscr');
      }
    });

    if(opts.infiniteScroll){
      // bind scroll handler to element (if its a local scroll) or window
      $(opts.localMode ? this : window)
        .bind('scroll.infscr', function(){ infscrSetup(path,opts,props,callback); } )
        .trigger('scroll.infscr'); // trigger the event, in case it's a short page
    }else{
      $(opts.nextSelector).click(
        function(){
          infscrSetup(path,opts,props,callback);
          return false;
        }
      );
    }

    return this;

  }  // end of $.fn.infinitescroll()

  // options and read-only properties object

  $.infinitescroll = {
        defaults      : {
                          debug           : false,
                          infiniteScroll  : true,
                          preload         : false,
                          nextSelector    : "div.navigation a:first",
                          loadingImg      : "http://www.infinite-scroll.com/loading.gif",
                          loadingText     : "Loading the next set of posts...",
                          donetext        : "Congratulations, you've reached the end of the internet.",
                          navSelector     : "div.navigation",
                          contentSelector : null,           // not really a selector. :) it's whatever the method was called on..
                          extraScrollPx   : 150,
                          itemSelector    : "div.post",
                          animate         : false,
                          localMode      : false,
                          bufferPx        : 40,
                          errorCallback   : function(){}
                        },
        loadingImg    : undefined,
        loadingMsg    : undefined,
        container     : undefined,
        currPage      : 1,
        currDOMChunk  : null,  // defined in setup()'s load()
        isDuringAjax  : false,
        isInvalidPage : false,
        isDone        : false  // for when it goes all the way through the archive.
  };

})(jQuery);


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Plugin dscription.
#: InfiniteScrollPlugin.php:56
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""


code:
# Translation of StatusNet - InfiniteScroll to German (Deutsch)
# Exported from translatewiki.net
#
# Author: Fujnky
# Author: The Evil IP address
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: German <https://translatewiki.net/wiki/Portal:de>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: de\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll fügt die folgende Funktionalität zu deiner StatusNet-"
"Installation hinzu: Wenn ein Benutzer Richtung Seitenende scrollt, wird die "
"nächste Nachrichtenseite automatisch geladen und angefügt. Das bedeutet, "
"dass du nie „Nächste Seite“ klicken musst, was die Attraktivität dramatisch "
"erhöht."


code:
# Translation of StatusNet - InfiniteScroll to Spanish (español)
# Exported from translatewiki.net
#
# Author: Translationista
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: Spanish <https://translatewiki.net/wiki/Portal:es>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: es\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Desplazamiento Infinito añade la siguiente funcionalidad a tu instalación "
"StatusNet: Cuando un usuario se desplaza hacia el final de la página, la "
"próxima página de mensajes se recupera y añade automáticamente. Esto "
"significa que no será necesario hacer clic en \"Próxima página\", con lo que "
"se aumenta dramáticamente la capacidad de retención."


code:
# Translation of StatusNet - InfiniteScroll to Basque (euskara)
# Exported from translatewiki.net
#
# Author: Artsuaga
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: Basque <https://translatewiki.net/wiki/Portal:eu>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: eu\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll pluginak scrollarekin behera egin einean orria luzatzen du "
"ohar zaharrak azpikaldean gehituz, \"Hurrengo Orria\" linka ezabatzen du "
"aldi berean."


code:
# Translation of StatusNet - InfiniteScroll to French (français)
# Exported from translatewiki.net
#
# Author: Peter17
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: French <https://translatewiki.net/wiki/Portal:fr>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: fr\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"InfiniteScroll ajoute la fonctionnalité suivante à votre installation "
"StatusNet : lorsqu’un utilisateur fait défiler la page jusqu’à la fin, la "
"page d’avis suivante est automatiquement téléchargée et ajoutée à la suite. "
"Ceci signifie que l’utilisateur n’a plus besoin de cliquer sur le bouton « "
"Page suivante », ce qui augmente considérablement l’adhérence de "
"l’utilisateur."


code:
# Translation of StatusNet - InfiniteScroll to Galician (galego)
# Exported from translatewiki.net
#
# Author: Toliño
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: Galician <https://translatewiki.net/wiki/Portal:gl>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: gl\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll engade a seguinte funcionalizade á súa instalación de "
"StatusNet: Cando un usuario se despraza ata o pé da páxina, recupérase e "
"engádese a seguinte páxina de notas. Isto significa que non é necesario "
"premer en \"Páxina seguinte\", algo que aumenta considerablemente a "
"capacidade de retención."


code:
# Translation of StatusNet - InfiniteScroll to Hebrew (עברית)
# Exported from translatewiki.net
#
# Author: Amire80
# Author: YaronSh
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: Hebrew <https://translatewiki.net/wiki/Portal:he>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: he\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll (גלילה אינסופית) מוסיפה את התכונות הבאות להתקנת ה־StatusNet "
"שלך: כאשר משתמש גולל אל עבר תחתית הדף, דף העדכונים הבא נטען ונוסף אוטומטית. "
"משמעות הדבר היא שאין על המשתמשים ללחוץ על \"הדף הבא\", מה שמגביר את תחושת "
"הדבקות בצורה דרמטית."


code:
# Translation of StatusNet - InfiniteScroll to Interlingua (interlingua)
# Exported from translatewiki.net
#
# Author: McDutchie
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: Interlingua <https://translatewiki.net/wiki/Portal:ia>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: ia\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll adde le sequente functionalitate a tu installation de "
"StatusNet: Quando un usator face rolar le pagina verso le fundo, le sequente "
"pagina de notas es automaticamente recuperate e adjungite. Isto significa "
"que ille nunquam ha besonio de cliccar super \"Pagina sequente\", lo que "
"augmenta dramaticamente le adherentia."


code:
# Translation of StatusNet - InfiniteScroll to Indonesian (Bahasa Indonesia)
# Exported from translatewiki.net
#
# Author: Farras
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:51+0000\n"
"Language-Team: Indonesian <https://translatewiki.net/wiki/Portal:id>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: id\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll menambahkan fungsi berikut terhadap instalasi StatusNet "
"Anda: Ketika seorang pengguna melakukan skrol ke bawah halaman, halaman "
"pemberitahuan selanjutnya secara otomatis didapat dan ditambahkan. Ini "
"berarti tidak perlu menekan \"Halaman Berikutnya\" yang hanya menambah "
"ketergantungan."


code:
# Translation of StatusNet - InfiniteScroll to Italian (italiano)
# Exported from translatewiki.net
#
# Author: GreenFox
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"InfiniteScroll aggiunge le seguenti funzionalità alla vostra installazione "
"di StatusNet: quando un utente scorre verso il fondo della pagina, la pagina "
"delle comunicazioni seguenti è automaticamente recuperata e messa di "
"seguito. Questo significa che gli utenti non necessitano di cliccare su "
"\"Pagina seguente\", che aumenta considerevolmente la concentrazione "
"dell'utilizzatore"


code:
# Translation of StatusNet - InfiniteScroll to Japanese (日本語)
# Exported from translatewiki.net
#
# Author: 青子守歌
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Japanese <https://translatewiki.net/wiki/Portal:ja>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: ja\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"無限スクロールは、StatusNetのインストールに次の機能を追加します：ユーザーが"
"ページの最後までスクロースしたとき、次のページの通知が自動的に取得され追加さ"
"れます。これはつまり、「次のページ」をクリックする必要がなく、手間を劇的に改"
"善します。"


code:
# Translation of StatusNet - InfiniteScroll to Macedonian (македонски)
# Exported from translatewiki.net
#
# Author: Bjankuloski06
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Macedonian <https://translatewiki.net/wiki/Portal:mk>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: mk\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n == 1 || n%10 == 1) ? 0 : 1;\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"„Бесконечно лизгање“ ја додава следнава функција во Вашата инсталација на "
"StatusNet: Кога еден корисник лизга кон дното на страницата, следната "
"страница автоматски се појавува во продолжение. Со ова се отстранува "
"потребата од стискање на „Следна страница“, што значително ја зголемува "
"лепливоста."


code:
# Translation of StatusNet - InfiniteScroll to Norwegian Bokmål (norsk (bokmål))
# Exported from translatewiki.net
#
# Author: Nghtwlkr
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Norwegian Bokmål <https://translatewiki.net/wiki/Portal:nb>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: nb\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll legger til følgende funksjonalitet til din StatusNet-"
"installasjon: Når en bruker ruller mot bunnen av siden hentes den neste "
"siden med notiser og legges til automatisk. Dette betyr at de aldri trenger "
"å klikke «Neste side». Dette øker «stickiness» dramatisk."


code:
# Translation of StatusNet - InfiniteScroll to Dutch (Nederlands)
# Exported from translatewiki.net
#
# Author: Siebrand
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Dutch <https://translatewiki.net/wiki/Portal:nl>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: nl\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Oneindig scrollen (Infinite Scroll) maakt het mogelijk om in een StatusNet-"
"site naar onderaan de pagina te scrollen en dan automatisch de volgende "
"pagina te zien laden. Een gebruiker hoeft dus nooit meer op \"Volgende pagina"
"\" te klikken zodat ze langers op de site blijven."


code:
# Translation of StatusNet - InfiniteScroll to Brazilian Portuguese (português do Brasil)
# Exported from translatewiki.net
#
# Author: Giro720
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Brazilian Portuguese <https://translatewiki.net/wiki/Portal:"
"pt-br>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: pt-br\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Infinite Scroll adiciona a seguinte funcionalidade a sua instalação "
"StatusNet: Quando um usuário se desloca para o final da página, a próxima "
"página de mensagens é recuperada e adicionada automaticamente. Isto "
"significa que não será necessário clicar em \"Próxima página\", que aumenta "
"drasticamente a capacidade de retenção de usuários."


code:
# Translation of StatusNet - InfiniteScroll to Russian (русский)
# Exported from translatewiki.net
#
# Author: Сrower
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Russian <https://translatewiki.net/wiki/Portal:ru>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: ru\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=3; plural=(n%10 == 1 && n%100 != 11) ? 0 : ( (n%10 >= "
"2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)) ? 1 : 2 );\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Бесконечная прокрутка добавляет следующую функциональность вашему сайту "
"StatusNet: Когда пользователь прокручивает страницу уведомлений до самого "
"низа, следующая страница уведомлений автоматически запрашивается и "
"добавлятся. Это значит, что вам никогда не прийдётся нажимать кнопку "
"\"Следующая страница\", что резко увеличивает клейкость."


code:
# Translation of StatusNet - InfiniteScroll to Tagalog (Tagalog)
# Exported from translatewiki.net
#
# Author: AnakngAraw
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Tagalog <https://translatewiki.net/wiki/Portal:tl>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: tl\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Nagdaragdag ang Walang Hangganang Balumbon ng sumusunod na tungkulin sa "
"iyong instalasyon ng StatusNet: Kapag ang isang tagagamit ay nagpapadulas "
"papunta sa ilalim ng pahina, ang susunod na pahina ng mga pabatid ay kusang "
"muling nakukuha at nadurugtong.  Nangangahulugan ito na hindi nila kailangan "
"kailanman na pindutin ang \"Susunod na Pahina\", na mabisang nagpapataas ng "
"pagkamadikit."


code:
# Translation of StatusNet - InfiniteScroll to Ukrainian (українська)
# Exported from translatewiki.net
#
# Author: Boogie
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Ukrainian <https://translatewiki.net/wiki/Portal:uk>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: uk\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=3; plural=(n%10 == 1 && n%100 != 11) ? 0 : ( (n%10 >= "
"2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)) ? 1 : 2 );\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"Нескінченна прокрутка сторінки додає наступні функції сайту StatusNet: коли "
"користувач прокручує сторінку до самого її низу, дописи з наступної сторінки "
"додаються автоматично. Це означає, що вам не доведеться натискати «Назад» (до "
"попередньої сторінки), аби переглянути повідомлення."


code:
# Translation of StatusNet - InfiniteScroll to Simplified Chinese (中文（简体）)
# Exported from translatewiki.net
#
# Author: ZhengYiFeng
# --
# This file is distributed under the same license as the StatusNet package.
#
msgid ""
msgstr ""
"Project-Id-Version: StatusNet - InfiniteScroll\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-30 11:07+0000\n"
"PO-Revision-Date: 2012-06-30 11:08:52+0000\n"
"Language-Team: Simplified Chinese <https://translatewiki.net/wiki/Portal:zh-"
"hans>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-POT-Import-Date: 2011-06-05 21:50:21+0000\n"
"X-Generator: MediaWiki 1.20alpha (233fc08); Translate 2012-06-21\n"
"X-Translation-Project: translatewiki.net <https://translatewiki.net>\n"
"X-Language-Code: zh-hans\n"
"X-Message-Group: #out-statusnet-plugin-infinitescroll\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin dscription.
msgid ""
"Infinite Scroll adds the following functionality to your StatusNet "
"installation: When a user scrolls towards the bottom of the page, the next "
"page of notices is automatically retrieved and appended. This means they "
"never need to click \"Next Page\", which dramatically increases stickiness."
msgstr ""
"无限滚动（Infinite Scroll）给你的 StatusNet 网站增加了这些功能：当用户滚动页"
"面到底部的时候，将自动获取下一页的消息并追加显示出来。这样用户就不用再去点"
"击“下一页”按钮了，大大的增加了黏贴度。"


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Send and receive notices using an IRC network
 *
 * 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  IM
 * @package   StatusNet
 * @author    Luke Fitzgerald <lw.fitzgerald@googlemail.com>
 * @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);
}

// We bundle the Phergie library...
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/phergie');

/**
 * Plugin for IRC
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Luke Fitzgerald <lw.fitzgerald@googlemail.com>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class IrcPlugin extends ImPlugin {
    public $host =  null;
    public $port = null;
    public $username = null;
    public $realname = null;
    public $nick = null;
    public $password = null;
    public $nickservidentifyregexp = null;
    public $nickservpassword = null;
    public $channels = null;
    public $transporttype = null;
    public $encoding = null;
    public $pinginterval = null;

    public $regcheck = null;
    public $unregregexp = null;
    public $regregexp = null;

    public $transport = 'irc';
    protected $whiteList;
    protected $fake_irc;

    /**
     * Get the internationalized/translated display name of this IM service
     *
     * @return string Name of service
     */
    public function getDisplayName() {
        // TRANS: Service name for IRC.
        return _m('IRC');
    }

    /**
     * Normalize a screenname for comparison
     *
     * @param string $screenname Screenname to normalize
     * @return string An equivalent screenname in normalized form
     */
    public function normalize($screenname) {
        $screenname = str_replace(" ","", $screenname);
        return strtolower($screenname);
    }

    /**
     * Get the screenname of the daemon that sends and receives messages
     *
     * @return string Screenname
     */
    public function daemonScreenname() {
        return $this->nick;
    }

    /**
     * Validate (ensure the validity of) a screenname
     *
     * @param string $screenname Screenname to validate
     * @return boolean true if screenname is valid
     */
    public function validate($screenname) {
        if (preg_match('/\A[a-z0-9\-_]{1,1000}\z/i', $screenname)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Load related modules when needed
     *
     * @param string $cls Name of the class to be loaded
     * @return boolean hook value; true means continue processing, false means stop.
     */
    public function onAutoload($cls) {
        // in the beginning of this file, we have added an include path
        if (substr($cls, 0, 7) == 'Phergie') {
            include_once str_replace('_', DIRECTORY_SEPARATOR, $cls) . '.php';
            return false;
        }

        return parent::onAutoload($cls);
    }

    /*
     * Start manager on daemon start
     *
     * @param array &$versions Array to insert manager into
     * @return boolean
     */
    public function onStartImDaemonIoManagers(&$classes) {
        parent::onStartImDaemonIoManagers($classes);
        $classes[] = new IrcManager($this); // handles sending/receiving
        return true;
    }

    /**
    * Ensure the database table is present
    *
    */
    public function onCheckSchema() {
        $schema = Schema::get();

        // For storing messages while sessions become ready
        $schema->ensureTable('irc_waiting_message', Irc_waiting_message::schemaDef());
        return true;
    }

    /**
    * Get a microid URI for the given screenname
    *
    * @param string $screenname Screenname
    * @return string microid URI
    */
    public function microiduri($screenname) {
        return 'irc:' . $screenname;
    }

    /**
     * Send a message to a given screenname
     *
     * @param string $screenname Screenname to send to
     * @param string $body Text to send
     * @return boolean true on success
     */
    public function sendMessage($screenname, $body) {
        $lines = explode("\n", $body);
        foreach ($lines as $line) {
            $this->fake_irc->doPrivmsg($screenname, $line);
            $this->enqueueOutgoingRaw(array('type' => 'message', 'prioritise' => 0, 'data' => $this->fake_irc->would_be_sent));
        }
        return true;
    }

    /**
     * Accept a queued input message.
     *
     * @return boolean true if processing completed, false if message should be reprocessed
     */
    public function receiveRawMessage($data) {
        if (strpos($data['source'], '#') === 0) {
            $message = $data['message'];
            $parts = explode(' ', $message, 2);
            $command = $parts[0];
            if (in_array($command, $this->whiteList)) {
                $this->handle_channel_incoming($data['sender'], $data['source'], $message);
            } else {
                $this->handleIncoming($data['sender'], $message);
            }
        } else {
            $this->handleIncoming($data['sender'], $data['message']);
        }
        return true;
    }

    /**
     * Helper for handling incoming messages from a channel requiring response
     * to the channel instead of via PM
     *
     * @param string $nick Screenname the message was sent from
     * @param string $channel Channel the message originated from
     * @param string $message Message text
     * @param boolean true on success
     */
    protected function handle_channel_incoming($nick, $channel, $notice_text) {
        $user = $this->getUser($nick);
        // For common_current_user to work
        global $_cur;
        $_cur = $user;

        if (!$user) {
            $this->sendFromSite($nick, 'Unknown user; go to ' .
                             common_local_url('imsettings') .
                             ' to add your address to your account');
            common_log(LOG_WARNING, 'Message from unknown user ' . $nick);
            return;
        }
        if ($this->handle_channel_command($user, $channel, $notice_text)) {
            common_log(LOG_INFO, "Command message by $nick handled.");
            return;
        } else if ($this->isAutoreply($notice_text)) {
            common_log(LOG_INFO, 'Ignoring auto reply from ' . $nick);
            return;
        } else if ($this->isOtr($notice_text)) {
            common_log(LOG_INFO, 'Ignoring OTR from ' . $nick);
            return;
        } else {
            common_log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
            $this->addNotice($nick, $user, $notice_text);
        }

        $user->free();
        unset($user);
        unset($_cur);
        unset($message);
    }

    /**
     * Attempt to handle a message from a channel as a command
     *
     * @param User $user User the message is from
     * @param string $channel Channel the message originated from
     * @param string $body Message text
     * @return boolean true if the message was a command and was executed, false if it was not a command
     */
    protected function handle_channel_command($user, $channel, $body) {
        $inter = new CommandInterpreter();
        $cmd = $inter->handle_command($user, $body);
        if ($cmd) {
            $chan = new ChannelResponseChannel($this, $channel);
            $cmd->execute($chan);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Send a confirmation code to a user
     *
     * @param string $screenname screenname sending to
     * @param string $code the confirmation code
     * @param User $user user sending to
     * @return boolean success value
     */
    public function sendConfirmationCode($screenname, $code, $user, $checked = false) {
        // TRANS: Body text for e-mail confirmation message for IRC.
        // TRANS: %1$s is a user nickname, %2$s is the StatusNet sitename,
        // TRANS: %3$s is the plugin display name ("IRC"), %4$s is the confirm address URL.
        $body = sprintf(_m('User "%1$s" on %2$s has said that your %3$s screenname belongs to them. ' .
          'If that\'s true, you can confirm by clicking on this URL: ' .
          '%4$s' .
          ' . (If you cannot click it, copy-and-paste it into the ' .
          'address bar of your browser). If that user is not you, ' .
          'or if you did not request this confirmation, just ignore this message.'),
          $user->nickname, common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', array('code' => $code)));

        if ($this->regcheck && !$checked) {
            return $this->checked_sendConfirmationCode($screenname, $code, $user);
        } else {
            return $this->sendMessage($screenname, $body);
        }
    }

    /**
    * Only sends the confirmation message if the nick is
    * registered
    *
    * @param string $screenname Screenname sending to
    * @param string $code The confirmation code
    * @param User $user User sending to
    * @return boolean true on succes
    */
    public function checked_sendConfirmationCode($screenname, $code, $user) {
        $this->fake_irc->doPrivmsg('NickServ', 'INFO '.$screenname);
        $this->enqueueOutgoingRaw(
            array(
                'type' => 'nickcheck',
                'prioritise' => 1,
                'data' => $this->fake_irc->would_be_sent,
                'nickdata' =>
                    array(
                        'screenname' => $screenname,
                        'code' => $code,
                        'user' => $user
                    )
            )
        );
        return true;
    }

    /**
    * Initialize plugin
    *
    * @return boolean
    */
    public function initialize() {
        if (!isset($this->host)) {
            // TRANS: Exception thrown when initialising the IRC plugin fails because of an incorrect configuration.
            throw new Exception(_m('You must specify a host.'));
        }
        if (!isset($this->username)) {
            // TRANS: Exception thrown when initialising the IRC plugin fails because of an incorrect configuration.
            throw new Exception(_m('You must specify a username.'));
        }
        if (!isset($this->realname)) {
            // TRANS: Exception thrown when initialising the IRC plugin fails because of an incorrect configuration.
            throw new Exception(_m('You must specify a "real name".'));
        }
        if (!isset($this->nick)) {
            // TRANS: Exception thrown when initialising the IRC plugin fails because of an incorrect configuration.
            throw new Exception(_m('You must specify a nickname.'));
        }

        if (!isset($this->port)) {
            $this->port = 6667;
        }
        if (!isset($this->transporttype)) {
            $this->transporttype = 'tcp';
        }
        if (!isset($this->encoding)) {
            $this->encoding = 'UTF-8';
        }
        if (!isset($this->pinginterval)) {
            $this->pinginterval = 120;
        }

        if (!isset($this->regcheck)) {
            $this->regcheck = true;
        }

        $this->fake_irc = new FakeIrc;

        /*
         * Commands allowed to return output to a channel
         */
        $this->whiteList = array('stats', 'last', 'get');

        return true;
    }

    /**
     * Get plugin information
     *
     * @param array $versions Array to insert information into
     * @return void
     */
    public function onPluginVersion(&$versions) {
        $versions[] = array('name' => 'IRC',
                            'version' => GNUSOCIAL_VERSION,
                            'author' => 'Luke Fitzgerald',
                            'homepage' => 'http://status.net/wiki/Plugin:IRC',
                            'rawdescription' =>
                            // TRANS: Plugin description.
                            _m('The IRC plugin allows users to send and receive notices over an IRC network.'));
        return true;
    }
}


code:
The IRC plugin allows users to send and receive notices over an IRC network.

Installation
============
add "addPlugin('irc',
    array('setting'=>'value', 'setting2'=>'value2', ...);"
to the bottom of your config.php

scripts/imdaemon.php included with StatusNet must be running. It will be started by
the plugin along with their other daemons when you run scripts/startdaemons.sh.
See the StatusNet README for more about queuing and daemons.

Settings
========
host*: Hostname of IRC server
port: Port of IRC server (defaults to 6667)
username*: Username of bot
realname*: Real name of bot
nick*: Nickname of bot
password: Password
nickservpassword: NickServ password for identification
nickservidentifyregexp: Override existing regexp matching request for identification from NickServ
channels: Channels for bot to idle in
transporttype: Set to 'ssl' to enable SSL
encoding: Set to change encoding
pinginterval: Set to change the number of seconds between pings (helps keep the connection open)
              Defaults to 120 seconds
regcheck: Check user's nicknames are registered, enabled by default, set to false to disable
regregexp: Override existing regexp matching response from NickServ if nick checked is registered.
           Must contain a capturing group catching the nick
unregregexp: Override existing regexp matching response from NickServ if nick checked is unregistered
             Must contain a capturing group catching the nick

* required

Example
=======
addPlugin('irc', array(
    'host' => '...',
    'username' => '...',
    'realname' => '...',
    'nick' => '...',
    'channels' => array('#channel1', '#channel2')
));

path: plugins/Irc/README


code:
<?php
/**
 * Table Definition for irc_waiting_message
 */

require_once INSTALLDIR.'/classes/Memcached_DataObject.php';

class Irc_waiting_message extends Managed_DataObject {

    public $__table = 'irc_waiting_message'; // table name
    public $id;                              // int primary_key not_null auto_increment
    public $data;                            // blob not_null
    public $prioritise;                      // tinyint(1) not_null
    public $attempts;                        // int not_null
    public $claimed;                         // datetime()
    public $created;                         // datetime()   not_null
    public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP

    public static function schemaDef()
    {
        return array(
            'fields' => array(
                'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for entry'),
                'data' => array('type' => 'blob', 'not null' => true, 'description' => 'data blob'),
                'prioritise' => array('type' => 'int', 'size' => 'tiny', 'description' => 'tinyint priority value'),
                'attempts' => array('type' => 'int', 'not null' => true, 'description' => 'attempts count'),
                'claimed' => array('type' => 'datetime', 'description' => 'date this irc message was claimed'),
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
            ),
            'primary key' => array('id'),
            'indexes' => array(
                'irc_waiting_message_prioritise_idx' => array('prioritise'),
            ),
        );
    }

    /**
     * Get the next item in the queue
     *
     * @return Irc_waiting_message Next message if there is one
     */
    public static function top() {
        $wm = new Irc_waiting_message();

        $wm->orderBy('prioritise DESC, created');
        $wm->whereAdd('claimed is null');

        $wm->limit(1);

        $cnt = $wm->find(true);

        if ($cnt) {
            // XXX: potential race condition
            // can we force it to only update if claimed is still null
            // (or old)?
            common_log(LOG_INFO, 'claiming IRC waiting message id = ' . $wm->id);
            $orig = clone($wm);
            $wm->claimed = common_sql_now();
            $result = $wm->update($orig);
            if ($result) {
                common_log(LOG_INFO, 'claim succeeded.');
                return $wm;
            } else {
                common_log(LOG_INFO, 'claim failed.');
            }
        }
        $wm = null;
        return null;
    }

    /**
    * Increment the attempts count
    *
    * @return void
    * @throws Exception
    */
    public function incAttempts() {
        $orig = clone($this);
        $this->attempts++;
        $result = $this->update($orig);

        if (!$result) {
            // TRANS: Exception thrown when an IRC attempts count could not be updated.
            // TRANS: %d is the object ID for which the count could not be updated.
            throw new Exception(sprintf(_m('Could not increment attempts count for %d.'), $this->id));
        }
    }

    /**
     * Release a claimed item.
     */
    public function releaseClaim() {
        // DB_DataObject doesn't let us save nulls right now
        $sql = sprintf("UPDATE irc_waiting_message SET claimed=NULL WHERE id=%d", $this->id);
        $this->query($sql);

        $this->claimed = null;
        $this->encache();
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie
 */

/**
 * Autoloader for Phergie classes.
 *
 * @category Phergie
 * @package  Phergie
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie
 */
class Phergie_Autoload
{
    /**
     * Constructor to add the base Phergie path to the include_path.
     *
     * @return void
     */
    public function __construct()
    {
        $path = realpath(dirname(__FILE__) . '/..');
        $includePath = get_include_path();
        $includePathList = explode(PATH_SEPARATOR, $includePath);
        if (!in_array($path, $includePathList)) {
            self::addPath($path);
        }
    }

    /**
     * Autoload callback for loading class files.
     *
     * @param string $class Class to load
     *
     * @return void
     */
    public function load($class)
    {
        include str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
    }

    /**
     * Registers an instance of this class as an autoloader.
     *
     * @return void
     */
    public static function registerAutoloader()
    {
        spl_autoload_register(array(new self, 'load'));
    }

    /**
     * Add a path to the include path.
     *
     * @param string $path Path to add
     *
     * @return void
     */
    public static function addPath($path)
    {
        set_include_path($path . PATH_SEPARATOR . get_include_path());
    }
}


code:
<?php
/**
 * Phergie
 *
 * PHP version 5
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://phergie.org/license
 *
 * @category  Phergie
 * @package   Phergie
 * @author    Phergie Development Team <team@phergie.org>
 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 * @license   http://phergie.org/license New BSD License
 * @link      http://pear.phergie.org/package/Phergie
 */

/**
 * Composite class for other components to represent the bot.
 *
 * @category Phergie
 * @package  Phergie
 * @author   Phergie Development Team <team@phergie.org>
 * @license  http://phergie.org/license New BSD License
 * @link     http://pear.phergie.org/package/Phergie
 */
class Phergie_Bot
{
    /**
     * Current version of Phergie
     */
    const VERSION = '2.0.1';

    /**
     * Current driver instance
     *
     * @var Phergie_Driver_Abstract
     */
    protected $driver;

    /**
     * Current configuration instance
     *
     * @var Phergie_Config
     */
    protected $config;

    /**
     * Current connection handler instance
     *
     * @var Phergie_Connection_Handler
     */
    protected $connections;

    /**
     * Current plugin handler instance
     *
     * @var Phergie_Plugin_Handler
     */
    protected $plugins;

    /**
     * Current event handler instance
     *
     * @var Phergie_Event_Handler
     */
    protected $events;

    /**
     * Current end-user interface instance
     *
     * @var Phergie_Ui_Abstract
     */
    protected $ui;

    /**
     * Current processor instance
     *
     * @var Phergie_Process_Abstract
     */
    protected $processor;

    /**
     * Returns a driver instance, creating one of the default class if
     * none has been set.
     *
     * @return Phergie_Driver_Abstract
     */
    public function getDriver()
    {
        if (empty($this->driver)) {
            // Check if a driver has been defined in the configuration to use
            // as the default
            $config = $this->getConfig();
            if (isset($config['driver'])) {
                $class = 'Phergie_Driver_' . ucfirst($config['driver']);
            } else {
                // Otherwise default to the Streams driver.
                $class = 'Phergie_Driver_Streams';
            }

            $this->driver = new $class;
        }
        return $this->driver;
    }

    /**
     * Sets the driver instance to use.
     *
     * @param Phergie_Driver_Abstract $driver Driver instance
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function setDriver(Phergie_Driver_Abstract $driver)
    {
        $this->driver = $driver;
        return $this;
    }

    /**
     * Sets the configuration to use.
     *
     * @param Phergie_Config $config Configuration instance
     *
     * @return Phergie_Runner_Abstract Provides a fluent interface
     */
    public function setConfig(Phergie_Config $config)
    {
        $this->config = $config;
        return $this;
    }

    /**
     * Returns the entire configuration in use or the value of a specific
     * configuration setting.
     *
     * @param string $index   Optional index of a specific configuration
     *        setting for which the corresponding value should be returned
     * @param mixed  $default Value to return if no match is found for $index
     *
     * @return mixed Value corresponding to $index or the entire
     *         configuration if $index is not specified
     */
    public function getConfig($index = null, $default = null)
    {
        if (empty($this->config)) {
            $this->config = new Phergie_Config;
            $this->config->read('Settings.php');
        }
        if ($index !== null) {
            if (isset($this->config[$index])) {
                return $this->config[$index];
            } else {
                return $default;
            }
        }
        return $this->config;
    }

    /**
     * Returns a plugin handler instance, creating it if it does not already
     * exist and using a default class if none has been set.
     *
     * @return Phergie_Plugin_Handler
     */
    public function getPluginHandler()
    {
        if (empty($this->plugins)) {
            $this->plugins = new Phergie_Plugin_Handler(
                $this->getConfig(),
                $this->getEventHandler()
            );
        }
        return $this->plugins;
    }

    /**
     * Sets the plugin handler instance to use.
     *
     * @param Phergie_Plugin_Handler $handler Plugin handler instance
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function setPluginHandler(Phergie_Plugin_Handler $handler)
    {
        $this->plugins = $handler;
        return $this;
    }

    /**
     * Returns an event handler instance, creating it if it does not already
     * exist and using a default class if none has been set.
     *
     * @return Phergie_Event_Handler
     */
    public function getEventHandler()
    {
        if (empty($this->events)) {
            $this->events = new Phergie_Event_Handler;
        }
        return $this->events;
    }

    /**
     * Sets the event handler instance to use.
     *
     * @param Phergie_Event_Handler $handler Event handler instance
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function setEventHandler(Phergie_Event_Handler $handler)
    {
        $this->events = $handler;
        return $this;
    }

    /**
     * Returns a connection handler instance, creating it if it does not
     * already exist and using a default class if none has been set.
     *
     * @return Phergie_Connection_Handler
     */
    public function getConnectionHandler()
    {
        if (empty($this->connections)) {
            $this->connections = new Phergie_Connection_Handler;
        }
        return $this->connections;
    }

    /**
     * Sets the connection handler instance to use.
     *
     * @param Phergie_Connection_Handler $handler Connection handler instance
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function setConnectionHandler(Phergie_Connection_Handler $handler)
    {
        $this->connections = $handler;
        return $this;
    }

    /**
     * Returns an end-user interface instance, creating it if it does not
     * already exist and using a default class if none has been set.
     *
     * @return Phergie_Ui_Abstract
     */
    public function getUi()
    {
        if (empty($this->ui)) {
            $this->ui = new Phergie_Ui_Console;
        }
        return $this->ui;
    }

    /**
     * Sets the end-user interface instance to use.
     *
     * @param Phergie_Ui_Abstract $ui End-user interface instance
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function setUi(Phergie_Ui_Abstract $ui)
    {
        $this->ui = $ui;
        return $this;
    }

    /**
     * Returns a processer instance, creating one if none exists.
     *
     * @return Phergie_Process_Abstract
     */
    public function getProcessor()
    {
        if (empty($this->processor)) {
            $class = 'Phergie_Process_Standard';

            $type = $this->getConfig('processor');
            if (!empty($type)) {
                $class = 'Phergie_Process_' . ucfirst($type);
            }

            $this->processor = new $class(
                $this,
                $this->getConfig('processor.options', array())
            );
        }
        return $this->processor;
    }

    /**
     * Sets the processer instance to use.
     *
     * @param Phergie_Process_Abstract $processor Processer instance
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function setProcessor(Phergie_Process_Abstract $processor)
    {
        $this->processor = $processor;
        return $this;
    }

    /**
     * Loads plugins into the plugin handler.
     *
     * @return void
     */
    protected function loadPlugins()
    {
        $config = $this->getConfig();
        $plugins = $this->getPluginHandler();
        $ui = $this->getUi();

        $plugins->setAutoload($config['plugins.autoload']);
        foreach ($config['plugins'] as $name) {
            try {
                $plugin = $plugins->addPlugin($name);
                $ui->onPluginLoad($name);
            } catch (Phergie_Plugin_Exception $e) {
                $ui->onPluginFailure($name, $e->getMessage());
                if (!empty($plugin)) {
                    $plugins->removePlugin($plugin);
                }
            }
        }
    }

    /**
     * Configures and establishes connections to IRC servers.
     *
     * @return void
     */
    protected function loadConnections()
    {
        $config = $this->getConfig();
        $driver = $this->getDriver();
        $connections = $this->getConnectionHandler();
        $plugins = $this->getPluginHandler();
        $ui = $this->getUi();

        foreach ($config['connections'] as $data) {
            $connection = new Phergie_Connection($data);
            $connections->addConnection($connection);

            $ui->onConnect($data['host']);
            $driver->setConnection($connection)->doConnect();
            $plugins->setConnection($connection);
            $plugins->onConnect();
        }
    }

    /**
     * Establishes server connections and initiates an execution loop to
     * continuously receive and process events.
     *
     * @return Phergie_Bot Provides a fluent interface
     */
    public function run()
    {
        set_time_limit(0);

        $timezone = $this->getConfig('timezone', 'UTC');
        date_default_timezone_set($timezone);

        $ui = $this->getUi();
        $ui->setEnabled($this->getConfig('ui.enabled'));

        $this->loadPlugins();
        $this->loadConnections();

        $processor = $this->getProcessor();

        $connections = $this->getConnectionHandler();
        while (count($connections)) {
            $processor->handleEvents();
        }

        $ui->onShutdown();

        return $this;
    }
}