first steps with Claus Dręby's unit++



0. Intro

why am i writing this?

basically, when i thought i should start learning c++, i found there was so much new stuff to learn. i had learned my programming with turbo pascal in a dos environment and then missed a few steps of the development. so now i find myself in a flurry of buzzwords and i don't know where the handle is that will let me shake all this into place.
writing this text helps me keep track of what i'm learning. if you are in a similar situation, then my hope is you can profit from these notes. they reflect the help that i have received from kind people, notably Claus who is a complete gem.
you should be prepared to spend some time with this. it is a keystroke-by-keystroke walk. you should really follow those keystrokes one by one. so please read slowly even you find my prose rather verbose.

do not expect any immediate progress in your current programming exercise. maybe you should think of this as some guided time spent in a car simulator, before your first driving lesson.

you may safely assume that every mistake mentioned hereinafter (ah, lawyers!!) is one that i made myself. i am certainly not god's gift to the programmer's guild, and it shows.
but then, i believe we all learn from mistakes, so i try to make plenty and then play intelligent by not repeating them. the master level in this game is attained when you learn from other people's mistakes.
the implication is that mistakes need to be shared...

where to start ?

this text assumes that

all examples i will give are based on the following:

simply because this is the case on my system as i write.

what is going to happen ?

i will take you through two very elementary steps.

step 1: a very trivial first encounter

this serves the purpose of seeing the mechanics of unit++ without bothering about any actual program you may wish to test later. the focus is really on getting to know the tool that is now new in your box.

step 2: applying the lessons of step 1 in some toy project.

the hope is that after these two, you will beginn to see how stuff interacts, when to look in the html documentation and what to find there, etc.
ready? let's go.

1. step 1: trying the new toy

just do it...

we start in the environment that i have outlined above. the first step tries to keep things really simple by changing one thing at a time only. this changed thing is the unit++ library. thus, i don't want any real application code for this. here is how.
  1. edit a new file to contain the following text. do not copy / paste this, for it contains html tags that may cause havoc with your compiler. also, do not type the line numbers.
       1 #include <unit++.h>
       2 #include <string>
       3 using namespace std;
       4 using namespace unitpp;
       5 namespace {
       6    class YourTest : public suite
       7            {
       8            void testEmptyString() {
       9            string joe;
      10            assert_eq("length check", (unsigned int) 0, joe.length() );  // parameter order: text, expected, actual
      11            assert_eq("content check", "", joe);
      12            }
      13    public:
      14            YourTest() : suite("YourFirstTest")
      15            {
      16            add("EmptyString", testcase(this, "TestEmptyString", &YourTest::testEmptyString));
      17            suite::main().add("YourTestSuite", this);
      18            }
      19    };
      20  * theTest = new YourTest();
      21 }
            
  2. save this file as mytest.cpp or find it in a directory nearby
  3. compile/build as follows: g++ -o mytest mytest.cpp -lunit++ -Wall
  4. run the resulting executable: ./mytest
  5. observe the result. it should look like this:
    Tests [Ok-Fail-Error]: [1-0-0]
    if it doesn't, that just goes to show that bugs travel mysterious ways doesn't it? may i humbly suggest you check for typing errors...
  6. that's it.

what's happening here?

clearly, this is not my invention at all. it is merely an adjusted copy/paste from the file unitpp.html from the documentation of unit++. let's take it line by line and see what we can learn:
 1     tell the system you are planning to use the fruits of Claus's work
 2     why string? because i am going to write a test for the string class, which is simple enough even for my
       feeble understanding ( a misunderstanding on my part, no doubt )
 3, 4  namespaces are a c++ feature. unit++ has one of it's own. std is the namespace for pretty much anything
       you would expect to find in a c++ environment. without the using clause for std, i would have to write std::string
       instead of just string. it is a bit like using the same street name in different towns, i suppose...
 5     this opens a so called anonymous name space. all the names defined now are valid exactly here and nowhere
       else. so nobody has to be a genius about name inventing. YourTest might have been called Test and the line
       cast in iron for all future applications.
 6     the beginning of a class definition. it ends in line 19. the class inherits from suite.
       suite is in unit++, so here you start using...
 8-12: this is a test. it comes as a method in your class. it declares an object, namely the string called joe.
       it also performs two checks on joe. the function called is part of unit++, and you are using again.
       the type cast stops a warning (int and unsigned int compared)
 13    why the test above is not public i do not understand as yet....
 14-19 the constructor method for your class. pretty complicated as constructors go.
       YourTest() : suite("YourFirstTest")   based on the constructor for class suite, (no surprise)
 16    the method testEmptyString is "registered" as a test case. more precisely, since the class is a suite, it
       can have tests added to it. so, this line defines a test and adds it to the suite.
 17    now this suite that i define is added to the main test suite. i will revisit this in "lessons learned" below
 19    end of the class definition
 20    this declares a variable of type pointer-to-YourTest and initializes it with a new instance.
 21    end of the anonymous namespace.

