computers are cool

mookid on code

Fun with RavenDB 2

November 5th, 2010 by mookid

This is the second post in a small series about RavenDB – a document database in .NET. I will try to touch the same areas as I did in my series on MongoDB, possibly comparing the two where I see fit.

Now, this time we will take a look at querying…

Introduction

Querying with MongoDB is extremely easy and intuitive when you’re used to relational databases – just type in some queries in the form of JSON documents and send them to the server and let it do its work.

Querying with RavenDB is a different story, because the only thing that can be queried is an index1. Let’s see…

Simple query

Let’s start out by handing a couple of documents to the server. Let’s execute the following:

using (var session = documentStore.OpenSession())
{
    session.Store(new Movie {Title = "The Big Lebowski", ViewCount = 200});
    session.Store(new Movie {Title = "Fear And Loathing In Las Vegas", ViewCount = 100});
    session.Store(new Movie {Title = "Adaptation", ViewCount = 20});
 
    session.SaveChanges();
}

Now, in order to be able to query these documents, we need to tell RavenDB to create an index… I like to be code-driven when I can, so let’s do it with C#… first, make a class somewhere derived from AbstractIndexCreationTask:

public class MoviesByViewCount : AbstractIndexCreationTask
{
    public override IndexDefinition CreateIndexDefinition()
    {
        return new IndexDefinition<Movie>
                    {
                        Map = movies => from movie in movies
                                        select new {movie.ViewCount}
                    }.ToIndexDefinition(DocumentStore.Conventions);
    }
}

In this example, I build the index purely from mapping the collection – i.e. there’s no reduce step. Note that the map step is a LINQ query that maps each document into the fields that should be used to build the index. That means that the example above will allow me to query this index and constrain by ViewCount of each movie.

Next, upon initialization, we need to tell RavenDB to create our indexes (if they have not already been created – otherwise, they’ll be updated):

var documentStore = new DocumentStore{...};
documentStore.Initialize();
 
IndexCreation.CreateIndexes(typeof (MoviesByViewCount).Assembly, documentStore);

That was easy. Now, let’s take the index for a spin… first let’s just get everything 2:

using(var session = documentStore.OpenSession())
{
    var movies = from m in session.Query<Movie>(typeof (MoviesByViewCount).Name)
                 select m;
 
    foreach(var movie in movies)
    {
        Console.WriteLine("Got {0} ({1} views)", movie.Title, movie.ViewCount);
    }
}

which results in the following output in the console:

Executing query '' on index 'MoviesByViewCount' in 'http://localhost:8080'
Query returned 3/3 results
Got The Big Lebowski (200 views)
Got Fear And Loathing In Las Vegas (100 views)
Got Adaptation (20 views)

which is pretty much what we expected. Note however that RavenDB is nice enough to tell when a query is executed and how many results are returned.

Now let’s use our index and change the query into this:

var movies = from m in session.Query<Movie>(typeof (MoviesByViewCount).Name)
                where m.ViewCount <= 100
                select m;

which gives me the following output:

Executing query 'ViewCount_Range:[* TO 0x00000064]' on index 'MoviesByViewCount' in 'http://localhost:8080'
Query returned 2/2 results
Got Fear And Loathing In Las Vegas (100 views)
Got Adaptation (20 views)

Note how the query criteria are translated into a Lucene query – that’s because RavenDB uses Lucene. NET for all of its indexing work. Just for the fun of it, let’s try using the index to constrain by title:

var movies = from m in session.Query<Movie>(typeof (MoviesByViewCount).Name)
             where m.Title == "The Big Lebowski"
             select m;

which results in the following output:

Executing query 'Title:[["The Big Lebowski"]]' on index 'MoviesByViewCount' in 'http://localhost:8080'
Query returned 0/0 results

It appears RavenDB will just go ahead and query Lucene for it, even though the index doesn’t have the specified field. Kind of weird, but maybe it’s because Lucene is itself a document DB, and there’s no way to tell beforehand whether a given index contains a document with the specified field.

