Blue Theme Orange Theme Green Theme Red Theme
 
Home | Forums | Videos | Photos | Downloads | Blogs | Interviews | Jobs | Beginners | Training
 | Consulting  
Submit an Article Submit a Blog 
 Login Close
User Id:
Password:
 
Forgot Password
Forgot Username
Why Register
 Jump to
Skip Navigation Links
TechnologyExpand Technology
WebsiteExpand Website
 Resources  
Close
 Our Network  
Close
Search :       Advanced Search »
Home » ASP.NET MVC & JQuery » MVP (Model View Presenter) – Supervising Controller.

MVP (Model View Presenter) – Supervising Controller.

This articles discusses a general implementation of the Supervising Controller MVP (Model View Presenter) pattern for a win-forms application and the use of a dialog broker to allow pulling additional logic into the controller class.

Author Rank:
Total page views :  9767
Total downloads :  362
   Print Read/Post comments Post a comment  Similar Articles  
   Email to a friend  Bookmark  Author's other articles  
Download Files:
SupervisingControllerSampleCode.zip
 
Become a Sponsor



Intro:
The Model-View-Control (MVC) was a breakthrough in its time and changed the way UI development was approached.  It provided a clean boundary between the core domain logic and the presentation logic.  Now, there are many descendants of the MVC pattern that accomplish this same goal.  One variation is the Model View Presenter (MVP) which has several different approaches, most of which differ in the amount of responsibility of the control.  We'll look at using the Supervising Controller which takes responsibility for the complex user interaction but tries to stay out of the way most of the time leaving the view to update itself through binding.  The Supervising Controller will step in when there is complex view logic.
If you are not familiar with the MVC pattern, check out my article here:  http://www.c-sharpcorner.com/UploadFile/rmcochran/MVC_intro12122005162329PM/MVC_intro.aspx
 A pure MVC implementation keeps all UI logic in the view.  The Supervising Controller pattern varies a bit in that we allow the view and the model to interact through binding mechanisms but try to move any complex UI logic into the controller.  When the model changes the view is notified through the bindings and updates itself.  We can manually code some extra binding functionality beyond what is already available in order to really make this pattern shine.  We try to keep the Control out of the way most of the time and after binding, just use it to handle requests that require complex UI interaction that can't be dealt with through binding alone.  The view is able to update itself by listening to changes in the model.  The Control also serves to encapsulate as many of the interactions with the user as possible.  This gives us the opportunity to separate out most (if not all) of the required validation logic and user interactions into the Control which we can then pin down with unit tests.   It would be possible to have the view update the model with a declarative syntax which I'll demonstrate in an upcoming article.

Setting up the model:
In order to use this pattern, the model must be constructed so that it broadcasts any state change so they can be bound to the view.  The System.ComponentModel namespace has most of the functionality we will need in order to wire up state changes on our classes, primarily by implementing the INotifyPropertyChanged interface.

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);


The PropertyChangedEventArgs just tells us which property changed:

public class PropertyChangedEventArgs : EventArgs
{
    public PropertyChangedEventArgs(string propertyName);
    public virtual string PropertyName { get; }
}



We'll implement this interface on our domain objects for each property that has a getter and on any methods that change the state of our object's properties.

public class Programmer : INotifyPropertyChanged
{
    #region Constructors
 
    public Programmer(string name)
    {
        m_Name = name;
    }
 
    #endregion
 
    #region Member Variables
 
    private event PropertyChangedEventHandler
        m_PropertyChanged;
 
    private string
        m_Name;
 
    #endregion
 
    #region Properties
 
    public string Name
    {
        get { return m_Name; }
        set
        {
            if (m_Name == value) // guard clause
                return;
 
            m_Name = value;
            FirePropertyChanged("Name");
        }
    }
 
    #endregion
 
    #region Methods
 
    private void FirePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler safeHandler = m_PropertyChanged;
 