lessons learned

not so bad for 20 lines, huh? this could become really useful if we learn to use it well.

open questions

some of these get addressed in the next step, some don't.

2. step 2: let's get ambitious

a toy project

i want some simple application that will allow me to try and use the test organisation features. i want to demonstrate the calling of methods in that application. i also want to demonstrate data access.
so lets try this:

now imagine you would buy this piece of software from some software house. how would you know that you get what you pay for? weeeelllllllll.............. ? So let's write the tests:

write a file cartest.cpp that contains these lines (not the numbers, no copy-paste, as above) you may find this in a directory #0 somewhere near this file
 1 #include <unit++.h>
 2 #include "car.h" //see lessons above: include your header file
 3 using namespace std;
 4 using namespace unitpp;
 5 namespace {
 6   class CarTestSuite : public suite
 7          {
 8          void testCarHasMaker() {
 9          Car myCar;
10          assert_eq("maker check", CRASH, myCar.getMaker() );
11          //this is a design decicion: default maker is CRASH motor co.
12          }
13          void testCarHasColor() {
14          Car myCar;
15          assert_eq("color check", BLUE, myCar.getColor() );
16          //another design decision: default color is blue
17          }
18          void testColorChange() {
19          Car myCar;
20          //we could do this
21          //assert_eq("colorchanged check", BLUE, myCar.getColor() );
22          myCar.setColor(GREEN);
23          assert_eq("colorchanged check", GREEN, myCar.getColor() );
24          }
25   public:
26          CarTestSuite() : suite("CarTestSuite")
27          {
28          add("CarHasMaker", testcase(this, "testCarHasMaker", &CarTestSuite::testCarHasMaker));
29          add("CarHasColor", testcase(this, "testCarHasColor", &CarTestSuite::testCarHasColor));
30          add("ColorChange", testcase(this, "testColorChange", &CarTestSuite::testColorChange));
31          suite::main().add("CarTestSuite", this);
32          }
33   };
34   CarTestSuite * theTest = new CarTestSuite();
34 }

prepare for a mild shock. are you sitting comfortably? good. then compile this.

WHAT??????????????

of course it won't work. we haven't written the Car.cpp yet, there is no Car.h. how could it work?
well this apparently is how "test first" works. you write the test first then check that they fail. this failure is the formal reason for writing any application code at all. and then you go on and write as little code as possible to make the tests work. if that code then doesn't make any sense, you know you need better tests.

g++ -o cartest cartest.cpp -lunit++ -Wall <enter> complains he cannot find this file Car to include from line 2. ok, give him an a car.h file. notice the compiler does not complain about the content of this file, so let's construct a file car.h with no content at all. then we compile again.
Ah, that's much better now: a list of complaints like so:
cartest.cpp: In method `void {anonymous}::CarTestSuite::testCarHasMaker()':
cartest.cpp:9: `Car' undeclared (first use this function)
cartest.cpp:9: (Each undeclared identifier is reported only once
cartest.cpp:9: for each function it appears in.)
cartest.cpp:9: parse error before `;'
cartest.cpp:10: `CRASH' undeclared (first use this function)
cartest.cpp:10: `myCar' undeclared (first use this function)
cartest.cpp: In method `void {anonymous}::CarTestSuite::testCarHasColor()':
cartest.cpp:14: parse error before `;'
cartest.cpp:15: `BLUE' undeclared (first use this function)
cartest.cpp: In method `void {anonymous}::CarTestSuite::testColorChange()':
cartest.cpp:19: parse error before `;'
cartest.cpp:22: `GREEN' undeclared (first use this function)

line 9: so Car is undeclared? alright, lets declare it, in car.h, which now looks like this:
1 class Car {};

cycle - still as bad as before. errors from line 10 down, like so:
cartest.cpp: In method `void {anonymous}::CarTestSuite::testCarHasMaker()':
cartest.cpp:10: `CRASH' undeclared (first use this function)
cartest.cpp:10: (Each undeclared identifier is reported only once
cartest.cpp:10: for each function it appears in.)
cartest.cpp:10: no matching function for call to `Car::getMaker ()'
cartest.cpp: In method `void {anonymous}::CarTestSuite::testCarHasColor()':
cartest.cpp:15: `BLUE' undeclared (first use this function)
cartest.cpp:15: no matching function for call to `Car::getColor ()'
cartest.cpp: In method `void {anonymous}::CarTestSuite::testColorChange()':
cartest.cpp:22: `GREEN' undeclared (first use this function)
cartest.cpp:23: no matching function for call to `Car::getColor ()'

