This page is an archive of my old blog. Please visit for my current blog.
This site is no longer being maintained and commenting is disabled.

Getting Started with Cairngorm – Part 4

The basic Cairngorm Event Flow that is handled in Part 3 is essential to any Cairngorm application, but most applications interact with a server. The Service to Worker pattern that was discussed in the previous tutorial is essential to this process. To learn the expanded Cairngorm Flow, you will need to learn a few new Cairngorm elements.

The Server Interaction Elements

There are three new types of classes that you will need to be familiar with to understand the full Service to Worker Pattern.

  • ServiceLocator [Reference] - The ServiceLocator is a singleton that contains references to all of the services that your application will use. It usually includes HTTPService, WebService, or RemoteObject calls.
  • Business Delegate - A Business Delegate has three functions: to locate the service that is needed, to call a method on the service, and to route the result to the specified responder. There is usually one Business Delegate for each service.
  • Value Object - Value Objects are classes that by definition do not require any methods, only properties. They allow for the application to transfer strongly-typed complex data objects to and from the server.

Organizing Your Cairngorm Project (With Server Interaction)

In the last tutorial you saw the standard Cairngorm structure for a project. To complete this structure, you will need to add an additional two folders:

  • /business - This folder typically contains two types of files: the ServiceLocator (named Services.mxml) and Business Delegates.
  • /vo - This folder contains the value objects that are passed to and from the server.

Understanding the Process

Before you begin crafting the server interaction for your project, you need to understand the full Service to Worker pattern. Figure 1 illustrates the entire process.

Full Cairngorm Diagram Final

Figure 1 - Cairngorm Event Flow with Server Interaction

Phase I - Execution Phase

  1. The user is viewing a component that has a login button. When the button is clicked, that component would dispatch an event named LoginEvent that extends CairngormEvent.
  2. The FrontController would receive the LoginEvent and execute the command that is mapped to that event. For this example, it will be named LoginCommand and will implement ICommand.
  3. The Command is executed and received the LoginEvent as an argument. The LoginCommand creates an instance of the Delegate while passing a reference to the Responder. The Command then calls the specified method on the Delegate.
  4. The Delegate gets the service from the ServiceLocator and calls the method on the specific service.
  5. The service defined in the ServiceLocator receives the information that is passed to it from the call in the Delegate.

Phase II - Application Tier Processing

Phase III - Response Phase

  1. The service that is defined in the ServiceLocator returns the result of the server-side processing.
  2. The Delegate receives the result and passes it to the specified responder.
  3. The Responder receives the result indicating a successful login.
  4. The ModelLocator will have a predefined constant for the "Logged in View". The Responder will change workflowState to this value.
  5. Since the view is bound to workflowState, it will automatically update itself to the new view.

Note: Traditionally the Command and Responder were the same class in a Cairngorm application. If you are working with other developers, the applications will probably be coded in this manner. However, most developers (including Adobe Consulting) are now separating these classes into two different classes. For a less complex project, it might not make sense to separate these items, but in a large application it could prove advantageous in organization and practice to have two different classes.

The ServiceLocator

The ServiceLocator is a singleton that contains references to all of the services that the application will be using. These services can be RemoteObjects, HTTPServices, WebServices, or custom services. Like the FrontController, this class is usually instantiated in your main application file. Unlike many of the other Cairngorm project assets that you have created, this class can be defined in MXML (as well as ActionScript). To properly define this in MXML, there must be a namespace that points to the business folder of the Cairngorm package. In this case the namespace cairngorm is typically used. The ServiceLocator in Code Example 1 has one service defined, loginService.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <cairngorm:ServiceLocator
  3.     xmlns:cairngorm="*"
  4.     xmlns:mx="">
  6.     <!-- Login Service -->
  7.     <mx:RemoteObject id="loginService"
  8.         showBusyCursor="true"
  9.         destination="ColdFusion"
  10.         source="CairngormTest.CairngormLogin">
  12.         <mx:method name="login" /> 
  14.     </mx:RemoteObject>
  16. </cairngorm:ServiceLocator>

Code Example 1 - Sample ServiceLocator

The ServiceLocator is typically named Services.mxml and resides in the business folder of your Cairngorm project.

Commands with Server Interaction