        if (null != safeHandler)
            safeHandler(this, new PropertyChangedEventArgs(propertyName));
    }
 
    #endregion
 
    #region INotifyPropertyChanged Members
 
    public event PropertyChangedEventHandler PropertyChanged
    {
        add { m_PropertyChanged += value; }
        remove { m_PropertyChanged -= value; }
    }
 
    #endregion
}


For exposing collections that can be monitored through a standard event, we'll add a reference to Windows.Base in order to get a reference to the ObservableCollection class. 

The ObservableCollection implements the INotifyCollectionChanged event:

public interface INotifyCollectionChanged
{
    event NotifyCollectionChangedEventHandler CollectionChanged;
}

public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e);


The NotifyCollectionChangedEventArgs holds all the state change information we would need for our view to update itself when it captures the event:

public class NotifyCollectionChangedEventArgs : EventArgs
{
    public NotifyCollectionChangedAction Action { get; }
    public IList NewItems { get; }
    public int NewStartingIndex { get; }
    public IList OldItems { get; }
    public int OldStartingIndex { get; }
}


I usually like to use an abstraction on top of this so we aren't bound to a particular implementation.

public interface IObservableCollection<T> :
    ICollection<T>,
    INotifyCollectionChanged,
    INotifyPropertyChanged
{
}


 Now we can easily create a class that implements our new interface by using the ObservableCollection and we have minimal code required to consume an abstraction of the ObservableCollection's functionality .

public class ModelCollection<T> : ObservableCollection<T>, IObservableCollection<T>
{
    public ModelCollection() : base() { }
    public ModelCollection(List<T> source) : base(source) { }
}



More Binding, Please:

To help our controller shine we'll extend some binding mechanisms by defining a IBindable<T> interface.  This will keep our code structured and consistent and (hopefully) provide 90% of the hooks we need for the controller to control the views.  We want to rely primarily on this binding interface for the controller to push data down to a coarse façade of the view where it will be distributed to widgets (controls) implementing the same interface.

public interface IBindable<T>
{
    void Bind(T value);
}


We'll be building reusable view components that implement IBindable<T> so our coarse form façade can pass the bindings to our widget.  For instance here is a BindableMenuItem<T> that we could reuse across multiple projects.  When we bind to a generic object we'll check if it broadcasts changes to its state by seeing if it implements NotifyPropertyChanged.  If so, we'll wire up the events so we know when to change how our bound object is displayed.

public class BindableMenuItem<T>:MenuItem, IBindable<T>
{
    public BindableMenuItem(T boundInstance)
    {
        Bind(boundInstance);
    }
 
    private T
        m_BoundInstance;
 
    public T BoundInstance
    {
        get { return m_BoundInstance; }
        internal set { Bind(value); }
    }
 
    #region IBindable<T> Members
 
    public void Bind(T value)
    {
        if (null != m_BoundInstance)// already bound to another object... need to unwire first
            Unwire(m_BoundInstance);
 
        if (null != value)
            Wire(value);
    }
 
    protected virtual void Unwire(T value)
    {
        INotifyPropertyChanged notifier = value as INotifyPropertyChanged;
 
        if (null == notifier)
            return;
 
        notifier.PropertyChanged -= BoundInstance_PropertyChanged;
    }
 
    protected virtual void Wire(T value)
    {
        m_BoundInstance = value;
 
        SetText();
 
        INotifyPropertyChanged notifier = value as INotifyPropertyChanged;
 
        if (null == notifier)
            return;
 
        notifier.PropertyChanged += BoundInstance_PropertyChanged;
    }
 
    private void SetText()
    {
        this.Text =  m_BoundInstance.ToString;
    }

 
    protected virtual void BoundInstance_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == m_BoundPropertyName)
            SetText();
    }
 
    #endregion
}