it is actually true on my system that the complaint re line 23 is new. strange...
now this obviously indicates that we didn't implement those methods - which we knew already, by the way - and now we have a reason for implementing them: a production fails and it is all our fault!. can you see the managers jumping up and down and eating their ties? while foam is dripping from their mouths? however, because this is my text and the fancy just tickles me, i'll start with the BLUE, GREEN and CRASH. not being overly malicious, i change car.h till it looks like this:
 1 enum Color {
 2    RED,
 3    BLUE,
 4    GREEN
 5 };
 6 enum Maker {
 7    CRASH,
 8    BOOM,
 9    BANG
10 };
11 class Car {};

cycle and and all references to GREEN and BLUE have disappeared from the error list above, as well as that to CRASH. isn't it cute how we didn't even need the car.cpp file up to this point? here's what we have now:
cartest.cpp: In method `void {anonymous}::CarTestSuite::testCarHasMaker()':
cartest.cpp:10: no matching function for call to `Car::getMaker ()'
cartest.cpp: In method `void {anonymous}::CarTestSuite::testCarHasColor()':
cartest.cpp:15: no matching function for call to `Car::getColor ()'
cartest.cpp: In method `void {anonymous}::CarTestSuite::testColorChange()':
cartest.cpp:22: no matching function for call to `Car::setColor (Color)'
cartest.cpp:23: no matching function for call to `Car::getColor ()'

now i shall write signatures for those car methods in the header file, i.o.w. add this to car.h, and notice as i do so that line 11 needs a little change as well:
11 class Car {
12    Maker getMaker();
13    Color getColor();
14    void setColor(Color _color);
15 };

this earns us a new complaint: them methods are private. hard dame! well you know what to do, do it after the old line 11:
11 class Car {
12 public:
13    Maker getMaker();
14    Color getColor();
15    void setColor(Color _color);
16 };

And here is what i get for my trouble.
/tmp/ccj0bKbB.o: In function `{anonymous}::CarTestSuite::testColorChange(void)':
/tmp/ccj0bKbB.o(.{anonymous}::CarTestSuite::gnu.linkonce.t.testColorChange(void)               +0x15): undefined reference to `Car::setColor(Color)'
/tmp/ccj0bKbB.o(.{anonymous}::CarTestSuite::gnu.linkonce.t.testColorChange(void)               +0x40): undefined reference to `Car::getColor(void)'
collect2: ld returned 1 exit status

So is this what you call progress? Actually, yes. You may notice that in this mumble jumble there is no reference to the source file cartest.cpp any more. this is g++'s way of reminding me that i didnt actually implement those methods i have prototyped. mother dog won't let me get away with anything...

