Merge branch 'master' into next
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 28 May 2012 11:06:41 +0000 (13:06 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 28 May 2012 11:06:41 +0000 (13:06 +0200)
16 files changed:
1  2 
pom.xml
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/FreenetInterface.java
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/core/SoneInserter.java
src/main/java/net/pterodactylus/sone/core/UpdateChecker.java
src/main/java/net/pterodactylus/sone/data/Sone.java
src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java
src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java
src/main/java/net/pterodactylus/sone/main/SonePlugin.java
src/main/java/net/pterodactylus/sone/template/SoneAccessor.java
src/main/java/net/pterodactylus/sone/text/SoneTextParser.java
src/main/java/net/pterodactylus/sone/web/CreateSonePage.java
src/main/java/net/pterodactylus/sone/web/SearchPage.java
src/main/java/net/pterodactylus/sone/web/WebInterface.java
src/main/java/net/pterodactylus/sone/web/page/FreenetTemplatePage.java

diff --combined pom.xml
+++ b/pom.xml
@@@ -2,12 -2,12 +2,12 @@@
        <modelVersion>4.0.0</modelVersion>
        <groupId>net.pterodactylus</groupId>
        <artifactId>sone</artifactId>
-       <version>0.8</version>
+       <version>0.8.1</version>
        <dependencies>
                <dependency>
                        <groupId>net.pterodactylus</groupId>
                        <artifactId>utils</artifactId>
 -                      <version>0.11.4</version>
 +                      <version>0.12-SNAPSHOT</version>
                </dependency>
                <dependency>
                        <groupId>junit</groupId>
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - Core.java - Copyright © 2010 David Roden
 + * Sone - Core.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -131,45 -131,45 +131,45 @@@ public class Core extends AbstractServi
  
        /** All local Sones. */
        /* synchronize access on this on itself. */
 -      private Map<String, Sone> localSones = new HashMap<String, Sone>();
 +      private final Map<String, Sone> localSones = new HashMap<String, Sone>();
  
        /** All remote Sones. */
        /* synchronize access on this on itself. */
 -      private Map<String, Sone> remoteSones = new HashMap<String, Sone>();
 +      private final Map<String, Sone> remoteSones = new HashMap<String, Sone>();
  
        /** All known Sones. */
 -      private Set<String> knownSones = new HashSet<String>();
 +      private final Set<String> knownSones = new HashSet<String>();
  
        /** All posts. */
 -      private Map<String, Post> posts = new HashMap<String, Post>();
 +      private final Map<String, Post> posts = new HashMap<String, Post>();
  
        /** All known posts. */
 -      private Set<String> knownPosts = new HashSet<String>();
 +      private final Set<String> knownPosts = new HashSet<String>();
  
        /** All replies. */
 -      private Map<String, PostReply> replies = new HashMap<String, PostReply>();
 +      private final Map<String, PostReply> replies = new HashMap<String, PostReply>();
  
        /** All known replies. */
 -      private Set<String> knownReplies = new HashSet<String>();
 +      private final Set<String> knownReplies = new HashSet<String>();
  
        /** All bookmarked posts. */
        /* synchronize access on itself. */
 -      private Set<String> bookmarkedPosts = new HashSet<String>();
 +      private final Set<String> bookmarkedPosts = new HashSet<String>();
  
        /** Trusted identities, sorted by own identities. */
 -      private Map<OwnIdentity, Set<Identity>> trustedIdentities = Collections.synchronizedMap(new HashMap<OwnIdentity, Set<Identity>>());
 +      private final Map<OwnIdentity, Set<Identity>> trustedIdentities = Collections.synchronizedMap(new HashMap<OwnIdentity, Set<Identity>>());
  
        /** All known albums. */
 -      private Map<String, Album> albums = new HashMap<String, Album>();
 +      private final Map<String, Album> albums = new HashMap<String, Album>();
  
        /** All known images. */
 -      private Map<String, Image> images = new HashMap<String, Image>();
 +      private final Map<String, Image> images = new HashMap<String, Image>();
  
        /** All temporary images. */
 -      private Map<String, TemporaryImage> temporaryImages = new HashMap<String, TemporaryImage>();
 +      private final Map<String, TemporaryImage> temporaryImages = new HashMap<String, TemporaryImage>();
  
        /** Ticker for threads that mark own elements as known. */
 -      private Ticker localElementTicker = new Ticker();
 +      private final Ticker localElementTicker = new Ticker();
  
        /** The time the configuration was last touched. */
        private volatile long lastConfigurationUpdate;
                        try {
                                sone = getLocalSone(ownIdentity.getId()).setIdentity(ownIdentity).setInsertUri(new FreenetURI(ownIdentity.getInsertUri())).setRequestUri(new FreenetURI(ownIdentity.getRequestUri()));
                        } catch (MalformedURLException mue1) {
-                               logger.log(Level.SEVERE, "Could not convert the Identity’s URIs to Freenet URIs: " + ownIdentity.getInsertUri() + ", " + ownIdentity.getRequestUri(), mue1);
+                               logger.log(Level.SEVERE, String.format("Could not convert the Identity’s URIs to Freenet URIs: %s, %s", ownIdentity.getInsertUri(), ownIdentity.getRequestUri()), mue1);
                                return null;
                        }
                        sone.setLatestEdition(Numbers.safeParseLong(ownIdentity.getProperty("Sone.LatestEdition"), (long) 0));
                try {
                        ownIdentity.addContext("Sone");
                } catch (WebOfTrustException wote1) {
-                       logger.log(Level.SEVERE, "Could not add “Sone” context to own identity: " + ownIdentity, wote1);
+                       logger.log(Level.SEVERE, String.format("Could not add “Sone” context to own identity: %s", ownIdentity), wote1);
                        return null;
                }
                Sone sone = addLocalSone(ownIdentity);
         */
        public Trust getTrust(Sone origin, Sone target) {
                if (!isLocalSone(origin)) {
-                       logger.log(Level.WARNING, "Tried to get trust from remote Sone: %s", origin);
+                       logger.log(Level.WARNING, String.format("Tried to get trust from remote Sone: %s", origin));
                        return null;
                }
                return target.getIdentity().getTrust((OwnIdentity) origin.getIdentity());
                try {
                        ((OwnIdentity) origin.getIdentity()).setTrust(target.getIdentity(), trustValue, preferences.getTrustComment());
                } catch (WebOfTrustException wote1) {
-                       logger.log(Level.WARNING, "Could not set trust for Sone: " + target, wote1);
+                       logger.log(Level.WARNING, String.format("Could not set trust for Sone: %s", target), wote1);
                }
        }
  
                try {
                        ((OwnIdentity) origin.getIdentity()).removeTrust(target.getIdentity());
                } catch (WebOfTrustException wote1) {
-                       logger.log(Level.WARNING, "Could not remove trust for Sone: " + target, wote1);
+                       logger.log(Level.WARNING, String.format("Could not remove trust for Sone: %s", target), wote1);
                }
        }
  
                if (hasSone(sone.getId())) {
                        Sone storedSone = getSone(sone.getId());
                        if (!soneRescueMode && !(sone.getTime() > storedSone.getTime())) {
-                               logger.log(Level.FINE, "Downloaded Sone %s is not newer than stored Sone %s.", new Object[] { sone, storedSone });
+                               logger.log(Level.FINE, String.format("Downloaded Sone %s is not newer than stored Sone %s.", sone, storedSone));
                                return;
                        }
                        synchronized (posts) {
         */
        public void deleteSone(Sone sone) {
                if (!(sone.getIdentity() instanceof OwnIdentity)) {
-                       logger.log(Level.WARNING, "Tried to delete Sone of non-own identity: %s", sone);
+                       logger.log(Level.WARNING, String.format("Tried to delete Sone of non-own identity: %s", sone));
                        return;
                }
                synchronized (localSones) {
                        if (!localSones.containsKey(sone.getId())) {
-                               logger.log(Level.WARNING, "Tried to delete non-local Sone: %s", sone);
+                               logger.log(Level.WARNING, String.format("Tried to delete non-local Sone: %s", sone));
                                return;
                        }
                        localSones.remove(sone.getId());
                        ((OwnIdentity) sone.getIdentity()).removeContext("Sone");
                        ((OwnIdentity) sone.getIdentity()).removeProperty("Sone.LatestEdition");
                } catch (WebOfTrustException wote1) {
-                       logger.log(Level.WARNING, "Could not remove context and properties from Sone: " + sone, wote1);
+                       logger.log(Level.WARNING, String.format("Could not remove context and properties from Sone: %s", sone), wote1);
                }
                try {
                        configuration.getLongValue("Sone/" + sone.getId() + "/Time").setValue(null);
         */
        public void loadSone(Sone sone) {
                if (!isLocalSone(sone)) {
-                       logger.log(Level.FINE, "Tried to load non-local Sone: %s", sone);
+                       logger.log(Level.FINE, String.format("Tried to load non-local Sone: %s", sone));
                        return;
                }
  
                        if (albumParentId != null) {
                                Album parentAlbum = getAlbum(albumParentId, false);
                                if (parentAlbum == null) {
-                                       logger.log(Level.WARNING, "Invalid parent album ID: " + albumParentId);
+                                       logger.log(Level.WARNING, String.format("Invalid parent album ID: %s", albumParentId));
                                        return;
                                }
                                parentAlbum.addAlbum(album);
                        } else {
 -                              topLevelAlbums.add(album);
 +                              if (!topLevelAlbums.contains(album)) {
 +                                      topLevelAlbums.add(album);
 +                              }
                        }
                }
  
         */
        public Post createPost(Sone sone, Sone recipient, long time, String text) {
                if (!isLocalSone(sone)) {
-                       logger.log(Level.FINE, "Tried to create post for non-local Sone: %s", sone);
+                       logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
                        return null;
                }
                final Post post = new Post(sone, time, text);
         */
        public void deletePost(Post post) {
                if (!isLocalSone(post.getSone())) {
-                       logger.log(Level.WARNING, "Tried to delete post of non-local Sone: %s", post.getSone());
+                       logger.log(Level.WARNING, String.format("Tried to delete post of non-local Sone: %s", post.getSone()));
                        return;
                }
                post.getSone().removePost(post);
         */
        public PostReply createReply(Sone sone, Post post, long time, String text) {
                if (!isLocalSone(sone)) {
-                       logger.log(Level.FINE, "Tried to create reply for non-local Sone: %s", sone);
+                       logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone));
                        return null;
                }
                final PostReply reply = new PostReply(sone, post, System.currentTimeMillis(), text);
        public void deleteReply(PostReply reply) {
                Sone sone = reply.getSone();
                if (!isLocalSone(sone)) {
-                       logger.log(Level.FINE, "Tried to delete non-local reply: %s", reply);
+                       logger.log(Level.FINE, String.format("Tried to delete non-local reply: %s", reply));
                        return;
                }
                synchronized (replies) {
         */
        private synchronized void saveSone(Sone sone) {
                if (!isLocalSone(sone)) {
-                       logger.log(Level.FINE, "Tried to save non-local Sone: %s", sone);
+                       logger.log(Level.FINE, String.format("Tried to save non-local Sone: %s", sone));
                        return;
                }
                if (!(sone.getIdentity() instanceof OwnIdentity)) {
-                       logger.log(Level.WARNING, "Local Sone without OwnIdentity found, refusing to save: %s", sone);
+                       logger.log(Level.WARNING, String.format("Local Sone without OwnIdentity found, refusing to save: %s", sone));
                        return;
                }
  
-               logger.log(Level.INFO, "Saving Sone: %s", sone);
+               logger.log(Level.INFO, String.format("Saving Sone: %s", sone));
                try {
                        /* save Sone into configuration. */
                        String sonePrefix = "Sone/" + sone.getId();
  
                        ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition()));
  
-                       logger.log(Level.INFO, "Sone %s saved.", sone);
+                       logger.log(Level.INFO, String.format("Sone %s saved.", sone));
                } catch (ConfigurationException ce1) {
-                       logger.log(Level.WARNING, "Could not save Sone: " + sone, ce1);
+                       logger.log(Level.WARNING, String.format("Could not save Sone: %s", sone), ce1);
                } catch (WebOfTrustException wote1) {
-                       logger.log(Level.WARNING, "Could not set WoT property for Sone: " + sone, wote1);
+                       logger.log(Level.WARNING, String.format("Could not set WoT property for Sone: %s", sone), wote1);
                }
        }
  
                try {
                        options.getIntegerOption(optionName).set(configuration.getIntValue("Option/" + optionName).getValue(null));
                } catch (IllegalArgumentException iae1) {
-                       logger.log(Level.WARNING, "Invalid value for " + optionName + " in configuration, using default.");
+                       logger.log(Level.WARNING, String.format("Invalid value for %s in configuration, using default.", optionName));
                }
        }
  
                        FreenetURI uri = new FreenetURI(uriString).setDocName("Sone").setMetaString(new String[0]);
                        return uri;
                } catch (MalformedURLException mue1) {
-                       logger.log(Level.WARNING, "Could not create Sone URI from URI: " + uriString, mue1);
+                       logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString, mue1));
                        return null;
                }
        }
         */
        @Override
        public void ownIdentityAdded(OwnIdentity ownIdentity) {
-               logger.log(Level.FINEST, "Adding OwnIdentity: " + ownIdentity);
+               logger.log(Level.FINEST, String.format("Adding OwnIdentity: %s", ownIdentity));
                if (ownIdentity.hasContext("Sone")) {
                        trustedIdentities.put(ownIdentity, Collections.synchronizedSet(new HashSet<Identity>()));
                        addLocalSone(ownIdentity);
         */
        @Override
        public void ownIdentityRemoved(OwnIdentity ownIdentity) {
-               logger.log(Level.FINEST, "Removing OwnIdentity: " + ownIdentity);
+               logger.log(Level.FINEST, String.format("Removing OwnIdentity: %s", ownIdentity));
                trustedIdentities.remove(ownIdentity);
        }
  
         */
        @Override
        public void identityAdded(OwnIdentity ownIdentity, Identity identity) {
-               logger.log(Level.FINEST, "Adding Identity: " + identity);
+               logger.log(Level.FINEST, String.format("Adding Identity: %s", identity));
                trustedIdentities.get(ownIdentity).add(identity);
                addRemoteSone(identity);
        }
         */
        @Override
        public void imageInsertStarted(Image image) {
-               logger.log(Level.WARNING, "Image insert started for " + image);
+               logger.log(Level.WARNING, String.format("Image insert started for %s...", image));
                coreListenerManager.fireImageInsertStarted(image);
        }
  
         */
        @Override
        public void imageInsertAborted(Image image) {
-               logger.log(Level.WARNING, "Image insert aborted for " + image);
+               logger.log(Level.WARNING, String.format("Image insert aborted for %s.", image));
                coreListenerManager.fireImageInsertAborted(image);
        }
  
         */
        @Override
        public void imageInsertFinished(Image image, FreenetURI key) {
-               logger.log(Level.WARNING, "Image insert finished for " + image + ": " + key);
+               logger.log(Level.WARNING, String.format("Image insert finished for %s: %s", image, key));
                image.setKey(key.toString());
                deleteTemporaryImage(image.getId());
                saveSone(image.getSone());
         */
        @Override
        public void imageInsertFailed(Image image, Throwable cause) {
-               logger.log(Level.WARNING, "Image insert failed for " + image, cause);
+               logger.log(Level.WARNING, String.format("Image insert failed for %s." + image), cause);
                coreListenerManager.fireImageInsertFailed(image, cause);
        }
  
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - FreenetInterface.java - Copyright © 2010 David Roden
 + * Sone - FreenetInterface.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -111,7 -111,7 +111,7 @@@ public class FreenetInterface 
                                        currentUri = fe1.newURI;
                                        continue;
                                }
-                               logger.log(Level.WARNING, "Could not fetch “" + uri + "”!", fe1);
+                               logger.log(Level.WARNING, String.format("Could not fetch “%s”!", uri), fe1);
                                return null;
                        }
                }
         */
        public void registerUsk(final Sone sone, final SoneDownloader soneDownloader) {
                try {
-                       logger.log(Level.FINE, "Registering Sone “%s” for USK updates at %s…", new Object[] { sone, sone.getRequestUri().setMetaString(new String[] { "sone.xml" }) });
+                       logger.log(Level.FINE, String.format("Registering Sone “%s” for USK updates at %s…", sone, sone.getRequestUri().setMetaString(new String[] { "sone.xml" })));
                        USKCallback uskCallback = new USKCallback() {
  
                                @Override
                                @SuppressWarnings("synthetic-access")
                                public void onFoundEdition(long edition, USK key, ObjectContainer objectContainer, ClientContext clientContext, boolean metadata, short codec, byte[] data, boolean newKnownGood, boolean newSlotToo) {
-                                       logger.log(Level.FINE, "Found USK update for Sone “%s” at %s, new known good: %s, new slot too: %s.", new Object[] { sone, key, newKnownGood, newSlotToo });
+                                       logger.log(Level.FINE, String.format("Found USK update for Sone “%s” at %s, new known good: %s, new slot too: %s.", sone, key, newKnownGood, newSlotToo));
                                        if (edition > sone.getLatestEdition()) {
                                                sone.setLatestEdition(edition);
                                                new Thread(new Runnable() {
                        soneUskCallbacks.put(sone.getId(), uskCallback);
                        node.clientCore.uskManager.subscribe(USK.create(sone.getRequestUri()), uskCallback, (System.currentTimeMillis() - sone.getTime()) < 7 * 24 * 60 * 60 * 1000, (HighLevelSimpleClientImpl) client);
                } catch (MalformedURLException mue1) {
-                       logger.log(Level.WARNING, "Could not subscribe USK “" + sone.getRequestUri() + "”!", mue1);
+                       logger.log(Level.WARNING, String.format("Could not subscribe USK “%s”!", sone.getRequestUri()), mue1);
                }
        }
  
                        return;
                }
                try {
-                       logger.log(Level.FINEST, "Unsubscribing from USK for %s…", new Object[] { sone });
+                       logger.log(Level.FINEST, String.format("Unsubscribing from USK for %s…", sone));
                        node.clientCore.uskManager.unsubscribe(USK.create(sone.getRequestUri()), uskCallback);
                } catch (MalformedURLException mue1) {
-                       logger.log(Level.FINE, "Could not unsubscribe USK “" + sone.getRequestUri() + "”!", mue1);
+                       logger.log(Level.FINE, String.format("Could not unsubscribe USK “%s”!", sone.getRequestUri()), mue1);
                }
        }
  
                        node.clientCore.uskManager.subscribe(USK.create(uri), uskCallback, true, (HighLevelSimpleClientImpl) client);
                        uriUskCallbacks.put(uri, uskCallback);
                } catch (MalformedURLException mue1) {
-                       logger.log(Level.WARNING, "Could not subscribe to USK: " + uri, uri);
+                       logger.log(Level.WARNING, String.format("Could not subscribe to USK: %s", uri), mue1);
                }
        }
  
        public void unregisterUsk(FreenetURI uri) {
                USKCallback uskCallback = uriUskCallbacks.remove(uri);
                if (uskCallback == null) {
-                       logger.log(Level.INFO, "Could not unregister unknown USK: " + uri);
+                       logger.log(Level.INFO, String.format("Could not unregister unknown USK: %s", uri));
                        return;
                }
                try {
                        node.clientCore.uskManager.unsubscribe(USK.create(uri), uskCallback);
                } catch (MalformedURLException mue1) {
-                       logger.log(Level.INFO, "Could not unregister invalid USK: " + uri);
+                       logger.log(Level.INFO, String.format("Could not unregister invalid USK: %s", uri), mue1);
                }
        }
  
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - SoneDownloader.java - Copyright © 2010 David Roden
 + * Sone - SoneDownloader.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -151,7 -151,7 +151,7 @@@ public class SoneDownloader extends Abs
         *         downloaded
         */
        public Sone fetchSone(Sone sone, FreenetURI soneUri, boolean fetchOnly) {
-               logger.log(Level.FINE, "Starting fetch for Sone “%s” from %s…", new Object[] { sone, soneUri });
+               logger.log(Level.FINE, String.format("Starting fetch for Sone “%s” from %s…", sone, soneUri));
                FreenetURI requestUri = soneUri.setMetaString(new String[] { "sone.xml" });
                sone.setStatus(SoneStatus.downloading);
                try {
                                /* TODO - mark Sone as bad. */
                                return null;
                        }
-                       logger.log(Level.FINEST, "Got %d bytes back.", fetchResults.getRight().size());
+                       logger.log(Level.FINEST, String.format("Got %d bytes back.", fetchResults.getRight().size()));
                        Sone parsedSone = parseSone(sone, fetchResults.getRight(), fetchResults.getLeft());
                        if (parsedSone != null) {
                                if (!fetchOnly) {
         * @return The parsed Sone, or {@code null} if the Sone could not be parsed
         */
        public Sone parseSone(Sone originalSone, FetchResult fetchResult, FreenetURI requestUri) {
-               logger.log(Level.FINEST, "Parsing FetchResult (%d bytes, %s) for %s…", new Object[] { fetchResult.size(), fetchResult.getMimeType(), originalSone });
+               logger.log(Level.FINEST, String.format("Parsing FetchResult (%d bytes, %s) for %s…", fetchResult.size(), fetchResult.getMimeType(), originalSone));
                Bucket soneBucket = fetchResult.asBucket();
                InputStream soneInputStream = null;
                try {
                        }
                        return parsedSone;
                } catch (Exception e1) {
-                       logger.log(Level.WARNING, "Could not parse Sone from " + requestUri + "!", e1);
+                       logger.log(Level.WARNING, String.format("Could not parse Sone from %s!", requestUri), e1);
                } finally {
                        Closer.close(soneInputStream);
                        soneBucket.free();
                }
                if (document == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Could not parse XML for Sone %s!", new Object[] { originalSone });
+                       logger.log(Level.WARNING, String.format("Could not parse XML for Sone %s!", originalSone));
                        return null;
                }
  
                        soneXml = SimpleXML.fromDocument(document);
                } catch (NullPointerException npe1) {
                        /* for some reason, invalid XML can cause NPEs. */
-                       logger.log(Level.WARNING, "XML for Sone " + sone + " can not be parsed!", npe1);
+                       logger.log(Level.WARNING, String.format("XML for Sone %s can not be parsed!", sone), npe1);
                        return null;
                }
  
                }
  
                if (protocolVersion < 0) {
-                       logger.log(Level.WARNING, "Invalid protocol version: " + protocolVersion + "! Not parsing Sone.");
+                       logger.log(Level.WARNING, String.format("Invalid protocol version: %d! Not parsing Sone.", protocolVersion));
                        return null;
                }
  
                /* check for valid versions. */
                if (protocolVersion > MAX_PROTOCOL_VERSION) {
-                       logger.log(Level.WARNING, "Unknown protocol version: " + protocolVersion + "! Not parsing Sone.");
+                       logger.log(Level.WARNING, String.format("Unknown protocol version: %d! Not parsing Sone.", protocolVersion));
                        return null;
                }
  
                String soneTime = soneXml.getValue("time", null);
                if (soneTime == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded time for Sone %s was null!", new Object[] { sone });
+                       logger.log(Level.WARNING, String.format("Downloaded time for Sone %s was null!", sone));
                        return null;
                }
                try {
                        sone.setTime(Long.parseLong(soneTime));
                } catch (NumberFormatException nfe1) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded Sone %s with invalid time: %s", new Object[] { sone, soneTime });
+                       logger.log(Level.WARNING, String.format("Downloaded Sone %s with invalid time: %s", sone, soneTime));
                        return null;
                }
  
                        String clientName = clientXml.getValue("name", null);
                        String clientVersion = clientXml.getValue("version", null);
                        if ((clientName == null) || (clientVersion == null)) {
-                               logger.log(Level.WARNING, "Download Sone %s with client XML but missing name or version!", sone);
+                               logger.log(Level.WARNING, String.format("Download Sone %s with client XML but missing name or version!", sone));
                                return null;
                        }
                        sone.setClient(new Client(clientName, clientVersion));
                                sone.setRequestUri(new FreenetURI(soneRequestUri));
                        } catch (MalformedURLException mue1) {
                                /* TODO - mark Sone as bad. */
-                               logger.log(Level.WARNING, "Downloaded Sone " + sone + " has invalid request URI: " + soneRequestUri, mue1);
+                               logger.log(Level.WARNING, String.format("Downloaded Sone %s has invalid request URI: %s", sone, soneRequestUri), mue1);
                                return null;
                        }
                }
                                sone.setLatestEdition(Math.max(sone.getRequestUri().getEdition(), sone.getInsertUri().getEdition()));
                        } catch (MalformedURLException mue1) {
                                /* TODO - mark Sone as bad. */
-                               logger.log(Level.WARNING, "Downloaded Sone " + sone + " has invalid insert URI: " + soneInsertUri, mue1);
+                               logger.log(Level.WARNING, String.format("Downloaded Sone %s has invalid insert URI: %s", sone, soneInsertUri), mue1);
                                return null;
                        }
                }
                SimpleXML profileXml = soneXml.getNode("profile");
                if (profileXml == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded Sone %s has no profile!", new Object[] { sone });
+                       logger.log(Level.WARNING, String.format("Downloaded Sone %s has no profile!", sone));
                        return null;
                }
  
                                String fieldName = fieldXml.getValue("field-name", null);
                                String fieldValue = fieldXml.getValue("field-value", "");
                                if (fieldName == null) {
-                                       logger.log(Level.WARNING, "Downloaded profile field for Sone %s with missing data! Name: %s, Value: %s", new Object[] { sone, fieldName, fieldValue });
+                                       logger.log(Level.WARNING, String.format("Downloaded profile field for Sone %s with missing data! Name: %s, Value: %s", sone, fieldName, fieldValue));
                                        return null;
                                }
                                try {
                                        profile.addField(fieldName).setValue(fieldValue);
                                } catch (IllegalArgumentException iae1) {
-                                       logger.log(Level.WARNING, "Duplicate field: " + fieldName, iae1);
+                                       logger.log(Level.WARNING, String.format("Duplicate field: %s", fieldName), iae1);
                                        return null;
                                }
                        }
                Set<Post> posts = new HashSet<Post>();
                if (postsXml == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded Sone %s has no posts!", new Object[] { sone });
+                       logger.log(Level.WARNING, String.format("Downloaded Sone %s has no posts!", sone));
                } else {
                        for (SimpleXML postXml : postsXml.getNodes("post")) {
                                String postId = postXml.getValue("id", null);
                                String postText = postXml.getValue("text", null);
                                if ((postId == null) || (postTime == null) || (postText == null)) {
                                        /* TODO - mark Sone as bad. */
-                                       logger.log(Level.WARNING, "Downloaded post for Sone %s with missing data! ID: %s, Time: %s, Text: %s", new Object[] { sone, postId, postTime, postText });
+                                       logger.log(Level.WARNING, String.format("Downloaded post for Sone %s with missing data! ID: %s, Time: %s, Text: %s", sone, postId, postTime, postText));
                                        return null;
                                }
                                try {
                                        posts.add(post);
                                } catch (NumberFormatException nfe1) {
                                        /* TODO - mark Sone as bad. */
-                                       logger.log(Level.WARNING, "Downloaded post for Sone %s with invalid time: %s", new Object[] { sone, postTime });
+                                       logger.log(Level.WARNING, String.format("Downloaded post for Sone %s with invalid time: %s", sone, postTime));
                                        return null;
                                }
                        }
                Set<PostReply> replies = new HashSet<PostReply>();
                if (repliesXml == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded Sone %s has no replies!", new Object[] { sone });
+                       logger.log(Level.WARNING, String.format("Downloaded Sone %s has no replies!", sone));
                } else {
                        for (SimpleXML replyXml : repliesXml.getNodes("reply")) {
                                String replyId = replyXml.getValue("id", null);
                                String replyText = replyXml.getValue("text", null);
                                if ((replyId == null) || (replyPostId == null) || (replyTime == null) || (replyText == null)) {
                                        /* TODO - mark Sone as bad. */
-                                       logger.log(Level.WARNING, "Downloaded reply for Sone %s with missing data! ID: %s, Post: %s, Time: %s, Text: %s", new Object[] { sone, replyId, replyPostId, replyTime, replyText });
+                                       logger.log(Level.WARNING, String.format("Downloaded reply for Sone %s with missing data! ID: %s, Post: %s, Time: %s, Text: %s", sone, replyId, replyPostId, replyTime, replyText));
                                        return null;
                                }
                                try {
                                        replies.add(core.getReply(replyId).setSone(sone).setPost(core.getPost(replyPostId)).setTime(Long.parseLong(replyTime)).setText(replyText));
                                } catch (NumberFormatException nfe1) {
                                        /* TODO - mark Sone as bad. */
-                                       logger.log(Level.WARNING, "Downloaded reply for Sone %s with invalid time: %s", new Object[] { sone, replyTime });
+                                       logger.log(Level.WARNING, String.format("Downloaded reply for Sone %s with invalid time: %s", sone, replyTime));
                                        return null;
                                }
                        }
                Set<String> likedPostIds = new HashSet<String>();
                if (likePostIdsXml == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded Sone %s has no post likes!", new Object[] { sone });
+                       logger.log(Level.WARNING, String.format("Downloaded Sone %s has no post likes!", sone));
                } else {
                        for (SimpleXML likedPostIdXml : likePostIdsXml.getNodes("post-like")) {
                                String postId = likedPostIdXml.getValue();
                Set<String> likedReplyIds = new HashSet<String>();
                if (likeReplyIdsXml == null) {
                        /* TODO - mark Sone as bad. */
-                       logger.log(Level.WARNING, "Downloaded Sone %s has no reply likes!", new Object[] { sone });
+                       logger.log(Level.WARNING, String.format("Downloaded Sone %s has no reply likes!", sone));
                } else {
                        for (SimpleXML likedReplyIdXml : likeReplyIdsXml.getNodes("reply-like")) {
                                String replyId = likedReplyIdXml.getValue();
                                String description = albumXml.getValue("description", "");
                                String albumImageId = albumXml.getValue("album-image", null);
                                if ((id == null) || (title == null) || (description == null)) {
-                                       logger.log(Level.WARNING, "Downloaded Sone %s contains invalid album!", new Object[] { sone });
+                                       logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid album!", sone));
                                        return null;
                                }
                                Album parent = null;
                                if (parentId != null) {
                                        parent = core.getAlbum(parentId, false);
                                        if (parent == null) {
-                                               logger.log(Level.WARNING, "Downloaded Sone %s has album with invalid parent!", new Object[] { sone });
+                                               logger.log(Level.WARNING, String.format("Downloaded Sone %s has album with invalid parent!", sone));
                                                return null;
                                        }
                                }
                                                String imageWidthString = imageXml.getValue("width", null);
                                                String imageHeightString = imageXml.getValue("height", null);
                                                if ((imageId == null) || (imageCreationTimeString == null) || (imageKey == null) || (imageTitle == null) || (imageWidthString == null) || (imageHeightString == null)) {
-                                                       logger.log(Level.WARNING, "Downloaded Sone %s contains invalid images!", new Object[] { sone });
+                                                       logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid images!", sone));
                                                        return null;
                                                }
                                                long creationTime = Numbers.safeParseLong(imageCreationTimeString, 0L);
                                                int imageWidth = Numbers.safeParseInteger(imageWidthString, 0);
                                                int imageHeight = Numbers.safeParseInteger(imageHeightString, 0);
                                                if ((imageWidth < 1) || (imageHeight < 1)) {
-                                                       logger.log(Level.WARNING, "Downloaded Sone %s contains image %s with invalid dimensions (%s, %s)!", new Object[] { sone, imageId, imageWidthString, imageHeightString });
+                                                       logger.log(Level.WARNING, String.format("Downloaded Sone %s contains image %s with invalid dimensions (%s, %s)!", sone, imageId, imageWidthString, imageHeightString));
                                                        return null;
                                                }
                                                Image image = core.getImage(imageId).setSone(sone).setKey(imageKey).setCreationTime(creationTime);
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - SoneInserter.java - Copyright © 2010 David Roden
 + * Sone - SoneInserter.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -214,11 -214,11 +214,11 @@@ public class SoneInserter extends Abstr
                                        if (fingerprint.equals(lastInsertedFingerprint)) {
                                                modified = false;
                                                lastModificationTime = 0;
-                                               logger.log(Level.FINE, "Sone %s has been reverted to last insert state.", sone);
+                                               logger.log(Level.FINE, String.format("Sone %s has been reverted to last insert state.", sone));
                                        } else {
                                                lastModificationTime = System.currentTimeMillis();
                                                modified = true;
-                                               logger.log(Level.FINE, "Sone %s has been modified, waiting %d seconds before inserting.", new Object[] { sone.getName(), insertionDelay });
+                                               logger.log(Level.FINE, String.format("Sone %s has been modified, waiting %d seconds before inserting.", sone.getName(), insertionDelay));
                                        }
                                        lastFingerprint = fingerprint;
                                }
                        }
  
                        if (insertInformation != null) {
-                               logger.log(Level.INFO, "Inserting Sone “%s”…", new Object[] { sone.getName() });
+                               logger.log(Level.INFO, String.format("Inserting Sone “%s”…", sone.getName()));
  
                                boolean success = false;
                                try {
                                        sone.setLatestEdition(finalUri.getEdition());
                                        core.touchConfiguration();
                                        success = true;
-                                       logger.log(Level.INFO, "Inserted Sone “%s” at %s.", new Object[] { sone.getName(), finalUri });
+                                       logger.log(Level.INFO, String.format("Inserted Sone “%s” at %s.", sone.getName(), finalUri));
                                } catch (SoneException se1) {
                                        soneInsertListenerManager.fireInsertAborted(se1);
-                                       logger.log(Level.WARNING, "Could not insert Sone “" + sone.getName() + "”!", se1);
+                                       logger.log(Level.WARNING, String.format("Could not insert Sone “%s”!", sone.getName()), se1);
                                } finally {
                                        sone.setStatus(SoneStatus.idle);
                                }
                                if (success) {
                                        synchronized (sone) {
                                                if (lastInsertedFingerprint.equals(sone.getFingerprint())) {
-                                                       logger.log(Level.FINE, "Sone “%s” was not modified further, resetting counter…", new Object[] { sone });
+                                                       logger.log(Level.FINE, String.format("Sone “%s” was not modified further, resetting counter…", sone));
                                                        lastModificationTime = 0;
                                                        lastInsertFingerprint = lastInsertedFingerprint;
                                                        core.touchConfiguration();
                                templateInputStreamReader = new InputStreamReader(getClass().getResourceAsStream(templateName), utf8Charset);
                                template = TemplateParser.parse(templateInputStreamReader);
                        } catch (TemplateException te1) {
-                               logger.log(Level.SEVERE, "Could not parse template “" + templateName + "”!", te1);
+                               logger.log(Level.SEVERE, String.format("Could not parse template “%s”!", templateName), te1);
                                return null;
                        } finally {
                                Closer.close(templateInputStreamReader);
                                bucket = new StringBucket(writer.toString(), utf8Charset);
                                return new ManifestElement(name, bucket, contentType, bucket.size());
                        } catch (TemplateException te1) {
-                               logger.log(Level.SEVERE, "Could not render template “" + templateName + "”!", te1);
+                               logger.log(Level.SEVERE, String.format("Could not render template “%s”!", templateName), te1);
                                return null;
                        } finally {
                                Closer.close(writer);
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - UpdateChecker.java - Copyright © 2011 David Roden
 + * Sone - UpdateChecker.java - Copyright © 2011–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -166,11 -166,11 +166,11 @@@ public class UpdateChecker 
                        @Override
                        @SuppressWarnings("synthetic-access")
                        public void editionFound(FreenetURI uri, long edition, boolean newKnownGood, boolean newSlot) {
-                               logger.log(Level.FINEST, "Found update for %s: %d, %s, %s", new Object[] { uri, edition, newKnownGood, newSlot });
+                               logger.log(Level.FINEST, String.format("Found update for %s: %d, %s, %s", uri, edition, newKnownGood, newSlot));
                                if (newKnownGood || newSlot) {
                                        Pair<FreenetURI, FetchResult> uriResult = freenetInterface.fetchUri(uri.setMetaString(new String[] { "sone.properties" }));
                                        if (uriResult == null) {
-                                               logger.log(Level.WARNING, "Could not fetch properties of latest homepage: %s", uri);
+                                               logger.log(Level.WARNING, String.format("Could not fetch properties of latest homepage: %s", uri));
                                                return;
                                        }
                                        Bucket resultBucket = uriResult.getRight().asBucket();
                                                parseProperties(resultBucket.getInputStream(), edition);
                                                latestEdition = edition;
                                        } catch (IOException ioe1) {
-                                               logger.log(Level.WARNING, "Could not parse sone.properties of " + uri, ioe1);
+                                               logger.log(Level.WARNING, String.format("Could not parse sone.properties of %s!", uri), ioe1);
                                        } finally {
                                                resultBucket.free();
                                        }
                if (version.compareTo(currentLatestVersion) > 0) {
                        currentLatestVersion = version;
                        latestVersionDate = releaseTime;
-                       logger.log(Level.INFO, "Found new version: %s (%tc)", new Object[] { version, new Date(releaseTime) });
+                       logger.log(Level.INFO, String.format("Found new version: %s (%tc)", version, new Date(releaseTime)));
                        updateListenerManager.fireUpdateFound(version, releaseTime, edition);
                }
        }
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - Sone.java - Copyright © 2010 David Roden
 + * Sone - Sone.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -33,7 -33,7 +33,7 @@@ import net.pterodactylus.sone.core.Opti
  import net.pterodactylus.sone.freenet.wot.Identity;
  import net.pterodactylus.sone.freenet.wot.OwnIdentity;
  import net.pterodactylus.sone.template.SoneAccessor;
 -import net.pterodactylus.util.filter.Filter;
 +import net.pterodactylus.util.collection.filter.Filter;
  import net.pterodactylus.util.logging.Logging;
  import net.pterodactylus.util.validation.Validation;
  import freenet.keys.FreenetURI;
@@@ -305,7 -305,7 +305,7 @@@ public class Sone implements Fingerprin
                        return this;
                }
                if (!this.requestUri.equalsKeypair(requestUri)) {
-                       logger.log(Level.WARNING, "Request URI %s tried to overwrite %s!", new Object[] { requestUri, this.requestUri });
+                       logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", requestUri, this.requestUri));
                        return this;
                }
                return this;
                        return this;
                }
                if (!this.insertUri.equalsKeypair(insertUri)) {
-                       logger.log(Level.WARNING, "Request URI %s tried to overwrite %s!", new Object[] { insertUri, this.insertUri });
+                       logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", insertUri, this.insertUri));
                        return this;
                }
                return this;
         */
        public void setLatestEdition(long latestEdition) {
                if (!(latestEdition > this.latestEdition)) {
-                       logger.log(Level.FINE, "New latest edition %d is not greater than current latest edition %d!", new Object[] { latestEdition, this.latestEdition });
+                       logger.log(Level.FINE, String.format("New latest edition %d is not greater than current latest edition %d!", latestEdition, this.latestEdition));
                        return;
                }
                this.latestEdition = latestEdition;
         */
        public void addPost(Post post) {
                if (post.getSone().equals(this) && posts.add(post)) {
-                       logger.log(Level.FINEST, "Adding %s to “%s”.", new Object[] { post, getName() });
+                       logger.log(Level.FINEST, String.format("Adding %s to “%s”.", post, getName()));
                }
        }
  
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - DefaultIdentity.java - Copyright © 2010 David Roden
 + * Sone - DefaultIdentity.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -254,7 -254,7 +254,7 @@@ public class DefaultIdentity implement
                                return trustCache.get(ownIdentity);
                        }
                } catch (CacheException ce1) {
-                       logger.log(Level.WARNING, "Could not get trust for OwnIdentity: " + ownIdentity, ce1);
+                       logger.log(Level.WARNING, String.format("Could not get trust for OwnIdentity: %s", ownIdentity), ce1);
                        return null;
                }
        }
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - WebOfTrustConnector.java - Copyright © 2010 David Roden
 + * Sone - WebOfTrustConnector.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -134,7 -134,7 +134,7 @@@ public class WebOfTrustConnector implem
         *             if an error occured talking to the Web of Trust plugin
         */
        public Set<Identity> loadTrustedIdentities(OwnIdentity ownIdentity, String context) throws PluginException {
 -              Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("TreeOwner", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).get());
 +              Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).get());
                SimpleFieldSet fields = reply.getFields();
                Set<Identity> identities = new HashSet<Identity>();
                int identityCounter = -1;
         */
        private synchronized Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException {
                reply = new Reply();
-               logger.log(Level.FINE, "Sending FCP Request: " + fields.get("Message"));
+               logger.log(Level.FINE, String.format("Sending FCP Request: %s", fields.get("Message")));
                synchronized (reply) {
                        pluginConnector.sendRequest(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, fields, data);
                        try {
                                reply.wait();
                        } catch (InterruptedException ie1) {
-                               logger.log(Level.WARNING, "Got interrupted while waiting for reply on " + fields.get("Message") + ".", ie1);
+                               logger.log(Level.WARNING, String.format("Got interrupted while waiting for reply on %s.", fields.get("Message")), ie1);
                        }
                }
-               logger.log(Level.FINEST, "Received FCP Response for %s: %s", new Object[] { fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null });
+               logger.log(Level.FINEST, String.format("Received FCP Response for %s: %s", fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null));
                if ((reply.getFields() == null) || "Error".equals(reply.getFields().get("Message"))) {
                        throw new PluginException("Could not perform request for " + fields.get("Message"));
                }
        @Override
        public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) {
                String messageName = fields.get("Message");
-               logger.log(Level.FINEST, "Received Reply from Plugin: " + messageName);
+               logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName));
                synchronized (reply) {
                        reply.setFields(fields);
                        reply.setData(data);
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - SonePlugin.java - Copyright © 2010 David Roden
 + * Sone - SonePlugin.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -68,22 -68,22 +68,22 @@@ public class SonePlugin implements Fred
                                Class<?> loggerClass = Logging.getLoggerClass(logRecord.getLoggerName());
                                int recordLevel = logRecord.getLevel().intValue();
                                if (recordLevel < Level.FINE.intValue()) {
-                                       freenet.support.Logger.debug(loggerClass, String.format(logRecord.getMessage(), logRecord.getParameters()), logRecord.getThrown());
+                                       freenet.support.Logger.debug(loggerClass, logRecord.getMessage(), logRecord.getThrown());
                                } else if (recordLevel < Level.INFO.intValue()) {
-                                       freenet.support.Logger.minor(loggerClass, String.format(logRecord.getMessage(), logRecord.getParameters()), logRecord.getThrown());
+                                       freenet.support.Logger.minor(loggerClass, logRecord.getMessage(), logRecord.getThrown());
                                } else if (recordLevel < Level.WARNING.intValue()) {
-                                       freenet.support.Logger.normal(loggerClass, String.format(logRecord.getMessage(), logRecord.getParameters()), logRecord.getThrown());
+                                       freenet.support.Logger.normal(loggerClass, logRecord.getMessage(), logRecord.getThrown());
                                } else if (recordLevel < Level.SEVERE.intValue()) {
-                                       freenet.support.Logger.warning(loggerClass, String.format(logRecord.getMessage(), logRecord.getParameters()), logRecord.getThrown());
+                                       freenet.support.Logger.warning(loggerClass, logRecord.getMessage(), logRecord.getThrown());
                                } else {
-                                       freenet.support.Logger.error(loggerClass, String.format(logRecord.getMessage(), logRecord.getParameters()), logRecord.getThrown());
+                                       freenet.support.Logger.error(loggerClass, logRecord.getMessage(), logRecord.getThrown());
                                }
                        }
                });
        }
  
        /** The version. */