A MenuItem is not normally an item we could bind,  but when we create a derived class that implements IBindable<T> in order to provide a binding mechanism.  I have found using the pattern of having virtual Wire() and Unwire() methods that are executed from inside the interface's Bind() methods allows us to extend the functionality even further if we need to later on.  If you download the code for this article, you'll see that the BindableTreeNode<T> class works in this way when it is extended by the ProgrammerTreeNode class in order to populate the child nodes.
The Supervising Controller pattern works very well when the view we bind to is very coarse (like at the form level).  These high-level binding surfaces act as a Façade and distribute the binding to all of the children components (the widgets/controls in the form).  This way we only really need one Supervising Control per coarse form which reduces object bloat in our project.  This also allows for only the view to be aware of its structure which is now hidden from the control and model so it is much more flexible.  We also keep the control dealing with a relatively light interface with a limited surface are that primarily needs to know how to push the model to the view through our binding mechanism (IBindable<>). 

public interface IConventionView:
    IBindable<Programmer>,
    IBindable<IObservableCollection<Programmer>>
{
}


Sadly, there are sometimes a few more functional stubs we have to put on the view to control view behavior that cannot be accessed through binding alone.  In order to keep the code maintainable, the goal should be to keep coupling and our view surface are to a minimum, ideally just through the IBindable<> interface where we pass objects that the view can get change notifications from.  
When we do have to expand our surface are on our view for the controller to hook into the view, we need to be sure the abstractions are on the level of the user interactions and not form-specific in order to keep everything at a consistent level of abstraction and not code directly against form widgets (like buttons).  For instance, if we need to disable a button, it is better to have a method on the view called "DisablePersonRemoval()" rather than "DisableXYZButton()" so we are not syntactically tied to any particular implementation.
The different kinds of reusable bindable widgets are pretty much endless but some are more reusable than others.  I have put together a few for this article to get you started and they are included with the code.
Interacting with the User:
A large portions of the Interactions with the user can be moved to the supervising controller and modeled with a dialog Pub-Sub (publish-subscribe) object that I'll go over in a bit that will serve as a message broker.  The dialog broker is not part of the Supervising Controller pattern, but I have found having a dialog broker to be extremely useful.  This allows us to further isolate the view from any user interaction logic having to do with interacting with the user such as confirmations and validation.  The Supervising Controller can now interact with the view by initiating requests instead of just responding to user input.   This way, more of our code is testable and it makes the view even lighter.

The interface for the dialog broker is below.  We'll code against the interface to this object so we can change implementation later and can stub out unit tests using the inversion of control pattern (dependency injection) and mock objects.  This is one of the cases where I would choose to expose an interface in addition to providing the class encapsulating the functionality.  This is because the dialog broker is non-domain specific and the surface area and functionality will be relatively stable.  I don't foresee any changes to this object.  I also want to be able to mock this object for testing and basically be able to mock every single method so will code against the interface rather than against an abstract class.

public interface IDialogBroker
{
    void RegisterNotifier<TMessage>(Action<TMessage> onNotify);
    void RegisterResponder<TRequest, TResponse>(Func<TRequest, TResponse> onGetResponse);
 
    void SendNotification<TMessage>(TMessage message);
    TResponse RequestResponse<TRequest, TResponse>(TRequest message);
 
    Boolean HasRegisteredResponder<TRequest, TResponse>();
    Boolean HasRegisteredNotifier<TMessage>();
}


Using the dialog broker allows us to build some reusable dialog widgets for registration with the broker's requests and/or messages.   To me this is a huge bonus because the pattern promotes building reusable view components for registering with the broker that can be used in other projects and reduce coding time.   
When the Form instantiates (our coarse view) when we would instantiate the new controller and register all the interactions the broker needs to handle.  The downside of using the dialog broker is that it must be aware of all the objects that need to be registered in order for the view to function.  I think this is a worthwhile tradeoff if we can keep the number of dialogs to a minimum by ensuring they are non-domain specific.  Anything more complex should be handled by another view with its own supervising controller.  If we don't allow the number or complexity of dialogs to get out of hand, we should be fine.

