Wednesday, February 13, 2008

I'm working on a sweet project at the moment using both WPF and WF. One of my custom activities has a property of type Type, where it would be cool for the user of the activity to be able to use the designer to select a type, just like what happens in the WF designer when I choose a type. However, no type picker popped up.

So I went googling and found that Daniel Cazzulino also ran into this problem and created a fantastic little project to harness the power of the real WF typebrowser. He writes about it on this blogpost and later moves the project to code project. You can find the article and his download code here.

However, as you can read in the comments, something was broken. Looking through the code, although small, made me not want to waste time on understanding the System.ComponentModel namespace in that much detail at this point ;-) (although, when working with WF, you will soon need to customize property pickers, so I will have to look into it someday soon).
Daniel himself points to the Patterns and Practises entlib library: they offer the same functionality. I downloaded their sourcecode, and I'm quite sure they just used Daniels code and improved upon it a bit. However, with all the Entlib references, the project felt a bit heavy.

What I have done is rip out all the references to entlib that I do not care about, used a few files from Daniels original solution and worked around a few shortcomings. Nothing fancy, I just hacked at it until it worked.

image

 

Now, since I have used some code (without license) by Daniel and code by the Entlib group, I'm not sure if I can publish a derivative without getting into problems. However, I've read their license, and I think it's okay.

You can download the project here, don't ask for changes because I'm not interested in spending more time on it. All credits go to Daniel.

(Also, find out how to create your own typefilters in his post).

Have fun with it. Leave a comment if you find it useful.

Wednesday, February 13, 2008 1:30:24 PM (Romance Standard Time, UTC+01:00)  #    Comments [7]  |  Trackback

Grigori Melnik just blogged about the release of the first CTP for the Unity Framework. It can be downloaded from codeplex here.

I think I mentioned Unity before. The Unity framework is build on top of ObjectBuilder2. ObjectBuilder2 seems a much better factory system than ObjectBuilder (infamous for it's bloated misuse in CAB). I have been following along with some sample on how to use ObjectBuilder2 and I quite like it. Obvious, nowhere near as powerful as Windsor, Spring.Net or StructureMap yet, but I understand Microsoft needs it's home-grown factory system, and ObjectBuilder2 seems easy enough to use.

The Unity framework uses ObjectBuilder2 to provide a IOC. It can be used like so:

UnityContainer container = new UnityContainer() 
                  .Register<ILogger, TraceLogger>() 
                  .Register<ISomething, Something>()
                  .Register<ISomethingElse, SomethingElse>();

container.Get<ISomething>();

I'll certainly be looking into it!

Wednesday, February 13, 2008 10:40:19 AM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback
 Tuesday, February 12, 2008

It frequently happens that you wish to enrich a valuetype with more data, most often the properties in your domainmodel. In this post I will present one way you could achieve that. But first, let's look at why you would want such a thing, then look at how you would go about this normally and finally look at another approach.

Why metadata about a property

Let's say you have a domainobject 'Person' like so:

    public class Person
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
    }

When working with this object, you will set the property 'Name' and property 'Birthday', but while setting these, you have no clue about what really is allowed to go in there. Maybe Name can not accept numerics and in our domain, any Birthday before 1-1-1990 is not allowed. These validationrules are unknown until you actually validate the object, using your preferred mechanism. At that point, there might be an error collection that will state which properties are set to disallowed values. Maybe validation will occur on each change to the data.

That's not really a problem for your businesslogic, but your UI might want to know about these validation rules beforehand! Maybe it could adjust to show a different textbox for 'Name', one which will not let you enter a number, for instance.
Yes, sure you could have put that specialized textbox in there yourself, but that means you will have to adjust your UI views when businessrules change. I would much rather just place a generic control, bind it to my property and let it decide for itself how best to present the data:

<MetaDataEditor Content="{Binding Path=Name}" />  <!-- this shows an alphanumerical textbox -->

So, why metadata: it allows you to optimize beforehand and simplify your UI.

Freaky
Oh, or maybe you want to give a 'friendly name' to the property. That friendly name could be presented in the UI as the label or used in error messages.
How do you go about this normally