Remark: This might be the moment for a little experiment. stop working on this. take a walk. come back in 45 to 90 minutes. with any luck, you will have forgotten all about this. i humbly suggest that all you need to do to get back in (you do want back in, don't you?) is rerun the last step, which was a compile. (once we have testable code, it will be the test execution instead, but for now the old compiler is doing us plenty of favours, ain't that true.

alright then, time to stand up and be a cheat. we will never do more than absolutely necessary. right now, them linker alarms tell us we need to implement them methods. doesn't say we have to be very smart about it. make a car.cpp like so:
1 #include "car.h"
2 Maker getMaker() {
3 };
4 Color getColor() {
5 };
6 void setColor(Color _color){
7 };

ok, 3 methods that do precisely nothing. what do we get? hold on to your ...oops, same errors! what happened? let's think a minute. we edited the car.cpp file. then we compiled the cartest.cpp file, which doesn't know anything about car.cpp, since all it wants is car.h, which we left unchanged this time. where do we leave news that cartest really does need car.cpp? i didn't know this myself so i checked in a book and the answer i found is "in the makefile". what makefile? i stole one from another project and made some obvious changes to get this:
all: cartest

cartest: car.o cartest.o
	g++ -o cartest car.o cartest.o -lunit++


car.o:       car.cpp        car.h
cartest.o:   cartest.cpp car.h

in theory, this should mean the following:
a) to make all, build cartest.
b) to build cartest, do stuff with car.o and cartest.o
where doing stuff means to call g++ to link some .o files and mind them libs
c) to build car.o, play with car.cpp and car.h
and just know in deep & mysterious ways that play means compile up to the .o file generation
d) cartest.o depends on cartest.cpp
well,as i said, in theory. in practice this doesn't work and i am getting rather tired so i'll call it a day for now.
time passed....and i followed my own advice and had a beer. i think i have seen the light. i run make one more time (to get back in, as explained above) and get this:
       
g++    -c -o car.o car.cpp
g++    -c -o cartest.o cartest.cpp
g++ -o cartest car.o cartest.o -Wall -lunit++
cartest.o: In function `{anonymous}::CarTestSuite::testColorChange(void)':
cartest.o(.{anonymous}::CarTestSuite::gnu.linkonce.t.testColorChange(void)               +0x15): undefined reference to `Car::setColor(Color)'
cartest.o(.{anonymous}::CarTestSuite::gnu.linkonce.t.testColorChange(void)               +0x40): undefined reference to `Car::getColor(void)'
collect2: ld returned 1 exit status
make: *** [cartest] Fehler 1

machine cannot find the reference to my functions because...oh dear, oh dear i haven't forgotten my syntax again have i? i have. how do you tell a method that it belongs to one class and not another? you prefix it with the class name and those ::. did i do this in car.cpp? no. who is an idiot? i am. if this were available as recorded music, would you buy it?
so i fix this and compile and - horror of horrors - i get a full execution, even with my grandiose makefile
the moment of truth then: will it execute? type ./cartest and strike ENTER and...

(...drumrolls...)

FAIL: testCarHasMaker
maker check [expected: `0' got: `-1073745573']
FAIL: testCarHasColor
color check [expected: `1' got: `-1073745573']
FAIL: testColorChange
colorchanged check [expected: `2' got: `-1073745573']
Tests [Ok-Fail-Error]: [0-3-0]

YES! failed tests. great!!!

just what we wanted at this point, remember? to commemorate this event, i have put cartest.cpp, car.h, car.cpp and makefile in their current state in a directory #1 somewhere around here
note: in a previous version of this text i did had coded a mistake in my assert_eq-calls, mixing up parameters 2 and 3. the result was that in the test log the values for "expected" and "got" were the wrong way round. i failed to pay attention to this, but fortunately Claus spotted it right away. i checked his remark by looking at assert_eq.html and found confirmation (what else?!?). well here is one example how the docu can help if you chose to read it. which i herewith recommend ;-)

so now we can go about fixing these bugs until the tests pass. take them in order. what's the cheapest way to satisfy the getMaker check? let this method return CRASH. cheap? sure, i said so, didn't i? run make then test. 1 ok 2 fail 0 error. good.
same thing for the getColor method gives 2ok 1 fail. we'r winning, friends....
well this is intersting now. we are supposed to set something that isn't even there. my silly little car class has no data. change this in car.h.

break
do not add the "maker" piece of info there just yet. it belongs there for sure, you know it, i know it, but we havent yet written a test for this thing, and this is just what unit testing is supposed to be good for. so, just the color field. and nothing else. now cycle. the setColor test still fails. and that is great. effectively this is what now forces me to beef up that cheap getColor routine.

ok, fix getColor now and cycle....actually, maybe not. i don't want this to get too silly after all. too late, you say? my apologies... there is a number of things wrong here and if even i can see that then it must be obvious. so what we do now is this:
1) introduce the color field in car.h (done)
2) adjust the get method to return this.
3) adjust the setColor method to write that field.