public partial class Form1 : Form, IConventionView
{
    public Form1()
    {
        InitializeComponent();
       
        m_DialogBroker = new DialogBroker();
        m_Controller = new ConventionSupervisingController(m_DialogBroker, this);
 
        #region Broker Registration
 
        m_DialogBroker.RegisterResponder<String, Boolean>(msg => MessageBox
Show(msg, msg, MessageBoxButtons.YesNo) == DialogResult.Yes);


        m_DialogBroker.RegisterResponder<SelectorRequest<Programmer>, Programmer[]>(request =>
        {
            SelectorDialog<Programmer> selector = new SelectorDialog<Programmer>();
            selector.Bind(request);
            selector.ShowDialog();
            return selector.GetSelection().ToArray();
        });

        m_DialogBroker.RegisterNotifier<String>(msg => MessageBox.Show(msg));

        m_DialogBroker.RegisterResponder<String, StringVerification>(msg =>
        {
            StringVerifierDialog selector = new StringVerifierDialog();
            selector.Bind(msg);
            selector.ShowDialog();
            return selector.GetResponse();
        });

        #endregion
    }
 
    private readonly DialogBroker
        m_DialogBroker;
 
    private readonly ConventionSupervisingController
        m_Controller;
}


Supervising Changes:
The view keeps a reference to the supervising controller and will use it to make change requests.  The controller will handle any dialog necessary with the user to make the change and update the model.

public class ConventionSupervisingController
{
    IDialogBroker DialogBroker { get; set; }
    void AddProgrammer();
    void ChangeSelectedProgrammerName(String newName);
    void AddFriendToSelectedProgrammer(Programmer newFriend);
    void RemoveFriendFromSelectedProgrammer(Programmer removedFriend);
    void AddFriendsToSelectedProgrammer();
    void RemoveFriendsFromSelectedProgrammer();
    void SelectProgrammer(Programmer dude);
}


Again this pattern works very nicely when the form acts as a façade and handles all the widget events that bubble up and sends change requests to the Control.  This makes our user interactions very testable.  We can set the DialogBroker so it acts as a Strategy pattern so in addition to changing how individual dialogs are handled we could change the whole broker on the fly.
Our supervising controller interacts with the dialog broker (and thus the view) by firing off notifications or requesting responses.  For example, here's the implementation for AddProgrammer() method.  You can see how we can model user interactions using the dialog broker in this way so our code is testable.  After the controller is satisfied that all requirements are met through the dialog with the user the broker updates the model.  The model then broadcasts its state change and the view will be updated.

public void AddProgrammer()
{
    StringVerification         response = m_DialogBroker.RequestResponse<String StringVerification>("What is the new programmers name?");
 
    if (!response.Verified)
    {
        m_DialogBroker.SendNotification("Action canceled");
        return;
    }
 
    if (String.IsNullOrEmpty(response.ResponseMessage))
    {
        m_DialogBroker.SendNotification("Invalid name.  Programmer will not be added");
        return;
    }
 
    Programmer newProgrammer = new Programmer(response.ResponseMessage);
 
    m_Convention.Add(newProgrammer);
 
    SelectProgrammer(newProgrammer);
}


In summary: The control encapsulates a large part of the user interactions and validation.  The view just handles changes to bound objects.  Our model is not polluted by any display logic because the control handles everything that is in the "grey" are between the UI and our model.
The Concrete Dialog Broker:
Our concrete dialog broker is a type-safe wrapper around non-type-safe code.  At its core are a couple of (non-type-safe) dictionaries that serve as lookups for the specific type of message being sent to the view or the type of request/response.  When we retrieve the registered notification or request/response object, we know the type of object that is returned (either an  Action<TMessage> in the case of a notifier, or a Func<TRequest, TResponse> in the case of a request/response) because we control the types that get put into our lookups.   

public class DialogBroker : IDialogBroker
{
    public DialogBroker()
    {
        m_NotifierLookup = new Dictionary<Type, object>();
        m_RequestResponseLookup = new Dictionary<Type, Dictionary<Type, object>>();
    }
 
    private readonly Dictionary<Type, Object>
        m_NotifierLookup;
 
    private readonly Dictionary<Type, Dictionary<Type, Object>>
        m_RequestResponseLookup;
 
