Limegarden.net Personal site of Wouter Lindenhof

2Mar/100

[DONE] Taking my time updating the website

Updating the site will take some time as I need to convert small parts of multiple posts to get it look correct. If you are using an RSS feed to keep track of the website, I'm sorry for any inconvenience it might cause.

If you find something missing or if your own links to my site, please send me a mail (or comment on this item) and I will try to fix it as soon as I can.

The good news is that wordpress is faster and easier to use than what I had before. The downside however is that all links need to be updated and some downloads won't be directly available until later.

UPDATE 2010-03-03 21:49: A quarter has now been done. It's going slower than expected as I need to correct quite a few pages and some of the links have changed so much that I lose at least a good 15 minutes to try and fix all of those. The good news is that I like wordpress, the interface is easy, although I miss the mugshot that I had on my old site ;)

UPDATE 2010-03-06 12:47: Most of the important post have been transfered and I have decided to skip the rest. From this point on no new "old posts" will be added unless I notice that someone is going to an old link. If you do need a certain article you can use the contact form to send me a notice.

Tagged as: No Comments
25Jan/100

Procedural story

story_03

A little while ago I was meeting a good friend of mine and we had a lot of things to talk about. For one he had just returned from Kenya and he had a lot to show and tell and the things he told me where amazing. But as the day went one, we almost always seem to come back to one subject: Games and developing of games. Funny enough the two of us have almost had the same kind of ideas.
Both of us are developing games in our free time and both have the idea of trying to make as much as possible procedural generated. One of the things we are both interested in is creating the story. While I look for an infinite solution (where the player can play forever and has an interesting storyline) he has a more pragmatic approach.
As we discussed procedural generated stories he pointed out that a story teller needs to tell his audience what happens where and when (not to be confused with why). This triggered a thinking path I had not yet explored. Until then I had simply assumed events happen in a certain order. When a user is playing a computer game he will grow a certain emotional attachment to the player. Emotions in a story are important. For example Romeo and Juliet is a story about hate between families, love between two person and has a lot of betray. Romeo and Juliet is considered one of the classic romantic stories and by some it is considered one of the most romantic stories ever written.
So after the talk and some thinking a procedural story generator could be written as a system that tries to move from emotion to another emotion both for individuals as a culture. To give yet another example: The player gets betrayed by a general and while he was betrayed the general does end the war (and the country he fought for sees him as a hero), while at the other side (the defeating side) wants to see the general death. You now have four elements: The player, the general, the winning country and the losing country. The player is angry as he is betrayed. The general is content and pleased as he is being seen as hero. The winning country feels superior to the losing country and the losing country feels disgust towards all other elements. See the diagram.

At this point the computer needs to "write" the next part of the story. The computer could now plot a new scheme by just adding or removing some story elements. The player could for example become the leader of the rebellion or he could join the general as one of his right-hand leaving his feelings of betray or he could kill the general and become the new general. In this case I want to add another character say the princess of the winning country and make the player the leader of the rebellion. The princess finds out that the generals betray and for some reasons she encounters the player and they fall in love with each other. Yet they can't be with each other as one country hates the other ruler. The general at this point hates the player. The graph might be clearer.

Moving forward we arrive at a point in the story where the player and the princess are married and they rule both countries. The general is now hated by all. And here is another graph.

For the story generator the only thing is how the possible futures of all elements could be. Once he knows the possible futures all it has to do is create "story chapters" which move the story toward the possible features. If needed a chapter could have a branch which excludes one of the possible features, for example the player kills the general before the princess was able to find out about the betray of the player so she never finds out the wrong he did and therefore never encounters the player.
Of course a lot more thought needs to go in this, but it solved for the procedural "writers-block".

4Jan/100

Gamer or developer?

Over the last few weeks I have constantly wondering one thing. Am I gamer or a developer? Today I have decided to find an answer.

My first encounter with games
Many years ago, when I was still a child I played a lot outside. I loved playing outside as I would climb trees, played hide & seek and got in to all kinds of petty fights. Your average kid. At a sunny day I went with a friend to her home and she showed something that would change my world. For the first time I played a game on a video console, I never remembered the name but for this entry I have looked it up. It was “Super Mario Bros. 2”. I looked at it and was stunned, she was not good at it and I refused to play as I was more interested in looking at it then actually playing. The only things I remember was the player select and the first level. I think I have only seen the game played once more after that until we got kicked out because it was such nice weather outside. I remember thinking it was such a stupid argument. But summer started and they went on vacation and just before they got back we left, then school started.

