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: 2019-06-12 01:23+0100\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Plugin description.
#: ActivityPubPlugin.php:212
msgid ""
"Follow people across social networks that implement ActivityPub."
msgstr ""

#: ActivityPubPlugin.php:254
msgid "Remote Profile"
msgstr ""

#. TRANS: Title. %s is a domain name.
#: ActivityPubPlugin.php:909
#, php-format
msgid "Sent from %s via ActivityPub"
msgstr ""

#. TRANS: Exception.
#: classes/Activitypub_profile.php:355
msgid "Not a valid webfinger address (via cache)."
msgstr ""

#. TRANS: Exception.
#: classes/Activitypub_profile.php:376
msgid "Not a valid webfinger address."
msgstr ""

#. TRANS: Exception. %s is a webfinger address.
#: classes/Activitypub_profile.php:416
#, php-format
msgid "Could not find a valid profile for \"%s\"."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Diogo Cordeiro <diogo@fc.up.pt>, 2019
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-12 01:23+0100\n"
"PO-Revision-Date: 2019-06-12 01:23+0100\n"
"Last-Translator: Diogo Cordeiro <diogo@fc.up.pt>\n"
"Language-Team: English (United Kingdom) (http://www.transifex.com/gnu-social/gnu-social/language/en_GB/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en_GB\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: ActivityPubPlugin.php:212
msgid ""
"Follow people across social networks that implement ActivityPub."
msgstr ""
"Follow people across social networks that implement ActivityPub."

#: ActivityPubPlugin.php:254
msgid "Remote Profile"
msgstr "Remote Profile"

#. TRANS: Title. %s is a domain name.
#: ActivityPubPlugin.php:909
#, php-format
msgid "Sent from %s via ActivityPub"
msgstr "Sent from %s via ActivityPub"

#. TRANS: Exception.
#: classes/Activitypub_profile.php:355
msgid "Not a valid webfinger address (via cache)."
msgstr "Not a valid WebFinger address (via cache)."

#. TRANS: Exception.
#: classes/Activitypub_profile.php:376
msgid "Not a valid webfinger address."
msgstr "Not a valid WebFinger address."

#. TRANS: Exception. %s is a webfinger address.
#: classes/Activitypub_profile.php:416
#, php-format
msgid "Could not find a valid profile for \"%s\"."
msgstr "Could not find a valid profile for \"%s\"."

repo_name: andremichelle/gnu

license: mit


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Diogo Cordeiro <diogo@fc.up.pt>, 2019
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-12 01:23+0100\n"
"PO-Revision-Date: 2019-06-12 01:23+0100\n"
"Last-Translator: Diogo Cordeiro <diogo@fc.up.pt>\n"
"Language-Team: Portuguese (http://www.transifex.com/gnu-social/gnu-social/language/pt/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: ActivityPubPlugin.php:212
msgid ""
"Follow people across social networks that implement ActivityPub."
msgstr ""
"Segue pessoas em redes sociais que implementam ActivityPub."

#: ActivityPubPlugin.php:254
msgid "Remote Profile"
msgstr "Perfil Remoto"

#. TRANS: Title. %s is a domain name.
#: ActivityPubPlugin.php:909
#, php-format
msgid "Sent from %s via ActivityPub"
msgstr "Enviado por %s via ActivityPub"

#. TRANS: Exception.
#: classes/Activitypub_profile.php:355
msgid "Not a valid webfinger address (via cache)."
msgstr "Endereço WebFinger inválido (via cache)."

#. TRANS: Exception.
#: classes/Activitypub_profile.php:376
msgid "Not a valid webfinger address."
msgstr "Endereço WebFinger inválido."

#. TRANS: Exception. %s is a webfinger address.
#: classes/Activitypub_profile.php:416
#, php-format
msgid "Could not find a valid profile for \"%s\"."
msgstr "Não foi possível encontrar um perfil válido para \"%s\"."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Diogo Cordeiro <diogo@fc.up.pt>, 2019
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-12 01:23+0100\n"
"PO-Revision-Date: 2019-06-12 02:24+0100\n"
"Last-Translator: Diogo Cordeiro <diogo@fc.up.pt>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/gnu-social/gnu-social/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt_BR\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: ActivityPubPlugin.php:212
msgid ""
"Follow people across social networks that implement ActivityPub."
msgstr ""
"Segue pessoas em redes sociais que implementam ActivityPub."

#: ActivityPubPlugin.php:254
msgid "Remote Profile"
msgstr "Perfil Remoto"

#. TRANS: Title. %s is a domain name.
#: ActivityPubPlugin.php:909
#, php-format
msgid "Sent from %s via ActivityPub"
msgstr "Enviado por %s via ActivityPub"

#. TRANS: Exception.
#: classes/Activitypub_profile.php:355
msgid "Not a valid webfinger address (via cache)."
msgstr "Endereço WebFinger inválido (via cache)."

#. TRANS: Exception.
#: classes/Activitypub_profile.php:376
msgid "Not a valid webfinger address."
msgstr "Endereço WebFinger inválido."

#. TRANS: Exception. %s is a webfinger address.
#: classes/Activitypub_profile.php:416
#, php-format
msgid "Could not find a valid profile for \"%s\"."
msgstr "Não foi possível encontrar um perfil válido para \"%s\"."


code:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>

        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
</phpunit>


code:
#!/usr/bin/env php
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

define('INSTALLDIR', realpath(__DIR__ . '/../../..'));

$shortoptions = 'u:af';
$longoptions = ['uri=', 'all', 'force'];

$helptext = <<<END_OF_HELP
update_activitypub_profiles.php [options]
Refetch / update ActivityPub RSA keys, profile info and avatars. Useful if you
do something like accidentally delete your avatars directory when
you have no backup.

    -u --uri ActivityPub profile URI to update
    -a --all update all

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$quiet = have_option('q', 'quiet');