    #region IMessageBroker Members
 
    public void RegisterNotifier<TMessage>(Action<TMessage> onNotify)
    {
        Type t = typeof(TMessage);
 
        if (m_NotifierLookup.ContainsKey(t))
            m_NotifierLookup[t] = onNotify;
        else
            m_NotifierLookup.Add(t, onNotify);
    }
 
    public void RegisterResponder<TRequest, TResponse>(Func<TRequest, TResponse> onGetResponse)
    {
        Type
            requestType = typeof(TRequest),
            responseType = typeof(TResponse);
 
        // nothing has been registered for a request type
        if (!m_RequestResponseLookup.ContainsKey(requestType))
        {
            m_RequestResponseLookup.Add(requestType, new Dictionary<Type, object>());
            m_RequestResponseLookup[requestType].Add(responseType, onGetResponse);
            return;
        }
 
        // request type has been registered, but not the response type
        if (!m_RequestResponseLookup[requestType].ContainsKey(responseType))
        {
            m_RequestResponseLookup[requestType].Add(responseType, onGetResponse);
            return;
        }
 
        // both request and response types have been registered... this is a replacement
        m_RequestResponseLookup[requestType][responseType] = onGetResponse;
 
    }
 
    public void SendNotification<TMessage>(TMessage message)
    {
        Type t = typeof(TMessage);
 
        (m_NotifierLookup[t] as Action<TMessage>)(message); // call the method
    }
 
    public TResponse RequestResponse<TRequest, TResponse>(TRequest message)
    {
        #region Validation
 
        return (m_RequestResponseLookup[typeof(TRequest)][typeof(TResponse)] as Func<TRequest, TResponse>)(message);
    }
 
    public bool HasRegisteredResponder<TRequest, TResponse>()
    {
        Type
            requestType = typeof(TRequest),
            responseType = typeof(TResponse);
 
        if (!m_RequestResponseLookup.ContainsKey(requestType))
            return false;
 
        if (!m_RequestResponseLookup[requestType].ContainsKey(responseType))
            return false;
 
        return m_RequestResponseLookup[requestType][responseType] != null;
    }
 
    public bool HasRegisteredNotifier<TMessage>()
    {
        Type t = typeof(TMessage);
 
        return
            m_NotifierLookup.ContainsKey(t) &&
            m_NotifierLookup[t] != null;
    }
 
    #endregion
}


The Supervising Controller as a State or Strategy Pattern.


We might need the functionality to change the controller on the fly (strategy pattern) or set the behavior of our app when the application starts (state pattern). This would be good for scenarios where we have different users with different levels of access to our model.  Some users may have access to the complete functionality of the app while some may be very limited in how they can interact with the model.  If our control has all virtual methods, we can just override some of our controller's methods and have a new set of functionality.

public class LimitedConventionSuervisingController : ConventionSupervisingController
{
    public LimitedConventionSuervisingController(IDialogBroker broker, IConventionView view)
        : base(broker, view)
    {
        view.AddMemberEnabled = false;
    }
 
    public override void AddProgrammer()
    {
        DialogBroker.SendNotification("Hey Dude... you are not allowed to do this");
    }
}


Then our controller could be chosen with a factory that takes advantage of our dialog broker to get login information.

public static class SupervisingControllerFactory
{
    public static ConventionSupervisingController Build(IDialogBroker broker, IConventionView view)
    {
        String name = broker.RequestResponse<String, String>("What is your name, my friend?");
 
        if(name.Equals("Dude", StringComparison.OrdinalIgnoreCase))
            return new ConventionSupervisingController(broker, view);
 
        broker.SendNotification("Only 'Dude' can add people... since you are a visitor here you can't");
 
        return new LimitedConventionSuervisingController(broker, view);
    }
}


 And we'll fire off the factory in the constructor of the form to retrieve the appropriate level of access for the user.

public Form1()
{
    InitializeComponent();
   
    m_DialogBroker = new DialogBroker();
 
    #region Broker Registration
    #endregion
 
    m_Controller = SupervisingControllerFactory.Build(m_DialogBroker, this);
 
}