(and I say 'normally' not in a bad way, it might still be the best way, depending on your situation).

You would define some interface:

    interface IMetadataProvider
    {
        Metadata GiveMetadataForProperty(string propertyName);
    }

and implement that on Person. Now, when you want your metadata object, you just get to the object on which the property is defined, and ask for it. Easy.

Metadata<T>

What I do not like about an interface, is the fact that you have separated the metadata from the property itself. There now is a method in my domainobject that will take a string (ouch) and probably go through a long list of  'if(propertyName == "???")' or switch/case statements until it gets to the correct name and then create or return a metadata object. That's a great deal of hooking up you need to do, and when passing strings, your domainmodel just became less easy to refactor.
When my magical MetaDataEditor needs the metadata, it will have to somehow find it by traversing from the bound property to it's parent and cast that to IMetadataProvider.

Oh, bad boy, don't even think about using reflection to magically connect the passed string to a metadataobject!

That is why I am experimenting with a little class, I like to call Metadata<T>.

    public class MetaData<T>
    {
        public T InnerValue { get; set; }
        .... goodness inside
    }

This way, you need to define a property on your businessobject like so:

private MetaData<string> name = new MetaData<string>();

public MetaData<string> Name
{
    get
    {
        return name;
    }
    set
    {
        name.InnerValue = value.InnerValue; 
    }
}

This way, you can rest assured the original metadata object is never discarded, but only the innervalue is changed.

We could work with the property like so (p is an instance of Person):
p.Name = new MetaData<string>("foo");

That's not easy, but we can also say:
p.Name.InnerValue = "foo";

Better. We can do one better though, by creating a few implicit operators on the metadataobject:

public static implicit operator T(MetaData<T> source)
{
    return source.InnerValue;
}

public static implicit operator MetaData<T>(T source)
{
    IMetaData md = source as IMetaData;
    if (md != null)
    {
        IConvertible convertible = md.InnerValue as IConvertible;
        if (convertible != null)
        {
            T converted = (T)convertible.ToType(typeof(T), null);
            return new MetaData<T> { InnerValue = converted };
        }

        throw new NotSupportedException();

    }
    else
    {
        return new MetaData<T> { InnerValue = source };
    }
}

This means, we can now use the property as follows:

p.Name = "foo";

The string "foo" can be translated to a MetaData<T> and that is going into the property-setter. Then, the setter will take the innervalue of that foo-metadataobject and use it to set it's own innervalue.

string importantname = p.Name   will work too.

One important note though: this might be misleading to your developers. They can not do p.Name.ToCharArray(), because p.Name really is not a string.
Or p.Car.Color. You would have to do p.Car.InnerValue.Color.

Now, whether you go with the implicit operators or not, you want to ease databinding especially. For that, a typeconverter can be used.

A typeconverter can be attached to a class by the use of an attribute, like so: [TypeConverter( typeof(MetadataForDatabindingConverter))]

The converter needs to inherit from TypeConverter. Let's implement one.

  1 public class MetadataForDatabindingConverter : TypeConverter
  2 {
  3     /// <summary>
  4     /// keep the real type of the metadata innervalue. Since we need it when we convert back to our metadata
  5     /// object.
  6     /// </summary>
  7     private Type databindingRealType;
  8
  9     public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
10     {
11         if (sourceType.Equals(typeof(string)))
12             return true;
13         else
14             return false;
15     }
16
17     public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
18     {
19         if (destinationType.Equals(typeof(string)))
20             return true;
21         else
22             return false;
23     }
24
25     public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
26     {
27         // ugly but necessary: when databinding to a ui control, it's likely that you want to go to a string representation
28         // when the ui control (textbox?) was changed, the incoming value is a string. I have not yet found a way to
29         // find out what the target really wants (for instance an MD<int>).
30         // This hack works fine
31
32
33         Type realtype = value.GetType();
34         if (databindingRealType != null)
35             realtype = databindingRealType;
36
37 
39         // or just do a switch on the type and create the correct type
40         //if(value is string)
41         //    return (IMetaData) new MD<String> { InnerValue = (string)value };
42
43         // because I don't feel like implementing the above statements.. bla!
44         Type d1 = typeof(MetaData<>);
45         Type constructed = d1.MakeGenericType(new Type[] { realtype });
46         IMetaData instance = (IMetaData)Activator.CreateInstance(constructed);
47
48         TypeConverter converter = TypeDescriptor.GetConverter(realtype);
49         converter.ConvertFrom(context, culture, value);
50
51         instance.InnerValue = converter.ConvertFrom(context, culture, value);
52
53         return instance;
54     }
55
56     public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
57     {
58         // so, this is a metadata object, and we are going to be converting the innervalue to a string (for textboxes etc).
59
60         IMetaData md = value as IMetaData;
61         if (md != null)
62         {
63             databindingRealType = md.InnerType;
64
65             TypeConverter converter = TypeDescriptor.GetConverter(databindingRealType);
66             if (converter.CanConvertTo(destinationType))
67             {
68                 return converter.ConvertTo(context, culture, md.InnerValue, destinationType);
69             }
70         }
71
72         throw new NotSupportedException(String.Format("Conversion of {0} to type {1} is not possible.",value.ToString(), destinationType.Name.ToString() ) );
73     }
74
75     public MetadataForDatabindingConverter()
76     {
77
78     }
79
80 }
 