Becoming a gamer
But from that moment I was interested in computer games and I started nagging about it that some kids have a game console and we don’t. I threw the entire “it’s not fair” argument but my parents decided against it. Until 5 December and it was Saint Nicholas’ eve (he is something like Santa). To our surprise the good Saint had given me and my brother our very first game console. A Sega Mega Drive II and the game that was with it was a US version of Street Fighter 2. Now candy was competing with games for my allowance. Years later I was in a local shop and saw a game magazine, I didn’t know they existed (I dislike shopping, it takes so much time) and on the cover was an image of a young child holding a sword in front of a pedestal while blue energy was around him. It took me a few days, but then I decided to spend my money on that magazine. The kid on the cover was Link from the Zelda: The Ocarina of Time and it was about the Japanese preview. I remember that they showed a boss that was not in the actual release (although I think it was later modified and included in Majora’s Mask). We sold our Mega Drive and bought an Nintendo 64 with Lylat Wars (Star Fox 64).

Deciding my future
When I entered high school I told my parents I wanted to work in the video game industry and they shook their heads but later on changed that in “we shall see”.
So that is my history where I became a gamer. But now starts my history in becoming a developer. I sucked at a lot of high school subjects, but I had a lot of trouble fitting in and failed first year. I remember the huge contradiction on what level I should start. The previous school said I should started at the second lowest level, while an national independent organization said I should start at the second highest. As I struggled through high school there were a lot of strange events. In my first year I failed France but when I retook that year I was the only one as far as they can remember who had 10 on his pre-midterm report. Normally the range was between a 3 and an 8 but since I had done everything perfect they decided to give me a ten. I struggled through high school with a lot of help from my parents and teachers.Since there was no game education I decided to do IT. On the ICT course I made a lot of friends and had a lot of fun and me and a friend where “the best programmers”. I was surprised to see how little effort it took me to program.

Am I gamer or am I a developer?
Now I’m a student of the International Game Architecture and Design (IGAD) program. I’m having an internship at Codeglue, Rotterdam. And the internship has made some things really clear for me. I don’t think I’m a gamer in the same sense as others are at the IGAD course or at my internship. I like to play games from time to time and in my drawer I have two complete game design and an half dozen ideas that still need work.
But when I’m working I don’t think like a gamer especially when it’s programming that needs to be done. Oh yes, I know I’m working on a game, but a game is nothing more than an illusion. And because I know that I realize that I’m not a gamer but an illusionist. I let people thinkthat they are saving the world. I know that the a kid dressed in green is nothing more than a lot of different colored triangles. And it’s my job to uphold such illusions in new games. Because of the above conclusion, I should not be a gamer. A true illusionist is not bedazzled with his own illusions or those from others. And although as a programmer you don’t always design the tricks, you make certain that they work. You create parts of the machine, you help artists apply the paint and you listen and tell what is and what is not impossible to those who designed the illusion. Once the work is done and the illusion is complete you demonstrate it to the public and watch them enjoy (and pay) for something that is nothing more than a good illusion. So the only conclusion is that I’m a developer. I look in despair at near broken machines and I enjoy myself immensely when I see a proper created machine. I love to create superior machines that support the illusion and are often capable of much more than the one who designed it wants it to.

I’m not just a developer. I’m a developer who loves my job. I’m a developer who loves to see his creations being the cause of entertainment of thousands. 

Final words
I know this has been a long rant but it has been something I want to get off my chest for a long time. Personally I find the game industry as it’s now young and naïve. It believes a little too much in its own illusion. But the cold hard truth is that in the end you are creating an illusion. Some people use poor quality machine parts, don’t give every detail or the painting thought or think that once a simple design is done you can work as it goes. Some companies require that the staff to go in crunch mode extended periods of consecutive overtime) with all it’s faults.
From a business perspective I think it should look and learn more from a young but more mature market, the IT sector. But at the ICT course I had one teacher who I understood after I started on the IGAD course. He said: “Always take in account the three P’s: Product, Project and process”. And many game developers are ignorant of the last one. The process is that what breaks or makes your illusion better than the rest.

Filed under: Uncategorized No Comments
4Jan/100