In the last tutorial you hard-coded some values into the LoginCommand to check for a specific username and password. Here was the execute method:

  1. public function execute(event:CairngormEvent):void {
  2.     var loginEvent:LoginEvent = event as LoginEvent;
  3.     if( (loginEvent.username == "david") && (loginEvent.password == "password")) {
  4.         modelLocator.workflowState = ViewModelLocator.WELCOME_SCREEN;
  5.     }
  6. }

Code Example 2 - Command Without Delegate

This methodology will hold true for any Command that doesn't have server interaction, but if you do have server interaction, it will need to be modified to include the delegate. First, you will need to make a decision. As stated earlier, you can have separate Commands and Responders, or they can be the same class. For this example, they will be the same class. The Command will now also need to implement the mx.rpc.IResponder class (please note that is deprecated and should no longer be used).

The other initial change is that the execute method now instantiates a class named LoginDelegate (which will be created shortly). The LoginDelegate class required one argument in its constructor, the Responder of the service. In this case, the Command will function both as the command and the responder, so you simply need to insert the this keyword inside the parenthesis. If you chose to have a separate responder, you would insert the reference to it here (instead of the this keyword).

  1. package net.davidtucker.CairngormSample.commands {
  3.     import com.adobe.cairngorm.commands.ICommand;
  4.     import com.adobe.cairngorm.control.CairngormEvent;
  5.     import mx.controls.Alert;
  6.     import mx.rpc.IResponder;
  7.     import;
  8.     import;
  9.     import net.davidtucker.CairngormSample.model.ViewModelLocator;
  11.     public class LoginCommand implements ICommand,IResponder {
  13.         public var modelLocator:ViewModelLocator = ViewModelLocator.getInstance();
  15.         public function LoginCommand() {
  16.         }
  18.         public function execute(event:CairngormEvent):void {
  19.             var loginEvent:LoginEvent = event as LoginEvent;
  20.             var delegate:LoginDelegate = new LoginDelegate( this );
  21.             delegate.login(loginEvent.loginAttempt);
  22.         }
  24.         public function result( event:Object ):void {
  25.             if(event.result == true) {
  26.                 modelLocator.workflowState = ViewModelLocator.WELCOME_SCREEN;
  27.             } else {
  28.       "Password Incorrect","ERROR");
  29.             }
  30.         }
  32.         public function fault( event:Object ):void {
  33.             trace("Service Error");
  34.         }
  36.     }
  37. }

Code Example 3 - Command with Server Interaction Through a Delegate

Value Objects

A Value Object does not extend or implement any Cairngorm class. As stated earlier, it simply is a class that is only required to have properties, but not methods. For example, if you created a Value Object for a Login - it would have a property for username and a property for password.

  1. package net.davidtucker.CairngormSample.vo {
  3.     [RemoteClass(alias="CairngormTest.LoginVO")]
  4.     public class LoginVO {
  6.         public var username:String;
  7.         public var password:String;
  9.         public function LoginVO(username:String,password:String) {
  10.             this.username = username;
  11.             this.password = password;
  12.         }
  14.     }
  15. }

Code Example 4 - Value Object for Login

The RemoteClass metatag is important to note. This will allow the corresponding server-side object (ColdFusion Component, PHP Class, Java Class, etc...) to be mapped to this Value Object. In this case, it is mapped to a ColdFusion component named LoginVO in the CairngormTest folder.

Business Delegates

The final design pattern in the Cairngorm Micro-Architecture is the Business Delegate. A Business Delegate essentially is the abstraction layer between your services and the rest of your application. As stated earlier, it has three functions. First, the Business Delegate will locate the service that is needed in the ServiceLocator. Second, it will call a method on that service. Finally, it will route the response back to the specified responder (usually either a command or separate responder).

A Delegate class doesn't extend or implement and Cairngorm classes, but it generally follows the following guidelines.

  • The Delegate has at least two properties: one named service which is a reference to a service in the ServiceLocator and one named responder which is the responder for the service calls.
  • There is a method for each server-side method that you will be calling.
  • Both the responder and the service variables are set in the constructor.
  1. package {
  3.     import mx.rpc.IResponder;
  4.     import net.davidtucker.CairngormSample.vo.LoginVO;
  5.     import;
  7.     public class LoginDelegate {
  8.         private var responder : IResponder;
  9.         private var service : Object;   
  11.         public function LoginDelegate( responder:IResponder ) {
  12.             this.responder = responder;
  13.             this.service = ServiceLocator.getInstance().getRemoteObject("loginService");
  14.         }
  16.         public function login(login:LoginVO):void {
  17.             var call:Object = service.login( login );
  18.             call.addResponder( responder );
  19.         }
  21.     }
  22. }