Now that was a couple of simple queries. Next time, let’s try building a map/reduce query!

  1. Or is it? I should point out that Ayende said that RavenDB would have dynamically generated temporary indexes in the future, allowing ad-hoc quering… but what’s more, those temporary indexes would “materialize” and become permanent if you hit them enough times… that actually sounds extremely cool, and should allow for some truly frictionless and agile-feeling development.
  2. Note that because of RavenDB’s excellent safe-by-default philosophy, at most 128 documents will be returned! Therefore, the usual .Skip(n) and .Take(m) methods should be used to properly page the result sets.

    Note also, that by default you can perform only 30 operations resulting in remote calls within one IDocumentSession. This is another constraint that will guide you away from blowing off that left foot of yours :)

Fun with RavenDB 1

November 1st, 2010 by mookid

This is the first post in a small series about RavenDB – a document database in .NET. I will try to touch the same areas as I did in my series on MongoDB, possibly comparing the two where I see fit.

Now, first – let’s see if the raven can fly…

Getting started

I am extremely happy to see that Ayende has created the same installation experience as I got with MongoDB… i.e., to get the server running, perform the following steps (assuming the .NET 4 framework is installed on your system):

  1. Grab a ZIP with the lastest build here
  2. Unzip somewhere
  3. Go to /Server and run Raven.Server.exe

- and now the RavenDB server will be running on localhost:8080. That was easy. Now, try visiting http://localhost:8080 in your browser – now you should see the administration interface of RavenDB.

By the way, have you ever tried installing Microsoft SQL Server? Shudder!! :)

Connecting with the .NET client

I’m old school, so I am still using Visual Studio 2008. If you’re old school like me, add a reference to /Client-3.5/Raven.Client-3.5.dll – otherwise add a reference to /Client/Raven.Client.Lightweight.dll.

Now, to open a connection, do this:

var documentStore = new DocumentStore {Url = "http://localhost:8080"};
documentStore.Initialize();
 
using (var session = documentStore.OpenSession())
{
    // ....
}

- and then store the DocumentStore as a singleton in your program.

Inserting a document

Now, let’s try inserting a document… say we have a POCO model representation of a person that looks like this (allowing Address to be either DomesticAddress or ForeignAddress):

public class Person
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}
 
public abstract class Address
{
    public abstract string ToString(string separator);
}
 
public class ForeignAddress : Address
{
    public string[] AddressLines { get; set; }
 
    public override string ToString(string separator)
    {
        return string.Join(separator, AddressLines ?? new string[0]);
    }
}
 
public class DomesticAddress : Address
{
    public string Street { get; set; }
    public string HouseNumber { get; set; }
    public string PostalCode { get; set; }
    public string City { get; set; }
 
    public override string ToString(string separator)
    {
        return string.Join(separator, new[]
                                          {
                                              string.Format("{0} {1}", Street, HouseNumber),
                                              string.Format("{0} {1}", PostalCode, City)
                                          });
    }
}

Then, do this:

using (var session = documentStore.OpenSession())
{
    session.Store(new Person
                      {
                          FirstName = "Mogens Heller",
                          LastName = "Grabe",
                          Address = new DomesticAddress
                                        {
                                            Street = "Torsmark",
                                            HouseNumber = "4",
                                            PostalCode = "8700",
                                            City = "Horsens"
                                        }
                      });
    session.SaveChanges();
}

Now, let’s visit http://localhost:8080/raven/documents.html in the browser… it will probably look something like this:

Document in RavenDB

As you can see, RavenDB stores all documents in a single collection. Right now, there’s one person in there, and then there’s a document that RavenDB uses to generate integer IDs based on the hi-lo-algorithm. Rob Ashton has an explanation here on the design decisions made for this particular piece of RavenDB.

I like this particular decision, because it makes for some really nice human-readable, human-typeable IDs.

Note how the ID of the document is people/1 – RavenDB is smart enough to pluralize most names, which is pretty cool. Let’s click the document to see what’s in it:

Document in RavenDB

Note also how RavenDB puts type information in the document, allowing the proper subtype to be deserialized. Now, let’s try this out:

using (var session = documentStore.OpenSession())
{
    var me = session.Load<Person>("people/1");
    Console.WriteLine(@"{0} {1}
{2}", me.FirstName, me.LastName, me.Address);
}

- which results in the following console output:

Loading document [people/1] from http://localhost:8080
Mogens Heller Grabe
Torsmark 4
8700 Horsens

How cool is that?! (pretty cool, actually…)

Note that the pretty UI is based on the actual RavenDB interface to the world, which is REST-based. That means we can go to a DOS prompt and do this:

C:\>curl -X GET localhost:8080/docs/people/1
{"FirstName":"Mogens Heller","LastName":"Grabe","Address":{"$type":"raventjek.Class1+DomesticAddress, raventjek","Street":"Torsmark","HouseNumber":"4","PostalCode":"8700","City":"Horsens"}}

Now, that was a short dive into storing documents and retrieving them again by ID. We need to do more than that, though – otherwise we would have been content using a simple key/value-store. Therefore, in the next post, I will take a look at querying

Trifork Geek Night moved

October 20th, 2010 by mookid

Just want to say that the planned Trifork Geek Night on “Advanced Windsor-tricks” I mentioned earlier on the 23rd of November is moved to the 13th of December.

Somehow someone double-booked our presentation facilities in Taastrup – sorry, if it has caused inconvenience for you.

To sum it up: Trifork Geek Night on “Advanced Windsor-tricks” on the 13th of December at the Trifork office in Copenhagen.

Book review: NHibernate 3.0 Cookbook

October 8th, 2010 by mookid

NHibernate 3.0 Cookbook coverPackt Publishing has before asked if I was interested in reviewing some of their books, which I was – this time, however, I asked them if they were interested in me reviewing their upcoming NHibernate 3.0 Cookbook by Jason Dentler.

I did that, because I like NHibernate very much, and I would like to help promote good fresh litterature about the subject. And this book really stands out as fresh, because it covers NHibernate 3.0 which has not even been officially released yet!

My first impressions are good – it starts out with creating a model and the usual XML-mapping stuff, and then it dives directly into modeling an inheritance hierarchy. I think this is pretty cool, because it is a sign that the book has a fairly high level of ambition: It is not just about stuffing away rows in the db, it’s about persisting an actual model!

It covers Fluent NHibernate and Fabio’s ConfORM as well, so it provides a really good foundation to anyone interested in learning the intricacies of configuring NHibernate. And it is pretty true to the model-first approach, which is how I like it.

Then it goes on with a chapter on how to manage sessions and transactions including – among other things – an example on how to manage the session from an ASP.NET MVC action filter (which is not “best practice” from an ASP.NET MVC perspective IMO, as it relies on static gateways, but I digress… the book is not about ASP.NET MVC :) )

The query chapter is great, because it covers everything I can think of: Criteria, QueryOver, HQL, both in their normal and multi forms, futures, LINQ to NHibernate, detached criteria, and the new HQL bulk operations, insert and update. If I must put my finger on something, I think that the different areas are covered a little too lightly, but hey – there’s plenty of information on this stuff on the internet, and you could probably write an entire book entirely about how to put HQL to use.

The testing chapter is great as well, as it touches on nice-to-know stuff and some of “the new developments” in the area: NHibernate Profiler, Fluent NHibernate automatic persistence testing, using in-memory SQLite for persistence testing, + more.

The chapter on implementing a data access layer shows a typical data access object and a repository implementation which will probably look familiar to a lot of people, implemented with NHibernate. They both have the ability to automatically perform their operations withing transactions, if one is not already active. This makes the implementations pretty flexible, as they can be used either “by themselves”, or they can implicitly enlist in an ongoing unit of work. Moreover, a pretty nifty named query implementation is shown, complete with automated test that checks whether all implemented named query classes have corresponding named queries in an HBM XML file.

The rest of the book shows how various common tasks can be achieved using NHibernate or some of the many NHContrib projects, like e.g. creating an audit trail by listening to events, creating an IUserType to encrypt strings, using Burrows to manage session, putting NHibernate Search to use, etc… As you can probably imagine, this stuff is covered pretty lightly, but it’s sufficient to give an impression on the huge ecosystem that surrounds NHibernate, which is great.

Conclusion

It strikes me that the book is definitely a “no BS-book” – there’s plenty of code, which is mostly high quality and sufficiently best practice-compliant, and recommendations throughout when there are decisions to be made. If I should criticize something, I think the sheer amount of code makes for an exhausting casual read :) it does, however, claim to be a “cookbook”, so I guess that’s just the way it is.

The book is probably great for developers, who are either new to or semi-experienced in using NHibernate, but have a general high level of experience and skills.