Wrap-up:
Take a look at the attached code for a full example of how to wire up a supervising controller, extend some more simple widgets for binding and see the implementation for our concrete DialogBroker.  The sample has a UI for interacting with a simple model that keeps track of people at a convention and who their friends are.
To select a person, we just click on a node in the tree.

If we change the name of any person, all the view elements displaying that name will automatically update through binding.

I we change the list of friends for any person, the tree will automatically update through binding.

Hopefully this simple UI demonstrates how nice it is to keep the model, view and UI logic separated so we have flexibility to easily change the behavior of our application.
I hope you found this article and the attached code useful.
Until next time,
Happy Coding


Login to add your contents and source code to this article
 About the author
 
Matthew Cochran
Looking for C# Consulting?
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional consulting company, our consultants are well-known experts in .NET and many of them are MVPs, authors, and trainers. We specialize in Microsoft .NET development and utilize Agile Development and Extreme Programming practices to provide fast pace quick turnaround results. Our software development model is a mix of Agile Development, traditional SDLC, and Waterfall models.
Click here to learn more about C# Consulting.
 
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
Go.NET
Build custom interactive diagrams, network, workflow editors, flowcharts, or software design tools. Includes many predefined kinds of nodes, links, and basic shapes. Supports layers, scrolling, zooming, selection, drag-and-drop, clipboard, in-place editing, tooltips, grids, printing, overview window, palette. 100% implemented in C# as a managed .NET Control. Document/View/Tool architecture with many properties&events. Optional automatic layout.
Dundas Software
Dundas Chart for .NET is the most advanced .NET charting package available today.  With an extremely complete feature set, elegant architecture and easy implementation, Dundas Chart can quickly add advanced Charting functionality to enhance and transform ASP.NET and Windows Forms applications.  Whether you are implementing charting into internal projects, or building applications for clients, Dundas Chart offers advanced technology and advanced results to get the most out of data.
Clickatell's SMS Gateway
Clickatell's Developer Solutions allow you to SMS enable any website or application via a range of API's. Learn More about our API connections.
Free access to .NET Memory Management video
Everything you need to know about Garbage Collection, Temporary Objects, Fragmentation, Finalization and common causes of memory leaks in .NET. Watch the video here.
Microsoft Visual Studio 2010 Professional
Microsoft Visual Studio 2010 Professional will launch on April 12, but you can beat the rush and secure your copy today by pre-ordering at the affordable estimated retail price of $549 (US). Pre-order now.
Nevron Chart for .NET 2010.1 Now Available
The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
Developer-Ready ASP.NET 2.0 Web Hosting with 3 MONTHS FREE
Now supporting .NET 3.0 Framework with Windows Workflow Foundation, Windows Communication Foundation (WCF), Windows Presentation Foundation (WPF), windows CardSpace (WCS)! Providing more flexibility for Developers with Web Services Support and a User/Permission Manger. Also supporting MS SQL 2005/2000 with Real-Time Backups, FREE Automated Attach .MDF Tool, FREE SQL Restore and Shrink SQL DB Tools, and SQL
 
   Print Read/Post comments Post a comment  Similar Articles  
   Email to a friend  Bookmark  Author's other articles  
Download Files:
SupervisingControllerSampleCode.zip
 
 Post a Feedback, Comment, or Question about this article
Subject:  
Comment:  
Become a Sponsor
 Comments
Pictures are broken by Artyom On June 30, 2009
Best regards, Artyom.
Reply | Email | Delete | Modify | 
Nice article by Evg On August 15, 2009
ty, very usefull
Reply | Email | Delete | Modify | 

 Hosted by MaximumASP  |  Found a broken link?  |  Contact Us  |  Terms & conditions  |  Privacy Policy  |  Site Map  |  Suggest an Idea  |  Media Kit
Current Version: 5.2009.6.2
 © 2010  contents copyright of their authors. Rest everything copyright Mindcracker. All rights reserved.