Code Example 5 - Service Delegate

There are many benefits to having this layer. If coded correctly, you should be able to change out the server interaction (going from PHP to ColdFusion for example) and only have to change the code in your ServiceLocator and your Delegate. You also can easily insert "stub code" to simulate the actual server interaction during the early stages of development.

The Application Tier

In this example, the Application Tier will be handled by a ColdFusion 8 installation. It will contain two Coldfusion components. These components are purposefully simple.

  1. LoginVO.cfc - This component will correspond to the ActionScript class LoginVO that you created earlier.
  2. CairngormLogin.cfc - This component will perform the actual login processing.

In this example, the Flex application will pass a LoginVO ActionScript object to the CairngormLogin.cfc's login method through a RemoteObject call. This will be mapped to a LoginVO.cfc object. If this LoginVO.cfc object has the username "david" and the password "password" the method will return true. If not, it will return false.

  1. <cfcomponent displayname="LoginVO" hint="Login VO For CairngormTest" output="false">
  3.     <cfset this.username = "" />
  4.     <cfset this.password = "" />
  6. </cfcomponent>

Code Example 6 - LoginVO.cfc

  1. <cfcomponent displayname="CairngormLogin" hint="CFC to Test Cairngorm Service Interaction" output="false">
  3.     <cffunction name="login" displayname="login" access="remote" output="false" returntype="boolean">
  4.         <cfargument name="loginAttempt" type="LoginVO" required="true" />
  6.             <cfif (loginAttempt.username EQ "david") AND (loginAttempt.password EQ "password")>
  7.                 <cfreturn true />
  8.             <cfelse>
  9.                 <cfreturn false />
  10.             </cfif>
  12.     </cffunction>
  14. </cfcomponent>

Code Example 7 - CairngormLogin.cfc

Application Code
Download (11 Kb)

Looking Ahead

There are only two tutorials remaining in the Cairngorm series. In the next tutorials you will learn about code generation options for Cairngorm, and you will also build an actual application using Cairngorm.


The following resouces should assist you in getting Flex connected to your application server.

