Michel Krämer http://www.michel-kraemer.com Michel Krämer's blog about Open Source software development with Scala, Java and C++, as well as other helpful tips and tricks. 2014-04-13 14:41:24 +0200 en hourly 1 gradle-download-task: download files with progress http://www.michel-kraemer.com/gradle-download-task-download-files-with-progress http://www.michel-kraemer.com/gradle-download-task-download-files-with-progress#comments 2014-03-22T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/gradle-download-task-download-files-with-progress I really like how Gradle displays progress while it’s fetching artifacts from Maven repositories, but I was always wondering why you cannot use the same functionality when you’re downloading arbitrary files in your build script. You can of course use Ant’s download task to fetch files, but it does not display progress information. Since I couldn’t find a solution on the Internet I decided to write a plugin.

gradle-download-task has initially been released in September 2013 and is now available in version 1.0. The plugin contributes a download task that shows progress information just like Gradle does when it fetches artifacts from a repository.

You can use it like this:

task downloadFile(type: Download) {
    src 'http://www.example.com/index.html'
    dest buildDir
}

The output will look like this:

Download http://www.example.com/index.html
> Building > :downloadFile > 320 KB/6,78 MB downloaded

In order to use the plugin you have to add the following lines to your build file:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'de.undercouch:gradle-download-task:1.0'
    }
}

import de.undercouch.gradle.tasks.download.Download

You can also use the download extension to retrieve a file anywhere in your build script:

apply plugin: 'download-task'

task myTask << {
    //do something ...
    //... then download a file
    download {
        src 'http://www.example.com/index.html'
        dest buildDir
    }
    //... do something else
}

With version 1.0 you can now also sequentially download a list of files to a directory. Please note that you have to specify a directory as destination if you download multiple files. Otherwise the plugin will fail.

task downloadMultipleFiles(type: Download) {
    src([
        'http://www.example.com/index.html',
        'http://www.example.com/test.html'
    ])
    dest buildDir
}

Many thanks go to Bright Fulton who contributed support for custom HTTP request headers. You can use this new feature as follows:

task downloadWithCustomHeader(type: Download) {
    src 'http://download.oracle.com/otn-pub/java/jdk/8-b132/jre-8-windows-x64.exe'
    dest buildDir
    header 'Cookie', 'oraclelicense=accept-securebackup-cookie'
}

The plugin supports a wide range of other options. Please read the README file for more information.

Happy downloading!

]]>
I really like how Gradle displays progress while it’s fetching artifacts from Maven repositories, but I was always wondering why you cannot use the same functionality when you’re downloading arbitrary files in your build script. You can of course use Ant’s download task to fetch files, but it does not display progress information. Since I couldn’t find a solution on the Internet I decided to write a plugin.

gradle-download-task has initially been released in September 2013 and is now available in version 1.0. The plugin contributes a download task that shows progress information just like Gradle does when it fetches artifacts from a repository.

You can use it like this:

task downloadFile(type: Download) {
    src 'http://www.example.com/index.html'
    dest buildDir
}

The output will look like this:

Download http://www.example.com/index.html
> Building > :downloadFile > 320 KB/6,78 MB downloaded

In order to use the plugin you have to add the following lines to your build file:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'de.undercouch:gradle-download-task:1.0'
    }
}

import de.undercouch.gradle.tasks.download.Download

You can also use the download extension to retrieve a file anywhere in your build script:

apply plugin: 'download-task'

task myTask << {
    //do something ...
    //... then download a file
    download {
        src 'http://www.example.com/index.html'
        dest buildDir
    }
    //... do something else
}

With version 1.0 you can now also sequentially download a list of files to a directory. Please note that you have to specify a directory as destination if you download multiple files. Otherwise the plugin will fail.

task downloadMultipleFiles(type: Download) {
    src([
        'http://www.example.com/index.html',
        'http://www.example.com/test.html'
    ])
    dest buildDir
}

Many thanks go to Bright Fulton who contributed support for custom HTTP request headers. You can use this new feature as follows:

task downloadWithCustomHeader(type: Download) {
    src 'http://download.oracle.com/otn-pub/java/jdk/8-b132/jre-8-windows-x64.exe'
    dest buildDir
    header 'Cookie', 'oraclelicense=accept-securebackup-cookie'
}

The plugin supports a wide range of other options. Please read the README file for more information.

Happy downloading!

]]>
Command line tool for citations and bibliographies http://www.michel-kraemer.com/command-line-tool-for-citations-and-bibliographies http://www.michel-kraemer.com/command-line-tool-for-citations-and-bibliographies#comments 2013-10-25T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/command-line-tool-for-citations-and-bibliographies I was working very hard on the new version of citeproc-java lately and I’m glad to announce that it has just been released. The highlights in version 0.6 are:

  • The binary distribution of citeproc-java contains a command line tool that can be used to generate citations and bibliographies without setting up a complete development environment. Just download and extract the zip file and then run citeproc-java -b references.bib -s ieee to create a bibliography in ieee style for your BibTeX input file. This feature makes the library very useful even for non-programmers.
  • The new Mendeley connector allows you to use documents stored in Mendeley Web as input for citations and bibliographies. Of course this feature also works on the command line.
  • The library has been tested with the CSL test suite. All 750+ tests run successfully! I put a lot of work into this to bring citeproc-java on par with other CSL processors.
  • Performance has been improved a lot.

I particularly like the new command line tool that can be used to generate citations and bibliographies from various sources such as BibTeX files or your Mendeley Web catalog. I expect the tool to be quite useful for the following users:

  • Authors who want a quick way to preview citations or bibliographies in various styles
  • Citation Style Language style authors who want to test their style files very quickly

In order to use the tool you just have to download citeproc-java and extract the ZIP file. Then you can run the following command to convert a BibTeX file to a bibliography using the ieee style, for example:

citeproc-java -b references.bib

If you want to generate a bibliography that only contains items with certain citation IDs (for example Fowler_2010 and Kisker_2012) use the following command:

citeproc-java -b references.bib Fowler_2010 Kisker_2012

The tool will even notify you if you misspelled a citation ID:

citeproc-java: unknown citation id: Fwler_2010
Did you mean `Fowler_2010'?

If you want to connect to your Mendeley Web account, use the following command:

citeproc-java --mendeley Fowler_2010 Kisker_2012

The tool has a lot more to offer. For more information run citeproc-java --help or read the library’s documentataion.

]]>
I was working very hard on the new version of citeproc-java lately and I’m glad to announce that it has just been released. The highlights in version 0.6 are:

  • The binary distribution of citeproc-java contains a command line tool that can be used to generate citations and bibliographies without setting up a complete development environment. Just download and extract the zip file and then run citeproc-java -b references.bib -s ieee to create a bibliography in ieee style for your BibTeX input file. This feature makes the library very useful even for non-programmers.
  • The new Mendeley connector allows you to use documents stored in Mendeley Web as input for citations and bibliographies. Of course this feature also works on the command line.
  • The library has been tested with the CSL test suite. All 750+ tests run successfully! I put a lot of work into this to bring citeproc-java on par with other CSL processors.
  • Performance has been improved a lot.

I particularly like the new command line tool that can be used to generate citations and bibliographies from various sources such as BibTeX files or your Mendeley Web catalog. I expect the tool to be quite useful for the following users:

  • Authors who want a quick way to preview citations or bibliographies in various styles
  • Citation Style Language style authors who want to test their style files very quickly

In order to use the tool you just have to download citeproc-java and extract the ZIP file. Then you can run the following command to convert a BibTeX file to a bibliography using the ieee style, for example:

citeproc-java -b references.bib

If you want to generate a bibliography that only contains items with certain citation IDs (for example Fowler_2010 and Kisker_2012) use the following command:

citeproc-java -b references.bib Fowler_2010 Kisker_2012

The tool will even notify you if you misspelled a citation ID:

citeproc-java: unknown citation id: Fwler_2010
Did you mean `Fowler_2010'?

If you want to connect to your Mendeley Web account, use the following command:

citeproc-java --mendeley Fowler_2010 Kisker_2012

The tool has a lot more to offer. For more information run citeproc-java --help or read the library’s documentataion.

]]>
Generating citations and bibliographies with CSL and citeproc-java http://www.michel-kraemer.com/generating-citations-and-bibliographies-with-CSL-and-citeproc-java http://www.michel-kraemer.com/generating-citations-and-bibliographies-with-CSL-and-citeproc-java#comments 2013-09-16T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/generating-citations-and-bibliographies-with-CSL-and-citeproc-java I was recently writing a scientific document with AsciiDoc. As usual my toolchain was AsciiDoc → DocBook → FO → PDF. It really worked quite well until I came to the point where manually adding citations and editing the biblioghraphy by hand became really complex and I suddenly found myself yearning for more automation.

I asked Google what I could do and Google told me about BibTeX and all that stuff. There even was a tool called asciidoc-bib by Peter Lane that was able to read BibTeX files to generate citations and bibliographies and then put them into an AsciiDoc source file. I tested this tool for a while and contributed one or two commits via GitHub. However, I was not yet convinced by the flexibility and maturity of asciidoc-bib by that time, so I started looking for ways how to extend it.