4) remember that we have not written any constructors for our car. this means it enters the world without a maker and a color. will that show in the tests? let's code 1 through 3 and try what that does before we write code to clear up this item 4. in other words there is now in car.h

* a new line 13 private:
  a new line 14 Color color;
and in car.cpp we have
#include "car.h"
Maker Car::getMaker() {
  return CRASH;
};
Color Car::getColor() {
  return color;
};
void Car::setColor(Color _color){
  color = _color;
};
time to cycle. i got this remarkable result:
FAIL: testCarHasColor
color check [expected: `1' got: `-947200']
Speicherzugriffsfehler

Speicherzugriffsfehler = memory access error for the not so teutonic

is this a surprise? well, the testCarHasColor method has failed. that's the second of my tests, which worked a minute ago. i clearly destroyed something. namely the unconditional return of BLUE in that get method. the answer of course is the missing constructor: the init-car has no color, iow some rubbish is in that piece of memory allocated for color. and i was lucky that the rubbish didnt accidentally match with one of my Color values defined in car.h.

remark : i am not really happy with this. the accidental element says i don't really have a good test for "does the constructor do its job right?". this may be trivial in car.h, but imagine that problem in a real world project, with 20 varieties of overload and whatnot...there ought to be a technique for checking this sort of thing....can't think of one right now, though.

so i shall write a constructor and init my car as promised in that 4 line spec way above. i also stop playing blind and introduce the maker field with a reasonable get method - nothing in any unit test literature told me to not apply common sense when i see a chance. my code bits now look line this (you may find hem in subdir #2 for reference):

car.h:

enum Color {
   RED,
   BLUE,
   GREEN
};
enum Maker {
   CRASH,
   BOOM,
   BANG
};
class Car {
private:
  Maker maker;
  Color color;
public:
   Car();
   Maker getMaker();
   Color getColor();
   void setColor(Color _color);
};

car.cpp:

#include "car.h"

Car::Car() {
  maker = CRASH;
  color = BLUE;
}

Maker Car::getMaker() {
  return maker;
};
Color Car::getColor() {
  return color;
};
void Car::setColor(Color _color){
  color = _color;
};

i cycle, and i get 3 OK test cases, no fails, no errors, no memory access errors. back to work, then. i have 3 tests and all pass. time to invent some new functionality.i haven't really used my 3 car makers yet. i need a way to tell a new car who made it. write a new test case.
void testAllColorsAndMakers() {
Car RedCrashCar(CRASH, RED);
Car BlueBoomCar (BOOM, BLUE);
Car GreenBangCar (BANG, GREEN);
assert_eq("initcheck", RedCrashCar.getColor(), RED);
assert_eq("initcheck", BlueBoomCar.getColor(), BLUE);
assert_eq("initcheck", GreenBangCar.getColor(), GREEN);
assert_eq("initcheck", RedCrashCar.getMaker(), CRASH);
assert_eq("initcheck", BlueBoomCar.getMaker(), BOOM);
assert_eq("initcheck", GreenBangCar.getMaker(), BANG);
}

and add it to the test suite. i cycle naively and find that i have introduced new notation: there is no constructor with parameters, as the following complaints show:
g++    -c -o cartest.o cartest.cpp
cartest.cpp: In method `void {anonymous}::CarTestSuite::testAllColorsAndMakers()':
cartest.cpp:26: no matching function for call to `Car::Car (Maker, Color)'
car.h:16: candidates are: Car::Car()
car.h:20:                 Car::Car(const Car &)
cartest.cpp:27: no matching function for call to `Car::Car (Maker, Color)'
car.h:16: candidates are: Car::Car()
car.h:20:                 Car::Car(const Car &)
cartest.cpp:28: no matching function for call to `Car::Car (Maker, Color)'
car.h:16: candidates are: Car::Car()
car.h:20:                 Car::Car(const Car &)
make: *** [cartest.o] Fehler 1

ok, let's code one by adding the following to car.cpp:
Car::Car(Maker _maker, Color _color)
: maker(_maker), color(_color)
{ };

lets also add as new line 17
Car(Maker _maker, Color _color);

to car.h. now cycle. how disappointing, this works first time round. to be fair, i read up about constructors with parameters before i wrote this.i left this in subdir #3 for your convenience.

goal checking

i wanted to do this:
i want some simple application that will allow me to try and use the test organisation features. i want to demonstrate the calling of methods in that application. i also want to demonstrate data access.
i have used methods if only very simple get/set-stuff. by implication, i have also seen data access. and i have seen how several test cases go together to make a test suite.

but i also have a few more things that i would like to see, like for example: and then, there is the fact that i thought i needed to test the first of my two constructors. i did change my third test case to do this (even if only out of desperation...). by now, testColorChange does a lot more than that. i should really refactor this before i do anything else. like move the call to the default constructor to the fourth testcase.
while i am at it, the getColor and getMaker tests seem redundant now, because that happens in cases 3 and 4 as well.
however, all these things smell like some step 3, and i promised to get by with two.

is it time to stop this?

frankly, i think so. this thing has gone far enough to show a number of things: so, let me wrap this up and leave you so you can try to fall on your own face ;-)

a few comments on the feel of all this

from wanting to learn c++, i have migrated to reading about light weight processes, in which unit testing can play a significant part, and a few other things. my current understanding is that "learning c++" is a rather short sighted proposition in as far as any programming language isn't just a bunch of syntax rules and flame wars about notation and so forth: they are means, not ends.
i find that this test first approach keeps me focused as i write. at my level, even a failed compile is a help - i am sure this is not part of the big *unit tests to save the world* plan, but it seems to blend in rather nicely. or maybe it compensates for the fact that i have no sidekick to do pair programming with when i sit in my cavern and hack.
i don't write so much code at any given time - just enough for a little test or three, but i write until stuff more or less works. for a little code change i only need to touch one or two files at a time. this is much easier to control. also, i can go away and do something else most any time. it helps me to look at my workload as a pile of handfuls (each of which is more or less easy) rather than a mountain (which can be depressing sometimes).

i find unit++ nicely unobtrusive for this style of work. it just quietly sits there and waits to be used. i look forward to carrying on in this manner as i continue to worm my way through my c++ books. more questions will come up, some of those open items i listed above, some will lose their apparent significance. i will learn...

oh, before i forget: thanks for keeping me company on my cerebral mud paths up to this point. writing your own live commentry during he first few stunbling steps has been a strange experience but mostly fun. i do hope this carried over and you don't feel you wasted your time entirely.

PS-1: a few points for those who want more.

there is any number of things that i can and will not discuss here because they are not first steps. some of the more obvious points follow:

unit testing in general

there is great debate about when to use unit testing and what it can achieve. it makes sense to follow this debate, but i won't replicate this here. search the web or read some books and articles.

when it gets hard in a real project

sadly, i have nothing to say on the matter since i am still very much in the learning phase. i know there is literature out there discussing the ins and outs of unit testing in the face of concurrency, distributed computing, and other such harsh realities. if you have these problems, please accept my congratulations for having escaped the scope of this text.

unit testing in other programming languages

this again is a wide field. naturally, programming language specifics impact the things any available implementation of XUnit can offer. one example is the so called refection mechanism in java which is used in JUnit (according to what i read, anyway). this simply does not exist in C++ so unit++ cannot use it, so here are two XUnit flavours with differing functionality. this text is about getting started in one implementation. the rest is nice to know, quite possibly important, but not my concern here. search the web if your mileage varies.

integration into your IDE

this is happening all the time anyway. unit testing is *hip* right now and tool makers are responding, from what i gather. me, i want to learn the knitty gritty of my new language first then start playing with new tools which is why i have stuck with the text only approach.

extending this framework

if you have a real project on your hands, you may find that you want different asserts. my understanding at this point is that you would be expected to add such functions and make them available for the restoftheworld if they work for you. don't let my ignorance stop you.

installation issues and using the gui

the installation - for me, anyway - was pretty much the usual:. /configure-make-make install. do use the --with-qt option if you want the gui - and read the text bits in the configure file for this and other related info. much to my shame, i could not make the gui work. maybe this is somehow related to the fact that i am using qt3 libs (not qt2), but we simply don't know at this point. i like a green bar as much as anybody (in fact i like a whole lot of bars, cheers) but since it just wont work on my system, i am applying pragmatics and remain in text mode while learning. i wish you better luck... i receive info from behind the curtains that this particular gui implementation may not be the final word on the matter, so you may want to watch the sourceforge for updates or - heck, why not? - come and help!!

PS-2: things to read for understanding everything else

the following is an unordered list (and this is not a html joke)

German stuff

English stuff