Live Talkback and the Flash Platform Bring a Live Studio Audience to You

As loud as we may shout at the TV watching sports or offer our own advice during a talk show, the people on the tube never hear our insights—until now. U.K. based interactive content developer, Live Talkback, used the Adobe Flash Platform  and Adobe Creative Suite  to engage U.K. audiences during broadcasts with live polling, allowing them to use their PCs and mobile devices to vote during live broadcasts.  Live Talkback displays those voting results in real-time, keeping viewers on top of the buzz before, during and after these live events. Live Talkback applications include a “Clapometer,” which uses PC and mobile phone microphones to measure audience noise during a show.

An Adobe MAX 2010 award finalist, Live Talkback uses Adobe Flash Builder, Adobe Flash Player and the Flex framework because the technologies provide a flexible development environment and an easy integration process, allowing Live Talkback to create the polling tools in a fraction of the time and cost. Popular U.K. morning show, “This Morning,” and top soccer club, Liverpool FC, have used Live Talkback to engage with its audiences. “This Morning” received more than 57,000 live votes in a recent live broadcast segment. The company is looking forward to emerging in other markets, namely in the U.S.

To learn more about Live Talkback and how it used Adobe technologies to enhance audience engagement with live broadcasts, read more here and check out the video below.

 

Hospital Records Go Digital with the Flash Platform

ImageTrend, a software application developer, is bridging the information and communications gap between first responders and emergency room physicians with a powerful, secure electronic patient records management platform. Using the Adobe Flash Platform and Adobe ColdFusion, ImageTrend created the Hospital Dashboard (an Adobe MAX 2010 Awards finalist) so emergency response personnel and physicians could share medical records before a patient arrives at an emergency room. This paperless solution helps physicians make better decisions about how to care for patients and increases the likelihood of saving a life.

ImageTrend chose to develop the Hospital Dashboard using the Flash Platform because it allows the company to quickly develop, launch and maintain secure, enterprise-level applications—with the potential to expand services to mobile phones and other devices in the future. One of the key technologies used was Adobe ColdFusion, which let ImageTrend expand the user-interface to securely deliver data over the Web and display the information on TVs in the ER.

Along with Adobe ColdFusion, the Hospital Dashboard uses applications built with the Flex framework to gather real-time information and transfer it to an interactive dashboard, which displays the data across various Web browsers. Additionally, Adobe Flash Builder allowed ImageTrend developers to instantly create a higher performing application using features designed to build Flex applications with a ColdFusion back-end. With Adobe’s tools, ImageTrend had what they needed to develop and launch an application at a faster pace while managing millions of patient records more efficiently and lowering hospital costs.

You can learn more about how ImageTrend used Adobe technologies to create the Hospital Dashborad here.

ADC Presents: Work with Web Services in Flex

A new tutorial video, featuring Duane Nickull, has just been released by Adobe Developer Connection on Adobe TV. This 7-minute step-by-step tutorial will show you how to quickly set up web services, specifically SOAP-WSDL in Flex Builder. Check it out and let us know what you think.

Free Flex Builder 3 for Unemployed Developers

Even though there are some signs of economic recovery, the job market continues to get worse. With the offer of free Flex Builder 3, we’d like to make it easier for unemployed developers to add Flex skills to their skill set, which even now remains in high demand. For details and to apply for the program, please visit https://freeriatools.adobe.com/learnflex/

Join me in San Jose Aug 19th and explore Adobe LiveCycle and the Flash Platform

If you are near San Jose, CA and are curious about the Adobe Flash Platform and/or Adobe LiveCycle, please join me Wednesday, August 19th at Adobe Corporate Headquarters for a 5 hour demo-filled, action-packed free event. It’s a great opportunity to get introduced to what Adobe has going on in both client-side and server-side [...]

A Week of Flash Collaboration: Shared Models and Collection Nodes

Update: This blog post took me the better part of a day and a half and just as I was posting it I realized I had a huge hole in the logic for my application because of the problem at the bottom. My plan is to come back and clean this up, as Peter suggested, divide it up into a couple of parts. The most important parts are the first couple of paragraphs that talk about the sharedModel classes and the last paragraph that mentions how the AFCS team architected things to build on top of very low level base classes like CollectionNode. Largely this blog post is a mess and digging into CollectionNode was interesting but I recommend it only after having some time playing with the other classes in sharedModel. After that this might be a useful post to read. Diving into the video tutorials is also highly recommended.

The basic building blocks of Adobe Flash Collaboration Services (AFCS) are really the sharedModel package which includes the CollectionNode classes. Using the classes in the sharedModel package you can share any piece of data across AFCS connections and use these classes to build custom collaboration components like charts or maps where data can be updated and must change for everyone who is connected. I’ll first talk about some of the classes in the sharedModel package and then dive into how to use the CollectionNode, which provides the base functionality for sharing data.

Shared Models
The classes in the Shared Model package include a number of ways to share data and actions with AFCS. For the most part, the classes in sharedModel all use the CollectionNode to exchange data but they abstract a bit of the nuts and bolts of CollectionNode to make it easier to use. For instance the SharedProperty class lets you take any arbitrary property and share it across AFCS instances. It includes the ability to specify a CollectionNode or to just use one that will be generated as soon as the component using SharedProperty is created. Nigel Pegg has a great tutorial which covers using SharedProperty. Another set of classes in the sharedModel package are the Baton classes. The Baton is essentially a SharedProperty that gives you more control over when a user can edit something. The Baton class helps define when something is currently in use and shouldn’t be editable by anyone else in the room. It includes methods to grab() and putDown() a baton as well as a batonHolderChange event that can be used to make changes to the user interface. Nigel’s video goes through this as well using the example of a TextInput box. Using the Baton classes it is easy to disable editing of the TextInput while someone else is typing inside of it.

CollectionNode</strong
All of the classes above use collection nodes and there are three major parts to the basic CollectionNode: creation, configuration, usage. As the documentation states, an AFCS room is essentially a bunch of CollectionNodes exchanging data and each of those nodes has specific configurations that define who and how people can interact with them. One thing to note is that CollectionNodes can only be created by a room owner, or someone with UserRoles.OWNER so when creating a CollectionNode, the owner must be the first person in the room so they can “initialize” it. After that the developer can use the NodeConfiguration classes to customize what level of user has read or write access to the node.

Creating a new CollectionNode is pretty straight forward. In this example I’m going to create a mini-game where the participants have to match up a ColorPicker to “win”. To set up the game, I’ve got one CollectionNode with a “Color” node that will contain the values of the ColorPicker. Here’s how I create the CollectionNode:

protected function application1_creationCompleteHandler(event:FlexEvent):void
{
nodeGame = new CollectionNode();
nodeGame.sharedID = "gameNodes";
nodeGame.addEventListener(CollectionNodeEvent.SYNCHRONIZATION_CHANGE, onSync);
nodeGame.addEventListener(CollectionNodeEvent.ITEM_RECEIVE, onItemRecieve);
nodeGame.subscribe();
}

A few things to notice. First, the sharedID property is described in the docs as the “logical address of the collection within the room” and is how AFCS will refer to it so it needs to be unique. It is also the name that you will see when you browse the nodes in the room console that comes with the SDK. Second, in order to use the node we have to make sure it’s synchronized or we’ll get an error. After creating the node I added a CollectionNodeEvent listener that fires when we have a synchronization change event. I also added an event handler for when we receive messages upon subscribing to the node which I’ll talk about later. Once the SYNCHRONIZATION_CHANGE event fires we can start making changes to our CollectionNode:

protected function onSync(event:CollectionNodeEvent):void
{
var config:NodeConfiguration = new NodeConfiguration();
config.modifyAnyItem = false;
config.userDependentItems = true;
 
nodeGame.createNode("Color",config);
createMessage(false);
}

Now that we’re able to make changes to the CollectionNode I can create the Node that will store messages, in this case the “Color” Node. First I need to use the NodeConfiguration class to set up some rules for the game. By setting the modifyAnyItem property to False I make sure we’re not allowing users to modify messages that aren’t created by them. The userDependentItems property set to true means that when the user leaves the room, we clear out all of the messages belonging to them. In our game we don’t want to find a match with someone who isn’t playing any more. The NodeConfiguration classes allow us to tweak things like what happens to messages as well as define permissions for specific nodes within my CollectionNode. Once we’ve created the NodeConfiguration I can use the createNode() method to create a Node named “Color” and pass in the configuration values I just created. The last method there is a function I created. After we create the node and configure it I want to send the value of my ColorPicker to AFCS so I can start playing the game. I do that with a createMessage()</code< function.

protected function createMessage(overwrite:Boolean):void
{
var colorMessage:MessageItem = new MessageItem("Color");
colorMessage.itemID = cSession.userManager.myUserID + "_color";
colorMessage.body = color1.selectedColor;
 
nodeGame.publishItem(colorMessage,overwrite);
}

My createMessage() takes one variable, a Boolean that we'll use to tell AFCS whether or not we are allowed to overwrite an existing message. The first part of the code is where we create our MessageItem to be sent. I'm just creating a new MessageItem and passing in which Node it will belong to, in this case the "Color" node I created above. Then I give it an itemID which is how it will be referred to by AFCS. I use the current userID and prepend that to the word color. Finally I set the body of the message. The body of a MessageItem can be a String, a Boolean, a Number,or a key-value pair. In this case we're just going to pass in our selectedColor value. Once we create the MessageItem we need to add it to the Node. To do that we use the publishItem() method on the CollectionNode. This is where I pass in the overwrite flag. In this case, I don't want the MessageItem to be overwritten because this should be the first time we're adding it since we called it from the OnSync method. But later I want to make sure we overwrite it because we're making updates to it.

As soon as we publish our message, it's going to go into AFCS and then AFCS is going to send it back to us so we make sure it was sent correctly. When that happens it will fire an ITEM_RECEIVE event which we added an event handler for in our initial function. That code looks like this:

protected function onItemRecieve(event:CollectionNodeEvent):void
{
var tempMessage:MessageItem = event.item;
var userName:String = cSession.userManager.getUserDescriptor(tempMessage.associatedUserID).displayName
 
arrColors.push({color:tempMessage.body,user:userName});
if(tempMessage.associatedUserID != cSession.userManager.myUserID)
{
if( tempMessage.body == color1.selectedColor )
{
Alert.show('Winner! Your partner is: ' + userName);
}
}
}

This is where we start to get to the game. The first to lines just put the MessageItem and user displayName into their own variables. Next we put the selectedColor from our message and the displayName into an array that's stored on the client. This is kind of important. A lot of the sharedModel classes, like SharedProperty for instance, will handle storing data for you but the CollectionNode class doesn't, it's a very basic, low level component. So in this case we can't tell AFCS to send us a list of messages to check and see if there is a match, we have to keep a record within our own application. I do that by storing the information in an Array. Once I do that I want to check if we have a match but I need to make sure we're not matching our own color so I do a quick check using the associatedUserID and myUserID from the ConnectSession. Once we know that isn't the case I can check the body of the message with my current color to see if there is a match and pop up the appropriate dialogue.

When we make changes to our color to try and find a match we also need to send the update to AFCS and check our Array so I added an event handler to my ColorPicker for any change event:

protected function color1_changeHandler(event:ColorPickerEvent):void
{
createMessage(true);
for(var i:Number=0; i<arrColors.length; i++)
{
if(event.color == arrColors[i].color)
{
Alert.show('Winner! Your partner is: ' + arrColors[i].user);
}
}
}

In this case the first thing we do is call createMessage() with the overwrite flag set to true so we are overwriting our current message with the new color value instead of creating a new one. Then we run through our array of colors to see if this new color matches anything on the system. Do you notice a problem?

The problem is this: We configured our Node to remove all messages as soon as someone leaves the room but because we're using CollectionNode instead of one of the higher level classes we also have that array that is storing the values. We're using that array to check for a match after we change our color but we don't ever clear out old messages from our array so we might get a match from someone who is no longer logged in. We're also not checking the array and updating values so we have a lot of old data.

Welcome to Multi-User Applications
Multi-user applications are fun but there is also a lot to deal with. Luckily, the AFCS team has done a very good job of building base functionality into classes like CollectionNode and then building on top of them with classes like SharedProperty that take care of a lot of the complicated parts of managing a collaborative application. I tried to get nitty gritty and show how CollectionNode works but I really encourage you to start with the higher level classes, get an idea of what's happening, then break down to the low level base classes when you need to start creating very customized collaborative applications with specific rules, custom components, and many different types of data.

You can grab the full project here (Flash Builder 4 FPX file) and see how the parts fit together. I'll be updating it in the next few days to take into account the problem above and include a version that people can play.

AIR-based Mortgage Calculator Desktop Widget (with ILOG Gauges)

Here is a simple example of using a chromeless, transparent window in AIR to build a widget-type application. I know: yet another mortgage application… but to make things more interesting, I used the cool ILOG Elixir gauges to display and enter the principal, monthly payment, rate, and term. No rocket science here, but a nice [...]

Building Custom Components in Flex 4: SkinParts

I built my first Flex 4 custom component today, a basic sortable list component that extends List. The only modification I added was a button that you could click to resort your list in alphanumeric order. I mostly wanted to get a feel for building a custom component and get a sense for how to use SkinParts. Hopefully this will be useful to others getting their feet wet in Flex 4 custom components.

The concept of a SkinPart in Flex 4 is one that gives the developer and the designer a lot of power. By listing something as a SkinPart, it means that you can put that particular item anywhere in your custom component using a skin file. SkinParts are also just other components so you can get the built-in functionality as well as any skinning that can take place by using them. In my SortableList, I decided to use a basic Button as the header. Defining a SkinPart is very straightforward, here’s the code for my custom component with the SkinPart definition.

public class SortableList extends List
{
public function SortableList()
{
super();
}
 
[SkinPart(required="true")]
public var header:Button;
}

All you have to do is create a metadata tag with SkinPart and the required attribute set to true or false. Right below that define what the id if your skin part has to be and then what kind of component it is.

To show and use the SkinPart you need to add it to the skin file and make sure the component type and id match. In my case, I’ve got a component with an id of header.

<s:Button id="header" width="100" height="20" x="0" y="0" />

Presumably, you want your new SkinPart to do something and this is where I ran into trouble. At first inside of my SortableList constructor I added an event listener on my header component. The problem is that when the constructor is called it doesn’t create the SkinPart. That happens during a separate operation. The secret then is to override the partAdded function, which is a method in the SkinnableComponent class, the basis for every new spark component.

The partAdded function is automatically called and will add all of the SkinParts you specify in your custom component. It takes two parameters, the partName and the instance. Make sure to call super.partAdded so that your SkinPart gets added to the component and then you can use the instance variable to check when your SkinPart is being created. That lets you add the event listeners that will fire when a user interacts with your skin part. In my case I just added a simple click handler:

override protected function partAdded(partName:String, instance:Object):void
{
super.partAdded(partName, instance);
 
if( instance == header)
{
header.addEventListener(MouseEvent.CLICK,header_clickHandler);
}
}

If you just have one SkinPart, there doesn’t seem to be any need for the if statement because it will only run once. I have it there just to be safe. You also need to add code so that if the SkinPart is removed you also remove the event listener. That’s done by overriding the partRemoved function.

override protected function partRemoved(partName:String, instance:Object) : void
{
super.partRemoved(partName, instance);
 
if( instance == header )
{
header.removeEventListener(MouseEvent.CLICK, header_clickHandler);
}
}

And that’s pretty much all there is to it. This is just a very basic implementation but it should get you started. The design/development flexibility you get by using SkinParts in custom components makes it a great feature. When I finish with my SortableList component I’ll blog it and talk more about things I run into.

New Content in the Adobe Developer Connection

As part of our weekly content launches in the Adobe Developer Connection, we’ve recently published some new articles for Flash Platform developers.

The new skinning architecture in Flex 4 beta makes it easy to completely change the look and feel of an application. Follow Ryan Frishberg to learn about the new improvements by writing a basic skin for a button and then delving into skinnable components. Building on what you’ve learned there, Evtim Georgiev addresses a number of pain points in skinning, CSS, components, states, animation, text, and graphics tags. He also shows you how to create a custom layout in his article, Spark layouts with Flex 4 beta. Meanwhile, read Tim Buntel’s article to learn how a brand new approach in Flash Builder beta can simplify the development of data-centric applications.

If you are working with web video, you’ll want to learn how to customize the ActionScript 3 FLVPlayback component, the built-in solution in Adobe Flash CS4 Professional for displaying video on the web. Also be sure to download two updated templates: spokesperson presentation with synchronized graphics and showcase website for personal video.

Flash animators: Dig into Chris Georgenes’ popular series covering the entire process of creating a digital animated character in Flash CS4 Professional. And there’s a bonus: a killer animation technique that creates convincing 3D effects while remaining in the 2D realm. Also be sure to check out Tom Green’s article on Integrating Flash CS4 with After Effects CS4.

To get e-mail updates of our new content, subscribe to our newsletters: News Flash, The Edge, and the ADC update. You can also visit the Adobe Developer Connection to check for new content.