Enter the Citation Style Language (CSL). CSL is an XML-based description of citation styles and bibliographies that’s maintained by a number of people from the scientific community. They say it’s “by academics, for academics”. I really loved the idea of having a more modern alternative to BibTeX and natbib which I never found particularly mind-blowing by the way.

I started with extending asciidoc-bib with support for a library called citeproc-ruby by Sylvester Keil. citeproc-ruby is a so-called CSL processor. That means it reads CSL styles and transforms them to citations and bibliographies. However, I still found asciidoc-bib too cumbersome to use, in particular since it was written in Ruby and my toolchain was based on Java.

So I asked Google again, if they could tell me something about CSL and Java, but they said they didn’t know very much about that. That was when I finally decided to write my own CSL processor for Java.

citeproc-java

Today I’m pleased to announce the first release of citeproc-java, a CSL processor for Java! An (almost) complete documentation is available at the following site:

http://michel-kraemer.github.io/citeproc-java/

I have to be honest with you guys. I didn’t implement the whole CSL specification myself. Instead I tried to incorporate existing code as much as possible. citeproc-java uses the great citeproc-js by Frank G. Bennett, Jr. internally. It is therefore fully CSL 1.0.1-compliant. Apart from that, it offers some cool additional features such as BibTeX import as well as export to AsciiDoc and FO.

For convenience I uploaded citeproc-java and the CSL styles and locales to Maven central. Please see the installation instructions for more information:

http://michel-kraemer.github.io/citeproc-java/download/

citeproc-java’s BibTeX to CSL mapping is based on the one used in the Docear software. It has been converted to Java by permission from the Docear authors, in particular Joeran Beel. The BibTeX converter imports author names using the name parser from the citeproc-ruby project. It has been converted to Java by permission from Sylvester Keil. Thank you very much for that!

Although citeproc-java is a very young project and this is the very first release, I consider it rather stable already—not least because it uses citeproc-js under the hood. Nevertheless, development of citeproc-java has just begun and I’m sure there are great features to come. If you want to participate, don’t hesitate to fork my GitHub repository and send me pull requests:

https://github.com/michel-kraemer/citeproc-java

Finally, big thanks go to the CSL community for the great work and support!

License

citeproc-java is licensed under the Apache License, Version 2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

]]>
I was recently writing a scientific document with AsciiDoc. As usual my toolchain was AsciiDoc → DocBook → FO → PDF. It really worked quite well until I came to the point where manually adding citations and editing the biblioghraphy by hand became really complex and I suddenly found myself yearning for more automation.

I asked Google what I could do and Google told me about BibTeX and all that stuff. There even was a tool called asciidoc-bib by Peter Lane that was able to read BibTeX files to generate citations and bibliographies and then put them into an AsciiDoc source file. I tested this tool for a while and contributed one or two commits via GitHub. However, I was not yet convinced by the flexibility and maturity of asciidoc-bib by that time, so I started looking for ways how to extend it.

Enter the Citation Style Language (CSL). CSL is an XML-based description of citation styles and bibliographies that’s maintained by a number of people from the scientific community. They say it’s “by academics, for academics”. I really loved the idea of having a more modern alternative to BibTeX and natbib which I never found particularly mind-blowing by the way.

I started with extending asciidoc-bib with support for a library called citeproc-ruby by Sylvester Keil. citeproc-ruby is a so-called CSL processor. That means it reads CSL styles and transforms them to citations and bibliographies. However, I still found asciidoc-bib too cumbersome to use, in particular since it was written in Ruby and my toolchain was based on Java.

So I asked Google again, if they could tell me something about CSL and Java, but they said they didn’t know very much about that. That was when I finally decided to write my own CSL processor for Java.

citeproc-java

Today I’m pleased to announce the first release of citeproc-java, a CSL processor for Java! An (almost) complete documentation is available at the following site:

http://michel-kraemer.github.io/citeproc-java/

I have to be honest with you guys. I didn’t implement the whole CSL specification myself. Instead I tried to incorporate existing code as much as possible. citeproc-java uses the great citeproc-js by Frank G. Bennett, Jr. internally. It is therefore fully CSL 1.0.1-compliant. Apart from that, it offers some cool additional features such as BibTeX import as well as export to AsciiDoc and FO.

For convenience I uploaded citeproc-java and the CSL styles and locales to Maven central. Please see the installation instructions for more information:

http://michel-kraemer.github.io/citeproc-java/download/

citeproc-java’s BibTeX to CSL mapping is based on the one used in the Docear software. It has been converted to Java by permission from the Docear authors, in particular Joeran Beel. The BibTeX converter imports author names using the name parser from the citeproc-ruby project. It has been converted to Java by permission from Sylvester Keil. Thank you very much for that!

Although citeproc-java is a very young project and this is the very first release, I consider it rather stable already—not least because it uses citeproc-js under the hood. Nevertheless, development of citeproc-java has just begun and I’m sure there are great features to come. If you want to participate, don’t hesitate to fork my GitHub repository and send me pull requests:

https://github.com/michel-kraemer/citeproc-java

Finally, big thanks go to the CSL community for the great work and support!

License

citeproc-java is licensed under the Apache License, Version 2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

]]>
bson4jackson 2.2 has just been released! http://www.michel-kraemer.com/bson4jackson-2.2-has-just-been-released http://www.michel-kraemer.com/bson4jackson-2.2-has-just-been-released#comments 2013-05-09T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/bson4jackson-2.2-has-just-been-released Version 2.2 of bson4jackson has just been released. bson4jackson adds support for BSON, a binary representation of JSON, to the Jackson JSON processor.]]> Version 2.2 of bson4jackson has just been released. bson4jackson adds support for BSON, a binary representation of JSON, to the Jackson JSON processor.

The latest release of bson4jackson now supports Jackson 2.2. Apart from that, Ben McCann and John Stoneham fixed the Maven dependencies and updated some 3rd party libraries, so project builds depending on bson4jackson should now be more stable. Thanks a lot for that, guys!

Projects using bson4jackson

bson4jackson is used in several other Open Source projects including the following one:

  • Jongo is a rather cool library that allows MongoDB to be queried in Java just like you would query it in the MongoDB shell. Jongo uses bson4jackson to serialize objects before they are sent to the database, and of course to deserialize queried documents.

    http://jongo.org/

  • MongoJack is a POJO mapper that uses Jackson and bson4jackson to serialize and deserialize objects before they are sent to the database. MongoJack is extremely fast and very easy to handle.

    http://mongojack.org/

I know that there are a lot of other projects out there that use bson4jackson. If you want your project to be added to this list please leave a comment below or send me a message.

More information

For a complete description of bson4jackson (including how to download it) have a look at my tutorial.

]]>
Spamihilator website now Open Source http://www.michel-kraemer.com/spamihilator-website-open-source http://www.michel-kraemer.com/spamihilator-website-open-source#comments 2013-05-02T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/spamihilator-website-open-source I’ve just released the source code of the Spamihilator website as Open Source. You can download it from the following GitHub repository:

https://github.com/michel-kraemer/spamihilator.com

Everyone is invited to make contributions! I’m open to all kind of changes. You may submit new content (e.g. FAQ), change the design or style, etc.

If you want to contribute please fork the GitHub repository and send me pull requests. I will check and upload them to the Spamihilator web server as soon as possible. Further instructions can be found below or in the README file.

Building

The Spamihilator website has been created using Jekyll. If you want to build it please follow these steps:

  1. Download and install Ruby 1.8.7 (if you haven’t done so already).

    Under Windows I recommend to use RubyInstaller. Under Linux and Mac OS I highly recommend to use rvm as the repository already contains proper .ruby-version and .ruby-gemset files.

  2. Install the bundler gem (if you haven’t done so already).

    gem install bundler

  3. Clone or download this repository.

  4. Open a command line shell in the cloned directory and enter the following command:

    bundle install

  5. After that you are ready to build the website using the following commands:

    compass compile
    jekyll

  6. Repeat these commands whenever you make a change. The files will be compiled to the subdirectory _site.

Run locally

You may also run and test the website locally before uploading your changes. In order to do this, follow the instructions above and then run the following command:

jekyll --server

Launch a web browser and open http://localhost:4000 to view the site. For more information see Jekyll’s website.

License

Creative Commons License
If not noted otherwise the files in the Spamihilator website repository are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

]]>
I’ve just released the source code of the Spamihilator website as Open Source. You can download it from the following GitHub repository:

https://github.com/michel-kraemer/spamihilator.com

Everyone is invited to make contributions! I’m open to all kind of changes. You may submit new content (e.g. FAQ), change the design or style, etc.

If you want to contribute please fork the GitHub repository and send me pull requests. I will check and upload them to the Spamihilator web server as soon as possible. Further instructions can be found below or in the README file.

Building