A typeconverter should override the CanConvertFrom/To methods to indicate if it is able to convert between certain types. Our UI will present data as strings (textbox), so I have opted to only convert to and from strings.

Line 7 keeps a variable where the 'real type' will be put. The databinding engine does not give much information during the call to convert. So if we have a MetaData<int> and bind that to a textbox, the ConvertFrom only gives us information about the value being set (the string "1234"). How do we know we have to convert to MetaData<int> instead of MetaData<string>?
Well, turns out we do know at an earlier conversion that always happens: converting our metadata to a string that will be put into the textbox. I cache the 'realtype' at that moment. (I'm not happy with that solution, if you know how to get rid of the obvious codesmell there, leave a comment!).

The ConvertTo method is easy enough to not have to describe here, but in the ConvertFrom, we do have to jump through some hoops. I've opted to create a metadata<T> with reflection, using the correct type for T. Then, convert the passed in string to the correct type.

This works brilliantly and it allows you to bind like this:

<TextBox Text="{Binding Path=Name}" />

(When it is time to navigate through a property, you will have to go through InnerValue again though, like {Binding Path=Car.InnerValue.Color} .)

Microsoft's latest approach: IDataErrorInfo

The WPF team has invented dependency properties as another way to do something similar (for different reasons though). You obviously do not want to use dependency properties in your domain model.

The recently introduced IDataErrorInfo has the following definition:

        #region IDataErrorInfo Members

        public string Error
        {
            get { throw new NotImplementedException(); }
        }

        public string this[string columnName]
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

I hate that.

Especially the name of the argument 'columnName'. Drives me mad. My business object is a person or a car, not a databasetable. F*ck off.

Besides, what if you want to do something useful with an index on your object? Madness, I tell you!

Conclusion

It's annoying that you have to go to the innervalue property to get to the real value you are interested in. Implicit operators make this a lot more transparent but possibly confusing. Besides, there is a tiny performance loss here.

However, you can do great stuff with such a setup. Let the metadataobjects implement INotifyPropertyChanged as well and use them in pipelines (more on this later), query validation rules from it without having to think about getting to the object that holds the property, and more.

What do you think?

Tuesday, February 12, 2008 8:08:58 PM (Romance Standard Time, UTC+01:00)  #    Comments [2]  |  Trackback
 Saturday, February 09, 2008
update 2: I also posted this on the forums and the team finally found what was causing this. They explain:

There have been several reports where intellisense has completely stopped working for all projects after installing a version of the Windows SDK or MSDN. We have been able to track down the source of this problem. This seems to only affect installs of the SDK/MSDN post the installation of Visual Studio. One registry value has been incorrectly reset after these installs causing this failure. This issue has been handed off to setup team for a future fix.

In the meantime, if you encounter this issue, it can be fixed using regedit. First, determine if you are seeing this same issue by opening regedit and looking at the key:

HKEY_CLASSES_ROOT\CLSID\{73B7DC00-F498-4ABD-AB79-D07AFD52F395}\InProcServer32

If (Default) is empty you are hitting this issue. To correct the problem, change the value of (Default) to point to the location of TextMgrP.dll on your system (C:\Program Files\Common Files\Microsoft Shared\MSEnv\TextMgrP.dll in my case with a C: OS drive and accepting all the defaults). Restart Visual Studio and intellisense should be working again. Thanks to everyone who submitted reports of this issue and gave us the additional details needed to track it down quickly.

Update: If you are running a 64-bit version of Windows, you will need to make sure you are running the correct regedit version (%systemroot%\syswow64\regedit - see http://support.microsoft.com/kb/305097) and you will need to locate the correct path to TextMgrP.dll (such as C:\Program Files (x86)\Common Files\Microsoft Shared\MSEnv\TextMgrP.dll)

 

Update: a repair of visual studio eventually fixed this. Lesson learned: a repair does not damage already installed hotfixes and addins, so you do not have to fear losing anything.

I lost my xaml intellisense and I really miss it. I installed SDK 6.1, but I do not know if that was the cause. I was using Resharper, so I didn't notice. However, when I uninstalled resharper, intellisense did not appear again! It could have been the sdk. It could have been resharper. Or something else all together. I just don't know.

Lot's of googling did not really help (2008 is different than 2005), but did point to the importance of two files in your xml/schemas folder:

- XamlPresentation2006.xsd
- xaml2006.xsd

However, VS 2008 does not work with xsd anymore to supply intellisense. I was under the impression that a Xaml-parser service was build. I do not have those files and on another computer (where intellisense works fine), I did not find them either.

I copied them from a vs2005 install, and opened a xaml file in the xml editor. No schemas were defined (nor are they on the healthy computer), but when I pointed to the just copied files, intellisense does work partially again. It does not see usercontrols and stuff. This is not the way it is supposed to work in 2008!

Funny thing though: I now have this intellisense in the xmleditor, but not in sourcecode editor or the designer. In the healthy install, it's the other way around.

Let me know if you have a solution!

Saturday, February 09, 2008 11:06:22 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

Dax Pandhi, of Reuxables is offering a lite version of their commercial theme: paper. You only get the compiled dll, but still, it's a bargain ;-)

I have not used any commercial themes yet, and as I am not working for a client at this point, I probably won't at this moment ;-) I also do not know yet whether I like the theme. I am going to use it and just see!

Are there other commercial theme packs around? I would like a pack that makes my applications look like this application ;-)

Saturday, February 09, 2008 9:05:07 PM (Romance Standard Time, UTC+01:00)  #    Comments [2]  |  Trackback

If you are working with clients that do not see the use of automated testing (be it in unit tests of code blocks, or specific UI testing), you are in for a hard time. Maybe you should walk away, but let's face it: you will probably give in and try to do your best.
I have even had heated discussions with developers that do not see the use of it, certainly when there are monkey-testers to do it.

Testing the userinterface is incredibly hard to do. When you're testers are brave, they might use a testtool (robot) that will simulate clicks and read out information. However, these scripts have to be updated when the software changes and that is costly.

WPF has great support for UI Automation, which allows other programs to interact with your application's UI from the outside. It does this by naming the elements of your UI and offers 'strategies' to interact with them (Press this button).
It's not an easy framework, but workable.

Project White seems to be an abstract layer on top of the UI Automation stack, released to the public domain by ThoughtWorks today. It's aimed at simplifying your scripts and presenting a uniform API for both Winform and WPF technologies.

I'm looking forward to discovering it's api. This looks nice:

 

Application application = Application.Launch("foo.exe");
   Window window = application.GetWindow("bar", InitializeOption.NoCache);
Button button = window.Get<Button>("save");
button.Click();

Do you use UI automation to test your application?

Saturday, February 09, 2008 8:54:33 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback

Maybe old new, but Microsoft put up new site here which looks like a very nice collection of all the tools that you can get for visual studio.

Resource Refactoring Tool

Saturday, February 09, 2008 6:05:29 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback
 Monday, February 04, 2008

I'm a strange man: I seem to be equally interested in EntityFramework and in WPF. They are such different beasts, and still I take great pleasure in using them both! That's possibly because I view them as enablers of the kind of projects I like to do. Weird.

Anywho, it's been a long time since I blogged about WPF. And even longer since I blogged about unittesting WPF. The simple trick in this post is probably widely used already in the community: I haven't paid any attention ;-)