Finishing my school project

This is an old post from my previous blog which might show up again in your feed

As some know I have talked a lot about procedural generation and since last summer one of my ideas has been accepted. And now two months later I have finished my research paper.

I never really liked research papers, in many cases there is too much data to work through and in generally I’m only interested in the solution. However when you have to write your very  own research paper of 3000 words your glad to have much data except when it reaches 4500 words then it becomes a pain since you have to spell-check and grammar-check those extra 1500 words. And then to think that I’m still not glad with some explanations and think some part of the document needs to be improved. Currently I’m guessing it’s going to be around the 5250 words. 

The cool thing is that I’m going to make the research paper freely available for everyone. I have been pleasantly surprised that some people have used the feedback form to either respond or ask me a question. Some of the feedback was really nice and has been a great help to me. Those people have my thanks. As for releasing the paper it will most likely be next week. 

Filed under: Uncategorized No Comments
4Jan/100

Writing using Latex

Writing is something I always enjoyed, but there were always obstacles that I had to work around. In the past I always had to deliver documents but this became more and more troublesome as there was a difference between Microsoft Word and Word Perfect and these days I sometimes encounter someone who has MS Word 2003, which is really outdated by now.

I have made it a habit to present my documents in PDF format. I have never been a fan of PDF until I noticed that nobody complained about it (which often happened with Doc(x)-files). However word documents are hardly flexible and often enough I’m more busy with formatting than I’m busy writing. Also as a programmer I noticed that I can rarely write comments in the document and when working with others I have to explain the “Keep track of changes” function that is in Word.

For my research paper I started writing in Word but at certain point I got so fed up because I had to print the document, write comments as I read it and then go back to my computer to act on my own remarks. At the same time it was no longer possible to have the document being split in multiple files, something I do when I’m programming. Instead I look through the entire document, finding the correct section and then correct it.

As you can understand this is quite time consuming and I’m quite certain it could be done better. I had heard of LaTeX before but it seems complicated and more for *NIX systems than for windows. But I finally decided to see how it can be done and installed both MikTex and TeXnicCenter, which are awesome pieces of software. While at the same time I started reading up on LaTeX. And after using it for a week I must say I wish I had discovered it earlier.

LaTeX was made for programmers who often need to write documentation. It can be compared to programming and it often feels like that. It was not hard as I thought it would be and by now I prefer it to working in word. I don’t have to worry about formatting, it converts to a PDF, I can split my documents over various source files, write comments and with a little bit of work using the viewers (you can export to DVI or PDF) I can double click on a paragraph I think that needs to be changed and it brings me directly to the source code. The only thing that I really miss is the grammar checking (it does have a spell-checker) but that is not that important for me now.

One really cool thing is that I don’t have to worry about the formatting of images. I just include them like \includegraphics{myImageFile} and when I compile it gives me a warning that the file does not exist. Normally I was always busy creating images while I wanted to be writing and fixing the images until they matched the format of the rest of the document but that all seems to be in the past.

However there are a few things that I wished were different. For one exporting it to a different format is hard, which means that if someone wants to give feedback by highlighting the text and then write some comments they have to extract it since they don’t have access to the source files or have the knowledge to work with it. The exported text however uses hard returns every time it needs to wrap the text. But I think I can fix that by compiling it to html. And of course it takes some time to get used to writing LaTeX. So far I’m quite positive about LaTeX and I hope that it stays that way.

Filed under: Uncategorized No Comments
18May/090

Independence

This is an old post from my previous blog, which might show up in the feed again

 I don't care much for a country. If the netherlands was attacked by an enemy and I got a call in which they say I'm drafted, everyone in the netherlands is excused when they become 18 (but this might change at anytime), I would pick up my bags and flee. I don't mind fighting for things I'm proud of, but I'm not the least bit proud of the netherlands (goverment) so I won't fight for it. Just so you know I'm proud of our men at arms, where ever they might be, whatever they might be doing. They often have to do what cowardly people require them to do (invasion in Irak was pressed by the goverement).

Anyway at diner I thought wouldn't it be cool to create an independent country. Let's say we buy everything there is on a small island (so we own the island and everything on it) and then declare independence. The next morning the army arrives to supress the freedom fighters (aka you, who owns the entire island, is the only inhabitant and freedom fighter).