All-in-all a good read, and it’s great that it touches on so many things in and around this huge framework!

Title: NHibernate 3.0 Cookbook
Author: Jason Dentler
ISBN 10/13: 184951304X / 978-1-84951-304-3
Publisher: Packt Publishing

Trifork Geek Nights

September 30th, 2010 by mookid

Just wanted to say that I will be speaking at a couple of Trifork Geek Nights in November and December, about Castle Windsor and NServiceBus respectively.

First,

Advanced Windsor-Tricks

A quick introduction followed by some of the more advanced features of my favorite IoC container. If you’re new to IoC, or you are wondering what the fuzz is about, or you are interested in letting your container do some more work for you, you should come to this one :)

Will be held on

from 4:30 pm to 6:30 pm.

And then,

Distributed systems in .NET with NServiceBus

Introduction to messaging in .NET with NServiceBus. Will give an introduction to some fundamental messaging patterns and go on to show how these can be put to use with NServiceBus.

If you’re new to IoC, you can probably benefit from showing up at the “Advanced Windsor-Tricks” geek night before going to this one, because NServiceBus is relying heavily on having a container.

Will be held on

from 4:30 pm to 6:30 pm as well.

Hope to see some enthusiastic coders there.

PS: The Geek Nights will be held in Danish :)

Shouldly – better assertions

September 21st, 2010 by mookid

Today I came across Shouldly, as I followed a link in a tweet by Rob Conery. I have a thing for nifty mini-projects, so I immediately git clone http://github.com/shouldly/shouldly.git‘d it, and pulled it into a small thing I am building.

What is Shouldly? Basically, it’s just a niftier way of writing assert statements in tests. It fits right in between NUnit and Rhino Mocks, so you will get the most out of it if you are using those two for your unit tests. Check out this repository test – first, arrange and act:

var notes = new Notes{Artist="Josh Rouse", Title="Winter In The Hamptons"};
repo.Save(notes);
var id = notes.Id;
 
var loadedNotes = repo.FindOne(id);

and then, usually the assert would look something like this:

Assert.AreEqual("Joe Rouse", loadedNotes.Artist);
Assert.AreEqual("Winter In The Hamptons", loadedNotes.Title);

- yielding error messages like this:

NUnit.Framework.AssertionException:   Expected string length 9 but was 10. Strings differ at index 2.
  Expected: "Joe Rouse"
  But was:  "Josh Rouse"
  -------------^

which is probably OK and acceptable, because how would NUnit know any better than that?

Check out what Shouldly can do:

loadedNotes.Artist.ShouldBe("Joe Rouse");
loadedNotes.Title.ShouldBe("Winter In The Hamptons");

- yielding error messages like this:

NUnit.Framework.AssertionException: loadedNotes.Artist
        should be
    "Joe Rouse"
        but was
    "Josh Rouse"

which IMO is just too nifty to ignore!

Shouldly takes advantage of the fact the the current StackTrace has all the information we’re after when the assert is an extension method, which is extremely cool and well thought out.

Moreover, it integrates with Rhino Mocks, yielding better messages when doing AssertWasCalled stuff: Instead of just telling that the test did not pass, it tells you exactly which calls were recorded and which one was expected – a thing that Rhino Mocks has always been missing.

Conclusion: YourNextProject.ShouldContain("Shouldly")

Castle Windsor debugger visualization

September 15th, 2010 by mookid

A while ago, I noticed that Krzysztof Ko?mic was tweeting regularly about adding debugger visualization to Windsor. At the time, I wasn’t really paying attention, so I didn’ t actually understand what he was doing.

Today, I was coding some stuff, and I downloaded the latest and greatest Windsor 2.5 (from August 2010), and after a while I found myself stepping through some code in a small web application I was building from scratch – and that’s when I found out what he was rambling about…. check this out:

Windsor debugger visualization

See how the container renders itself as a list of all the components it contains, followed by a list of “Potentially Misconfigured Components”…?

How cool is that? (pretty cool, that’s how cool it is!)

Not a ground-breaking earth-shaking feature on the grand scale of cool stuff, but sometimes it’s the little things…

(I’m puzzled, however, as to why the headline says “Count = 4″ in the “Potentially Misconfigured Components” section when the count is clearly 2…?)

Scheduling recurring tasks in NServiceBus

