dlog preview
twitter, Flex, dlogHere's a preview of dlog, my AIR (desktop) app for blogging and microblogging built completely in Flex. Currently it handles service interfaces to twitter and instantspot. It's final release will include the ability to interact with twitter, pownce, friendfeed and jaiku for microblogging and any blogging site that uses the MetaWeblog API (XMLRPC). If you have any suggested services that could be integrated in please let me know, I'm always open to adding more functionality.
Here's the video!
dlog - v0.0.2b - 9-26-2008 from Steve Good on Vimeo
Here's a link to the uncompressed version, just a little over 6MB.
dl.getdropbox.com/u/208899/dlog-preview.mp4
Widget Outage - Widgets Back Online
Coldfusion, twitter, Flex, Widgetsx10hosting.com, the host where my widgets were being stored was doing server updates. I've moved the widgets to the lanctr.com domain. They are all back online again, but the wizards will need to be re-run to get the object and embed tags with the new domain.
Also, I had to remove the 2 minute Twitter widget refresh. This morning I quickly hit the 100 requests per hour limit on my twitter proxy. I'm looking into a solution for this and will have the widget updated when the solution is in hand.
Thanks for your patience!
Twitter Badge Wizard
Coldfusion, twitter, FlexI've created a Twitter badge wizard. It generates the object and embed needed to display your own twitter feed.
Here's the link: learncf.lanctr.com/badges/twitterbadge.cfm
Enjoy!
Twitter Badge - How I Did It
Coldfusion, twitter, FlexLet me start by saying that twitter.com's crossdomain.xml does not allow for flash / flex clients to read from their RSS feeds unless they are within the same domain, highly inconvenient. For that reason I created a proxy to twitter on one of my domains using ColdFusion to read and relay the RSS feed.
<cfif isDefined("twitterID")>
<cfset twitterFeedURL = "http://twitter.com/statuses/user_timeline/#twitterID#.rss">
<cfhttp url="#twitterFeedURL#" method="GET"/>
<cfxml variable="theFeedXML">
<cfoutput>#XMLParse(cfhttp.fileContent)#</cfoutput>
</cfxml>
<cfheader name="Content-Type" value="text/xml">
<cfoutput>#theFeedXML#</cfoutput>
</cfif>
This takes a Twitter ID and reads the feed on twitter.com, stores it in an XML variable, sets the document header Content-Type to text/xml, then outputs the XML variable's contents, the related RSS feed for the twitter ID.
For my example I am going to be using my twitterproxy.cfm page as my proxy, but because of twitter's refresh interval limits, you should use a proxy of your own. Yahoo Pipes looked promising, but they are currently fighting with the refresh interval limits like everyone else.
Ok, let's jump into the Flex code.
Here is how I have my source directory setup.

First we need to setup the visual components of the badge.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="doIt()"
paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0" color="#FFFFFF"
themeColor="#00FF12" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#676767, #676767]"
horizontalAlign="center" verticalAlign="middle">
<mx:Script source="as/main.as" />
<mx:HTTPService id="twitterService" url="{twitterFeedURL}"
resultFormat="e4x" result="twitterServiceHandler(event);" fault="twitterFaultHandler(event);"/>
<mx:Panel id="twitterPanel" width="170" height="153" layout="absolute"
paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0" color="#FFFFFF" title="Twitter / Loading...">
<mx:TextArea width="100%" height="100%" color="#000000"
backgroundColor="#FFFFFF" editable="false" wordWrap="true" id="twitterTA"/>
<mx:SWFLoader x="0" y="0" width="100%" height="100%" id="theLoader" name="theLoader" source="{loadingSWF}"/>
</mx:Panel>
</mx:Application>
The interface is pretty straight forward. I used a panel for my main container. The panel contains the textArea we'll use to display the feed and a SWFloader that displays a "loading" animation. Above the panel is the HTTPService component used to get the feed from my twitter proxy. Lastly, above the HTTPService component is the Script component, who's source points to the main.as actionscript file in the assets directory.
In the main.as file I've imported mx.rpc.events.FaultEvent and max.rpc.events.ResultEvent to handle both result and fault events from the HTTPService.
import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent;
Next I've defined the variables I want available to all methods in the script.
[Bindable] private var twitterFeed:XML; [Bindable] private var twitterRSSID:String; [Bindable] private var twitterFeedURL:String; [Bindable] private var twitterName:String; [Bindable] private var twitterLink:String; private var twitterInterval:int;
I then embeded my "loading" animation SWF.
[Embed(source="assets/flash/spinning ring.swf")] [Bindable] private var loadingSWF:Class;
Finally, I declared a namespace to use for reading the RSS feed and set the script to use the new namespace.
private namespace atom = "http://www.w3.org/2005/Atom"; use namespace atom;
In main.mxml's Appllication component I am calling the doIt() method from the creationComplete listener. This method reads any data being passed in through the HTML document via the FlashVars object. It then sets up the initial variable values and calls the getTwitterFeed method and the twitterRefreshInterval method.
private function doIt():void{
twitterRSSID = Application.application.parameters.twitterID;
if (twitterRSSID == null) {
twitterRSSID = "9813122";
}
twitterFeedURL = "http://learncf.lanctr.com/twitterproxy.cfm?twitterID=" + twitterRSSID;
getTwitterFeed();
twitterRefreshInterval();
}
The getTwitterFeed method only contains a single line. In it we invoke the HTTPService.
private function getTwitterFeed():void {
twitterService.send();
}
The result handler for the HTTPService is triggered when data is received from my twitter proxy. twitterServiceHandler, the result handler for the HTTPService, stores the returned XML in an XML datatyped variable. I set the panel's title to the value of the title node from twitterFeed. I also set the link to the user's twitter profile in the twitterLink variable, I get the URL from the link node in twitterFeed. Next I created a RegEx to scrape out the user's twitter name from the title since the feed doesn't explicitly specify this value. Following that, the first item node in the XML feed is passed through my URLsToLinks method to replace any URLs with clickable links and to replace profile names with clickable profile names. For instance, @stevegood is changed into a link that will point to the profile of stevegood. Lastly, if the "loading" animation exists we remove it from the panel.
private function twitterServiceHandler(event:ResultEvent):void {
twitterFeed = event.result as XML;
twitterPanel.title = twitterFeed.channel.title;
twitterLink = twitterFeed.channel.link;
var reString:String = "Twitter\\s/\\s";
var reObject:RegExp = new RegExp(reString,"ig");
twitterName = twitterPanel.title.replace(reObject,'');
twitterTA.htmlText = URLsToLinks(twitterFeed.channel.item[0].description);
var loaderExists:DisplayObject = twitterPanel.getChildByName("theLoader");
if (loaderExists) {
twitterPanel.removeChild(theLoader);
}
}
The fault handler for the HTTPService is pretty straight forward. If there is a fault it removes the "loading" animation, if it exists, changes the panel's title and textArea's htmlText to reflect that there was an error.
private function twitterFaultHandler(event:FaultEvent):void {
var loaderExists:DisplayObject = twitterPanel.getChildByName("theLoader");
if (loaderExists) {
twitterPanel.removeChild(theLoader);
}
twitterPanel.title = "Twitter / Error";
twitterTA.htmlText = "An error has occurred and the feed cannot be shown. Try again later.";
}
One of the reasons I set out to build my own twitter badge was because I didn't like that the official badge didn't auto update. To make mine autoupdate I created a method that sets an interval of 2 minutes, and at the end of each interval it calls the getTwitterFeed method, which retrieves the RSS feed from my proxy.
private function twitterRefreshInterval(delay:int = 120000):void {
twitterInterval = setInterval(getTwitterFeed, delay);
}
And finally, here is the URLsToLinks method. It uses a couple of RegEx expressions to parse and replace matching strings to create the clickable links I mentioned previously, then returns the formatted string.
private function URLsToLinks(theString:String):String {
// define the RegEx strings
var URLRE:String = "(https?)://([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+([a-zA-Z]{2,9})(:\\d{1,4})?([-\\w/#~:.?+=&%@~]*)";
var twitterRE:String = "(?<![\\w\\.])(?<=@)([-\\w]*)(?![\\w\\.])";
// Create the RegEx objects
var urlPattern:RegExp = new RegExp(URLRE,"ig");
var twitterPattern:RegExp = new RegExp(twitterRE,"ig");
var twitterNamePattern:RegExp = new RegExp(twitterName,"ig");
// replace text in the string that matches the RegEx objects
var result:String = theString.replace(urlPattern,'<a href="$&" target="_blank"><font color="#0000FF"><u>$&</u></font></a>');
result = result.replace(twitterPattern,'<a href="http://twitter.com/$&" target="_blank"><font color="#0000FF"><u>$&</u></font></a>');
result = result.replace(twitterNamePattern,'<a href="' + twitterLink + '" target="_blank"><font color="#0000FF"><u>$&</u></font></a>');
// return the formatted string
return result;
}
Here is the complete main.as file.
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
[Bindable] private var twitterFeed:XML;
[Bindable] private var twitterRSSID:String;
[Bindable] private var twitterFeedURL:String;
[Bindable] private var twitterName:String;
[Bindable] private var twitterLink:String;
private var twitterInterval:int;
[Embed(source="assets/flash/spinning ring.swf")]
[Bindable] private var loadingSWF:Class;
private namespace atom = "http://www.w3.org/2005/Atom";
use namespace atom;
private function doIt():void{
twitterRSSID = Application.application.parameters.twitterID;
if (twitterRSSID == null) {
twitterRSSID = "9813122";
}
twitterFeedURL = "http://learncf.lanctr.com/twitterproxy.cfm?twitterID=" + twitterRSSID;
getTwitterFeed();
twitterRefreshInterval();
}
private function getTwitterFeed():void {
twitterService.send();
}
private function twitterServiceHandler(event:ResultEvent):void {
twitterFeed = event.result as XML;
twitterPanel.title = twitterFeed.channel.title;
twitterLink = twitterFeed.channel.link;
var reString:String = "Twitter\\s/\\s";
var reObject:RegExp = new RegExp(reString,"ig");
twitterName = twitterPanel.title.replace(reObject,'');
twitterTA.htmlText = URLsToLinks(twitterFeed.channel.item[0].description);
var loaderExists:DisplayObject = twitterPanel.getChildByName("theLoader");
if (loaderExists) {
twitterPanel.removeChild(theLoader);
}
}
private function twitterFaultHandler(event:FaultEvent):void {
var loaderExists:DisplayObject = twitterPanel.getChildByName("theLoader");
if (loaderExists) {
twitterPanel.removeChild(theLoader);
}
twitterPanel.title = "Twitter / Error";
twitterTA.htmlText = "An error has occurred and the feed cannot be shown. Try again later.";
}
private function twitterRefreshInterval(delay:int = 120000):void {
twitterInterval = setInterval(getTwitterFeed, delay);
}
private function URLsToLinks(theString:String):String {
// define the RegEx strings
var URLRE:String = "(https?)://([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+([a-zA-Z]{2,9})(:\\d{1,4})?([-\\w/#~:.?+=&%@~]*)";
var twitterRE:String = "(?<![\\w\\.])(?<=@)([-\\w]*)(?![\\w\\.])";
// Create the RegEx objects
var urlPattern:RegExp = new RegExp(URLRE,"ig");
var twitterPattern:RegExp = new RegExp(twitterRE,"ig");
var twitterNamePattern:RegExp = new RegExp(twitterName,"ig");
// replace text in the string that matches the RegEx objects
var result:String = theString.replace(urlPattern,'<a href="$&" target="_blank"><font color="#0000FF"><u>$&</u></font></a>');
result = result.replace(twitterPattern,'<a href="http://twitter.com/$&" target="_blank"><font color="#0000FF"><u>$&</u></font></a>');
result = result.replace(twitterNamePattern,'<a href="' + twitterLink + '" target="_blank"><font color="#0000FF"><u>$&</u></font></a>');
// return the formatted string
return result;
}
You can view an example of the badge working here: http://learncf.lanctr.com/badges/twitterbadge.cfm
**Edit: I removed the source download link since I no longer have an account at x10hosting. You should be able to use the post as a source reference though.
Side Pods
General, twitter, FlexI've recreated many of my pods in flex. The only one giving me issues is the twitter pod. If you want to check em out, just look to the right side of the blog.
I'm working on getting the webcam image to update itself every 60 seconds. The twitter feed will also auto refresh, once it's working that is.
If you'd like to use my flex pods let me know and I'll hook you up with the embed tags.
Twitter Feed
General, twitterI've added a twitter feed to my pods. I've been getting more an more into twitter lately. I started just using the web interface to post and read, but after finding twhirl (an AIR app used to post and view tweets) I've really become addicted. Go ahead and follow me if you want to read my yammerings, there's a link below my feed.





Loading....