In this post, I explained how to setup a tracelistener to listen for binding errors. In the months that followed, this proved to be less than convenient! In WPF views, even when everything is setup great, there might be binding errors that you wish to accept. For instance: a view binds to an instance of type Foo, and is later subsituted by an instance of type Bar. Bar has the same properties as Foo, except 1. The binding engine just clears the bound label, and you are fine with it (yes, sure.. it smells a bit, but you get the example).
Using the tracelistener, you have less control over what the process.

It is much better to have total control over the binding objects in a view. With some exceedingly simple methods, you can get to them to query their status:

First, let's start with an enumeration over all the visuals in your view:

public
IEnumerable<Visual> EnumVisual(Visual visual)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
 {
   Visual childVisual = (Visual) VisualTreeHelper.GetChild(visual, i);
   yield return childVisual;
 }
}

Then, we use some cleverness by dr. WPF that enumerates all the bindings found on a visual:

private IEnumerable<BindingExpression> EnumerateBindings(DependencyObject target)
{
   if(target is ContentControl && ((ContentControl)target).Content is DependencyObject)
   {
      EnumerateBindings( (DependencyObject) ((ContentControl)target).Content);
   }

LocalValueEnumerator lve = target.GetLocalValueEnumerator();

while (lve.MoveNext())
   {
      LocalValueEntry entry = lve.Current;

      if (BindingOperations.IsDataBound(target, entry.Property))
      {
         Binding binding = (entry.Value as BindingExpression).ParentBinding;

         yield return entry.Value as BindingExpression;
      }
   }
}