August 10th, 2010 by mookid

A while ago, on a project I am currently involved with which is based on NServiceBus, we needed to publish certain pieces of information at fixed intervals. I was not totally clear in my head on how this could be implemented in an NServiceBus service, so I asked for help on Twitter, which resulted in a nifty piece of advice from Andreas Öhlund: Set up a timer to do a bus.SendLocal at the specified interval.

That’s exactly what we did, and I think we ended up with a pretty nifty piece of code that I want to show off :)

PS: bus.SendLocal(message) effectively does a bus.Send(((UnicastBus)bus).Address, message) – i.e. it puts a message, MSMQ and all, in the service’s own input queue.

First, we have an API that looks like this (looking a little funny, I know – wait and see…):

public interface ISchedule
{
    void Every(TimeSpan interval, Func<IMessage> messageFactoryMethod);
}

- which is implemented like this (registered as a singleton in the container):

public class ServerBasedTimerSchedule : ISchedule, IDisposable
{
    readonly IBus bus;
    readonly List<System.Timers.Timer> timers = new List<System.Timers.Timer>();
 
    public ServerBasedTimerSchedule(IBus bus)
    {
        this.bus = bus;
    }
 
    public void Every(TimeSpan interval, Func<IMessage> messageFactoryMethod)
    {
        var timer = new System.Timers.Timer();
        timer.Elapsed += (_, __) => bus.SendLocal(messageFactoryMethod());
        timer.Interval = interval.TotalMilliseconds;
        timer.Start();
        timers.Add(timer);
    }
 
    public void Dispose()
    {
        timers.ForEach(timer => timer.Dispose());
    }
}

The System.Timers.Timer is a timer which uses the thread pool to schedule callbacks at the specified interval. It’s pretty easy to use, and it fits nicely with this scenario.

Now, in combination with this nifty class of extension goodness:

public static class TimeSpanExtensions
{
    public static TimeSpan Seconds(this int seconds)
    {
        return TimeSpan.FromSeconds(seconds);
    }
 
    public static TimeSpan Minutes(this int minutes)
    {
        return TimeSpan.FromMinutes(minutes);
    }
 
    // ... etc + for doubles as well
}

- we can schedule our tasks like so:

public class ScheduleRealTimeDataPublishing : IWantToRunAtStartup
{
    public ScheduleRealTimeDataPublishing(ISchedule schedule)
    {
        this.schedule = schedule;
    }
 
    public void Run()
    {
        schedule.Every(5.Seconds(), () => new PublishRealTimeDataMessage());
    }
 
    public void Stop()
    {
    }
}

Now, why is this good? It’s good because the actual task will then be carried out by whoever implements IHandleMessages<PublishRealTimeDataMessage> in the service, processing the tasks with all the benefits of the usual NServiceBus message processing pipeline.

Nifty, huh?

Looking over the simplicity and elegance of this solution, I’m kind of embarassed to tell that my first take on this was to implement the timer almost exactly like above, except instead of bus.SendLocal in the Elapsed-callback, we had a huge event handler that simulated most of our message processing pipeline – including NHibernateMessageModule, transactions, and whatnot….

Please note that ScheduleRealTimeDataPublishing is not re-entrant – in this form its Every method should only be used from within the Run and Stop methods of implementors of IWantToRunAtStartup, as these are run sequentially.

Code golf

July 30th, 2010 by mookid

The result of Kodehoved’s code golf competition has been found, and I got a shared 5th place.

The task was to add two large integers together by representing the integers with arrays of their digits, thus allowing them to become extremely large.

My contribution looks like this (weighing in at 138 characters):

public static int[] Mookid8000_Add(int[] a,int[] b){
   var r="";
   for(int n=a.Length,m=b.Length,s,c=0;n+m+c>0;c=s/10)
      r=(s=(n>0?a[--n]:0)+(m>0?b[--m]:0)+c)%10+r;
   return r.Select(t=>t-48).ToArray();
}

Asger‘s and Lars‘ contribution looks like this (135 characters):

public static int[] AsgerHallasOgLarsUdengaard_Add(int[] a,int[] b){
   var r="";
   for(int c=0,x=a.Length,y=b.Length;x+y>0|c>9;)
      r=(c=(x>0?a[--x]:0)+(y>0?b[--y]:0)+c/10)%10+r;
   return r.Select(s=>s-48).ToArray();
}