Personally I want to do something like that as I want to create an utopia. It will have to start out small and then it will slowly need to grow. All people allowed to enter in the first 25 years should be hard working to make certain progress continues and afterwards the entry rules might become more lenient, to ensure quality. In the end you can be anything you want, you don't need to work, free health care and so on.

The only question that I have is how long it will take after creating this "utopia" for it to fall.

Filed under: Uncategorized No Comments
17May/090

Challenge: Procedural generated space ship #2

 It has been a month since I last talked about Procedural generated spaceships. I haven't had much time to work on because of my internship and other work however the progress that I have made has shown this might be a bigger challenge then I had hoped it would be. 

The general idea is that you first create the bones (like a stick figure but then from a space ship), then you create the flesh or hull of the ship and then you will start adding rooms, corridors and all kind of objects so that you can walk through it as if it were a spaceship. However I found two things that I find in dire need of my attention.

The first thing is that you need detail. Even though a starship can have the shape of a cube (borg cube) it will never look like a cube if you get up close. The second thing is that I have not yet found a strategy (a way of approaching the problem) that can guarantee proper use of space. For example how can I be certain that chamber doesn't go outside the spaceship?

Personally I think I need to do some more drawing, thinking like an artist before I can give an answer to questions like those. After I have answer to both question it will only be a case of setting up the implementation and be done with it.

Filed under: Uncategorized No Comments
27Mar/090

Acyclic Visitor

Thanks to Jasper Bekkers, a good friend of mine, the design pattern described in "Possible connector design pattern in c++?" finally has a name. It is actually an Acyclic Visitor combined with an Observer Pattern. The reason why I didn't know of this pattern is because (again, thanks to Jasper for explaining) this pattern was not in the book of GoF and partly because of that it is not wide-spread. I only own two books on design pattern (actually one, since I lent the otherone to another friend) and neither of them described the Acyclic Visitor.

On the website of c2.com there is also a nice link to a pdf in which the original acyclic visitor pattern is designed including code samples. They use dynamic_cast though, while I use typeid. The downside of dynamic_cast is that the cast is not constant while typeid is  constant. I do expect however that using typeid is generally slower (especially since i perform a string comparison) but dynamic_cast did not feel natural for me. In retrospect it is rather easy to use dynamic_cast once you accept that once it returns a NULL pointer the casting was incorrect.

Filed under: Uncategorized No Comments
23Mar/090

Possible connector design pattern in c++?

Recently I was working on an AI assignment and I needed a method to pass around notification which would cause the receiving objects to act upon it. Problem however was that none of the objects knew each other. I had many AI modules which were all split up (for example driving to a destination would exist out of destination chooser, path-finding algorithm, obstruction evader , driver mechanism, etc) and not all of them needed to concern themselves with notifications (a notification would be “change destination”) and often they only cared about a single notification.

As long as the AI stays simple, you are good with a few notification (in fact I think I only needed two) but as I was writing it I noticed that adding another notification would require changing 4 different classes. If I would heavily rely on my notification passing system I would have been in big trouble. 
There are a few ways to make the system simpler and the first one would be that there was only one notification which hold all possible data a notification could have and an ID which would help figure out what the type of message it was. The downside of this method I would need to check the ID and then act upon it. This was something I did not like.

Another method would be to have all AI components derive from a base class which had all the receiving notification messages ( OnChangeTarget(int targetID); ). This was the method I choose in the end (as I started to get me more and more off track while I should be working on the assignment) and since I need only two functions (remember, two messages) it wasn’t that hard . However I promised myself that after delivering the assignment I would find a way to improve this.

And this morning while I was walking the dog something suddenly hit me. Since neither type can recognize the other one (they both start as abstract classes) I need to find a way to connect the types. I had thought of this option before, but since the connecting method would need to be able to handle abstract types it should be abstract as well.

Since I'm assume this has become quite confusing so far I will post the code that demonstrate what I want to do.


//////////////////////////////////////////////////////////////////////////
// Two different notifications
struct HelloNote : public INotification {};
struct WorldNote : public INotification {};

// The receivers
// ...
// 