The Spamihilator website has been created using Jekyll. If you want to build it please follow these steps:

  1. Download and install Ruby 1.8.7 (if you haven’t done so already).

    Under Windows I recommend to use RubyInstaller. Under Linux and Mac OS I highly recommend to use rvm as the repository already contains proper .ruby-version and .ruby-gemset files.

  2. Install the bundler gem (if you haven’t done so already).

    gem install bundler

  3. Clone or download this repository.

  4. Open a command line shell in the cloned directory and enter the following command:

    bundle install

  5. After that you are ready to build the website using the following commands:

    compass compile
    jekyll

  6. Repeat these commands whenever you make a change. The files will be compiled to the subdirectory _site.

Run locally

You may also run and test the website locally before uploading your changes. In order to do this, follow the instructions above and then run the following command:

jekyll --server

Launch a web browser and open http://localhost:4000 to view the site. For more information see Jekyll’s website.

License

Creative Commons License
If not noted otherwise the files in the Spamihilator website repository are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

]]>
5 anti-spam measures for phpBB 3.0 http://www.michel-kraemer.com/5-anti-spam-measures-for-phpbb3 http://www.michel-kraemer.com/5-anti-spam-measures-for-phpbb3#comments 2013-03-30T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/5-anti-spam-measures-for-phpbb3

This is an English translation of my German blog post. I updated it so the measures described here are compatible to the latest phpBB 3.x version.

phpBB is an open-source forum software that is very popular and widely used. This makes it an ideal target for spammers. The phpBB developers therefore implemented an improved Captcha in version 3.0. But spammers have already adapted to this and have implemented improved bots that are able to break the new Captcha and to automatically create junk posts. In the following I will describe five anti-spam measures that effectively reduce spam in every phpBB 3.x instance. The main goal of these measures is to block as many spam posts as possible without affecting normal forum users.]]>

This is an English translation of my German blog post. I updated it so the measures described here are compatible to the latest phpBB 3.x version.

phpBB is an open-source forum software that is very popular and widely used. This makes it an ideal target for spammers. The phpBB developers therefore implemented an improved Captcha in version 3.0. But spammers have already adapted to this and have implemented improved bots that are able to break the new Captcha and to automatically create junk posts. In the following I will describe five anti-spam measures that effectively reduce spam in every phpBB 3.x instance. The main goal of these measures is to block as many spam posts as possible without affecting normal forum users.

Typically spammers try to advertise certain websites. About 95% of all spam posts contain links or URLs. The most effective way to block those posts is to completely forbid links. However, this would also affect normal forum users.

Spammers usually sign in to a forum and then immediately start posting junk. We can make use of this and forbid links only to guests and users with less than a certain number of posts. Once a normal user has reached this number of posts links will be enabled. Typical spam bots will never reach this number since all their posts will be blocked.

To forbid posting links you have to add the following to the function submit_post() in the file includes\functions_posting.php.

//Define the minimum number of posts for "good" users
//Users below this threshold are considered potential spammers
$user_posts_threshold = 3;
 
//strip whitespace characters in the post body
$msgwows = $data['message'];
$msgwows = str_replace(" ", "", $msgwows);
$msgwows = str_replace("\n", "", $msgwows);
$msgwows = str_replace("\r", "", $msgwows);
$msgwows = str_replace("\t", "", $msgwows);
 
if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (strpos($msgwows, 'http://') !== FALSE ||
      strpos($msgwows, 'ftp://') !== FALSE ||
      strpos($msgwows, 'www.') !== FALSE ||
      strpos($msgwows, '[url') !== FALSE) {
    trigger_error("You are not allowed to post URLs!");
  }
}

This code should be put at the beginning of the submit_post() function to check all posts before they are saved to the database.

Measure #2: images

Spammers often try to trick spam filters by posting images instead of text. They put their junk messages and links into image files and then attach them to forum posts. You can use the same technique as the one described in measure #1 to block images for guests and users with less than a certain number of posts. Put the following code in the function submit_post() in the file functions/functions_posting.php.

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (strpos($msgwows, '[img') !== FALSE) {
    trigger_error("You are not allowed to post images!");
  }
}

Measure #3: Russian and Chinese posts?

A lot of spam posts are written in Russian or Chinese or simply contain a lot of special characters and garbage. If your forum is targeted to English users you can check if a post is written in English before it is submitted. Posts that mostly contain special characters or foreign characters can then be treated as spam.

Cory Mawhorter has developed a PHP funktion (is_english()) that is able to recognise special characters. You can use this function to differentiate English posts from any other.

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (!is_english($msgwows, 0.75)) {
    trigger_error("Only English posts are allowed here!");
  }
}

Measure #4: http:BL

Project Honey Pot offers an effective system to keep spammers and mail address harvesters away from websites. http:BL matches the website visitor’s IP address against a database. If the IP address is known to be used by a spammer the visitor will be blocked before the website is even rendered. The system uses DNS which makes queries very fast.

In order to use http:BL you first have to sign up for Project Honey Pot. You will receive a special key that is used to authenticate against the system. They already offer a MOD for phpBB but it is only compatible to version 2.0. You may be able to make it compatible to phpBB 3, but alternatively you can simply put the following code at the end of the file common.php.

Update (2013-08-06): As Paul M. Edwards pointed out in the comments there is an updated http:BL MOD that supports phpBB3:
https://www.phpbb.com/customise/db/mod/advanced_block_mod/

Thank you very much, Paul!

//configure your http:BL Access Key here
$httpblkey = "xxxxxxxxxxx";
$httpblmaxdays = 21;
$httpblmaxthreat = 25;
 
//if you already configured a honey pot on your website use this line:
//$httpblhoneypot = "http://xxxxxxxxxxx";
 
function httpbl_check() {
  global $httpblkey, $httpblmaxdays, $httpblmaxthreat, $httpblhoneypot;
 
  $ip = $_SERVER["REMOTE_ADDR"];
 
  $result = explode(".", gethostbyname($httpblkey."."
    .implode(".", array_reverse(explode(".", $ip)))
    .".dnsbl.httpbl.org"));
 
  if ($result[0] != 127) {
    //something went wrong or the IP is not in the database.
    //ignore this one.
    return;
  }
 
  $days = $result[1];
  $threat = $result[2];
 
  if ($days < $httpblmaxdays && $threat > $httpblmaxthreat) {
    if ($httpblhoneypot) {
      header("HTTP/1.1 301 Moved Permanently");
      header("Location: ".$httpblhoneypot);
    }
    die();
  }
}
httpbl_check();

Please make sure to put your http:BL access key in the variable $httpblkey.

Measure #5: Akismet

Another technique to block Internet spam is Akismet. This system is usually used in WordPress blogs to block comment spammers. Just like for Project Honey Pot you need to sign up to receive an API key.

You can use Akismet to block posts in phpBB 3 forums as well. The system may produce false positives (normal posts accidentally identified as spam). I therefore recommend to only check the first posts of a new user until he or she has reached a certain number of posts. The following code uses the file Akismet.class.php that can be downloaded from Alex Potsides’ GitHub repository. Put the code in the function submit_post() in the file includes/functions_posting.php.

//configure your Akismet API key here
$akismet_key = 'xxxxxxxxxxx';
 
//the URL you entered when you registered for a Wordpress account
$akismet_url = 'xxxxxxxxxxx';
 
include('Akismet.class.php');
 
$akismet = new Akismet($akismet_url, $akismet_key);
if (!$user->data['is_registered'])
  $akismet->setCommentAuthor($username);
else
  $akismet->setCommentAuthor($user->data['username']);
$akismet->setCommentContent($data['message']);
$akismet->setUserIP($user->ip);
if ($user->data['is_registered'])
{
  $akismet->setCommentAuthorEmail(strtolower($user->data['user_email']));
  $akismet->setCommentAuthorURL(strtolower($user->data['user_website']));
}
 
if ((!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) &&
    $akismet->isCommentSpam()) {
    trigger_error("Akismet says your post is spam");
}

Put your Akismet API key into the variable $akismet_key. The URL you entered during sign-up has to be put in the variable $akismet_url.

Akismet can also be used reasonably to block spammers who try to sign up to your forum. Put the following code into the function user_add() in the file includes/functions_user.php.

//configure your Akismet API key here
$akismet_key = 'xxxxxxxxxxx';
 
//the URL you entered when you registered for a Wordpress account
$akismet_url = 'xxxxxxxxxxx';
 
include('Akismet.class.php');
 
$akismet = new Akismet($akismet_url, $akismet_key);
$akismet->setCommentAuthor($username_clean);
$akismet->setUserIP($user->ip);
$akismet->SetCommentAuthorEmail(strtolower($user_row['user_email']));
 
if($akismet->isCommentSpam()) {
  trigger_error("Akismet says you are a spammer");
}

Conclusion

The measures presented here help drastically reduce spam in phpBB 3.0-based forums. Since I implemented them in the Spamihilator forum a couple of years ago only a very small number of spammers were actually able to post. However, none of their messages contained links, URLs or images. They mostly consisted of a number of meaningless and motley words.

Forbidding links and images is in my experience the most effective way to block spammers. Searching for special characters and foreign languages blocks all other spam posts that do not contain links or images. Normal users are typically not affected by these measures. As soon as a normal user reaches a certain number of ‘good’ posts the anti-spam measures are disabled. Up to now, in the Spamihilator forum no spammer was able to reach this limit. 3 or 5 posts is in my experience a good threshold. If ever needed, this limit can easily be raised.

