This tutorial will give you a start on how by fso56144


									jCreek Programmers Guide – modelling and matching.

This tutorial will give you a quick start on how to write a program using the functionality
available in jCreek, the java version of CREEK. The API to the system is not rigorously
defined, it consist of the public methods of the classes available in the distribution (of this
evolving software). The tutorial will attempt to give you a glance of its contours, especially
the representational part as found in the package jcreek.representation.

As an API tutorial this document assumes that you are able to write and compile java
programs1. Any compilation problems you are unable to remedy hopefully will disappear by
putting the precompiled files, jCreekComplete.jar, in the search path of your OS and
building on top of them. With this library you may start any executable class from the
distribution, or your own built upon them, with the command line:

              java –cp jCreekComplete.jar <fully-qualified-name-of-the-class>

You should be aware that this is a modelling guide. Its main purpose is to show how
modelling can be done programmatically from code, as opposed to manually through a User
Interface (UI).

There exists another modelling guide, a user guide named “TrollCreek Tutorial”, describing
how modelling is done through a User Interface. That guide also elaborates more on how
modelling should be done in general, including the meaning of representational terms like
entity, relation and frame (and graphs representing frames) as well as diagnostic terms like
case and finding. This guide assumes you are somewhat familiar with the fundamental
concepts. Working through the tutorial might still be a nice way of becoming more familiar
with them.

Feel free to comment on the contents of this tutorial (or on typos or anything else). Your
comment might be of value to other readers of the document.

Good luck!

 If your centre of attention is representational (modelling) and reasoning (case matching) issues strictly, this will
do. GUI-elements are another matter though. Whether you plan to understand, create or only use them makes a
difference. If you only plan to use the elements provided with the distribution, you might not need any
additional skills. If you plan to understand the available custom GUI elements some familiarity with Swing
(Sun’s own GUI framework) will be useful. If you wish to create your own GUI elements, please read Sun’s
documentation on the matter. This tutorial is not about GUI-elements, but it will use one: namely the
FrameBrowser showing FramePanes.
The representation
We will give you a reminder right away: you have three, increasingly structured, perspectives
on the representation:

      Graphs, a pure mathematical structure built from nodes and interconnecting links.
      Ascribe meaning to graph parts making it a Semantic Network (entities, relations).
      Collect every relation (value in a slot) from an entity, and you have its Frame.

That is, slots can be reduced to relations and further to graph links. Slot-values can be reduced
to entities and further to graph nodes.

The code in this tutorial
This text mainly uses two classes, both enclosed in the library. When the tutorial suggests
running example code you should usually run the class examples.ModellingTutorial. The
other class used heavily is examples.CreekExample. Have a look at the source code files for
both of these two classes to see the code used herein in its natural, complete surroundings.
The first one is commented on in this document. It uses the second one, which is so well
commented in-line in itself that it might be all you will ever need to get going. The bold
reader may perhaps skip this tutorial all together and go straight there!

If you use the snippets of code provided herein in your own code, you are encouraged to
elaborate the catch clauses more than what is done here. In this document the exception
handling is kept at its bare minimum: an e.printStackTrace() statement. This is done to
keep the coding examples clean of general non-creek code, staying more focused on the
system specific one.

This UML diagram pretty much summarises what is coming up ahead. Remember the
simplicity of it while you proceed through the rest of this document!
What CREEK can do? – What we must do!
Creek is a Case-Based Reasoning system, which means that is uses previously recorded
experiences (cases) to solve new problems of the same kind by comparing the new case
(called a input case or problem case) with the existing cases. By using the solutions of the
most similar cases already solved, a solution to the new problem can be suggested by the

Let us start with a simple example. A dull side of cars, hopefully not occurring too often, is
that they sometimes fail to start. After several starting attempts you might notice that the
starting engine is not turning and conclude that the battery is flat. The obvious solution to this
problem is to recharge the battery.

Given experience with cars (and thereby suggested solutions to typical problems with cars),
this is an easy problem to recognize and fix. Creek can potentially reach the same conclusion
as we did in the example, but the program lacks experience with cars, of course. It will use a
knowledge model as a substitute.