-       public static final Version VERSION = new Version(0, 8);
+       public static final Version VERSION = new Version(0, 8, 1);
  
        /** The logger. */
        private static final Logger logger = Logging.getLogger(SonePlugin.class);
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - SoneAccessor.java - Copyright © 2010 David Roden
 + * Sone - SoneAccessor.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -107,7 -107,7 +107,7 @@@ public class SoneAccessor extends Refle
                                return null;
                        }
                        Trust trust = core.getTrust(currentSone, sone);
-                       logger.log(Level.FINEST, "Trust for %s by %s: %s", new Object[] { sone, currentSone, trust });
+                       logger.log(Level.FINEST, String.format("Trust for %s by %s: %s", sone, currentSone, trust));
                        if (trust == null) {
                                return new Trust(null, null, null);
                        }
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - FreenetLinkParser.java - Copyright © 2010 David Roden
 + * Sone - FreenetLinkParser.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -237,8 -237,8 +237,8 @@@ public class SoneTextParser implements 
                                int nextSpace = matcher.find(0) ? matcher.start() : line.length();
                                String link = line.substring(0, nextSpace);
                                String name = link;
-                               logger.log(Level.FINER, "Found link: %s", link);
-                               logger.log(Level.FINEST, "CHK: %d, SSK: %d, USK: %d", new Object[] { nextChk, nextSsk, nextUsk });
+                               logger.log(Level.FINER, String.format("Found link: %s", link));
+                               logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
  
                                if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) {
                                        FreenetURI uri;
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - CreateSonePage.java - Copyright © 2010 David Roden
 + * Sone - CreateSonePage.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -115,7 -115,7 +115,7 @@@ public class CreateSonePage extends Son
                        /* create Sone. */
                        Sone sone = webInterface.getCore().createSone(selectedIdentity);
                        if (sone == null) {
-                               logger.log(Level.SEVERE, "Could not create Sone for OwnIdentity: %s", selectedIdentity);
+                               logger.log(Level.SEVERE, String.format("Could not create Sone for OwnIdentity: %s", selectedIdentity));
                                /* TODO - go somewhere else */
                        }
  
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - SearchPage.java - Copyright © 2010 David Roden
 + * Sone - SearchPage.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -40,12 -40,12 +40,12 @@@ import net.pterodactylus.util.cache.Cac
  import net.pterodactylus.util.cache.DefaultCacheItem;
  import net.pterodactylus.util.cache.MemoryCache;
  import net.pterodactylus.util.cache.ValueRetriever;
 -import net.pterodactylus.util.collection.Mapper;
 -import net.pterodactylus.util.collection.Mappers;
  import net.pterodactylus.util.collection.Pagination;
  import net.pterodactylus.util.collection.TimedMap;
 -import net.pterodactylus.util.filter.Filter;
 -import net.pterodactylus.util.filter.Filters;
 +import net.pterodactylus.util.collection.filter.Filter;
 +import net.pterodactylus.util.collection.filter.Filters;
 +import net.pterodactylus.util.collection.mapper.Mapper;
 +import net.pterodactylus.util.collection.mapper.Mappers;
  import net.pterodactylus.util.logging.Logging;
  import net.pterodactylus.util.number.Numbers;
  import net.pterodactylus.util.template.Template;
@@@ -230,7 -230,7 +230,7 @@@ public class SearchPage extends SoneTem
         * @return The score of the expression
         */
        private double calculateScore(List<Phrase> phrases, String expression) {
-               logger.log(Level.FINEST, "Calculating Score for “%s”…", expression);
+               logger.log(Level.FINEST, String.format("Calculating Score for “%s”…", expression));
                double optionalHits = 0;
                double requiredHits = 0;
                int forbiddenHits = 0;
                                }
                                score += Math.pow(1 - position / (double) expression.length(), 2);
                                index = position + phraseString.length();
-                               logger.log(Level.FINEST, "Got hit at position %d.", position);
+                               logger.log(Level.FINEST, String.format("Got hit at position %d.", position));
                                ++matches;
                        }