Spammers often try to put links and images into signatures. I highly recommend to disable this in phpBB’s administration area. You may also try to apply the link and image filters from measure #1 and #2 respectively to signatures.

Many phpBB forums plagued by spammers disable guest posts. Users have to be registered to post. For support forums like Spamihilator’s this can be tedious for users who would like to easily post support requests without have to go through the complete sign-up procedure. The measures presented here allow forum administrators to leave guest posts enabled.

]]>
bson4jackson 2.0 has just been released! http://www.michel-kraemer.com/bson4jackson-2.0-has-just-been-released http://www.michel-kraemer.com/bson4jackson-2.0-has-just-been-released#comments 2012-04-09T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/bson4jackson-2.0-has-just-been-released Version 2.0 of bson4jackson has just been released. bson4jackson adds support for BSON, a binary representation of JSON, to the Jackson JSON processor. The latest release of bson4jackson now supports Jackson 2.0.]]> Version 2.0 of bson4jackson has just been released. bson4jackson adds support for BSON, a binary representation of JSON, to the Jackson JSON processor. The latest release of bson4jackson now supports Jackson 2.0.

Enda O’Donohoe fixed two bugs regarding the UTF-8 decoder. Thanks for that!

Support for Jackson 2.0 was greatly supported by James Roper. Thanks again for your contributions, James!

Support for older Jackson versions will be dropped with bson4jackson 2.0. If you’re looking for a version supporting the Jackson 1.x branch, then please download bson4jackson 1.3.0.

More information

For a complete description of bson4jackson (including how to download it) have a look at my tutorial.

]]>
Improved MongoDB compatibility for bson4jackson http://www.michel-kraemer.com/improved-mongodb-compatibility-for-bson4jackson http://www.michel-kraemer.com/improved-mongodb-compatibility-for-bson4jackson#comments 2011-12-17T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/improved-mongodb-compatibility-for-bson4jackson Version 1.2.0 of bson4jackson has just been released. bson4jackson adds support for BSON, a binary representation of JSON, to the Jackson JSON processor. Thanks to contributions from the community, the latest release of bson4jackson now includes better support for MongoDB.]]> Version 1.2.0 of bson4jackson has just been released. bson4jackson adds support for BSON, a binary representation of JSON, to the Jackson JSON processor. Thanks to contributions from the community, the latest release of bson4jackson now includes better support for MongoDB.

Gergő Ertli has fixed the support for the ObjectId type. Object IDs are used as the primary key for MongoDB documents.

Support for the UUID type has been added by Ed Anuff. He added a new module which can be registered to Jackson’s ObjectMapper:

ObjectMapper om = new ObjectMapper(new BsonFactory());
om.registerModule(new BsonUuidModule());

Thanks to the contribution by James Roper the BsonParser class now supports the new HONOR_DOCUMENT_LENGTH feature which makes the parser honor the first 4 bytes of a document which usually contain the document’s size. Of course, this only works if BsonGenerator.Feature.ENABLE_STREAMING has not been enabled during document generation.

This feature can be useful for reading consecutive documents from an input stream produced by MongoDB. You can enable it as follows:

BsonFactory fac = new BsonFactory();
fac.enable(BsonParser.Feature.HONOR_DOCUMENT_LENGTH);
BsonParser parser = (BsonParser)fac.createJsonParser(...);

Apart from that, a lot of other minor bugs have been fixed. The library has been tested with Jackson 1.7 up to 1.9.

More information

For a complete description of bson4jackson (including how to download it) have a look at my tutorial.

]]>
Build Scala projects with Eclipse Buckminster http://www.michel-kraemer.com/build-scala-projects-with-eclipse-buckminster http://www.michel-kraemer.com/build-scala-projects-with-eclipse-buckminster#comments 2011-06-26T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/build-scala-projects-with-eclipse-buckminster In one of my previous posts I talked about how to build Scala projects with PDE Build. However, PDE Build is rather old and has long been superseded by Buckminster. The great advantage of Buckminster is that it is actually a lightweight Eclipse SDK with all that you need to build an RCP application: a workspace of projects, a target platform, and so on. To build Scala projects in Eclipse you will most likely install the Scala IDE. Unfortunately, this plug-in cannot be installed in Buckminster right away. But there is a workaround…]]> In one of my previous posts I talked about how to build Scala projects with PDE Build. However, PDE Build is rather old and has long been superseded by Buckminster. The great advantage of Buckminster is that it is actually a lightweight Eclipse SDK with all that you need to build an RCP application: a workspace of projects, a target platform, and so on. To build Scala projects in Eclipse you will most likely install the Scala IDE. Unfortunately, this plug-in cannot be installed in Buckminster right away. But there is a workaround…

Short disclaimer: in this article I'm not going to describe how to actually build projects with Buckminster. This article is rather about how to install Buckminster, so it is able to handle Scala projects like any other project. If you need a more general description, please refer to the Buckminster website.

Why Buckminster?

Let’s first talk about why I prefer Buckminster over other solutions. Compared to other build tools, Buckminster has one great advantage: it provides an environment very similar to the one you’re developing in—the Eclipse SDK. You can see Buckminster as a lightweight Eclipse SDK without all this distracting UI stuff, but with a command line interface instead. However, Buckminster still has a workspace where you can import your projects into, and of course a target platform which defines the environment for your RCP application. Running a Buckminster-driven build with continuous integration systems like Hudson/Jenkins is also very easy, since all you have to do is to create some configuration files—a resource map and a CQuery—and then run a simple command on the shell like buckminster build. However, there there is also a plug-in available for Hudson/Jenkins, which automatically downloads and installs Buckminster if necessary. For more information on the usage please refer to the great book Buckminster, The definitive guide by Henrik Lindberg and Thomas Hallgren.

Buckminster is also one of the few tools that are able to build a full-featured Eclipse RCP application. There are extensions for other build tools like Ant or—since we’re talking about building Scala projects here—sbt. For example, Bnd is one of them. It allows building OSGi bundles without the need for creating a MANIFEST.MF file manually. Besides, you can always package your OSGi bundles yourself using the jar tool, but that is really not enough for serious RCP development.

If you want to build your RCP application headlessly, you have to use a tool that is really aware of what it is building. It has to understand the complex dependencies between your projects and the OSGi bundles from the target platform you use. Apart from that, it has to be able to parse files like MANIFEST.MF, build.properties, plugin.xml as well as configurations stored in .product or feature.xml files.

As far as I know, there are only three products available which support all these features—or at least most of them: PDE Build, Maven Tycho and of course Buckminster. I mention PDE Build here since it was formerly the recommended way to build RCP applications, but has now been superseded by Buckminster. PDE Build is also only a set of Ant scripts and does not support all of the aforementioned features. Tycho, on the other hand, has recently become a mature solution. It integrates very tightly into the well-known Maven build tool. This makes it very easy for people who are using Tycho for the first time, but already know Maven. Apart from that, Tycho contains some cool features like archetypes which automatically create pom.xml files for the bundles to build.

Nevertheless, I found Tycho always being slower than Buckminster—at least for very large projects with a lot of bundles. I don’t know if this has something to do with the support for incremental builds in multi-module projects (Is this still a problem with Maven 3 anyhow?) or with the way Tycho is resolving the target platform and how it calculates bundle dependencies. Apart from that, Tycho builds projects in a slightly different environment than they are developed in. This eliminates all of the aforementioned advantages of having a build environment that is very similar to the Eclipse SDK—as I said, this is in fact what you have when you use Buckminster. These disadvantages make it of course not impossible to build RCP applications, but they are the reason why I would prefer Buckminster over Tycho. Of course, this may change eventually, since Tycho is continuously developed.

How to install Buckminster and the Scala IDE normally

There is a Buckminster plug-in for the Eclipse SDK which adds a context menu with build tasks to all workspace projects. You simply install it using the p2 update manager. The current update site can be found at http://www.eclipse.org/buckminster/downloads.html.

Installing this plug-in and then installing the Scala IDE is very easy and lets you build Scala-featured OSGi bundles in a few minutes. Nevertheless, setting up Buckminster with the Scala IDE for headless operation is a little bit harder. If you follow the documentation very strictly, you will do the following things:

First you have to download the latest version of the p2 director application: director_latest.zip. You can then install the Buckminster RCP application with the following command:

$ director -r <url to headless repo> -d <buckminster install folder>
      -p Buckminster -i org.eclipse.buckminster.cmdline.product

This will download Buckminster from the supplied update site—which can be found on this site—and install it into the given folder. After that you will most likely want to install some additional features in order to enable headless builds. Change into the directory where you installed Buckminster and run the following commands, for example:

$ buckminster install <headless repo> org.eclipse.buckminster.core.headless.feature
$ buckminster install <headless repo> org.eclipse.buckminster.emma.headless.feature
$ buckminster install <headless repo> org.eclipse.buckminster.git.headless.feature
$ buckminster install <headless repo> org.eclipse.buckminster.pde.headless.feature