And the winners’ (Mads and Peter Sandberg Brun) contribution looks like this (weighing in at an incredibly compact, but almost unreadable, 132 characters :) ):

public static int[] MadsOgPeterSandbergBrun_Add(int[] a,int[] b){  
   var c="";  
   for(int o=a.Length,p=b.Length,s=0;-o-p<(s=s/10+(0<o?a[--o]:0)+(0<p?b[--p]:0));)  
      c=s%10+c;  
   return c.Select(i=>i-48).ToArray();  
}

I usually don’t compete in competitions like this, because I’ve always thought of myself as pretty lame when it comes to solving coding puzzles, but this time it was great fun – especially since I was pretty motivated by my desire to beat Asger (my little sister’s boyfriend), who pushed me several iterations further than I would have gone on my own. He ended up beating me though, but I am still pretty satisfied with my fairly compact and almost readable solution.

Fun with NoRM 4

July 26th, 2010 by mookid

This time, a short post on how to model inheritance, which (at least in a class-oriented programming language) is one of the foundations of object-oriented programming.

Let’s take an example with a person, who has a home address that can be either domestic or foreign. Consider this:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
 
    public Address HomeAddress { get; set; }
}
 
public abstract class Address
{
    public abstract string FormatAddress(string separator);
}
 
public class DomesticAddress : Address
{
    public string Street { get; set; }
    public string Number { get; set; }
    public string PostalCode { get; set; }
    public string City { get; set; }
    // and 17 other fields here, according to whatever is standard in your country
 
    public override string FormatAddress(string separator)
    {
        return string.Join(separator, new[] { Street + " " + Number, PostalCode + " " + City });
    }
}
 
public class ForeignAddress : Adress
{
    public string[] AddressLines { get; set; }
 
    public override string FormatAddress(string separator)
    {
        return string.Join(separator, AddressLines);
    }
}

Now, when I create a Person with a DomesticAddress and save it to my local Mongo, it looks like this:

var people = mongo.GetCollection<Person>();
people.Insert(new Person
{ 
    FirstName = "Mogens Heller", 
    LastName = "Grabe",
    HomeAddress = new DomesticAddress 
    { 
        Street = "Torsmark", 
        Number = "4", 
        // etc
    }
});

which is all fine and dandy – and in the db:

> db.Person.findOne();
{
    "FirstName": "Mogens Heller",
    "LastName": "Grabe",
    "HomeAddress": {
        "Street": "Torsmark",
        "Number": "4",
        // etc...
    }
}

which looks pretty good as well. BUT when I try to load the person again by doing this:

var people = mongo.GetCollection<Person>();
var me = people.FindOne();

I get BOOM!!: Norm.MongoException: Could not find the type to instantiate in the document, and Address is an interface or abstract type. Add a MongoDiscriminatedAttribute to the type or base type, or try to work with a concrete type next time.

Why of course! JSON (hence BSON) only specifies objects – even though we consider them to be logical instances of some class, they’ re actually not! – they’re just objects!

So, we need to help NoRM a little bit. Actually the exception message says it all: Add a MongoDiscriminatedAttribute to the abstract base class, like so:

[MongoDiscriminated]
public abstract class Address
{
    public abstract string FormatAddress(string separator);
}

That was easy. Now, if I do a db.People.drop(), followed by my people.Insert(...)-code from before, I get this in the db:

> db.Person.findOne();
{
    "FirstName": "Mogens Heller",
    "LastName": "Grabe",
    "HomeAddress": {
        "__type": "MongoTest.DomesticAddress, MongoTest",
        "Street": "Torsmark",
        "Number": "4",
        // etc...
    }
}

See the __type field that NoRM added to the object? As you can see, it contains the assembly-qualified name of the concrete type that resulted in that particular object, allowing NoRM to deserialize properly when loading from the db.

Now, this actually makes working with inheritance hierarchies and specialization pretty easy – just add [MongoDiscriminated] to a base class, resulting in concrete type information being saved along with objects of any derived type.

Only thing that would be better is if NoRM would issue a warning or an exception when saving something that could not be properly deserialized – this way, one would not easily get away with saving stuff that could not (easily) be retrieved again.

« Previous Entries Next Entries »