We are going to give that model to the system. As least illustrate how you programmatically
might go about to do so. Our task is to enable Creek to reach the correct conclusion by giving
it the necessary knowledge to draw the conclusion upon, i.e. knowledge modelling. We are
going to describe a problem domain, “car starting problems”, by defining the terms involved
in a manner recognizable for the system. The foremost purpose of the model is to support
case-based reasoning, more than picturing the world precisely.

The steps involved
We will start by making a new knowledge model containing the system’s own terms, and
capture it in a file. We then (a) define our own domain terms, (b) make sure the system
understands something by our terms, (c) add some cases described in those terms, and finally
(d) adds a causal model.

Between c) and d) we perform a case retrieval to confirm that our modelling has enabled the
system to conclude on its own behalf the solution to our illustrating example (as given to it
through our modelling).

Some of the code snippets given below are accompanied by a textbox similar to the one right
bellow. The successive boxes will contain an argument (in bold font) that can be given to the
class examples.ModellingTutorial. Replace the bracket parenthesis part in the command
line given in this first box with the arguments given in successive boxes will run a code
snippet equivalent to the one you find in this document.

 java –cp jCreekComplete.jar examples.ModellingTutorial [<argument>]

Now, let us at last spotlight the programming. Inspect the source files right away if you need
to figure out details, like import statements, or want a more global view on the code.
Making a new knowledge model

    We will start by creating a new model and saving it to a file (new [filename]):

    KnowledgeModel km = new LocalKnowledgeModel();
    try {
      ((LocalKnowledgeModel)km).saveAs(filename); // store the model
    } catch(IOException e) {

Now, that was really easy, don’t you think so?

KnowledgeModel is a java interface to a model. LocalKnowledgeModel implements the
interface as a model, and has a means of storage. It can be serialized to a binary file
(unreadable for us). You are encouraged to access the model through the general interface as
much as possible – keeping its way of living transparent – and use downcasting (as shown in
the snippet) when necessary.

If you need to save a model of any other type to a file, you should transfer the contents of the
model to a LocalKnowledgeModel. first using a constructor (se CreekExample.saveModel
for details):

    localModel = new LocalKnowledgeModel(model);

When you create a new model it isn’t empty. It comes with predefined terms. You could find
out which terms it comes with if you knew how to take a peek inside a freshly created model.
To facilitate your ability to check up on the predefined contents of a model as well as
enabling you to confirm your own changes to a model, we will sidestep our progress a little to
show you how you can pop up a GUI-element – read on!

 An existing storage alternative is as XML in a plain text file. Future development of the system might provide
other means of storage, like a SQL database.
Browsing a knowledge model

                                                                                FrameBrowser     is the
                                                                                only GUI-element used
                                                                                in this document. It
                                                                                enables you to browse a
                                                                                model, seen as frames,
                                                                                by following the link-
                                                                                symbols (mouse click
                                                                                them). You may alternate
                                                                                with the full blown
                                                                                knowledge editor as
                                                                                described in the
                                                                                “TrollCreek Tutorial” if
                                                                                you need more.

                                                                                The whole picture shows
                                                                                the FrameBrowser. It
                                                                                contains an internal
                                                                                window (titled entity)
                                                                                with a FramePane3 in it.
                                                                                It shows the frame for the
                                                                                concept entity.

                                                                                With a loaded model,
                                                                                you only need two lines
                                                                                of code to pop up this
                                                                                custom GUI element.

    Inspect any model visually through a GUI element (browse [filename [startingConcept]]):

    try {
       KnowledgeModel km = new LocalKnowledgeModel(filename); // load model
       FrameBrowser frameBrowser = new FrameBrowser(km, conceptName); // show it.
    } catch ( e) {
    } catch ( e)
    } catch (ClassNotFoundException e) {

Enough about looking at models – let us get back on track – next up we are going to define
our own domain specific attributes.

  FramePane is the element coming closest to capturing the concept of a frame. Do not mix up the
representation’s frame with the Swing component JFrame which is more of a window. In general any class
name starting with a capital J comes from the Swing packages. The package named jcreek (observe the little j)
obviously belongs to jcreek.
(a) Describing the domain – establishing our vocabulary

We start modelling the possible Case attributes and belonging values by enumerating them.
Our knowledge base will contain cases of car starting problems, each consisting of four
attributes corresponding to properties of the problematic car that any car owner able to
actually recharge their battery can come up with: colour, engine status, battery status, and age.
These are used to describe the car in question. Notice the special attribute to hold the
suggested solution for a solved problem.

Car attributes           Possible values
Colour                   red, blue
Engine status            running, not starting
Battery status           empty, low, OK
Age                      any number
Solution                 recharge battery, ignore it

For each of these attributes we define which values it can possibly have. Not having any value
is modelled by dropping the attribute from the case all together (adding an attribute with the
predefined entity “No value” as its value is an alternative, usually used for making templates).

Values should be unique for their attribute. Please take note of this important fact. Values
used for colour is no problem, nothing else than colours are red or blue. The value empty of
battery status are different. You could fell like using it for a new attribute, like gas-tank-
status, which could also be empty. This would not be the way to do it in jCreek. You would
make a unique value for each of the attributes maybe naming them something like empty-
battery and empty-tank in bigger models. Here we stick with basic names.

All the words in the table entries make up our terms or vocabulary, so to speak, for describing
the domain. They should be added to the system as Entities, living in some knowledge model
(the km-argument) dedicated to the domain.
     Entity colour = new Entity(km, "colour", "the colour of something");

Remember that entities could be seen as nodes in a graph? This can be understood as drawing
a node (small circle) in the graph with the name “colour”. The graph equivalent of drawing a
line between two nodes in the graph is described in the following.

The possible values for an attribute should be defined as instances. But there is no class
named Instance in the system. Instead of making any new objects you would model the fact
that red and blue are the values of the colour attribute. This is easy; the colour-object is of
class Entity. Its method addRelation(String relationType, Entity value) would be
called like this (remember to add the values themselves as entities first, here red and blue):
     colour.addRelation("has instance", red); # variant 1
     colour.addRelation("has instance", blue);

Or, better, like this:
     colour.addRelation(IsoPodModel.HAS_INSTANCE, red); # variant 2
     colour.addRelation(IsoPodModel.HAS_INSTANCE, blue);
These code snippets have equivalent effect. The difference lies in the use of constants in the
second version. There are more constants defined in jcreek.representation.IsoPod.
Actually there are constants for all of the predefined terms (a new empty model isn’t empty, it
comes populated with some terms as we saw above, remember?) thereby making them
predefined not only in the system, but also in your compiler as a help for you.

Use them since names may change over time as this is an evolving system. One benefit of
constants over text strings is that you find all the affected places in your code with a
recompilation instead of using a search-replace operation. If this doesn’t convince you, let me
add that constants are checked at compile time, reducing the chance of typos which could pass
unseen until runtime in the first version (even before the system has changed at all).

To be precise, the graph equivalent of the above is not drawing one line between a pair of
nodes, but drawing two lines with opposite direction. One labelled “has instance” and the
other “instance of”. You might ask where the opposing label comes from. The answer is from
the relation type. You would get the answer “Instance of” if you call
  String hasInstanceName = IsoPodModel.HAS_INSTANCE;
  RelationType hasInstance = km.getRelationType(hasInstanceName);
  System.out.println( hasInstance.getInverseName() );

This gives us a third alternative as well as the two above since the Entity-class not only
defines addRelation(String relationType, Entity value), but also defines the method
addRelation(RelationType relationType, Entity value):

  String hasInstanceName = IsoPodModel.HAS_INSTANCE;
  RelationType hasInstance = km.getRelationType(hasInstanceName);
  Entity red = km.getEntity(“red”);
  colour.addRelation(hasInstance, red); # variant 3 using EntityType.

Needless to say, there are no constants for your own defined entities unless you also add your
own constants for them.

We have to repeat this process for all the attributes with values in our table. This connects
each attribute with its values. But they are still unconnected with the rest of the graph.
The terms are still only mnemonics (to make it clear to us what we mean by them). Let us add
some meaning to them for the system.
(b) Integrate our terms – adding semantics for the system

To connect our terms with the system’s we have to link them to predefined system terms.
Attributes are a subclass-of Symbol or Number.

Tip: Take a look at the Symbol-frame and see if you can find any subclasses of symbol, i.e.
predefined attributes.

This lets the system “understand” something by our words, namely how they will be used in
the system, so we better keep this straight. Each nominal attribute will be represented as a
subclass-of Symbol, while numeric attributes are a subclass-of Number (thereby inheriting
different ways of comparing symbols and numbers). Again the code to do so is simple, use the
method addRelation, either relying on using strings naming the arguments with
addRelation(String relationType, Entity value)

  colour.addRelation("subclass of", km.getEntity("Symbol"));

Or, preferably, use the same method with constants referring to those strings, like this:
  Entity symbol = km.getEntity(IsoPodModel.SYMBOL);
  colour.addRelation(IsoPodModel.SUBCLASS_OF, symbol);

Or, again, use the method signature with an EntityType argument instead of the String:

  Entity symbol = km.getEntity(IsoPodModel.SYMBOL);
  RelationType sybclassOf = km.getRelationType(IsoPodModel.SUBCLASS_OF);
  colour.addRelation(subclassOf, symbol);

After doing this we could start defining cases by simply linking each case to it’s attributes by
using the predefined relation has-finding. Doing so makes the attribute available for the
system during case matching.

However, adding each case-finding less anonymously, with an informative name, makes more
sense (to us, for the system it is the same). Especially later, when the system presents which
links it has followed to reach its conclusion, meaningful names will make the conclusion
more meaningful (to us). This can be done simply by making your own relations witch are
subclass-of has-finding.

We will define these named relations (defining their inverse at the same time) and use them to
connect the cases with their attributes. For example, the attribute Colour will give rise to the
relation has-colour (and the inverse colour-of).

     RelationType hasColor = new RelationType( km,
        // The superclass of this relation
        // The name, description and default strength of the relation.
        "has colour", "the color of an object", 0.1,
        // Ditto for the inverse
        "colour of", "the origin is the color of the target", 0.1
Remember how adding the “has instance” relation between two nodes actually resulted in two
opposing relations? Here we clearly see how a relation type always has an opposite. This is
like drawing two nodes with two opposing edges between them in the graph. The nodes are
labelled “has colour” and “colour of”; the edges are labelled “has inverse” and “inverse of”.

Notice the two places with a 0.1 in the code above? All relations have a value from 0 to 1
attached to them. When you make a relation type you provide a default value for every
relation of that type. These numbers weight the importance of the attribute in Case-matching.
That two cars have the same colour is not so important for figuring out the problem at hand,
so we give it a low weight (0.1). You should probably give has-battery-status the highest
weight (0.8). If you are curious about the detailed consequence of these numbers you can
have a look at appendix A.

Repeating this process (along the lines of the code for has-colour above) for each attribute,
gives us the necessary links to start defining cases. The relation has-solution comes
predefined. These named and prioritized links are a great improvement over the general has-
finding. The name is a mnemonic for us. The strengths are a means for both the system and us
to know what traits are important and not.

Tip: You may want to browse the model again with the FrameBrowser (as described above in
Browsing a knowledge model) to see that your changes indeed are in the model. Also open
the Case-frame, for example by following the link from the Entity-frame, and verify that the
Case-frame doesn’t contain any car cases before we continue.
(c) Add some cases

First of all we will make a new entity classifying a special type of cases, our “car starting

    Entity car = new Entity(km, "car case", "a car starting problem");

We make it our own category of cases simply by inheriting the match-ability of cases.

    car.addRelation(IsoPodModel.INSTANCE_OF, km.getEntity(IsoPodModel.CASE));

We are now ready to add a new case to our base, again notice the km argument ensuring this.

    Case case2 = new Case(km, "car problem 2", "Some description…", car);
    case2.addRelation("has colour", blue);
    case2.addRelation("has engine status", engineRunning);
    case2.addRelation("has battery status", goodBT);
    case2.addRelation("has age", new NumberEntity(km, new Integer(15), age));
    case2.addRelation("has solution", noProblem);

This snippet assumes you have java variables referring to the proper entities in the knowledge
base, as car above. If not, km.getEntity("car case") would do the trick in the place of car,
and so on. You can name your java variables anything you fancy according to your style of
coding, but you have to use the proper name of an entity when getting it from the knowledge
model, i.e. the same name you used when creating it. The compiler will not help you (unless
you refer to predefined terms via constants, as is done in the IsoPodModel).

As you can see in the last line of the above code, the method setStatus4 is called on the case
object. The Case-constructor adds it as an unsolved case; we change this status with this
method call. This has significance for how the system treats the case. A case can be tagged as
UNSOLVEDCASE, PROCESSCASE, and SOLVEDCASE. A new problem is tagged unsolved. Only
cases tagged as solved are used to look for solutions to unsolved ones. The middle tag
indicates that the case is in transition between the other two.

The inclusion of a number is bothersome. You can’t just add the number. You have to make
an entity out of the number, new NumberEntity(km, new Integer(15), age), and tell
the system what the number is used for, here as an age. The upside of this is that the system
will figure out on its own how different ages are based on the range of all car ages in it.

When you have added a case to the base you may get it back like this:

    Case case2 = new Case(km.getEntity("car problem 2"));

  The method is actually just a convenience method for accessing the underlying graph in a manner close to
addRelation("has case status", km.getEntity(Case.SOLVEDCASE));.
But the method also makes sure that additional system logic is followed, like having only one status-relation
pointing out from the case. Normally we might have many relations of the same type/name doing so. The system
in no way stops you from giving a car two colours! It might be a modelling error to do so, but it is no system
error since you might actually want to do so. As is the case with has-finding, you may add as many as you like
Case matching

Let us build another case, this time leaving the status as unsolved:

  Entity car = new Case(km.getEntity("car case");
  Entity age = km.getEntity("age");
  KnowledgeModel km = new LocalKnowledgeModel(filename); // load model

  Case case3 = new Case(km, "new case", "My problem", car);
  case3.addRelation("has colour", getEntity(km, "blue"));
  case3.addRelation("has engine status", getEntity(km, "not starting"));
  case3.addRelation("has battery status", getEntity(km, "empty"));
  case3.addRelation("has age", new NumberEntity(km, new Integer(16), age));
  case3.setStatus(Case.UNSOLVEDCASE); // actually not needed.

In order to solve this case, you can use the RetrieveResult class, which attempts to match
the new case with all the solved cases in the case base and return the closest case(s).
Furthermore, ReuseResult uses the cases retrieved by a RetrieveResult object to select a
solultion. Combining the two gives us a solution:
  // CBR retrieve and reuse gives a suggested solution.
  ReuseResult reuse = new ReuseResult(new RetrieveResult(case3));
  System.out.println("\n" + reuse.toString()); // print it.

To add the domain model including cases run car, then perform a match by running match.
(d) Creating a causal model

Remember the traits we decided to use in our descriptions of cars? You may have noticed that
the starting engine was left out. It is something the ignorant, blissful owner didn’t need to
know about. It is considered expert knowledge in our example. You might also remember that
the actual reasoning step performed in the example included the starting motor, so we are
obviously going to add it if the system should perform that particular reasoning in our place.

Another matter is that in a plain match only direct, syntactic, matches are considered. We
could try to connect the rest of the traits found in the cases, until now unmatched, with each
other through an indirect match.

The system will do both by finding a path through cause relations in the graph. This path is
seen as the explanation for the match.

The rationale behind this is that two (more than syntactically) different traits can be different
symptoms caused by the same reason, or – the other way around – two different traits causing
the same effect. The system can find them as long as we provide them, so let us add a very
simplistic causal model to our example. It consists of a single fact, that both an empty battery
and a low battery arguably will cause the engine to not start, pictured like this (read arrow as

Adding it amounts to the following code.

  Entity starterStop = new Entity(km, "starter              engine   won't   turn",
                                      "starter              engine   won't   turn");
  Entity starterSlow = new Entity(km, "starter              engine   turns   slowly",
                                      "starter              engine   turns   slowly");

  Entity emptyBT = getEntity(km, "empty");
  Entity lowBT = getEntity(km, "low");
  Entity notStarting = getEntity(km, "not starting");
  emptyBT.addRelation(IsoPodModel.CAUSES, starterStop);
  lowBT.addRelation(IsoPodModel.CAUSES, starterSlow);
  starterStop.addRelation(IsoPodModel.CAUSES, notStarting);
  starterSlow.addRelation(IsoPodModel.CAUSES, notStarting);

We added two new intermediate entities that connect three old ones with causes-relations.
This will enable the system to match low and empty battery status.
More matching traits give a higher matching strength. You can see the effect of the causal
model by running a small experiment comparing the matching strength in a plain match with
an explained one.

 Running experiment without any options will create all of the above from a clean scratch
 and do a case match. Running experiment –c (that is, adding the option –c) will do the
 same, and also include a small causal model making an explained match possible.
 Combine with the option –v (verbose) to see what is going on.

If you run this small experiment you will see how it raises the matching strength (from around
0.34 to 0.43). Sometimes this may make a whole lot of a difference. If the small adjustments
to the strength changes which case come out as the winning one, and further: if this contribute
to a change in the suggested solution, we have a qualitative difference.

In our example we only have tree cases: a single problem case and two stored cases. We have
already demonstrated how the system selects the right match for the problem among the two
solution alternatives, but for the sake of argument we will try to provoke the system into
selecting the other, wrong one. We simply do this by raising the importance of the colour trait
so much that we get a match based on colour instead of the more important traits battery- and
engine-status, let us say to 0.36.

  RelationType hasColour = new RelationType(km.getEntity("has colour"));
  hasColour.setExplanationStrength(0.36); // only effects new relations.

 Run experiment –s to redefine the strength of has-colour from 0.1 to 0.36 before doing a
 plain match, and see how the solution changes from “recharge battery” into “ignore it”.

Interestingly, when redefining the importance of your car’s colour for getting it to start, using
the causal model again will compensate for this mistake and save the situation! See it for
yourself by running the experiment with both options (–c and –s).
To summarize modelling (alphabet rule)

   Decide what you are going to model (your domain), create the knowledge model file.

   a. Attributes and values are added.
         i.  Add all the descriptive words you are going to use as entities.
        ii.  Define possible values for your attributes as instances.
       iii. Optionally organize your terms into a hierarchy (using subclass-of etc.)
   b. Base your terms or hierarchy (system integration):
         i.  Let your attributes (possibly indirectly) be subclass-of Symbol or Number.
        ii.  Make relations (subclass-of has-finding) corresponding to the attributes.
   c. Cases are added, built from the terms.
   d. Deep knowledge, i.e. a causal model, is added to enable explained matches (optional).

Notice that you don’t need to finish all of step a) before continuing to step b), etc. This is an
incremental process. If you need other terms then the existing ones, for example during case-
building, just go back and add them.

The order of the modelling steps is strictly creational. You need a term before you can use it
in a case. But you have the cases in mind when you create your terms, probably making this a
cyclic modelling process.

If you are concerned about the semantic of the terms involved – and want less syntactic
matches – you should take special care in step b) ii) and d). There you define the strength of
relations (see more about this in appendix A) and add the deep knowledge. The better your
modelling is in these critical points, the better your matches will become.
Appendix A: Trait relevance

At the end of step b) we said that all relations have a value in the range 0…1 attached to them.

The consequence of this value is system central. It is a very important aspect of defining the
system semantics of your relations. Just using has-finding makes all attributes equally
important in revealing car starting problems. This is not the case, of course.

The colour of the car is of low importance to starting problems5. We indicate this by setting
the strength of the has-colour relation to 0.1. Equal battery status is more important than
equal colour when matching cases. Our priorities are summarized in the table.

has-finding              strength     inverse           relevance %
has-colour               0.1          0.1               0.1        5,0
has-engine-status        0.8          0.5               0.65      32,5
has-battery-status       0.8          0.8               0.8       40,0
has-age                  0.5          0.4               0.45      22,5
                                                        Sum: 2.0 100,0

The two numbers you provide during modelling is under the headings strength and inverse.
The column labelled inverse shows the strengths of the inverse relations, that is colour-of,
engine-status-of, etc.

What is the precise meaning of these two numbers? The theoretic framework of the creek
system makes a semantic distinction between the measures. As far as jCreek is concerned, all
that really matters is the average (add them together and divide by two). It might in fact be a
whole lot easier for you to just use the same numbers for both strengths since you then
immediately know what the average is. This average is called the relevance of the trait, and
can be normalized into a %-weight (divide by the total relevance and multiply by 100). We
see that the battery status is given a weight of 40%, making it pretty important for finding
solutions to starting problems. This means that a direct match on the values of the battery
status values gives you a matching score for the cases in question of 40% (when the other
traits are present, but unmatched), and so on cumulatively.

The main point is how you can take another small step upwards from a pure graph towards a
semantic network by making meaningful priorities between the traits (relations).

  The percentages here might arguably be adjusted to better values. To be realistic has-colour should be set to
cero, as the colour of a car has no influence what so ever on car starting problems. If this has been your reaction
to this discussion all the way, you have probably understood it.

To top