It uses the GetLocalValueEnumerator, which is a largely unknown method that gets all the properties on a dependencyobject.
I first check to see if the target is a content control, if it is, I go for its content as well.

Now, let's see all the bindings:

private IEnumerable<BindingExpression> GetFlattenedBindings(Visual root)
{
   foreach (Visual child in EnumVisual(root))
   {
      foreach (BindingExpression childBinding in GetFlattenedBindings(child))
      {
         yield return childBinding;
      }

      foreach (BindingExpression binding in EnumerateBindings(child))
      {
         yield return binding;
      }
   }
}

Use it in your unittest to get all the bindings that are available in the visualtree. Test specific bindings or just fail if one breaks.

foreach(BindingExpression b in GetFlattenedBindings(this))
{
   Debug.WriteLine(b.ParentBinding.Path + "=" + b.Status + " on item:" + b.DataItem.ToString() );
}

Ofcourse, it's cool to change the helper methods to extension methods.

Beware that I have not really tested the code. Copy pasting it, I see a few errors, but you get the drift.

 

Monday, February 04, 2008 11:31:58 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback
 Tuesday, January 29, 2008

In my previous project, we used the Composite Application Block with WPF to decouple our application. Lately I have been thinking alot about this, and found some good material on the subject that I wanted to share. But first, let me give a high-level overview of my previous approach. If you are in need to first learn about MVP, check out this dnrTV video where Jean Paul Boodhoo talks about Model View Presenter.

First off, keep in mind that CAB was not written for WPF and has to be hacked to actually be usable.
Secondly, Acropolis is dead and is being turned into guidance material in the future (think end of 2008!).