int main ()
{
	INotification* Note1 = new HelloNote();
	INotification* Note2 = new WorldNote();

	INotification* AllNotes[2] = {Note1, Note2};

	IReceiver* HelloRCV = new HelloReceiver();
	IReceiver* WorldRCV = new WorldReceiver();
	IReceiver* HelWoRCV = new HelloWorldReceiver();

	IReceiver* AllReceivers[3] = {HelloRCV, WorldRCV, HelWoRCV};

	for(int i = 0; i < 2; i++)
	{
		for(int j = 0; j < 3; j++)
		{
			AllReceivers[j]->InitialReceive(AllNotes[i]);
		}
	}

	// Removing all types types
	delete Note1;
	delete Note2;

	delete HelloRCV;
	delete WorldRCV;
	delete HelWoRCV;

	return 0;
}

As you noticed there is no coded type identification within the message (in fact except their names they are identical) and because the receivers are downcasted as well you can no longer see which type should recieve what kind of message. However after we run the final version of the exact same code (I promise I won’t change main at all) the classes will recieve the correct messages.

I’m not certain if the following method is an existing design pattern (believe me, I looked for it). But it is similar to the mediator pattern, but were the mediator pattern acts between two different set of variables, I'm acting between two different types. The solution I provide mediates based on type and not on instance. For now I think the description of an "abstract connector" would be better, but since I'm not 100% certain I will leave it at "possible".

Although I Intended to explain it I decided against it, since the code looks simple (as it is in fact), but it will be faster to experience and then explain it than the otherway around.


#include <iostream>
#include <typeinfo>  //for 'typeid' to work
#include <list>

//-------------------------------------------------------------------------------------
// Library code
// You can copy this straight in your code and it will never have a need for
// modification.
//-------------------------------------------------------------------------------------
struct INotification{
	virtual ~INotification(){};
};

class IReceiver;

struct BaseConnector
{
public:
	virtual void Connect(IReceiver* aRCV, INotification* aNote) = 0;
};

struct Translator
{
	const char*		m_Type;
	BaseConnector*	m_Interupter;
	Translator(const char* type, BaseConnector* inter) :
	m_Type(type), m_Interupter(inter)
	{}
};

typedef std::list<Translator> TranslationList;
class IReceiver
{
protected:
	TranslationList	m_Translators;
public:
	void InitialReceive(INotification* aNote) {
		TranslationList::iterator begin = m_Translators.begin();
		while(begin!=m_Translators.end())
		{
			if(strcmp((*begin).m_Type,(typeid(*aNote).raw_name())) == 0)
			{
				(*begin).m_Interupter->Connect(this, aNote);
			}
			begin++;
		}
	}
	void Receive(INotification* aNote) { std::cout << "Unhandled\n"; }
};

template <typename R, typename N>
struct TConnector : public BaseConnector
{
public:
	void Connect(IReceiver* aRCV, INotification* aNote)
	{
			((R*)aRCV)->Receive((N*)(aNote));
	}
};

template <typename R, typename N>
struct CTranslator : public Translator
{
	CTranslator() : Translator(typeid(N).raw_name(), new TConnector<R, N>) {}
};
//-------------------------------------------------------------------------------------
// User code
// This is what you will be writing.
//-------------------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////
// Two different notifications
struct HelloNote : public INotification {};
struct WorldNote : public INotification {};

//////////////////////////////////////////////////////////////////////////
// Our Hello Reciever, only accepts HelloNotes
class HelloReceiver : public IReceiver
{
public:
	HelloReceiver()
	{
		m_Translators.push_back(CTranslator<HelloReceiver, HelloNote>() );
	}

	void Receive(HelloNote* aHello) {
		std::cout << " " << __FUNCTION__ << "(HelloNote* aHello)\n";
	}
};

//////////////////////////////////////////////////////////////////////////
// Our world Reciever, only accepts WorldNotes
class WorldReceiver : public IReceiver
{
public:
	WorldReceiver()
	{
		m_Translators.push_back(CTranslator<WorldReceiver, WorldNote>() );
	}

	void Receive(WorldNote* aWorld) {
		std::cout << " " << __FUNCTION__ << "(WorldNote* aWorld)\n"
	}
};

//////////////////////////////////////////////////////////////////////////
// Our HelloWorld Reciever, accepts both messages
class HelloWorldReceiver : public IReceiver
{
public:
	HelloWorldReceiver()
	{
		m_Translators.push_back( CTranslator<HelloWorldReceiver, WorldNote>() );
		m_Translators.push_back( CTranslator<HelloWorldReceiver, HelloNote>() );
	}