Additionally, you have to install the Scala IDE into Buckminster. Go to http://download.scala-ide.org and select the update site that fits your needs. Then run the following command:

$ buckminster install <scala ide repo> org.scala-ide.sdt.feature

Cannot complete the install because one or more required items could not be found.
[0]Software being installed: Scala IDE for Eclipse 2.0.0
     (org.scala-ide.sdt.feature.feature.group 2.0.0)
[0]Missing requirement: Scala IDE for Eclipse 2.0.0
     (org.scala-ide.sdt.feature.feature.group 2.0.0)
   requires 'org.eclipse.ui.navigator 0.0.0' but it could not be found

Oops! What happened? It seems like the Scala IDE requires user interface bundles, but my Buckminster runs on the command line!

Workaround

In order to work around this problem, you have to install Buckminster a little bit differently. First, you need the p2 director application again, but this time you will install the Eclipse SDK:

$ director -r <eclipse sdk repo url> -d <eclipse install folder>
      -profileProperties org.eclipse.update.install.features=true
      -p SDKProfile -i org.eclipse.sdk.ide

After that, change into the directory where you just installed Eclipse and run the following commands to install Buckminster:

$ eclipse -nosplash -application org.eclipse.equinox.p2.director
      -r <url to buckminster headless repo>
      -i org.eclipse.buckminster.core.headless.feature.feature.group
      -i org.eclipse.buckminster.emma.headless.feature.feature.group
      -i org.eclipse.buckminster.git.headless.feature.feature.group
      -i org.eclipse.buckminster.pde.headless.feature.feature.group

Please note the additional .feature.group at the end of each feature to install.

Finally, you can install the Scala IDE:

$ eclipse -nosplash -application org.eclipse.equinox.p2.director
      -r <scala ide repo>
      -i org.scala-ide.sdt.feature.feature.group
      -i org.scala-ide.sdt.weaving.feature.feature.group

This should succeed without errors.

From now on you can launch Buckminster with the following command:

$ eclipse -nosplash -application org.eclipse.buckminster.cmdline.headless

You may get the following exception when the Scala IDE bundles are started:

java.lang.IllegalStateException: Workbench has not been created yet

This is due to the fact that you don’t have a UI and thus no workbench. Fortunately, there’s an (undocumented?) system property you can set to avoid this exception. Simply add the following line at the end of your eclipse.ini:

-Dsdtcore.headless

This tells the Scala IDE that you’re running it in headless mode and that it should avoid accessing the workbench.

Summary

In this article I described how to headlessly build Scala projects with Buckminster. I talked about why I prefer Buckminster over other build tools and presented a workaround for installing Buckminster and the Scala IDE with the command line.

After installing Buckminster this way, you will have a full fledged tool to build Eclipse RCP applications including Scala plug-ins. However, installing a complete SDK would not be necessary if the Scala IDE bundles did not depend on Eclipse’s UI. It’s probably possible to create a feature containing only the core plugins like it has been done for the Groovy plug-in, but that’s something the Scala IDE team has to figure out in the future.

Nevertheless, a complete Eclipse SDK has also an advantage worth to mention: everything that works on your local machine will also work on your headless build server. Actually, you may even install your local Eclipse the same way as described above. Then you can absolutely be sure that your application is built in the same environment as it is developed in. This can make debugging a lot easier.

]]>
Binary JSON with bson4jackson http://www.michel-kraemer.com/binary-json-with-bson4jackson http://www.michel-kraemer.com/binary-json-with-bson4jackson#comments 2011-01-30T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/binary-json-with-bson4jackson Recently, JSON has become an excellent alternative to XML. But most JSON parsers written in Java are still rather slow. On my search for faster libraries I found two things: BSON and Jackson.]]> Recently, JSON has become an excellent alternative to XML. But most JSON parsers written in Java are still rather slow. On my search for faster libraries I found two things: BSON and Jackson.

BSON is binary encoded JSON. The format has been designed with fast machine readability in mind. BSON has gained prominence as the main data exchange format for the document-oriented database management system MongoDB. According to the JVM serializers benchmark Jackson is one of the fastest JSON processors available. Apart from that, Jackson allows writing custom extensions. This feature can be used to add further data exchange formats.

bson4jackson

This is the moment where bson4jackson steps in. The library extends Jackson by the capability of reading and writing BSON documents. Since bson4jackson is fully integrated, you can use the very nice API of Jackson to serialize simple POJOs. Think of the following class:

public class Person {
  private String _name;
 
  public void setName(String name) {
    _name = name;
  }
 
  public String getName() {
    return _name;
  }
}

You may use the so-called ObjectMapper to quickly serialize objects:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.undercouch.bson4jackson.BsonFactory;
 
public class ObjectMapperSample {
  public static void main(String[] args) throws Exception {
    //create dummy POJO
    Person bob = new Person();
    bob.setName("Bob");
 
    //serialize data
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectMapper mapper = new ObjectMapper(new BsonFactory());
    mapper.writeValue(baos, bob);
 
    //deserialize data
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    Person clone_of_bob = mapper.readValue(bais, Person.class);
 
    assert bob.getName().equals(clone_of_bob.getName());
  }
}

Or you may use Jackson’s streaming API and serialize the object manually:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import de.undercouch.bson4jackson.BsonFactory;
 
public class ManualSample {
  public static void main(String[] args) throws Exception {
    //create dummy POJO
    Person bob = new Person();
    bob.setName("Bob");
 
    //create factory
    BsonFactory factory = new BsonFactory();
 
    //serialize data
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    JsonGenerator gen = factory.createJsonGenerator(baos);
    gen.writeStartObject();
    gen.writeFieldName("name");
    gen.writeString(bob.getName());
    gen.close();
 
    //deserialize data
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    JsonParser parser = factory.createJsonParser(bais);
    Person clone_of_bob = new Person();
    parser.nextToken();
    while (parser.nextToken() != JsonToken.END_OBJECT) {
      String fieldname = parser.getCurrentName();
      parser.nextToken();
      if ("name".equals(fieldname)) {
        clone_of_bob.setName(parser.getText());
      }
    }
 
    assert bob.getName().equals(clone_of_bob.getName());
  }
}

Optimized streaming

One disadvantage of BSON is the fact that each document begins with a number denoting the document’s length. When creating an object this length has to be known in advance and bson4jackson is forced to buffer the whole document before it can be written to the OutputStream. bson4jackson’s parser ignores this length field and so you may also leave it empty. Therefore, you have to create the BsonFactory as follows:

BsonFactory fac = new BsonFactory();
fac.enable(BsonGenerator.Feature.ENABLE_STREAMING);

This trick can increase the serialization performance for large documents and reduce the memory footprint a lot. The official MongoDB Java driver also ignores the length field. So, you may also use this optimization if your bson4jackson-created documents shall be read by the MongoDB driver.

Performance

Version 1.1.0 of bson4jackson introduced support for Jackson 1.7 as well as a lot of performance improvements. At the moment, bson4jackson is much faster than the official MongoDB driver for Java (as of January 2011). For serialization, this is only true using the streaming API, since Jackson’s ObjectMapper adds a little bit of overhead (actually the MongoDB driver also uses some kind of a streaming API). Deserialization is always faster. The latest benchmark results can be reviewed on the following website:

https://github.com/eishay/jvm-serializers/wiki

Compatibility with MongoDB

In version 1.2.0 bson4jackson’s compatibility with MongoDB has been improved a lot. Thanks to the contribution by James Roper the BsonParser class now supports the new HONOR_DOCUMENT_LENGTH feature which makes the parser honor the first 4 bytes of a document which usually contain the document’s size. Of course, this only works if BsonGenerator.Feature.ENABLE_STREAMING has not been enabled during document generation.

This feature can be useful for reading consecutive documents from an input stream produced by MongoDB. You can enable it as follows:

BsonFactory fac = new BsonFactory();
fac.enable(BsonParser.Feature.HONOR_DOCUMENT_LENGTH);
BsonParser parser = (BsonParser)fac.createJsonParser(...);

Compatibility with Jackson

bson4jackson 2.x is compatible to Jackson 2.x and higher. Due to some compatibility issues both libraries’ major and minor version numbers have to match. That means you have to use at least bson4jackson 2.1 if you use Jackson 2.1, bson4jackson 2.2 if you use Jackson 2.2, etc. I will try to keep bson4jackson up to date. If there is a compatibility issue I will update bson4jackon, usually within a couple of days after the new Jackson version has been released.

Here’s the compatibility matrix for the current library versions:

  Jackson 2.2.x Jackson 2.1.x Jackson 2.0.x
bson4jackson 2.2.x Yes Yes Yes
bson4jackson 2.1.x No Yes Yes
bson4jackson 2.0.x No No Yes

If you’re looking for a version compatible to Jackson 1.x, please use bson4jackson 1.3. It’s the last version for the 1.x branch. bson4jackson 1.3 is compatible to Jackson 1.7 up to 1.9.

Download

Pre-compiled binaries

Pre-compiled binary files of bson4jackson can be downloaded from Maven Central. Additionally, you will need a copy of Jackson to start right away.

Maven/Gradle/buildr/sbt

Alternatively, you may also use Maven to download bson4jackson:

<dependencies>
  <dependency>
    <groupId>de.undercouch</groupId>
    <artifactId>bson4jackson</artifactId>
    <version>2.2.0</version>
  </dependency>
</dependencies>

For Gradle you may use the following snippet:

compile 'de.undercouch:bson4jackson:2.2.0'

For buildr use the following snippet:

compile.with 'de.undercouch:bson4jackson:jar:2.2.0'

If you’re using sbt, you may add the following line to your project:

val bson4jackson = "de.undercouch" % "bson4jackson" % "2.2.0"

License

bson4jackson is licensed under the Apache License, Version 2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

]]>
Scala projects with Eclipse PDE Build (2) http://www.michel-kraemer.com/scala-projects-with-eclipse-pde-build-2 http://www.michel-kraemer.com/scala-projects-with-eclipse-pde-build-2#comments 2010-11-20T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/scala-projects-with-eclipse-pde-build-2 Some time ago I wrote about how to let Eclipse PDE Build automatically compile Scala projects. Therefore a special Ant script (customBuildCallbacks.xml) had to be created in the project’s root directory. This script looked for the Scala library and compiler and then built the project’s source files.]]> Some time ago I wrote about how to let Eclipse PDE Build automatically compile Scala projects. Therefore a special Ant script (customBuildCallbacks.xml) had to be created in the project’s root directory. This script looked for the Scala library and compiler and then built the project’s source files.

This method still works. The OSGi bundles containing the Scala library and compiler are delivered together with the Scala IDE for Eclipse. This project is now not affiliated with the EPFL anymore and is developed mostly independently from the Scala tool chain. Hence, the OSGi bundle names have changed and so the Ant script from my previous post does not work anymore.

The following things have to be changed:

  • The symbolic name of the Scala library OSGi bundle now starts with org.scala-ide.scala.library_
  • The compiler is now provided by a bundle whose name starts with org.scala-ide.scala.compiler_
  • The Scala Ant task now resides in scala-compiler.jar which is provided by the compiler bundle

I created a new script that can be downloaded here:

customBuildCallbacks.xml (4.0 KiB)

]]>
Easier use of Git http://www.michel-kraemer.com/easier-use-of-git http://www.michel-kraemer.com/easier-use-of-git#comments 2010-06-04T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/easier-use-of-git I’m using Git as the version control system for my projects for some time now. Since the graphical user interfaces are not very mature yet and I like having full control over everything, I’m using Git on the command line (i.e. Bash). In order to avoid entering the same commands all over again, I wrote some Bash aliases and functions which ease the use of Git.]]> I’m using Git as the version control system for my projects for some time now. Since the graphical user interfaces are not very mature yet and I like having full control over everything, I’m using Git on the command line (i.e. Bash). In order to avoid entering the same commands all over again, I wrote some Bash aliases and functions which ease the use of Git.

The simplified commands can be downloaded from my Github repository. Instructions for installing and usage can be found in the README.

This is a short summary of the most used commands:

add

Verbose add (executes git add -v and then git status). All parameters will be forwarded to git add.

Example:
add -p foobar.txt

commit

Alias for git commit

gadd

Pipes the output of git ls-files to grep to add only those files that match a given pattern. All parameters (including the pattern) will be forwarded to grep. Like add this command is verbose and calls git status at the end.

Example:
gadd -i '\.java$'

log

Alias for git log

pull

Executes git pull --rebase and then displays all commits since the last pull in a short format.

push

Alias for git push

st

Alias for git status

The commands have been tested unter msysgit, but they should also work on other platforms. A complete list can be found in the README.

In the future I may add further commands. I would appreciate any feedback.

Finally, I want to thank Simon Templer and Simon Thum for their ideas!

]]>
Multilingual websites with Lift and OSGi http://www.michel-kraemer.com/multilingual-websites-with-lift-and-osgi http://www.michel-kraemer.com/multilingual-websites-with-lift-and-osgi#comments 2010-04-05T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/multilingual-websites-with-lift-and-osgi Lift already provides some mechanisms to publish a website in different languages. If Lift is used within an OSGi environment, a little workaround is needed in order to make it find the Resource Bundles containing language-dependent strings (usually provided as property files).]]> Lift already provides some mechanisms to publish a website in different languages. If Lift is used within an OSGi environment, a little workaround is needed in order to make it find the Resource Bundles containing language-dependent strings (usually provided as property files).

Internationalization with Lift

First of all, let me summarize the possibilities of internationalization with Lift: String resources have to be placed in so-called “property bundles”. These are normal Java property files like the following:

title=My Website
yes=Yes
no=No
deletequestion=Do you want to delete everything?

The name of a property bundle always starts with lift, but different suffixes in the ISO format will be appended describing the file’s language and country. For example, the file lift_en.properties contains English string resources, lift_de.properties contains German ones and lift_en_US.properties US American English. The prefix lift can be specified in the web application’s boot loader:

LiftRules.resourceNames = "anotherPrefix" :: Nil

The variable resourceNames is a list of strings. Therefore, resource bundles can be divided into multiple files with different prefixes. This is useful for larger projects with a lot of string resources.

After the resource bundles have been created, strings in HTML templates can be translated using the <lift:loc locid="..." /> tag. For example, following template:

<html>
<head>
<title><lift:loc locid="title" /></title>
</head>
<body>
<lift:loc locid="deletequestion" />
<button><lift:loc locid="yes" /></button>
<button><lift:loc locid="no" /></button>
</body>
</html>

will be translated to the following HTML code (using the properties file from above):

<html>
<head>
<title>My Website</title>
</head>
<body>
Do you want to delete everything?
<button>Yes</button>
<button>No</button>
</body>
</html>

In the Scala source code the stateful object net.liftweb.http.S can be used instead. It provides the method ? which takes a string and looks for the corresponding translation in the resource bundle:

def snippet(xhtml: NodeSeq): NodeSeq =
  <p>{ S ? "deletequestion" }</p>

Tip: If you want to translate a tag’s attribute in a HTML template (e.g. the attribute value of the inputtag), you should copy the respective code into a snippet. Therefore you can use the S object to translate the attribute:

def inputButton(xhtml: NodeSeq): NodeSeq =
  <input type="button" value={ S ? "yes" } />

Resource Bundles in the OSGi environment

Lift tries to find resource bundles in the classpath using the method getClass.getClassLoader.getResourceAsStream(). In an OSGi environment this is not going to work, because the classloader of the net.liftweb.lift-webkit bundle is used.

As mentioned above, this can be solved with a little workaround. A resource bundle factory has to be added in the application’s boot loader:

LiftRules.resourceBundleFactories prepend {
  case (basename, locale) => ResourceBundle.getBundle(basename, locale)
}

Therefore, the resource bundles will be loaded by the classloader of the bundle that contains the boot loader.

Conclusion

The means for internationalization provided by Lift are comprehensive enough for most websites. If something is not translatable using the <lift:loc> tag (e.g. attributes) or if more control over the process is needed, snippets can be used instead. In OSGi environments a resource bundle factory has to be created, so property files will be loaded by the correct classloader.

]]>
Scala projects with Eclipse PDE Build http://www.michel-kraemer.com/scala-projects-with-eclipse-pde-build http://www.michel-kraemer.com/scala-projects-with-eclipse-pde-build#comments 2010-03-30T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/scala-projects-with-eclipse-pde-build PDE Build is the standard build tool from Eclipse. It is used to export OSGi bundles, plugins, features or products. Running in headless mode, PDE Build can be used for automatic builds without a GUI. The Scala IDE does not support PDE Build yet. In order to compile Scala projects you have to do some manual work.]]> PDE Build is the standard build tool from Eclipse. It is used to export OSGi bundles, plugins, features or products. Running in headless mode, PDE Build can be used for automatic builds without a GUI. The Scala IDE does not support PDE Build yet. In order to compile Scala projects you have to do some manual work.

This article relates to an old version of the Scala IDE for Eclipse. Information about the latest version can be found in a newer post!

First of all, you need an Ant script that can be hooked into the build process. The script’s name should be customBuildCallbacks.xml and it should be located at the project’s root:

de.michel-kraemer.myplugin/
  |- bin
  |- META-INF
  |- src
  |- build.properties
  |- customBuildCallbacks.xml

The same directory contains the plugin’s build.properties file. (Please do not mix this one up with the more general build.properties file used for headless builds!) The following lines have to be added to this file to hook the new Ant script into the build process:

customBuildCallbacks=customBuildCallbacks.xml
customBuildCallbacks.inheritall=true

The second line enables access to global properties like ${build.result.folder}.

The Ant script can contain targets with predefined names. They will be called by PDE Build eventually during the build process. You can copy a template, that already contains all predefined targets (but empty) from the following directory: ${eclipse.home}/plugins/org.eclipse.pde.build_*/templates/plugins/

The post.compile.@dot target will be called when the source files are about to be compiled, so that’s the best point to execute the Scala compiler manually. Therefore, some additional Ant tasks have to be defined. These can be found in the Scala Library which is delivered with the Scala IDE. You can automatically search for the required jar files using the following snippet:

<!-- find eclipse.home -->
<pathconvert property="eclipse.home">
    <path location="${eclipse.launcher}" />
    <mapper>
        <!-- map "${eclipse.home}/eclipse.exe" to "${eclipse.home}" -->
        <globmapper from="*/eclipse.exe" to="*" handledirsep="true" />
    </mapper>
</pathconvert>
 
<!-- find scala bundle -->
<pathconvert property="scala_bundle">
    <path>
        <fileset dir="${eclipse.home}/plugins">
            <include name="scala.library_*" />
        </fileset>
    </path>
</pathconvert>
 
<!-- find scala tools -->
<pathconvert property="scala_tools_jar">
    <path>
        <fileset dir="${eclipse.home}/plugins">
            <include name="scala.tools.nsc_*" />
        </fileset>
    </path>
</pathconvert>

This places the path to the Scala OSGi bundle in the variable ${scala_bundle}. The variable ${scala_tools_jar} will point to the jar file that contains the Scala Tools and, thus, the Ant tasks.

The library bundle has to be extracted first, so the actual Scala library scala-library.jar can be used in the classpath during the build. Therefore, you can use the temporary build directory ${build.result.folder}:

<unjar dest="${build.result.folder}/scala-library" src="${scala_bundle}" />
<property name="scala_library_jar"
    location="${build.result.folder}/scala-library/lib/scala-library.jar" />

After this, the Ant targets can be defined:

<!-- define scalac task -->
<taskdef resource="scala/tools/ant/antlib.xml">
    <classpath>
        <pathelement location="${scala_tools_jar}" />
        <pathelement location="${scala_library_jar}" />
    </classpath>
</taskdef>

Before the source files can be compiled, a valid classpath has to be created. It consists of the classpath defined by PDE Build @dot.classpath and the Scala library:

<pathconvert property="my.classpath">
    <restrict>
        <path>
            <path refid="@dot.classpath" />
            <pathelement location="${scala_library_jar}" />
        </path>
        <!-- remove libraries from classpath that don't exist (optional) -->
        <rsel:exists />
    </restrict>
</pathconvert>

Removing non-existing libraries using <rsel:exists /> is optional. To make it work, you have to add the following namespace to the Ant script’s root node:

<project name="Build specific targets and properties"
    xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
    ...

Finally, the source code can be compiled:

<!-- compile scala source files -->
<mkdir dir="${target.folder}" />
<scalac srcdir="${source.folder1}"
    destdir="${target.folder}"
    classpath="${my.classpath}">
    <include name="**/*.scala" />
</scalac>

For production use, it is also a good idea to delete the source files from the target folder, so they are not deployed together with the binaries:

<!-- delete scala source files in output folder -->
<delete>
    <fileset dir="${target.folder}" includes="**/*.scala" />
</delete>

Conclusion

The method presented here uses the possibility to hook custom Ant targets into the PDE build process. The scripts try to find the Scala library and tools delivered with the IDE. If you don’t like that, you may also copy the files scala-library.jar and scala-compiler.jar (contains the Ant task) from the Scala distribution into some directory of your project and change the classpath respectively.

The complete source of the generic customBuildCallbacks.xml file can be downloaded with the following link:

customBuildCallbacks-old.xml (3.8 KiB)

This article relates to an old version of the Scala IDE for Eclipse. An updated Ant script can be found in a newer post!

This file can be copied without changes into every OSGi bundle that should be compiled with PDE and that contains Scala code. You only have to change the build.properties file as described above.

]]>
Scala Style Guide http://www.michel-kraemer.com/style-guide-for-scala http://www.michel-kraemer.com/style-guide-for-scala#comments 2010-03-22T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/style-guide-for-scala Scala does not have an official style guide yet. Because of this, Daniel Spiewak posted such a document in November 2009 on the Scala mailing list. As can be read there, even Martin Odersky, the inventor of Scala, likes that idea and thinks about publishing the document on the official Scala website.]]> Scala does not have an official style guide yet. Because of this, Daniel Spiewak posted such a document in November 2009 on the Scala mailing list. As can be read there, even Martin Odersky, the inventor of Scala, likes that idea and thinks about publishing the document on the official Scala website.

The PDF version can be downloaded from the following website:
http://www.codecommit.com/scala-style-guide.pdf

An online version is available under the following address:
http://davetron5000.github.com/scala-style/

The style guide is well structured. Each definition also contains the reason why you should format your code this way. Counter-examples show how unreadable code becomes, if you don’t.

Since I’m a proponent of structured coding I can recommend this document to everyone working with Scala. If you’re new to the language, you should read the style guide very soon to avoid getting into “bad habits”. By following the rules from the style guide you can increase readability of your Scala program which also improves extensibility and maintainability.

]]>
Browse phpBB with the iPhone/iPod Touch http://www.michel-kraemer.com/browse-phpbb-with-the-iphone-ipod-touch http://www.michel-kraemer.com/browse-phpbb-with-the-iphone-ipod-touch#comments 2010-03-03T00:00:00+01:00 Michel Krämer http://www.michel-kraemer.com/browse-phpbb-with-the-iphone-ipod-touch The iPhone is very useful for forum administrators who are often on the road and like to answer posts on the train, for example. Unfortunately, the default theme of phpBB is hardly usable on the iPhone (or the iPod Touch). Apart from that, the font size of most discussion boards is so small that you constantly have to zoom.]]> The iPhone is very useful for forum administrators who are often on the road and like to answer posts on the train, for example. Unfortunately, the default theme of phpBB is hardly usable on the iPhone (or the iPod Touch). Apart from that, the font size of most discussion boards is so small that you constantly have to zoom.

The free theme phpbb-iphone-style especially developed for the iPhone adds a lot of comfort. It removes unnecessary display elements, increases font size and improves controlling the forum with the touch screen.

The theme can be installed very easily. You simply have to download the project’s source code and copy it onto your web server under the styles directory. If you like, you can also follow the instructions found in the read-me file, so the forum automatically uses the new theme if someone visits the site with a mobile device. Finally, you may disable the theme in the administration panel, so it cannot be activated in normal browsers.

I installed phpbb-iphone-style into the Spamihilator support forum. Here are some screenshots:

During the next few days I will add some enhancements, so the theme will fit the overall style of the Spamihilator website.

]]>
5 Anti-Spam-Maßnahmen für phpBB 3.0 http://www.michel-kraemer.com/anti-spam-phpbb3 http://www.michel-kraemer.com/anti-spam-phpbb3#comments 2009-04-08T00:00:00+02:00 Michel Krämer http://www.michel-kraemer.com/anti-spam-phpbb3

Note: There is an updated English version of this blog post available.

phpBB ist als Foren-Software mit offenem Quellcode sehr beliebt und weit verbreitet. Aus diesem Grund ist es aber auch häufig das Ziel von Spammern. In der Version 3.0 wurde deshalb unter anderem ein besseres Captcha eingeführt. Leider haben sich die Spammer inzwischen auf die neue Version eingestellt und Bots geschrieben, die das Captcha automatisch überwinden und Beiträge absetzen können. Im Folgenden werden deshalb fünf Anti-Spam-Maßnahmen beschrieben, die sich in jeder phpBB-3.0-Installation einsetzen lassen und sehr effektiv sind. Ziel ist es dabei, möglichst viele Spam-Beiträge zu blockieren ohne den normalen Betrieb des Forums zu beeinträchtigen.]]>

Note: There is an updated English version of this blog post available.

phpBB ist als Foren-Software mit offenem Quellcode sehr beliebt und weit verbreitet. Aus diesem Grund ist es aber auch häufig das Ziel von Spammern. In der Version 3.0 wurde deshalb unter anderem ein besseres Captcha eingeführt. Leider haben sich die Spammer inzwischen auf die neue Version eingestellt und Bots geschrieben, die das Captcha automatisch überwinden und Beiträge absetzen können. Im Folgenden werden deshalb fünf Anti-Spam-Maßnahmen beschrieben, die sich in jeder phpBB-3.0-Installation einsetzen lassen und sehr effektiv sind. Ziel ist es dabei, möglichst viele Spam-Beiträge zu blockieren ohne den normalen Betrieb des Forums zu beeinträchtigen.

Spammer versuchen meist bestimmte Websites zu bewerben. Deshalb enthalten etwa 95% aller Spam-Beiträge Links bzw. URLs. Die effektivste Methode solche Beiträge zu verhindern, ist Links komplett zu sperren. Da die hier vorgestellten Maßnahmen normale Benutzer aber möglichst wenig beeinträchtigen sollen, kann ein kleiner Trick verwendet werden: Es wird davon ausgegangen, dass ein Spammer sich in einem Forum neu anmeldet und direkt damit beginnt, Werbebotschaften zu schreiben. Das heißt, Gäste und Benutzer mit weniger als einer bestimmten Zahl von Beiträgen werden als potenzielle Spammer behandelt. Ihre Beiträge werden genauer untersucht. Alle anderen Benutzer bleiben von den Maßnahmen unbetroffen.

Um Beiträge mit Links zu blockieren, kann die Funktion submit_post() in der Datei includes\functions_posting.php um folgende Zeilen ergänzt werden:

//Define the minimum number of posts for "good" users
//Users below this threshold are considered potential spammers
$user_posts_threshold = 3;
 
//strip whitespace characters in the post body
$msgwows = $data['message'];
$msgwows = str_replace(" ", "", $msgwows);
$msgwows = str_replace("\n", "", $msgwows);
$msgwows = str_replace("\r", "", $msgwows);
$msgwows = str_replace("\t", "", $msgwows);
 
if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (strpos($msgwows, 'http://') !== FALSE ||
      strpos($msgwows, 'ftp://') !== FALSE ||
      strpos($msgwows, 'www.') !== FALSE ||
      strpos($msgwows, '[url') !== FALSE) {
    trigger_error("You are not allowed to post URLs!");
  }
}

Dieser Code sollte selbstverständlich ganz am Anfang der Funktion stehen, damit die Beiträge vor dem Speichern gefiltert werden.

Maßnahme 2: Bilder

Spammer versuchen Filter oftmals durch den Einsatz von Bildern zu umgehen. Dazu schreiben sie ihre Werbebotschaften und Links in Bilddateien und hängen diese an Foren-Beiträge an. Mit dem gleicher Methode wie oben beschrieben, können in der Funktion submit_post() in der Datei functions/functions_posting.php Beiträge mit Bildern geblockt werden:

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (strpos($msgwows, '[img') !== FALSE) {
    trigger_error("You are not allowed to post images!");
  }
}

Maßnahme 3: Russische und Chinesische Beiträge?

Einige Spam-Beiträge sind auf Russisch oder Chinesisch oder enthalten einfach nur eine Menge unleserlicher Sonderzeichen. Man kann sich zunutze machen, dass in deutsch- und englischsprachigen Foren in der Regel nur Deutsche bzw. Englische Beiträge erwünscht sind. Beiträge mit sehr vielen Sonderzeichen bzw. Zeichen aus fremdsprachigen Alphabeten können problemlos als Spam betrachtet werden.

Cory Mawhorter hat eine kleine PHP-Funktion veröffentlicht (is_english()), die auf einfache Weise Sonderzeichen erkennt. Diese kann verwendet werden, um Deutsche bzw. Englische Texte von fremdsprachigen zu unterscheiden:

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (!is_english($msgwows, 0.75)) {
    trigger_error("Only German or English posts are allowed here!");
  }
}

Maßnahme 4: http:BL

Das Project Honey Pot bietet ein effektives System an, um Spammer und Adresssammler von Webseiten fern zu halten. http:BL gleicht die IP-Adresse eines Besuchers mit einer Datenbank ab. Ist die IP-Adresse bekannt und verbirgt sich dahinter ein Spammer, dann kann der Besucher schon gesperrt werden bevor er die Webseite sieht. Das System verwendet DNS, wodurch die Abfragen relativ schnell sind.

Um http:BL zu verwenden, muss man sich bei Project Honey Pot registrieren. Dadurch erhält man einen Schlüssel, der dem eigenen Benutzernamen eindeutig zugeordnet ist. Project Honey Pot will dadurch Missbrauch des Systems verhindern. Ein MOD für phpBB wird angeboten, allerdings nur für Version 2.0. Diesen kann man unter Umständen an phpBB 3.0 anpassen. Alternativ kann man folgenden Code an das Ende der Datei common.php kopieren:

//configure your http:BL Access Key here
$httpblkey = "xxxxxxxxxxx";
$httpblmaxdays = 21;
$httpblmaxthreat = 25;
 
//if you already configured a honey pot on your website use this line:
//$httpblhoneypot = "http://xxxxxxxxxxx";
 
function httpbl_check() {
  global $httpblkey, $httpblmaxdays, $httpblmaxthreat, $httpblhoneypot;
 
  $ip = $_SERVER["REMOTE_ADDR"];
 
  $result = explode(".", gethostbyname($httpblkey."."
    .implode(".", array_reverse(explode(".", $ip)))
    .".dnsbl.httpbl.org"));
 
  if ($result[0] != 127) {
    //something went wrong or the IP is not in the database.
    //ignore this one.
    return;
  }
 
  $days = $result[1];
  $threat = $result[2];
 
  if ($days < $httpblmaxdays && $threat > $httpblmaxthreat) {
    if ($httpblhoneypot) {
      header("HTTP/1.1 301 Moved Permanently");
      header("Location: ".$httpblhoneypot);
    }
    die();
  }
}
httpbl_check();

In der Variablen $httpblkey muss der http:BL Access Key angegeben werden.

Maßnahme 5: Akismet

Eine weitere Methode Spam zu blockieren, ist Akismet. Dieses System wird auch gerne in WordPress-Blogs eingesetzt. Wie für Project Honey Pot, benötigt man hierfür einen API-Key, den man durch eine Registrierung erhält.

In Foren kann Akismet zum Beispiel beim Absenden von Beiträgen verwendet werden. Das System kann zu Falschmeldungen führen, weshalb die Filterung auch hier wieder nur auf die ersten Beiträge eines Benutzers beschränkt wird. Der folgende Code verwendet die Datei Akismet.class.php, die man von Alex Potsides’ GitHub-Repository herunterladen kann. Der Code kann in die Funktion submit_post() in der Datei includes/functions_posting.php eingefügt werden:

//configure your Akismet API key here
$akismet_key = 'xxxxxxxxxxx';
 
//the URL you entered when you registered for a Wordpress account
$akismet_url = 'xxxxxxxxxxx';
 
include('Akismet.class.php');
 
$akismet = new Akismet($akismet_url, $akismet_key);
if (!$user->data['is_registered'])
  $akismet->setCommentAuthor($username);
else
  $akismet->setCommentAuthor($user->data['username']);
$akismet->setCommentContent($data['message']);
$akismet->setUserIP($user->ip);
if ($user->data['is_registered'])
{
  $akismet->setCommentAuthorEmail(strtolower($user->data['user_email']));
  $akismet->setCommentAuthorURL(strtolower($user->data['user_website']));
}
 
if ((!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) &&
    $akismet->isCommentSpam()) {
    trigger_error("Akismet says your post is spam");
}

Die Variable $akismet_key muss den Akismet API Key enthalten. Die URL, die man bei der Registrierung für einen WordPress-Account angegeben hat, muss in der Variablen $akismet_url stehen.

Akismet kann desweiteren sinnvoll bei der Registrierung von neuen Benutzern eingesetzt werden. Dazu ist folgender Code in die Funktion user_add() in der Datei includes/functions_user.php einzufügen:

//configure your Akismet API key here
$akismet_key = 'xxxxxxxxxxx';
 
//the URL you entered when you registered for a Wordpress account
$akismet_url = 'xxxxxxxxxxx';
 
include('Akismet.class.php');
 
$akismet = new Akismet($akismet_url, $akismet_key);
$akismet->setCommentAuthor($username_clean);
$akismet->setUserIP($user->ip);
$akismet->SetCommentAuthorEmail(strtolower($user_row['user_email']));
 
if($akismet->isCommentSpam()) {
  trigger_error("Akismet says you are a spammer");
}

Fazit

Die hier vorgestellten Maßnahmen helfen, das Spam-Aufkommen in phpBB-3.0-Foren drastisch zu reduzieren. Seit dem Aktivieren der verschiedenen Filter im Spamihilator-Forum konnte kein einziger Spammer einen Beitrag absetzen. Das Blockieren von Links und Bildern ist dabei die effektivste Methode. Durch das Filtern von Sonderzeichen werden alle anderen Spam-Beiträge verhindert. Der normale Betrieb wird kaum gestört, da die Maßnahmen nur neue Benutzer betreffen. Sobald ein Benutzer eine bestimmte Anzahl von “guten” Beiträgen geschrieben hat, werden die Filter deaktiviert. Bisher hat dies noch kein Spammer ausgenutzt. Falls dies jemals der Fall sein sollte, kann die Schwelle sehr leicht erhöht werden.

Trotz aller Filtermaßnahmen beim Schreiben von Beträgen, bleibt immer noch das Problem, dass Spammer sich nach wie vor registrieren und in ihrer Signatur auf eine Webseite verlinken können. Maßnahmen für dieses Problem sind noch zu entwickeln.

In vielen von Spam geplagten Foren sind Gäste nicht zugelassen. Man muss sich registrieren, um Beiträge schreiben zu können. Dies kann für einfache Support-Foren zu umständlich sein. Die Benutzer möchten gerne Beiträge schreiben können ohne lange und komplizierte Registrierungsverfahren zu durchlaufen. Mit den in diesem Artikel vorgestellten Maßnahmen können Gäste grundsätzlich wieder zugelassen werden, denn die Filterung ist für solche immer aktiv.

Abschließend bleibt zu erwähnen, dass der Einsatz von Akismet auf deutschen Webseiten zur Zeit noch umstritten ist. Weiteres darüber findet man unter anderem in folgendem Artikel: http://www.drweb.de/magazin/akismet-und-der-datenschutz/. Maßnahme 5 kann bei Bedarf ausgelassen werden.

]]>