Cab exposes workitems, controllers and views. We approached the workitem as a simple configurator, which meant it just grabbed the view it wanted and showed it. That was all the responsibility a workitem got, even in wizard style screens.
The controller was our main class, implementing all the screen logic. It was responsible for retrieving and saving data through services and did not communicate directly with the view. The only communication was through the model, that we dubbed as state.
The view was bound to this state class, which could indeed be seen as a viewmodel-model (see Dan Creviers posts on this subject here). We kept the view as dumb as possible and only let it decide on view specific things, never implementing logic. This means, that the controller could decide when a particular state was prudent (for instance, 'this item is on sale'), but the view gets to decide how to present that item to the world ('wow, I'm going to turn the background to yellow').
The codebehind of the view was only a translation layer between the WPF specific calls (events defined in Xaml) and calls to the controller.

This worked great for us, although in hindsight, we did find that the whole solution was a bit over-the-top. We stuck with it though, and I think it worked out well enough. I feel we could have done without the workitems (in our approach atleast).

Since I'm on sabbatical now, I've been reflecting somewhat more on this issue and found a series of incredible posts by Jeremy Miller on how to build your own CAB. Basically, he points out that it's not that hard to implement MVP in your application by building the pieces you need yourself. The upside would be that CAB is a big monster (I completely agree here),not worthy to be used in your kick-ass application (my own interpretation ;-) ) and building the components you need yourself would buy you a much more lightweight system custom fitted to your problem domain.

While reading all of his posts, I kept feeling that most of what is needed for building a more loosely coupled system is already provided by WPF. The resources system is a possible way to inject dependencies and retrieve them. The routed events and usage of commands is also great. Then just now I've found a post which proves that I am right (and the rest of the world is wrong ;-) ) written by Josh Smith himself, a notable wpf blogger. He shows how he actually uses the resources system to inject classes and even mocks.

My main interest at this moment is to decide how to build big systems with big teams and offer tangible guidance on that subject. One of the most important aspects of that is to Keep It Simple, Stupid! I saw that my team was strugling a bit with bending their minds around the whole MVC concept. This might be attributed to lacking explanations by myself, but at the very least, it was also caused by the feeling it brought-in more complexity then it took away. Certainly the less experienced of the team did not feel the de-coupling was worth it. That is why Jeremy's stand on this felt so 'right' for me. I do think that a simpler solution then CAB would be great.

However, Joshes solution does feel a bit contrived to me. A view would indeed be able to find it's presenter(s), but how does the presenter find it's services? Will they also be defined within the resources? Could be. I find some piece of inversion of control is a more straight forward way to configure your components than 'misusing' the resources functionality. Because that's basically what is being done here.
Keep in mind though, that it is mighty handy to be able to use the injected components within the userinterface without having to do weird things. Say you have an 'edit' button and a controller that was created to manage these things. Your view will want to bind the 'enabled' property to that controller. If it was injected somehow behind the scenes, you will have to find a way to bring it into scope for the button.
We solved this, but it's not pretty!

Another solution being worked on is a WPF specific MVC platform by Rob Eisenberg: Caliburn. His solution does tackle one important issue I have with current systems, which is the communication between the view and the controller. He introduces 'ActionMessages' which can be used in xaml like so:

  1.       <Button Content="="    
  2.               Margin="3">    
  3.          <Engine:Views.AddMessageSource>    
  4.             <Engine:ActionMessage Trigger="Click"    
  5.                                   Action="Divide"    
  6.                                   Return="{Binding ElementName=result, Path=Text}">    
  7.                <Engine:Parameter Value="{Binding ElementName=leftSide, Path=Text}" />    
  8.                <Engine:Parameter Value="{Binding ElementName=rightSide, Path=Text}" />    
  9.             </Engine:ActionMessage>    
  10.          </Engine:Views.AddMessageSource>    
  11.       </Button> 

When the button is clicked, the method 'Divide' will be called on your controller, with two parameters. It's return value will be bound to the result textbox.

Talk about a great idea!! He has used this framework for great succes and I can see why. Incredibly powerful.

However, it does bring in yet another mechanism unfamiliar to your teammembers. Probably worth it though, I'm looking forward to delving into the project and using it myself.
I don't like the introduction of yet another class of things that can go wrong at runtime though: the Action method (here: Divide) should exist on your presenter. If it's not, I'm sure you will only get an error at runtime. As if the binding syntax wasn't enough ;-)

All in all, it seems there is lots of movement in the Microsoft community. People have been thinking about how to build userinterfaces for a long time, and I'm happy to see that this is also the case in the .Net world and very happy to see movement in the WPF camp on this front.

More on this soon!

Tuesday, January 29, 2008 12:19:38 AM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback