Home > Builder > ActionScript 3.0 Builder Design Pattern Part II: Multiple Builds

ActionScript 3.0 Builder Design Pattern Part II: Multiple Builds

As a concrete follow-up to Part I of this two-part post, I thought that once I decided on which graphics, text and video to use the development would go pretty quickly. It took a lot longer than I thought, but now that the concrete example is ready it’s pretty easy to see how to put a practical Builder together and re-use and extend it. Because this second part builds on the first part, if you’re only vaguely familiar with the Builder Design Pattern, you might want to review Part I.

What to Build?

In ActionScript 3.0 Builder Design Pattern Part I, we set up a vacation-building site using trace statements to display different characteristics. To make these characteristics come alive and work in some practical matter, the goal is to create a builder that does the following:

  • Load an external graphic
  • Play a video that can be displayed in any format used by Flash Media Server or Progressive Download
  • Display a different background for each vacation destination. The background is made of an external .swf file
  • Present text write-up using external text source

In looking at those four actions, you might be thinking, that’s not exactly rocket science. You’d be right. However, when you start adding more and more vacation destinations, keeping track of everything can dampen one’s resolution. With the Builder, though, I found it very easy to add, change, and delete. In fact, I encourage you to add your own favorite vacation place and add it using the builder described in this post.

The Design

In Part I, I talked about different variations in the Builder’s design. The one we’re using closely follows the first as far as the Product class is concerned. All of the concrete builder classes use the same Product class. The Product class assembles the different parts under construction. However, in order to keep the Product class manageable, I added several Helper classes to take care of the details for the different parts that need to be built for the final product. Figure 1 shows the file pattern for the design:

<em><strong>Figure 1: </strong> File Class Diagram of Builder Design Pattern</em>

Figure 1: File Class Diagram of Builder Design Pattern

As you can see, several classes use the Product class, and it uses all of the helper classes. Even the Client holds a reference to the Product class. As far as design is concerned, though, this one is identical to the one we used in Part I with the added helper classes.

The Client Class

One of the interesting features of the Client class in this design is that it initiates the request through the Director and then holds a reference to the Product whose creation it initiated. (It’s sort of like throwing a ball and then running to catch it.) To see the path initiated by the Client’s request consider the following sequence:

  1. private var director:Director=new Director();
    Client instantiates instance of the Director class. The Director has a single method, construct, and instantiating an instance of Director makes the construct method available.
  2. private var trip1:IBuilder=new ConcreteBuilder1();
    A variable specifies which concrete product it wants constructed.
  3. private var srilanka:Product;
    A reference is established in a variable to the Product.
  4. director.construct(trip1);
    The Director instance constructs the specified concrete builder
  5. srilanka=trip1.getResult();
    The Builder instance passes the constructed elements to the Product reference
  6. srilanka.disclose();
    The Product variable creates the details of the concrete builder using the helper classes to handle the details of each element. It takes care of housekeeping chores by removing the previous build from the display list.

The following listing shows the entire Client class. The constructor function brings up a background and places the buttons on the display list. I suppose there’s some irony in throwing together a “home page” with no information other than three buttons and the background pattern. I could have added all of the elements that the individual vacation destinations include, but instead I kept it open for anyone who wants to add a more substantial home page.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
 package
{
	import flash.display.Sprite;
	import fl.controls.Button;
	import flash.events.MouseEvent;
 
	public class Client extends Sprite
	{
		private var magicCarpet:Sprite=new Sprite();
		private var navContainer:Sprite=new Sprite();
		private var il:ImageLoader;
 
		private var director:Director=new Director();
 
		//Concrete builders
		private var trip1:IBuilder=new ConcreteBuilder1();
		private var trip2:IBuilder=new ConcreteBuilder2();
		private var trip3:IBuilder=new ConcreteBuilder3();
		//Products
		private var srilanka:Product;
		private var sanfrancisco:Product;
		private var prague:Product;
		//Buttons
		private var btn1:Button=new Button();
		private var btn2:Button=new Button();
		private var btn3:Button=new Button();
 
		public function Client()
		{
			il=new ImageLoader("vacationBG.swf");
			addChild(magicCarpet);
			magicCarpet.addChild(il);
			addChild(navContainer);
			setButtons();
		}
 
		private function setButtons():void
		{
			btn1.x=16;
			btn1.y=64;
			btn1.label="Sri Lanka";
			btn1.addEventListener(MouseEvent.CLICK,goSriLanka);
			navContainer.addChild(btn1);
 
			btn2.x=16;
			btn2.y=96;
			btn2.label="San Francisco";
			btn2.addEventListener(MouseEvent.CLICK,goSanFrancisco);
			addChild(btn2);
 
			btn3.x=16;
			btn3.y=128;
			btn3.label="Prague";
			btn3.addEventListener(MouseEvent.CLICK,goPrague);
			navContainer.addChild(btn3);
		}
 
		private function goSriLanka(e:MouseEvent):void
		{
			carpetCleaner();
			director.construct(trip1);
			srilanka=trip1.getResult();
			srilanka.disclose();
			magicCarpet.addChild(srilanka);
		}
 
		private function goSanFrancisco(e:MouseEvent):void
		{
			carpetCleaner();
			director.construct(trip2);
			sanfrancisco=trip2.getResult();
			sanfrancisco.disclose();
			magicCarpet.addChild(sanfrancisco);
		}
 
		private function goPrague(e:MouseEvent):void
		{
			carpetCleaner();
			director.construct(trip3);
			prague=trip3.getResult();
			prague.disclose();
			magicCarpet.addChild(prague);
		}
 
		private function carpetCleaner():void
		{
			while(magicCarpet.numChildren > 0)
			{
				magicCarpet.removeChildAt(0);
			}
		}
	}
}

As you can see, the Client is pretty busy, and as the number of vacation destinations grows the Client will need the assistance of helper classes to generate the necessary UIs to handle a wider variety of requests.

The Director Class and IBuilder Interface

In some respects the Director is like a template method. It lines up the operations required to build a product. However, the operations all use the builder interface (IBuilder) to set up the steps to put everything together. What’s more, both the Director and IBuilder are identical to the same class and interface used in the abstract Builder used in Part I. The following listing shows the two unchanged design participants:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//Director
package
{
	public class Director
	{
		public function construct(builder:IBuilder):void
		{
			builder.buildHotel();
			builder.buildSight();
			builder.buildEvent();
			builder.buildWriteUp();
		}
	}
}
 
//Builder interface
package
{
	interface IBuilder
	{
		function buildHotel():void;
		function buildSight():void;
		function buildEvent():void;
		function buildWriteUp():void;
		function getResult():Product;
	}
}

The IBuilder interface holds a reference to the Product in the getResult() method. In this particular design, I added it because all of the concrete builder classes use the method. By doing so, I was able to type the individual concrete builders to the interface (keeping things loose) and then call the getResult() method from a builder instance. (See the Client listing above.)

The Concrete Builders

Even the concrete builders seem fairly abstract in this design. All they do is pass strings to the product for construction via the helper classes. However, the concrete builders, like just about everything else in a design pattern, are communication nodes. Remember, in OO,

a process is expressed as a succession of messages across objects

So what we’re seeing is the process of messages passed through the classes (objects). In the concrete builders, the content of the messages is carved in the stone of literal values. This may bring up some short with the query, Why didn’t you put them in variables? First, keep in mind that literals are assigned somewhere, and all that’s being done is placing the assignment in the concrete builders. Second, adding variables would only back up the assignment of the literals and add unnecessary code.

Other than assembling the product, the concrete builders are also returning a completed product. Given the complex nature of the building process, one might wonder whether the job gets done by the time its ready to return something. The process returns the Product object in some shape, but not necessarily the one you’re expecting. After all, this builder is accessing video, loading text, graphics, and SWF files. What if the FMS server isn’t quite awake? All kinds of things have to happen, and I’ve found that on initial tests some parts get left behind or are a bit late in getting in place. Preloaders give me the creeps because they imply you haven’t paid attention to the size of your files and the user is going to be kept waiting. For a prime time version of this application, you might want to think about some kind of notification that the product is fully assembled and perhaps a” be with you in a jiffy” note to the user who’s waiting for the product.

I placed the finished product on three different servers and got three different reactions. On my LAN, the San Francisco video (plain vanilla FLV running on Flash Media Server) works perfectly, but when I posted it on a different remote Flash Media Server, it did a quick entrance and exit. One server did not play the progressive download, while another played the progressive download but did not put in the background. Click the Play button and see what you get.
play

The following three listings show the concrete builders in the design:

Sri Lanka is the first destination. The video uses a progressive download, and in case you can’t work with Flash Media Server 3.5.2 (or later), you can change all of the concrete builders to work with progressive downloads as well. All you have to do is the use the “.flv” suffix. (See how easy it is to change things using a Builder pattern?)

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package
{
	public class ConcreteBuilder1 implements IBuilder
	{
		private var product:Product = new Product();
 
		public function buildHotel():void
		{
			product.assemble("srilanka/hotel.jpg");
		}
 
		public function buildSight():void
		{
			product.assemble("srilanka/sriLankaBG.swf");
		}
 
		public function buildEvent():void
		{
			product.assemble("srilanka/sriLanka.flv");
		}
 
		public function buildWriteUp():void
		{
			product.assemble("srilanka/sriLanka.txt");
		}
 
		public function getResult():Product
		{
			return product;
		}
	}
}

Figure 2 shows what the builder generates for this concrete builder:

<em><strong>Figure 2:</strong> Sri Lanka is colorful, and the background reflects this character </em>

Figure 2: Sri Lanka is colorful, and the background reflects this character

The second destination is San Francisco. Everything is pretty much the same except the video file is being streamed from Flash Media Server. If you want to run an FLV file named sanFrancisco using progressive download, just change the value to “sanFrancisco.flv” and any local folder in use.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package
{
	public class ConcreteBuilder2 implements IBuilder
	{
		private var product:Product = new Product();
 
		public function buildHotel():void
		{
			product.assemble("sf/hotel.jpg");
		}
 
		public function buildSight():void
		{
			product.assemble("sf/sfBG.swf");
		}
 
		public function buildEvent():void
		{
			product.assemble("sanFrancisco");
		}
 
		public function buildWriteUp():void
		{
			product.assemble("sf/sf.txt");
		}
		public function getResult():Product
		{
			return product;
		}
	}
}

Coming up with a color combination for San Francisco was a little tricky, and I finally settled on one I found at Kuler. (In fact I got all of my color combinations there.) Figure 3 shows the results:

<em><strong>Figure 3:</strong> San Francisco's Fairmont Hotel's lobby is featured</em>

Figure 3: San Francisco's Fairmont Hotel's lobby is featured

The third concrete builder is built around a visit to Prague, Czech Republic I took. The color combination for the background is named on Kuler, Mala Strana (little district) where I happened to stay on my visit. The video is an HD one taken with a Mino HD Flip camera and rendered into H.264 format—f4v. You will notice that the buildEvent() method passes a literal with a long reference—”mp4:pragueFolk.f4v”. Unfortunately, H.264 format is not available for progressive download, but you can substitute any .flv file you want.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package
{
 
	public class ConcreteBuilder3 implements IBuilder
	{
		private var product:Product = new Product();
 
		public function buildHotel():void
		{
			//graphic
			product.assemble("prague/hotel.jpg");
		}
 
		public function buildSight():void
		{
			//swf file
			product.assemble("prague/pragueBG.swf");
		}
 
		public function buildEvent():void
		{
			//video
			product.assemble("mp4:pragueFolk.f4v");
		}
 
		public function buildWriteUp():void
		{
			//import text
			product.assemble("prague/prague.txt");
		}
 
		public function getResult():Product
		{
			return product;
		}
	}
}

Figure 4 shows the combined elements for this third rendered build:

<em><strong>Figure 4: </strong> Prague's flavor is captured in text, image and video.</em>

Figure 4: Prague's flavor is captured in text, image and video.

While the classes that make up the concrete builders are very similar, you can see that the exact nature of the builds and their content is quite different.

The Product Class and Helper Classes

All of the heavy lifting is done by the Product class and its helpers. (Think of the Product class as Santa Claus and the helpers as his elves.) As you can see in the Product class listing, the object uses an array to assemble the product. Then it goes through the array using a switch statement to create the requested element using the helper classes (ImageLoader, EventPlayer and TextLoader). Once it is finished, it empties the array (features.length=0).

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package
{
	import flash.display.Sprite;
	public class Product extends Sprite
	{
		private var features:Array=new Array();
		private var ep:EventPlayer;
		private var tl:TextLoader;
		private var il:ImageLoader;
		private var bg:ImageLoader;
		private var productHolder:Sprite=new Sprite();
 
		public function assemble(...rest ):void
		{
			features.push(rest);
		}
 
		public function disclose():void
		{
			cleanProduct();
			addChild(productHolder);
 
			var counter:uint=0;
 
			for each (var facet:Array in features)
			{
				switch (counter)
				{
					//Graphic
					case 0 :
						il=new ImageLoader(String(facet));
						productHolder.addChild(il);
						il.x=410,il.y=10;
						break;
					//Swf
					case 1 :
						bg=new ImageLoader(String(facet));
						productHolder.addChildAt(bg,0);
						break;
					//Video
					case 2 :
						ep=new EventPlayer(String(facet));
						productHolder.addChild(ep);
						break;
					//Text write-up
					case 3 :
						tl=new TextLoader(String(facet));
						productHolder.addChild(tl);
						break;
				}
				counter++;
			}
 
			features.length=0;
		}
 
		private function cleanProduct():void
		{
			while (productHolder.numChildren>0)
			{
				productHolder.removeChildAt(0);
			}
		}
	}
}

The Product class has to deal with placing materials on the display list and removing them once its finished. I found that the easiest way to handle the DisplayObject was to create a sprite to act as a holder. Before adding new materials to the display list, everything in the holder is removed using the code:

while (productHolder.numChildren>0)
{
productHolder.removeChildAt(0);
}

I learned that if I used that code on the root display, it’d wipe out everything; however, it is a handy tool for cleaning up. So you can use it to clean up the just the holder sprite.

Loading images (jpg, png, gif) and compiled Flash (.swf) files use identical formats. So the ImageLoader helper could be used for both loading the image of the hotel and the background. Note, however, that the background has to be slipped beneath everything else, and so it was placed at the lowest level (0) using addChildAt(). The following script shows the code for this hard working helper:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package
{
	import flash.display.Loader;
	import flash.net.URLRequest;
	import flash.display.Sprite;
	import flash.display.Loader;
 
	public class ImageLoader extends Sprite
	{
		private var imgNow:String;
		private var loader:Loader=new Loader();
 
		public function ImageLoader(img:String)
		{
			imgNow=img;
			var url:URLRequest=new URLRequest(imgNow);
			loader.load(url);
			addChild(loader);
		}
	}
}

As you can see, the ImageLoader class doesn’t take much code. (You may have noticed that the Client uses it to load the initial background.) It’s small but mighty!

The EventPlayer class is essentially a video player class. It accommodates both streaming via Flash Media Player and progressive downloads. Basically, if it is passed a url with the “.flv” extension, it plays the video as a progressive download; otherwise, it plays the video using Flash Media Server.

As for placing the video object on the display list, the video object is removed from the list by itself. When the video ends, it tidies up after itself. The following listing shows this somewhat complex helper class.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package
{
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.display.Sprite;
	import flash.media.Video;
	import flash.events.NetStatusEvent;
 
	public class EventPlayer extends Sprite
	{
		private var vid:Video=new Video();
		private var nc:NetConnection=new NetConnection();
		private var ns:NetStream;
		private var rtmpNow:String="rtmpe://192.168.0.11/context/events";
		private var goodConnect:Boolean;
		private var theEnd:Boolean;
		private var metaSniffer:Object=new Object();
		private var flv:String;
		private var vidBed:Sprite=new Sprite();
 
		public function EventPlayer(flvNow:String)
		{
			addChild(vidBed);
			vidBed.addChild(vid);
			flv=flvNow;
 
			nc.addEventListener(NetStatusEvent.NET_STATUS,checkConnection);
			if (flv.substring(flv.length-4)!=".flv")
			{
				nc.connect(rtmpNow);
			}
			else
			{
				nc.connect(null);
				ns=new NetStream(nc);
				vid.x=60,vid.y=320;
				ns.play(flv);
				vid.attachNetStream(ns);
				ns.client=metaSniffer;
				metaSniffer.onMetaData=getMeta;
				ns.addEventListener(NetStatusEvent.NET_STATUS,checkComplete);
			}
		}
 
		private function checkConnection(e:NetStatusEvent):void
		{
			goodConnect=e.info.code=="NetConnection.Connect.Success";
			if (goodConnect)
			{
				ns=new NetStream(nc);
				vid.x=60,vid.y=320;
				ns.play(flv);
				vid.attachNetStream(ns);
 
				ns.client=metaSniffer;
				metaSniffer.onMetaData=getMeta;
 
				ns.addEventListener(NetStatusEvent.NET_STATUS,checkComplete);
 
			}
			else
			{
				//Add Error Handler
			}
		}
 
		private function getMeta(mdata:Object):void
		{
			if (mdata.width<=720)
			{
				vid.width=mdata.width/2;
				vid.height=mdata.height/2;
			}
			else
			{
				vid.width=mdata.width/3;
				vid.height=mdata.height/3;
			}
		}
 
		private function checkComplete(e:NetStatusEvent):void
		{
			theEnd=e.info.code=="NetStream.Play.Stop";
			if (theEnd)
			{
				ns.close();
				vid.clear();
				removeChild(vidBed);
			}
		}
	}
}

The EventPlayer class also deals with videos of different sizes using the file’s own metadata. It looks at the width and height of the video and then decides whether to divide the width and height by 2 or 3. (Anyone who’d like to add a more sophisticated algorithm for this process is welcomed.)

The final helper class loads the text stored in an external text file. The operations are fairly straightforward for text loading. However, it does have a load-checker to seen when all of the text from the file has been passed to the URLLoader object (txtLoader) which is then passed to the text property of the TextField instance.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package
{
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.events.Event;
 
	public class TextLoader extends Sprite
	{
		private var textContainer:Sprite=new Sprite();
		private var urlNow:URLRequest;
		private var txtLoader:URLLoader=new URLLoader();
		private var txtFld:TextField=new TextField();
		private var txtFormat:TextFormat=new TextFormat();
 
		public function TextLoader(textNow:String)
		{
			addChild(textContainer);
			urlNow=new URLRequest(textNow);
			txtLoader.addEventListener(Event.COMPLETE, addTxtFld);
			txtLoader.load(urlNow);
		}
 
		private function addTxtFld(e:Event):void
		{
			var loader:URLLoader=URLLoader(e.target);
			txtFormat=new  TextFormat();
			txtFormat.font="Verdana";
			txtFormat.size=11;
			txtFormat.color=0x000000;
			txtFld.defaultTextFormat=txtFormat;
			txtFld.multiline=true;
			txtFld.width=210;
			txtFld.height=250;
			txtFld.wordWrap=true;
			txtFld.x=163,txtFld.y=40;
			txtFld.text=loader.data;
			textContainer.addChild(txtFld);
		}
	}
}

When a new vacation destination is called, the text is removed by the Product class. In this way, you do not get text stacking on top of itself.

Do Something

I am hoping that some readers will add another vacation destination to better understand how the Builder pattern works and to see how easy it is to build a relatively complex object. All adding a new destination requires is building another concrete builder by copying and pasting one of the existing ones and adding the required text literals. Create a .swf file with a background for your new vacation and place it where it can be accessed from a Web server. Add a button to the Client and the sequence of steps used for the first three; and you’re done.

Share

Related posts:

  1. ActionScript 3.0 Builder Design Pattern Part I: Controlling Creation
  2. Friends with Benefits: Refactoring with Multiple Design Patterns—Part I
  3. ActionScript 3.0 Abstract Factory Design Pattern: Multiple Products and Factories
Categories: Builder
  1. Ben
    January 25, 2010 at 5:45 am | #1

    I found this nice video describing the Builder DP. Good to hear it from another angle.

    http://www.youtube.com/watch?v=jstef_eUM6E

    Cheers
    Ben

  2. Rob N.
    April 18, 2011 at 8:38 am | #2

    Hey Bill,
    With novice knowledge on DPs, I am making a 3D Carousel for my personal website in Papervision3D, and want to incorporate design patterns before just jumping into code. No events yet, just construct the carousel object. The carousel will contain multiple plane objects and then the Carousel would ultimately be the Product.

    Now ‘build’ jumps in my head when I describe making the Carousel Product. It seems like the Builder pattern is what that calls for. In my IBuilder, I see:
    +build(); //create the planes and save them into an array
    +arrange(); //use that array & arrange them in circle
    +getProduct(); //return product

    But in your example, I see that each function is used to create an separate component for each trip page. Am I misusing/misreading the Builder pattern? I feel like Bambi on ice. Close to getting it, but just not comfortable enough yet.

  3. Rob N.
    April 18, 2011 at 8:46 am | #3

    Oh and thank you for this website has been nothing but help introducing me into design patterns.

    Rob N.

    • April 18, 2011 at 3:18 pm | #4

      Hi Rob,

      You might want to take a look at the following posts:

      1. First, check out the Flyweight here–especially Figure 7 near the end of the post. (You did say airplanes on a carousel?) Anyway, if you’re going to be reusing the same object, the Flyweight may be an answer.

      2. Second, check out our series on Choosing a Design Pattern. I revisit it a lot!

      3. We’ve got a ton of AIR apps and other stuff as a beginner’s kit. I know you’re not a new beginner, but there’s lots of stuff that I use all the time for “reminders” that might be helpful.

      Then join Bambi and me on the ice!

      Kindest regards,
      Bill

  4. Rob N.
    April 21, 2011 at 11:09 am | #5

    Alright.

    1. The Flyweight is an interesting pattern. I am going to let it sink in and reread it again. Oh and you made me laugh about my carousel of airplanes, but it was a carousel of planes as 3D objects and not planes as Airplanes. Although airplane carousel could be a nice Delta project.

    2. I reread your ‘Choosing a Design Pattern’. That was one of the first posts I found, upon discovering this site. After digging around in some DP’s for the last 4 weeks or so, that article made even more sense this time around. Decomposition is definitely an acquired skill that needs to be practiced.

    3. Tried the AIR app, but it keeps trying to reinstall AIR every time I try and run the AIRmenu.app and freezes during the install. It does that with everything for some reason. I am looking into it.

    Thanks Bill

  5. April 21, 2011 at 11:30 am | #6

    Hi Rob,

    It’s probably an older version of AIR that I have, and it doesn’t understand the newer version. I’ll fix it.

    I’m planning a post on Object Communication for both beginners and parallel programming. In that way I can kill two birds with one stone, and I hope it helps to focus on some issues in DP/OOP and //P (my sign for “parallel programming”–PP just didn’t sound right.)

    Sorry for the confusion about the 3D plane and my airplanes…

    Kindest regards,
    Bill

  1. No trackbacks yet.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>