71 Responses to “Getting Started with Cairngorm – Part 4”

  1. David – I’m really enjoying this series. Keep up the good work – you’re helping a lot of people!

  2. David Tucker says:

    Thanks Jim! It is always encouraging to hear that people are benefiting from these tutorials.

  3. Joe rinehart says:


    This is a great series! Thanks for the note about folks separating the Command and the IResponder used. It’s bugged the heck out of me for a long time that they’re often one and the same, because it destroys a good deal of portability (a responder to a PHP-based XML service is likely to have to do different things than a responder to a CF-based AMF service!).

    One approach I’ve taken (posting to ask for your thoughts, not to suggest a reference model) that cuts down a bit on the number of classes is to go ahead and implement IResponder in the command (keeping the “unit of work” on both side of an sync request in one class), but to require it to only deal in domain object / vos of the application.

    In the delegate’s service invocation, the delegate creates its own Responder instance pointing to result/fault methods for the operation invoked. They’re responsible for handling the raw response (such as morphing XML results to VOs) then passing the (massaged) response back up the chain to the command itself. Any thoughts on that?

  4. Tony Chang says:

    It is the best tutorial for cairngorm in the net.Thanks a lot.


  5. David Tucker says:

    @Joe – Just to give a heads up, one of the next two tutorials will deal with “Best Practices”. This is one of the items that I will cover – and I will use a very similar method to what you are describing.

    Specifically, I create a Factory (generally one per data source) that has methods to transform my server side data into the VO or a Model object of the application. These factories are called by the response methods inside of the Delegate. This “massaged” data is passed to the Command responder (as you described). This is the best way that I have found to create an application where you truly can switch the server-side implementation without recoding both the Commands and Delegates.

    @Tony – Thanks! As I said earlier, it is great to hear that people enjoy (and can use) these tutorials.

  6. [...] Tucker has a 4 part series Flash video on the topic Getting Started with [...]

  7. Nshen says:

    could you explain the ViewHelper and ViewLocator classes in the PART 5 ?

  8. David Tucker says:

    @Nshen – I will address both ViewHelpers and ViewLocators in the next tutorial. The point I will make is that they both have fallen out of favor with most Cairngorm developers. The both are considered “bad practice” to use (quoting Jesse Warden on this one). However, if you have a specific question regarding these – feel free to leave a comment.

  9. Sean Moore says:

    Another solid tutorial. Thanks soo much for putting these together.

    On the topic of ServiceLocator, I was wondering how an AS3 lib such as flickrlib from Adobe could be used as a service in a Cairngorm app. Any info on that would be great.

    Thanks again for the outstanding work!!!!

  10. David Tucker says:

    @Sean – I am glad that you like the tutorials! I will probably use a Web API in the next tutorial. I am looking at several to determine what would work best.

  11. iuliub says:

    Hi David,

    On the ServiceLocator section of this article, it says:
    “Like the FrontController, this class is usually instantiated in your main application file. ”

    However ServiceLocator is a singleton class and can’t by instanciated, due to it’s singleton enforcer.

    Iuliu B.

  12. David Tucker says:

    @iuliub – Thanks for the good ear! Normally, you would be right. However, in Cairngorm, the ServiceLocator uses a different type of Singleton enforcement(which allows it be instantiated in MXML). When you first instantiate the ServiceLocator it creates the instance, but if you try to do it again – it will throw an error.

  13. Matt says:

    I loved this tutorial. Only problem is, I’m using amfphp 1.9 and cannot get it to return anything using Cairngorm 2.2.1 and FlexBuilder 2.1. I’ve managed to use it just fine without the Cairngorm framework.

    Anybody like to show how this would work with amfphp 1.9 as the remoteobject and CairngormLogin.php and LoginVO.php?

  14. David Tucker says:

    @Matt – I would first ask a few questions. Have you tested your service with the ServiceBrowser in AMFPHP (to ensure that there are no errors on the PHP side)? Have you set the “_explicitType” for your LoginVO.php class? Please let me know if you are still having problems.

  15. Matt says:

    Thanks for getting back so fast. Haven’t set “_explicitType”, I’ll try that. I get errors in the service browser when I include (“LoginVO.php”) in the CairngormLogin.php file

  16. David Tucker says:

    If you get errors, then there is probably an error in your LoginVO.php file – you can email it to me at david [at]

  17. Matt says:

    Finally figured out what I was doing wrong. The AS LoginVO is being parsed as an associative array by php. Tried placing it in the vo path specified by AMFPHP but don’t seem to be having much luck there. I guess I’ll stick with it being read by php as an array for now as that’s working.

  18. Laurens van der Plaat says:

    Hello David,

    Do you have any experience with a .net webservice?
    I’ve got a simple test service in .net (it just returns an xml). without cairngorm I just set an mx:WebService and in a DataGrid I set the dataProvider and the datafields. I wan’t to test it with cairngorm, but so far, I don’t know how.
    I hope you can help me.

  19. Shawn says:

    Hi David,

    Let me say THANK YOU THANK YOU for these tutorials. I am fairly new to Cairngorm and have struggled until I found your site.

    I have a couple of questions that Im hoping you can offer advice on. First, I am wanting to use e4x with my Cairngorm webservices and am having quite the time getting my command, delegates, and service locator to play nice. I would appreciate any advice you can offer.

    Second, I am wanting to create modules within my cairngorm application and was wondering if you had any tips or tutorials on this topic.

    And lastly, I want to make my projects localizable. Is there anything that I need to do different than a regular Flex project to ensure this works in Cairngorm?

    Thank you for taking the time to read and hopefully answer some or all of my questions.


  20. Laurens van der Plaat says:

    @ shawn

    I’m also new with cairngorm and flex. I’ve tried to use cairngorm with an .net webservice. And after 3 days it finally works :D !
    I also wanted to use e4x so I did the following:

    the service locator:

    now you can use e4x in your command/responder. If you use event.result in your result function you get the xml


    I hope this will help you

  21. Laurens van der Plaat says:

    ow I can’t type mxml tags here, I didn’t know that… I can email you the code if you like…

  22. David Tucker says:

    @Laurens – Feel free to email it to me at david [at]

  23. sakri says:

    Hi David,

    First of all, thanks for this great set of tutorials!

    I’d like to port an old app to cairngorm. The app uses NetConnection() to communicate to Java via amf. I’m not quite sure where to go… I don’t think I can use RemoteObject (could be wrong). Should I just skip the ServiceLocator bit (seems a bit wrong), or try to extend the ServiceLocator to support some “custom AMFConnection”, like “getAMFService()” or so… I’m sure enough people have done this, I just can’t find any documentation.

    thanks again!


  24. morten says:

    Hi David,

    How do you assure that a event has finished updating a vo before using the data from the vo that has to be updated?

  25. [...] Part 4 you saw the full Service to Worker pattern demonstrated. However, the method discussed in the last [...]

  26. Joe says:

    Great job. I really enjoy your tutorials. It helps me and my team a lot.

    Just one question. I did try to run your sample app on my local machnine and I found out the ColdFusion returns “true” as a string instead of boolean. I had to change the checkin of the “event.result” in loginCommand as following. Why did CF return the string of “true” instead of boolean true? I thought the cfc login method should return boolean.

    if (event.result == “true”) {
    //Change view
    modelLocator.workflowState = ModelLocator.WELCOME_SCREEN;

  27. David Tucker says:

    @Joe – I have had that happen before (only in Flex 2 if I remember correctly). Are you using Flex 2 of Flex 3 Beta?

  28. Joe says:

    I am using Flex 2. Is that a bug ?


  29. Matt Law says:


    Firstly, many many thanks, great series, and has taught me a lot of CFusion and Flex, and saved me a lot of time.

    Just for fun :) and to test my understanding, I thought I’d extend this example to return the LoginVO object after validation, rather than boolean.

    I hit a few problems which I’d like to share with everyone here, hopefully it will help someone.

    When I modified the CFC to return the loginAttempt rather than the boolean, I got a strange error in the Flex Builder console.

    ArgumentError: Error #1063: Argument count mismatch on com.divinecreations.ViewManager.vo::LoginVO(). Expected 2, got 0.

    I could see my object in the event.result.objectProxy, but I couldn’t coax it back out and into my waiting variable. I either got the above error, or null.

    Turns out, just like C# (so I should have spotted this much sooner), the serializer can not work with parameterized constructors.

    In the example on this tutorial, the LoginVO must be instantiated with 2 parameters, which means I could’nt use LoginVO to accept a returning CFC VO.

    Furthermore, to my suprise AS3 can not handle multiple constructors, so I had to ditch the elegant parameterized constructor in this example for a default parameterless one.

    Once I’d done this (and a few other subsequent modifications) I was able to extract the waiting VO from the result.event

    var user:LoginVO = event.result as LoginVO;

    A summary of my changes are:

    – — (created a default constructor)
    public function LoginVO()

    – LoginScreen.mxml — (modified the login event raiser)

    var loginEvent:LoginEvent = new LoginEvent(new LoginVO(username.text, password.text, false));

    Had to be replaced with a less elegant:

    var loginUser:LoginVO = new LoginVO();
    loginUser.username = username.text;
    loginUser.password = password.text;

    var loginEvent:LoginEvent = new LoginEvent(loginUser);

    If anyone knows how I can acheive the same effect, without having to revert to default constructors, I’d love to hear from you.



  30. Philip Bedi says:

    Hi David,

    I have got requirement of changing source in services.mxml on fly, is it possible to define it in action script?

    I tried like this, but it doesn’t compile.

    import mx.rpc.remoting.RemoteObject;

    public var sourcePath:String = “com.affino.showcasedesignelement.cfcs.ShowcaseDesignElement”;
    private var remoteObject:RemoteObject = new RemoteObject(‘ColdFusion’);
    remoteObject.destination = ‘ColdFusion’;
    remoteObject.source = sourcePath;

    Please let me know if this can be done?



  31. [...] Most Commented Post (32 Comments): Getting Started with Cairngorm – Part 4 [...]

  32. Mohamed says:

    David it was a great series. I am using drupal as a backend and flex as frontend but i am not able to connect my service using the cairngorm. I am using amfphp to connect drupla service to flex any idea please let me know how to connect the drupla model using cairngorm in flex.

  33. Pedro says:

    Hi David, great series, totally got me through the first steps of cairngorm, and i now see why, for flex, it might have some advantages to PureMVC. Great work man!
    @Matt, well not sure if this is what you want but a colleague of mine just described how to dynamically parse mxml,
    @David, sorry for the link, if it’s wrong feel free to remove it.

    Keep it up!

  34. shrikant says:

    Hi,.. david this is gr8 series of tutorials to understand Cairngorm. Actually i tried to learn Cairngorm lots of times, but each and every time i felt that it is a very confusional matter. but when i gone through your tutorial series,… NOW i m feeling COOL…… thnx for such a cool tutorials……

    Expecting more good tutorials for you.

    And One more thing…….. in video tutorials…….. your style of saying “davidtucker” is so nice…….. :)

  35. Darrin says:

    Good Day,
    I have been going though your classes here adn they are great, just one question. Where are you putting the CairngormTest folder (holds the cfcs) on your hard drive. I place teh folder in my wwwroot and when I run the code i am getting the fault message where in cannot talk to the cfc. the falut sting I am getting is, ‘Could not find the ColdFusion Component >com.stop_ing.CairngormSample.vo.LoginVO.’

    but the code is in C:\CFusionMX7\wwwroot\ViewManagercf

    my remoteObject call

    here is the alais code as well

    thanks again for you help,

  36. Ulysses Wong says:

    Good Day David,

    First of all, I really enjoy your video and I got hands dirty following your video. However for my case, I used Tomcat for the application server and Hessian as the remote protocol(cos i don’t have much experience with coldfusion)

    I manage to get the ServiceLocator to work with Hessian. However, one of the ServiceLocator.getService method is label as deprecated(I hope i get feedback to Adobe labs to give this method back :( )

    Ok to anyway out there wants to know how to get this part 4 tutorial work with Java tomcat app server.

    ServiceLocator —-

    LoginDelegate —-
    public function LoginDelegate(responder:IResponder) {
    this.responder = responder;
    this.service = ServiceLocator.getInstance().getService(“loginService”);

    public function login(loginAttempt:LoginVO): void {
    var token:Object = service.login.send(loginAttempt);

    Create Your Hessian Login Service
    package service;

    import com.caucho.hessian.server.HessianServlet;

    import vo.LoginVO;

    public class LoginServiceImpl extends HessianServlet implements LoginService {

    public int login(LoginVO vo) {
    if (vo.username.equals(“ulysses”) &&
    vo.password.equals(“qwaszx12″)) {
    return 1;
    return 0;


  37. Johan says:

    Thank you for putting together a nice series.

    It does seem “incorrect” to have a command displaying a popup (view) as above where you have an incorrect username/password service reponse. I’ve struck this issue a few times where I want to use a popup (maybe the same popup) in a number of places. I came across Alex Uhlmann post, the approach works for me:

    BTW I use the mx.binding.utils.ChangeWatcher in my script block. I also tried the observe tag and found that the original/simple observe tag by Paul Williams worked but not the updated one from Alex – the tag is nice if you want to implement the functionality in mxml.

  38. Any one have a example howto use with AMFPHP?

  39. David Tucker says:

    @Carros – The process of using Cairngorm with AMFPHP is no different. The code inside of Flex will be the same. The difference comes with just setting up AMFPHP – and being sure you enter the correct service information for your Flex project. Are you familiar with setting up an AMFPHP environment?

  40. Rob says:

    Can you post an example of the servicelocator in action script rather than mxml?

  41. sondang says:

    first thanks for the tutorial
    how to to get var username and password in php ????

  42. sondang says:

    class authentication {

    var $username =”;
    var $password =”;

    function login(){
    if($username == “admin” || $password ==”admin” ){
    $rtn = true;

    $rtn = false;

    return $rtn;


  43. sondang says:

    $username = null
    $password = null

    please help me :(

  44. Vardan says:

    Thanks David,

    Your Cairngorm tutorials are great. It helps me greatly.

    My best wishes to your newborn babies.

  45. Maggie says:

    Thanks so much for these tutorials – they are a HUGE benefit! Quick Question – what is the best way to set the username to a “global” variable that can be displayed in other views within the application? (e.g. in your example, if I wanted to display the username value in the welcome screen after the user logs in, what would you do)?

    Thanks again!

  46. Thanks David, these tutorials are excellent, and explain the Cairngorm framework better to a intermediate programmer like myself, then any other video series I’ve found to date.

    Keep up the good work, and thank you again!

  47. Ben Tate says:

    Thanks so much David. Excellent tutorials. THE best way to jump-start into Cairngorm that I’ve found by far!