if (!$quiet) {
    echo "ActivityPub Profiles updater will now start!\n";
    echo "Summoning Diogo Cordeiro, Richard Stallman and Chuck Norris to help us with this task!\n";
}

if (have_option('u', 'uri')) {
    $uri = get_option_value('u', 'uri');
    $discovery = new Activitypub_explorer();
    $discovery = $discovery->lookup($uri);
    if (empty($discovery)) {
        echo "Bad URI\n";
        exit(1);
    }
    $user = $discovery->lookup($uri)[0];
    try {
        $res = Activitypub_explorer::get_remote_user_activity($uri);
    } catch (Exception $e) {
        echo $e->getMessage()."\n";
        exit(1);
    }
    if (!$quiet) {
        echo "Updated ".Activitypub_profile::update_profile($user, $res)->getBestName()."\n";
    }
} elseif (!have_option('a', 'all')) {
    show_help();
    exit(1);
}

$user = new Activitypub_profile();
$cnt = $user->find();
if (!empty($cnt)) {
    if (!$quiet) {
        echo "Found {$cnt} ActivityPub profiles:\n";
    }
} else {
    if (have_option('u', 'uri')) {
        if (!$quiet) {
            echo "Couldn't find an existing ActivityPub profile with that URI.\n";
        }
    } else {
        if (!$quiet) {
            echo "Couldn't find any existing ActivityPub profiles.\n";
        }
    }
    exit(0);
}
while ($user->fetch()) {
    try {
        $res = Activitypub_explorer::get_remote_user_activity($user->uri);
        $updated_profile = Activitypub_profile::update_profile($user, $res);
        if (!$quiet) {
            echo "Updated ".$updated_profile->getBestName()."\n";
        }
    } catch (Exception $e) {
        // let it go
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

namespace Tests;

defined('GNUSOCIAL') || die();

trait CreatesApplication
{
    /**
     * Creates the application.
     *
     * @return todo
     */
    public static function createApplication()
    {
        if (!defined('INSTALLDIR')) {
            define('INSTALLDIR', __DIR__ . '/../../../');
        }
        if (!defined('GNUSOCIAL')) {
            define('GNUSOCIAL', true);
        }
        if (!defined('STATUSNET')) {
            define('STATUSNET', true);  // compatibility
        }

        require INSTALLDIR . '/lib/common.php';

        return true;
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

namespace Tests;

defined('GNUSOCIAL') || die();

use PHPUnit\Framework\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    protected function setUp()
    {
        $this->createApplication();
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

defined('GNUSOCIAL') || die();

require 'AcceptHeader.php';

class ContainerTest extends \PHPUnit_Framework_TestCase
{
    public function testHeader1()
    {
        $acceptHeader = new AcceptHeader('audio/*; q=0.2, audio/basic');
        $this->assertEquals('audio/basic', $this->_getMedia($acceptHeader[0]));
        $this->assertEquals('audio/*; q=0.2', $this->_getMedia($acceptHeader[1]));
    }

    public function testHeader2()
    {
        $acceptHeader = new AcceptHeader('text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5');
        $this->assertEquals('text/html; level=1', $this->_getMedia($acceptHeader[0]));
        $this->assertEquals('text/html; q=0.7', $this->_getMedia($acceptHeader[1]));
        $this->assertEquals('*/*; q=0.5', $this->_getMedia($acceptHeader[2]));
        $this->assertEquals('text/html; level=2; q=0.4', $this->_getMedia($acceptHeader[3]));
        $this->assertEquals('text/*; q=0.3', $this->_getMedia($acceptHeader[4]));
    }

    public function testHeader3()
    {
        $acceptHeader = new AcceptHeader('text/*, text/html, text/html;level=1, */*');
        $this->assertEquals('text/html; level=1', $this->_getMedia($acceptHeader[0]));
        $this->assertEquals('text/html', $this->_getMedia($acceptHeader[1]));
        $this->assertEquals('text/*', $this->_getMedia($acceptHeader[2]));
        $this->assertEquals('*/*', $this->_getMedia($acceptHeader[3]));
    }

    private function _getMedia(array $mediaType)
    {
        $str = $mediaType['type'] . '/' . $mediaType['subtype'];
        if (!empty($mediaType['params'])) {
            foreach ($mediaType['params'] as $k => $v) {
                $str .= '; ' . $k . '=' . $v;
            }
        }
        return $str;
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

namespace Tests\Unit;

defined('GNUSOCIAL') || die();

use Tests\TestCase;

class ProfileObjectTest extends TestCase
{
    public function testLibraryInstalled()
    {
        $this->assertTrue(class_exists('\Activitypub_profile'));
    }

    public function testActivitypubProfile()
    {
        // Mimic proper ACCEPT header
        $_SERVER['HTTP_ACCEPT'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams';

        /* Test do_insert() */
        $aprofile = new \Activitypub_profile();
        $aprofile->uri = 'https://testinstance.net/index.php/user/1';
        $aprofile->nickname = 'test1';
        $aprofile->fullname = 'Test User 1';
        $aprofile->bio      = 'I am a nice test 1 guy';
        $aprofile->inboxuri = "https://testinstance.net/index.php/user/1/inbox.json";
        $aprofile->sharedInboxuri = "https://testinstance.net/inbox.json";
        $aprofile->do_insert();

        /* Test local_profile() */
        $profile = $aprofile->local_profile();

        /* Test from_profile() and create_from_local_profile() */
        $this->assertTrue($this->compare_aprofiles($aprofile, \Activitypub_profile::from_profile($profile)));

        /* Create Keys for Test User 1 */
        $apRSA = new \Activitypub_rsa();
        $apRSA->profile_id = $profile->getID();
        \Activitypub_rsa::generate_keys($apRSA->private_key, $apRSA->public_key);
        $apRSA->store_keys();

        /* Test profile_to_array() */
        // Fetch ActivityPub Actor Object representation
        $profile_array = \Activitypub_profile::profile_to_array($profile);
        // Check type
        $this->assertTrue(is_array($profile_array));
        // Test with Explorer's Profile Tester
        $this->assertTrue(\Activitypub_explorer::validate_remote_response($profile_array));

        /* Test get_inbox() */
        $this->assertTrue($aprofile->sharedInboxuri == $aprofile->get_inbox());

        /* Test getUri() */
        $this->assertTrue($aprofile->uri == $aprofile->getUri());

        /* Test getUrl() */
        $this->assertTrue($profile->getUrl() == $aprofile->getUrl());

        /* Test getID() */
        $this->assertTrue($profile->getID() == $aprofile->getID());

        /* Test fromUri() */
        $this->assertTrue($this->compare_aprofiles($aprofile, \Activitypub_profile::fromUri($aprofile->uri)));

        /* Remove Remote User Test 1 */
        $old_id = $profile->getID();
        $apRSA->delete();
        $aprofile->delete();
        $profile->delete();
        // Check if successfuly removed
        try {
            \Profile::getById($old_id);
            $this->assertTrue(false);
        } catch (\NoResultException $e) {
            $this->assertTrue(true);
        }

        /* Test ensure_web_finger() */
        // TODO: Maybe elaborate on this function's tests
        try {
            \Activitypub_profile::ensure_web_finger('test1@testinstance.net');
            $this->assertTrue(false);
        } catch (\Exception $e) {
            $this->assertTrue($e->getMessage() == 'Not a valid webfinger address.' ||
                              $e->getMessage() == 'Not a valid webfinger address (via cache).');
        }
    }

    // Helpers

    private function compare_profiles(\Profile $a, \Profile $b)
    {
        if (($av = $a->getID()) != ($bv = $b->getID())) {
            throw new Exception('Compare Profiles 1 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getNickname()) != ($bv = $b->getNickname())) {
            throw new Exception('Compare Profiles 2 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getFullname()) != ($bv = $b->getFullname())) {
            throw new Exception('Compare Profiles 3 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getUrl()) != ($bv = $b->getUrl())) {
            throw new Exception('Compare Profiles 4 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getDescription()) != ($bv = $b->getDescription())) {
            throw new Exception('Compare Profiles 5 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getLocation()) != ($bv = $b->getLocation())) {
            throw new Exception('Compare Profiles 6 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getNickname()) != ($bv = $b->getNickname())) {
            throw new Exception('Compare Profiles 7 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->lat) != ($bv = $b->lat)) {
            throw new Exception('Compare Profiles 8 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->lon) != ($bv = $b->lon)) {
            throw new Exception('Compare Profiles 9 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        return true;
    }

    private function compare_aprofiles(\Activitypub_profile $a, \Activitypub_profile $b)
    {
        if (($av = $a->getUri()) != ($bv = $b->getUri())) {
            throw new Exception('Compare AProfiles 1 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getUrl()) != ($bv = $b->getUrl())) {
            throw new Exception('Compare AProfiles 2 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->getID()) != ($bv = $b->getID())) {
            throw new Exception('Compare AProfiles 3 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->profile_id) != ($bv = $b->profile_id)) {
            throw new Exception('Compare AProfiles 4 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->inboxuri) != ($bv = $b->inboxuri)) {
            throw new Exception('Compare AProfiles 5 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        if (($av = $a->sharedInboxuri) != ($bv = $b->sharedInboxuri)) {
            throw new Exception('Compare AProfiles 6 Fail: $a: '.$av.' is different from $b: '.$bv);
        }

        return true;
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

namespace Tests\Unit;

defined('GNUSOCIAL') || die();

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $this->assertTrue(true);
    }
}


code:
<?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.

/**
 * ActivityPub implementation for GNU social
 *
 * @package   GNUsocial
 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 * @copyright 2018-2019 Free Software Foundation, Inc http://www.fsf.org
 * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
 * @link      http://www.gnu.org/software/social/
 */

namespace Tests\Unit;

defined('GNUSOCIAL') || die();

use Tests\TestCase;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use HttpSignatures\Context;
use HttpSignatures\GuzzleHttpSignatures;

class HTTPSignatureTest extends TestCase
{
    /**
     * @var Context
     */
    private $context;
    /**
     * @var Client
     */
    private $client;
    /**
     * @var
     */
    private $history = [];

    public function testLibraryInstalled()
    {
        $this->assertTrue(class_exists('\GuzzleHttp\Client'));
        $this->assertTrue(class_exists('\HttpSignatures\Context'));
        $this->assertTrue(class_exists('\HttpSignatures\GuzzleHttpSignatures'));
    }

    public function setUp()
    {
        $this->context = new Context([
            'keys' => ['pda' => 'secret'],
            'algorithm' => 'hmac-sha256',
            'headers' => ['(request-target)', 'date'],
        ]);
        $stack = new HandlerStack();
        $stack->setHandler(new MockHandler([
            new Response(200, ['Content-Length' => 0]),
        ]));
        $stack->push(GuzzleHttpSignatures::middlewareFromContext($this->context));
        $stack->push(Middleware::history($this->history));
        $this->client = new Client(['handler' => $stack]);
    }
    /**
     * test signing a message
     */
    public function testGuzzleRequestHasExpectedHeaders()
    {
        $this->client->get('/path?query=123', [
            'headers' => ['date' => 'today', 'accept' => 'llamas']
        ]);
        // get last request
        $message = end($this->history);
        /** @var Request $request */
        $request = $message['request'];
        /** @var Response $response */
        $response = $message['request'];
        $expectedString = implode(
            ',',
            [
                'keyId="pda"',
                'algorithm="hmac-sha256"',
                'headers="(request-target) date"',
                'signature="SFlytCGpsqb/9qYaKCQklGDvwgmrwfIERFnwt+yqPJw="',
            ]
        );
        $this->assertEquals(
            [$expectedString],
            $request->getHeader('Signature')
        );
        $this->assertEquals(
            ['Signature ' . $expectedString],
            $request->getHeader('Authorization')
        );
    }
    /**
     * test signing a message with a URL that doesn't contain a ?query
     */
    public function testGuzzleRequestHasExpectedHeaders2()
    {
        $this->client->get('/path', [
            'headers' => ['date' => 'today', 'accept' => 'llamas']
        ]);
        // get last request
        $message = end($this->history);
        /** @var Request $request */
        $request = $message['request'];
        /** @var Response $response */
        $response = $message['request'];
        $expectedString = implode(
            ',',
            [
                'keyId="pda"',
                'algorithm="hmac-sha256"',
                'headers="(request-target) date"',
                'signature="DAtF133khP05pS5Gh8f+zF/UF7mVUojMj7iJZO3Xk4o="',
            ]
        );
        $this->assertEquals(
            [$expectedString],
            $request->getHeader('Signature')
        );
        $this->assertEquals(
            ['Signature ' . $expectedString],
            $request->getHeader('Authorization')
        );
    }
    public function getVerifyGuzzleRequestVectors()
    {
        return [
            /* path, headers */
            ['/path?query=123', ['date' => 'today', 'accept' => 'llamas']],
            ['/path?z=zebra&a=antelope', ['date' => 'today']],
        ];
    }
    /**
     * @dataProvider getVerifyGuzzleRequestVectors
     * @param string $path
     * @param array $headers
     */
    public function testVerifyGuzzleRequest($path, $headers)
    {
        $this->client->get($path, ['headers' => $headers]);
        // get last request
        $message = end($this->history);
        /** @var Request $request */
        $request = $message['request'];
        /** @var Response $response */
        $response = $message['request'];
        $this->assertTrue($this->context->verifier()->isValid($request));
    }
}


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

/**
 * Check new notices with activity spam service.
 *
 * @category  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011,2012 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class ActivitySpamPlugin extends Plugin
{
    const PLUGIN_VERSION = '2.0.0';

    public $server = null;
    public $hideSpam = false;

    const REVIEWSPAM = 'ActivitySpamPlugin::REVIEWSPAM';
    const TRAINSPAM = 'ActivitySpamPlugin::TRAINSPAM';

    /**
     * Initializer
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */
    function initialize()
    {
        $this->filter = new SpamFilter(common_config('activityspam', 'server'),
                                       common_config('activityspam', 'consumerkey'),
                                       common_config('activityspam', 'secret'));

        $this->hideSpam = common_config('activityspam', 'hidespam');

        // Let DB_DataObject find Spam_score

        common_config_set('db', 'class_location',
                          common_config('db', 'class_location') .':'.dirname(__FILE__));

        return true;
    }

    /**
     * Database schema setup
     *
     * @see Schema
     * @see ColumnDef
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */

    function onCheckSchema()
    {
        $schema = Schema::get();
        $schema->ensureTable('spam_score', Spam_score::schemaDef());

        Spam_score::upgrade();

        return true;
    }

    /**
     * When a notice is saved, check its spam score
     *
     * @param Notice $notice Notice that was just saved
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */

    function onEndNoticeSave($notice)
    {
        try {

            $result = $this->filter->test($notice);

            $score = Spam_score::saveNew($notice, $result);

            $this->log(LOG_INFO, "Notice " . $notice->id . " has spam score " . $score->score);

        } catch (Exception $e) {
            // Log but continue
            $this->log(LOG_ERR, $e->getMessage());
        }

        return true;
    }

    function onNoticeDeleteRelated($notice) {
        $score = Spam_score::getKV('notice_id', $notice->id);
        if (!empty($score)) {
            $score->delete();
        }
        return true;
    }

    function onUserRightsCheck($profile, $right, &$result) {
        switch ($right) {
        case self::REVIEWSPAM:
        case self::TRAINSPAM:
            $result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper'));
            return false;
        default:
            return true;
        }
    }

    function onGetSpamFilter(&$filter) {
        $filter = $this->filter;
        return false;
    }

    function onEndShowNoticeOptionItems($nli)
    {
        $profile = Profile::current();

        if (!empty($profile) && $profile->hasRight(self::TRAINSPAM)) {

            $notice = $nli->getNotice();
            $out = $nli->getOut();

            if (!empty($notice)) {

                $score = Spam_score::getKV('notice_id', $notice->id);

                if (empty($score)) {
                    // If it's empty, we can train it.
                    $form = new TrainSpamForm($out, $notice);
                    $form->show();
                } else if ($score->is_spam) {
                    $form = new TrainHamForm($out, $notice);
                    $form->show();
                } else if (!$score->is_spam) {
                    $form = new TrainSpamForm($out, $notice);
                    $form->show();
                }
            }
        }

        return true;
    }

    /**
     * Map URLs to actions
     *
     * @param URLMapper $m path-to-action mapper
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */

    public function onRouterInitialized(URLMapper $m)
    {
        $m->connect('main/train/spam',
                    array('action' => 'train', 'category' => 'spam'));
        $m->connect('main/train/ham',
                    array('action' => 'train', 'category' => 'ham'));
        $m->connect('main/spam',
                    array('action' => 'spam'));
        return true;
    }

    function onEndShowStyles($action)
    {
        $action->element('style', null,
                         '.form-train-spam input.submit { background: url('.$this->path('icons/bullet_black.png').') no-repeat 0px 0px } ' . "\n" .
                         '.form-train-ham input.submit { background: url('.$this->path('icons/exclamation.png').') no-repeat 0px 0px } ');
        return true;
    }

    function onEndPublicGroupNav($nav)
    {
        $user = common_current_user();

        if (!empty($user) && $user->hasRight(self::REVIEWSPAM)) {
            $nav->out->menuItem(common_local_url('spam'),
                                _m('MENU','Spam'),
                                // TRANS: Menu item title in search group navigation panel.
                                _('Notices marked as spam'),
                                $nav->actionName == 'spam',
                                'nav_timeline_spam');
        }

        return true;
    }

    function onPluginVersion(array &$versions)
    {
        $versions[] = array('name' => 'ActivitySpam',
                            'version' => self::PLUGIN_VERSION,
                            'author' => 'Evan Prodromou',
                            'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/ActivitySpam',
                            'description' =>
                            _m('Test notices against the Activity Spam service.'));
        return true;
    }

    function onEndNoticeInScope($notice, $profile, &$bResult)
    {
        if ($this->hideSpam) {
            if ($bResult) {

                $score = Spam_score::getKV('notice_id', $notice->id);

                if (!empty($score) && $score->is_spam) {
                    if (empty($profile) ||
                        ($profile->id !== $notice->profile_id &&
                         !$profile->hasRight(self::REVIEWSPAM))) {
                        $bResult = false;
                    }
                }
            }
        }

        return true;
    }

    /**
     * Pre-cache our spam scores if needed.
     */
    function onEndNoticeListPrefill(array &$notices, array &$profiles, array $notice_ids, Profile $scoped=null) {
        if ($this->hideSpam) {
            Spam_score::multiGet('notice_id', $notice_ids);
        }
        return true;
    }
}


code:
The ActivitySpam plugin is a spam filter for GNU social.

It needs to connect to a activityspam server.
You can run one yourself: https://github.com/e14n/activityspam
Or use a public instance ( ex: https://spamicity.info/ )

Installation
============
add "addPlugin('ActivitySpam');"
to the bottom of your config.php

Settings
========
server: URL to the activityspam server
consumerkey: The "key" provided by the activityspam server after you've registered and configured an account.
secret: The "secret" provided by the activityspam server after you've registered and configured an account

Example
=======
$config['activityspam']['server'] = 'https://spamicity.info/';
$config['activityspam']['consumerkey'] = 'CONSUMER_KEY';
$config['activityspam']['secret'] = 'SECRET';
addPlugin('ActivitySpam');

path: plugins/ActivitySpam/README


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2012, StatusNet, Inc.
 *
 * Stream of latest spam messages
 *
 * 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  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2012 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);
}

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

/**
 * SpamAction
 *
 * Shows the latest spam on the service
 *
 * @category  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2012 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class SpamAction extends Action
{
    var $page = null;
    var $notices = null;

    function title()
    {
        return _("Latest Spam");
    }

    /**
     * For initializing members of the class.
     *
     * @param array $args misc. arguments
     *
     * @return boolean true
     * @throws ClientException
     */

    function prepare(array $args = [])
    {
        parent::prepare($args);

        $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;

        // User must be logged in.

        if (!$this->scoped instanceof Profile) {
            throw new ClientException(_("You must be logged in to review."), 403);
        }

        // User must have the right to review spam

        if (!$this->scoped->hasRight(ActivitySpamPlugin::REVIEWSPAM)) {
            throw new ClientException(_('You cannot review spam on this site.'), 403);
        }

        $stream = new SpamNoticeStream($this->scoped);

        $this->notices = $stream->getNotices(($this->page - 1) * NOTICES_PER_PAGE,
            NOTICES_PER_PAGE + 1);

        if ($this->page > 1 && $this->notices->N == 0) {
            throw new ClientException(_('No such page.'), 404);
        }

        return true;
    }

    /**
     * Handler method
     *
     * @return void
     */

    function handle()
    {
        parent::handle();

        $this->showPage();
    }

    /**
     * Fill the content area
     *
     * Shows a list of the notices in the public stream, with some pagination
     * controls.
     *
     * @return void
     */

    function showContent()
    {
        $nl = new NoticeList($this->notices, $this);

        $cnt = $nl->show();

        if ($cnt == 0) {
            $this->showEmptyList();
        }

        $this->pagination($this->page > 1,
            $cnt > NOTICES_PER_PAGE,
            $this->page,
            'spam');
    }

    function showEmptyList()
    {
        // TRANS: Text displayed for public feed when there are no public notices.
        $message = _('This is the timeline of spam messages for %%site.name%% but none have been detected yet.');

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */

    function isReadOnly($args)
    {
        return true;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2012, StatusNet, Inc.
 *
 * Train a notice as spam
 *
 * 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  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2012 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);
}

/**
 * Train a notice as spam
 *
 * @category  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2012 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class TrainAction extends Action
{
    protected $notice = null;
    protected $filter = null;
    protected $category = null;

    /**
     * For initializing members of the class.
     *
     * @param array $args misc. arguments
     *
     * @return boolean true
     * @throws ClientException
     * @throws ServerException
     */

    function prepare(array $args = [])
    {
        parent::prepare($args);

        // User must be logged in.

        $user = common_current_user();

        if (empty($user)) {
            throw new ClientException(_("You must be logged in to train spam."), 403);
        }

        // User must have the right to review spam

        if (!$user->hasRight(ActivitySpamPlugin::TRAINSPAM)) {
            throw new ClientException(_('You cannot review spam on this site.'), 403);
        }

        $id = $this->trimmed('notice');

        $this->notice = Notice::getKV('id', $id);

        if (empty($this->notice)) {
            throw new ClientException(_("No such notice."));
        }

        $this->checkSessionToken();

        $filter = null;

        Event::handle('GetSpamFilter', array(&$filter));

        if (empty($filter)) {
            throw new ServerException(_("No spam filter configured."));
        }

        $this->filter = $filter;

        $this->category = $this->trimmed('category');

        if ($this->category !== SpamFilter::SPAM &&
            $this->category !== SpamFilter::HAM)
        {
            throw new ClientException(_("No such category."));
        }

        return true;
    }

    /**
     * Handler method
     *
     * @return void
     * @throws ClientException
     */

    function handle()
    {
        // Train

        $this->filter->trainOnError($this->notice, $this->category);

        // Re-test

        $result = $this->filter->test($this->notice);

        // Update or insert

        $score = Spam_score::save($this->notice, $result);

        // Show new toggle form

        if ($this->category === SpamFilter::SPAM) {
            $form = new TrainHamForm($this, $this->notice);
        } else {
            $form = new TrainSpamForm($this, $this->notice);
        }

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title for page on which we train the spam filter for ham or spam
            $this->element('title', null, _('Train spam filter'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $form->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            common_redirect(common_local_url('spam'), 303);
        }
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Score of a notice by activity spam service
 *
 * 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  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * Score of a notice per the activity spam service
 *
 * @category Spam
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @see      DB_DataObject
 */
class Spam_score extends Managed_DataObject
{
    const MAX_SCALE = 10000;
    public $__table = 'spam_score'; // table name

    public $notice_id;   // int
    public $score;       // float
    public $created;     // datetime

    public static function save($notice, $result)
    {

        $orig = null;
        $score = Spam_score::getKV('notice_id', $notice->id);

        if (empty($score)) {
            $score = new Spam_score();
        } else {
            $orig = clone($score);
        }

        $score->notice_id = $notice->id;
        $score->score = $result->probability;
        $score->is_spam = $result->isSpam;
        $score->scaled = Spam_score::scale($score->score);
        $score->created = common_sql_now();
        $score->notice_created = $notice->created;

        if (empty($orig)) {
            $score->insert();
        } else {
            $score->update($orig);
        }

        self::blow('spam_score:notice_ids');

        return $score;
    }

    /**
     * The One True Thingy that must be defined and declared.
     */
    public static function schemaDef()
    {
        return array(
            'description' => 'score of the notice per activityspam',
            'fields' => array(
                'notice_id' => array('type' => 'int',
                    'not null' => true,
                    'description' => 'notice getting scored'),
                'score' => array('type' => 'double',
                    'not null' => true,
                    'description' => 'score for the notice (0.0, 1.0)'),
                'scaled' => array('type' => 'int',
                    'description' => 'scaled score for the notice (0, 10000)'),
                'is_spam' => array('type' => 'tinyint',
                    'description' => 'flag for spamosity'),
                'created' => array('type' => 'datetime',
                    'not null' => true,
                    'description' => 'date this record was created'),
                'notice_created' => array('type' => 'datetime',
                    'description' => 'date the notice was created'),
            ),
            'primary key' => array('notice_id'),
            'foreign keys' => array(
                'spam_score_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
            ),
            'indexes' => array(
                'spam_score_created_idx' => array('created'),
                'spam_score_scaled_idx' => array('scaled'),
            ),
        );
    }

    public static function upgrade()
    {
        Spam_score::upgradeScaled();
        Spam_score::upgradeIsSpam();
        Spam_score::upgradeNoticeCreated();
    }

    protected static function upgradeScaled()
    {
        $score = new Spam_score();
        $score->whereAdd('scaled IS NULL');

        if ($score->find()) {
            while ($score->fetch()) {
                $orig = clone($score);
                $score->scaled = Spam_score::scale($score->score);
                $score->update($orig);
            }
        }
    }

    protected static function upgradeIsSpam()
    {
        $score = new Spam_score();
        $score->whereAdd('is_spam IS NULL');

        if ($score->find()) {
            while ($score->fetch()) {
                $orig = clone($score);
                $score->is_spam = ($score->score >= 0.90) ? 1 : 0;
                $score->update($orig);
            }
        }
    }

    protected static function upgradeNoticeCreated()
    {
        $score = new Spam_score();
        $score->whereAdd('notice_created IS NULL');

        if ($score->find()) {
            while ($score->fetch()) {
                $notice = Notice::getKV('id', $score->notice_id);
                if (!empty($notice)) {
                    $orig = clone($score);
                    $score->notice_created = $notice->created;
                    $score->update($orig);
                }
            }
        }
    }

    function saveNew($notice, $result)
    {

        $score = new Spam_score();

        $score->notice_id = $notice->id;
        $score->score = $result->probability;
        $score->is_spam = $result->isSpam;
        $score->scaled = Spam_score::scale($score->score);
        $score->created = common_sql_now();
        $score->notice_created = $notice->created;

        $score->insert();

        self::blow('spam_score:notice_ids');

        return $score;
    }

    public static function scale($score)
    {
        $raw = round($score * Spam_score::MAX_SCALE);
        return max(0, min(Spam_score::MAX_SCALE, $raw));
    }

    public function delete($useWhere = false)
    {
        self::blow('spam_score:notice_ids');
        self::blow('spam_score:notice_ids;last');
        return parent::delete($useWhere);
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Toggle indicating spam, click to train as ham
 *
 * 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  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

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

class TrainHamForm extends Form {

    var $notice  = null;

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

    /**
     * Name of the form
     *
     * Sub-classes should overload this with the name of their form.
     *
     * @return void
     */

    function formLegend()
    {
        return _("Train ham");
    }

    /**
     * Visible or invisible data elements
     *
     * Display the form fields that make up the data of the form.
     * Sub-classes should overload this to show their data.
     *
     * @return void
     */

    function formData()
    {
        $this->hidden('notice', $this->notice->id);
    }

    /**
     * Buttons for form actions
     *
     * Submit and cancel buttons (or whatever)
     * Sub-classes should overload this to show their own buttons.
     *
     * @return void
     */

    function formActions()
    {
        $this->submit('train-ham-submit-' . $this->notice->id,
                      _('Clear spam'),
                      'submit',
                      null,
                      _("Clear spam"));
    }

    /**
     * ID of the form
     *
     * Should be unique on the page. Sub-classes should overload this
     * to show their own IDs.
     *
     * @return int ID of the form
     */

    function id()
    {
        return 'train-ham-' . $this->notice->id;
    }

    /**
     * Action of the form.
     *
     * URL to post to. Should be overloaded by subclasses to give
     * somewhere to post to.
     *
     * @return string URL to post to
     */

    function action()
    {
        return common_local_url('train', array('category' => 'ham'));
    }

    /**
     * Class of the form. May include space-separated list of multiple classes.
     *
     * If 'ajax' is included, the form will automatically be submitted with
     * an 'ajax=1' parameter added, and the resulting form or error message
     * will replace the form after submission.
     *
     * It's up to you to make sure that the target action supports this!
     *
     * @return string the form's class
     */

    function formClass()
    {
        return 'form-train-ham ajax';
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Toggle indicating ham, click to train as spam
 *
 * 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  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

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

class TrainSpamForm extends Form {

    var $notice  = null;

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

    /**
     * Name of the form
     *
     * Sub-classes should overload this with the name of their form.
     *
     * @return void
     */

    function formLegend()
    {
        return _("Train spam");
    }

    /**
     * Visible or invisible data elements
     *
     * Display the form fields that make up the data of the form.
     * Sub-classes should overload this to show their data.
     *
     * @return void
     */

    function formData()
    {
        $this->hidden('notice', $this->notice->id);
    }

    /**
     * Buttons for form actions
     *
     * Submit and cancel buttons (or whatever)
     * Sub-classes should overload this to show their own buttons.
     *
     * @return void
     */

    function formActions()
    {
        $this->submit('train-spam-submit-' . $this->notice->id,
                      _('Train spam'),
                      'submit',
                      null,
                      _("Mark as spam"));
    }

    /**
     * ID of the form
     *
     * Should be unique on the page. Sub-classes should overload this
     * to show their own IDs.
     *
     * @return int ID of the form
     */

    function id()
    {
        return 'train-spam-' . $this->notice->id;
    }

    /**
     * Action of the form.
     *
     * URL to post to. Should be overloaded by subclasses to give
     * somewhere to post to.
     *
     * @return string URL to post to
     */

    function action()
    {
        return common_local_url('train', array('category' => 'spam'));
    }

    /**
     * Class of the form. May include space-separated list of multiple classes.
     *
     * If 'ajax' is included, the form will automatically be submitted with
     * an 'ajax=1' parameter added, and the resulting form or error message
     * will replace the form after submission.
     *
     * It's up to you to make sure that the target action supports this!
     *
     * @return string the form's class
     */

    function formClass()
    {
        return 'form-train-spam ajax';
    }
}


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

/**
 * Spam filter class
 *
 * Local proxy for remote filter
 *
 * @category  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2012 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class SpamFilter extends OAuthClient {

    const HAM  = 'ham';
    const SPAM = 'spam';

    public $server;

    function __construct($server, $consumerKey, $secret) {
        parent::__construct($consumerKey, $secret);
        $this->server = $server;
    }

    protected function toActivity($notice) {
        // FIXME: need this to autoload ActivityStreamsMediaLink
        $doc = new ActivityStreamJSONDocument();

        $activity = $notice->asActivity(null);

        return $activity;
    }

    public function test($notice) {

        $activity = $this->toActivity($notice);
        return $this->testActivity($activity);
    }

    public function testActivity($activity) {

        $response = $this->postJSON($this->server . "/is-this-spam", $activity->asArray());

        $result = json_decode($response->getBody());

        return $result;
    }

    public function train($notice, $category) {

        $activity = $this->toActivity($notice);
        return $this->trainActivity($activity, $category);

    }

    public function trainActivity($activity, $category) {

        switch ($category) {
        case self::HAM:
            $endpoint = '/this-is-ham';
            break;
        case self::SPAM:
            $endpoint = '/this-is-spam';
            break;
        default:
            throw new Exception("Unknown category: " + $category);
        }

        $response = $this->postJSON($this->server . $endpoint, $activity->asArray());

        // We don't do much with the results
        return true;
    }

    public function trainOnError($notice, $category) {

        $activity = $this->toActivity($notice);

        return $this->trainActivityOnError($activity, $category);
    }

    public function trainActivityOnError($activity, $category) {

        $result = $this->testActivity($activity);

        if (($category === self::SPAM && $result->isSpam) ||
            ($category === self::HAM && !$result->isSpam)) {
            return true;
        } else {
            return $this->trainActivity($activity, $category);
        }
    }

    function postJSON($url, $body)
    {
        $request = OAuthRequest::from_consumer_and_token($this->consumer,
                                                         $this->token,
                                                         'POST',
                                                         $url);

        $request->sign_request($this->sha1_method,
                               $this->consumer,
                               $this->token);

        $hclient = new HTTPClient($url);

        $hclient->setConfig(array('connect_timeout' => 120,
                                  'timeout' => 120,
                                  'follow_redirects' => true,
                                  'ssl_verify_peer' => false,
                                  'ssl_verify_host' => false));

        $hclient->setMethod(HTTP_Request2::METHOD_POST);
        $hclient->setBody(json_encode($body));
        $hclient->setHeader('Content-Type', 'application/json');
        $hclient->setHeader($request->to_header());

        // Twitter is strict about accepting invalid "Expect" headers
        // No reason not to clear it still here -ESP

        $hclient->setHeader('Expect', '');

        try {
            $response = $hclient->send();
            $code = $response->getStatus();
            if (!$response->isOK()) {
                throw new OAuthClientException($response->getBody(), $code);
            }
            return $response;
        } catch (Exception $e) {
            throw new OAuthClientException($e->getMessage(), $e->getCode());
        }
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2012, StatusNet, Inc.
 *
 * Spam notice stream
 *
 * 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  Spam
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2012 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

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

class SpamNoticeStream extends ScopingNoticeStream
{
    function __construct(Profile $scoped=null)
    {
        parent::__construct(new CachingNoticeStream(new RawSpamNoticeStream(), 'spam_score:notice_ids'),
                            $scoped);
    }
}

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

class RawSpamNoticeStream extends NoticeStream
{
    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        $ss = new Spam_score();

        $ss->is_spam = 1;

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

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

        $ss->orderBy('notice_created DESC, notice_id DESC');

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

        $ids = array();

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

        return $ids;
    }
}


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: 2019-06-08 18:20+0100\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: ActivitySpamPlugin.php:210
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:227
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: af\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar_EG\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:29+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ast\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Belarusian (Tarask) (http://www.transifex.com/gnu-social/gnu-social/language/be@tarask/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: be@tarask\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Bulgarian (http://www.transifex.com/gnu-social/gnu-social/language/bg/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bg\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Bengali (India) (http://www.transifex.com/gnu-social/gnu-social/language/bn_IN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bn_IN\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Breton (http://www.transifex.com/gnu-social/gnu-social/language/br/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: br\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan (http://www.transifex.com/gnu-social/gnu-social/language/ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ca\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Czech (http://www.transifex.com/gnu-social/gnu-social/language/cs/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: cs\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Danish (http://www.transifex.com/gnu-social/gnu-social/language/da/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: da\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2012 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:30+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: German (http://www.transifex.com/gnu-social/gnu-social/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Nachrichten am Activity-Spam-Service testen"


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Greek (http://www.transifex.com/gnu-social/gnu-social/language/el/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: el\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Luke Hollins <luke@farcry.ca>, 2015
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-03-07 12:32+0000\n"
"Last-Translator: Luke Hollins <luke@farcry.ca>\n"
"Language-Team: English (United Kingdom) (http://www.transifex.com/gnu-social/gnu-social/language/en_GB/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en_GB\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Test notices against the Activity Spam service."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Esperanto (http://www.transifex.com/gnu-social/gnu-social/language/eo/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: eo\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2012 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Juan Riquelme González <soulchainer@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-25 17:32+0000\n"
"Last-Translator: Juan Riquelme González <soulchainer@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/gnu-social/gnu-social/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Filtrar los mensajes con el servicio antispam."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Basque (http://www.transifex.com/gnu-social/gnu-social/language/eu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: eu\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Persian (http://www.transifex.com/gnu-social/gnu-social/language/fa/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fa\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Finnish (http://www.transifex.com/gnu-social/gnu-social/language/fi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fi\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2012 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:30+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: French (http://www.transifex.com/gnu-social/gnu-social/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Courrier polluant"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Avis de test à l'encontre du service d'activité du courrier polluant."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Adriano <biason.adriano@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-03-23 16:59+0000\n"
"Last-Translator: Adriano <biason.adriano@gmail.com>\n"
"Language-Team: Friulian (http://www.transifex.com/gnu-social/gnu-social/language/fur/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fur\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2012 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:30+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Galician (http://www.transifex.com/gnu-social/gnu-social/language/gl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: gl\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Probar os avisos co servizo de actividade de spam."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew (http://www.transifex.com/gnu-social/gnu-social/language/he/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: he\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Upper Sorbian (http://www.transifex.com/gnu-social/gnu-social/language/hsb/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: hsb\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hungarian (http://www.transifex.com/gnu-social/gnu-social/language/hu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: hu\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Armenian (Armenia) (http://www.transifex.com/gnu-social/gnu-social/language/hy_AM/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: hy_AM\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2012 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:30+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Interlingua (http://www.transifex.com/gnu-social/gnu-social/language/ia/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ia\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Testar avisos contra le servicio Activity Spam."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# zk <zamani.karmana@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-05-28 15:21+0000\n"
"Last-Translator: zk <zamani.karmana@gmail.com>\n"
"Language-Team: Indonesian (http://www.transifex.com/gnu-social/gnu-social/language/id/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: id\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
# Ciencisto Dementa <maliktunga@users.noreply.github.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-06-15 00:56+0000\n"
"Last-Translator: Ciencisto Dementa <maliktunga@users.noreply.github.com>\n"
"Language-Team: Ido (http://www.transifex.com/gnu-social/gnu-social/language/io/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: io\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Mesajacho"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Probo-avizi kontre la servado Activity Spam."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Icelandic (http://www.transifex.com/gnu-social/gnu-social/language/is/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: is\n"
"Plural-Forms: nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2012 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:30+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Italian (http://www.transifex.com/gnu-social/gnu-social/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr "Spam"

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr "Avvisi di prova contro il servizio Spam Activity."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:21+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Japanese (http://www.transifex.com/gnu-social/gnu-social/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ja\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#: ActivitySpamPlugin.php:208
msgctxt "MENU"
msgid "Spam"
msgstr ""

#: ActivitySpamPlugin.php:225
msgid "Test notices against the Activity Spam service."
msgstr ""