-                       logger.log(Level.FINEST, "Score: %f", score);
+                       logger.log(Level.FINEST, String.format("Score: %f", score));
                        if (matches == 0) {
                                continue;
                        }
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - WebInterface.java - Copyright © 2010 David Roden
 + * Sone - WebInterface.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -110,7 -110,7 +110,7 @@@ import net.pterodactylus.util.cache.Def
  import net.pterodactylus.util.cache.MemoryCache;
  import net.pterodactylus.util.cache.ValueRetriever;
  import net.pterodactylus.util.collection.SetBuilder;
 -import net.pterodactylus.util.filter.Filters;
 +import net.pterodactylus.util.collection.filter.Filters;
  import net.pterodactylus.util.logging.Logging;
  import net.pterodactylus.util.notify.Notification;
  import net.pterodactylus.util.notify.NotificationManager;
@@@ -749,7 -749,7 +749,7 @@@ public class WebInterface implements Co
                                }
                        }
                } catch (IOException ioe1) {
-                       logger.log(Level.WARNING, "Could not parse post text: " + text, ioe1);
+                       logger.log(Level.WARNING, String.format("Could not parse post text: %s", text), ioe1);
                }
                return Filters.filteredSet(mentionedSones, Sone.LOCAL_SONE_FILTER);
        }
                        try {
                                return templateCache.get(templateName);
                        } catch (CacheException ce1) {
-                               logger.log(Level.WARNING, "Could not get template for " + templateName + "!", ce1);
+                               logger.log(Level.WARNING, String.format("Could not get template for %s!", templateName), ce1);
                                return null;
                        }
                }
                        try {
                                template = TemplateParser.parse(templateReader);
                        } catch (TemplateException te1) {
-                               logger.log(Level.WARNING, "Could not parse template “" + templateName + "” for inclusion!", te1);
+                               logger.log(Level.WARNING, String.format("Could not parse template “%s” for inclusion!", templateName), te1);
                        }
                        return template;
                }
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Sone - FreenetTemplatePage.java - Copyright © 2010 David Roden
 + * Sone - FreenetTemplatePage.java - Copyright © 2010–2012 David Roden
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
@@@ -155,7 -155,7 +155,7 @@@ public class FreenetTemplatePage implem
                        long start = System.nanoTime();
                        processTemplate(request, templateContext);
                        long finish = System.nanoTime();
-                       logger.log(Level.FINEST, "Template was rendered in " + ((finish - start) / 1000) / 1000.0 + "ms.");
+                       logger.log(Level.FINEST, "Template was rendered in %dms.", ((finish - start) / 1000) / 1000.0);
                } catch (RedirectException re1) {
                        return new RedirectResponse(re1.getTarget());
                }