	void Receive(WorldNote* aWorld) {
		std::cout << " " << __FUNCTION__ << "(WorldNote* aWorld)\n";
	}
	void Receive(HelloNote* aHello) {
		std::cout << " " << __FUNCTION__ << "(HelloNote* aHello)\n";
	}
};

int main ()
{
	INotification* Note1 = new HelloNote();
	INotification* Note2 = new WorldNote();

	INotification* AllNotes[2] = {Note1, Note2};

	IReceiver* HelloRCV = new HelloReceiver();
	IReceiver* WorldRCV = new WorldReceiver();
	IReceiver* HelWoRCV = new HelloWorldReceiver();

	IReceiver* AllReceivers[3] = {HelloRCV, WorldRCV, HelWoRCV};

	for(int i = 0; i < 2; i++)
	{
		for(int j = 0; j < 3; j++)
		{
			AllReceivers[j]->InitialReceive(AllNotes[i]);
		}
	}

	// Removing all types types
	delete Note1;
	delete Note2;

	delete HelloRCV;
	delete WorldRCV;
	delete HelWoRCV;

	return 0;
}<

If you would look at TConnector you will notice that the virtual function (connect) has an implementation which based on the design casts the receiver and the notification to the correct type.

If now you would look at IReceiver you will see that the InitialRecieve function uses typeid to recover the type information and checks it against an internal list to see if we have a connection for it. Since by dereferencing we will find out the original type we will work with a known type.

Now look at the receiver classes. You see that in each receiver class we need to store a connection. We have to define a connection and the corresponding function. If the connection is missing the data will not be send to their respective receive function. If the function is missing you will get an error.

There are also many things that could still be done to improve it

Also attached to the article you will find the entire solution inside a zip file: PatternDesign Connector (4kb, source)

Filed under: Uncategorized No Comments
11Mar/090

Lime engine update

Today I worked on and finished texture support. So far everything has been quite simple and straight forward as most features are shared by both DirectX and OpenGL. My first primary goal, trying to keep the majority of the core components completely platform independent has been achieved. For example, textures are API independent, only until they enter the graphics system they will be transformed to a DirectX or OpenGL specific format. Of course there were some times where I really hated this goal of mine, because DirectX uses textures as in ARGB while OpenGL wants it in ABGR (compared to DirectX). This means that OpenGL will have a drastic performance impact and I know this can easily be solved by flipping it once before sending it to the engine, or let the engine create and store another texture for internal use.

However, the LimeEngine is just a baby and I knew that this part would be easy and yes the above problem is what I call easy. The next part is going to be hard since it is almost impossible to stay platform or API independent. The problem is called shaders.

There are three popular shading languages. DirectX HLSL, Nvidia CG and OpenGL GLSL. The problem is that although the languages look identical they are not the same. Sometimes the variable naming is different. Further HLSL can only be used with DirectX and GLSL can only be used by OpenGL. CG is an odd one in that category as it has an implementation for both API's. However that requires an additional library and to be honest I prefer HLSL as the documentation is better than that of CG. GLSL is completely new to me and it requires an extension. An alternative could be that I write my own shader language, but doing so would most likely mean that other developers would hang me, burn me and forbid me to ever touch a computer again.

However the problem won't be with the coding but the use of the engine. Everyone using my engine should be aware that the engine is not intended as API independent, since it never is. You can learn a cat to bark, but it will never be a dog. Working with my engine will bring you as close as possible to the API without actually having to work with it and in fact this has always been my intention. This line is paper-thin and you might be better off seeing the LimeEngine as huge library filled with helper functions than a separate API.

But the next part is going to be hard as Shaders languages are all unique and I still want to abstract it until it is being used by the graphics engine.
There is one thing that the engine doesn't have which I'm not certain of if I want to add it. Since the engine is focused on shader there is no real need to add TL (Transform & Lighting) as these transformations are done by the vertex shader while the lighting is done by the pixel shader.

After that the engine will hit it's very first milestone as it will have all the features I have set out to add. And with a bit of luck I will meet the requirements of that milestone tomorrow. Actually there is the fact that I have to correct the documentation and oh... the fact that there are many small bugs I have to hunt and I bet a lot not so fun things that require my attention but let's not spoil the fun, shall we?

Filed under: Uncategorized No Comments