January 28th, 2011

I created a Flex/AIR app that allows us to monitor the CPU usage, Memory usage and Server Load of our off site Linux server.
It alerts us when any of these values exceed our configured maximums as well as storing the results in a sqlite database for viewing in either graph or table form.
AIR’s Native Process connects to plink, commanding plink to log onto the required server and pass a shell script to be executed.
Plink – a command-line interface to the PuTTY back ends;
top.sh:
1 2 3 4 5 6 7 8 9 10 11 12
| #!/bin/sh
mpstat 1 1 | awk 'NR >3 {print $3}'
echo "~"
free -o | grep Mem | awk '{print $2}'
echo "~"
free -o | grep Mem | awk '{print $3}'
echo "~"
cat /proc/loadavg | awk '{print $1}'
echo "~"
cat /proc/loadavg | awk '{print $2}'
echo "~"
cat /proc/loadavg | awk '{print $3}' |
The shell script has six commands it expects values back from, they are delimited by tildes to allow me to parse the result of my concatenated ProgressEvent.STANDARD_OUTPUT_DATA results when the NativeProcessExitEvent.EXIT is fired.
MonitorService.as:
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
| //plink command
private function returnStartupArgs():Vector.<String>
{
var output:Vector.<String> = new Vector.<String>();
output.push("-batch");
output.push("-l");
output.push(configVO.username);
output.push("-pw");
output.push(configVO.password);
output.push("-m");
output.push(topSHFile.nativePath);
output.push(configVO.server);
return output;
}
//ProgressEvent.STANDARD_OUTPUT_DATA
private function handleOutputData(e:ProgressEvent):void
{
_output += _process.standardOutput.readUTFBytes(_process.standardOutput.bytesAvailable);
}
//NativeProcessExitEvent.EXIT
private function handleExit(e:NativeProcessExitEvent):void
{
var monitorResultVO:MonitorResultVO = iMonitorResultVOParser.createFromString(_output);
validateMonitorResult(monitorResultVO);
}
private function validateMonitorResult(monitorResultVO:MonitorResultVO):void
{
if (iValidateMonitorResultVO.validate(configVO, monitorResultVO))
{
successSignal.dispatch(monitorResultVO);
}else {
monitorResultVO.errorCode = MonitorErrorCode.MAXIMUM;
monitorResultVO.errorMessage = iValidateMonitorResultVO.errorMessage;
failSignal.dispatch(monitorResultVO);
}
}
} |
Gotcha:
The server’s host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
http://the.earth.li/~sgtatham/putty/0.55/htmldoc/Chapter10.html
This message comes up if you are trying to access a server and you dont have it’s key in your registry. In putty it is a popup which you click and in plink it requires y/n.
AIR or plink seems to close the process when this message is recieved and i am unable to repond. I now simply openWithDefaultApplication putty so it can it connect to the server and allow us to respond manually. Not very elegant but it only needs to happen once and then the app can carry on polling the server. Solution pending!
No Comments » |
air2, flex4, native process, robotlegs, signals, sqlite |
Permalink
Posted by Kyle Ward
December 22nd, 2010
Our product relies on a “SWF to EXE” solution to give it drag, document CRUD and other “Desktop” functionality.
The two products contending are MDM Zinc and Screentime mProjector, both have their Pros and Cons but both essentially do whats needed.
But we are not resolved on either of them yet and need to toggle them as we progress.
This is where Config Constants lends a hand. By setting these compiler constants in your IDE or ANT builds you can toggle what gets compiled:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private var _iDesktopS:IDesktopService;
private var _iDragS:IDragService;
private function configure():void
{
LIBRARY::MDM {
_iDesktopS = new MDMDesktopService();
_iDragS = new MDMDragService();
}
LIBRARY::MPROJECTOR {
_iDesktopS = new MProjectorDesktopService();
_iDragS = new MProjectorDragService();
}
_iDesktopS.setup(this);
_iDragS.setup(this);
}
private function handleCloseRequest(e:MouseEvent):void
{
_iDesktopS.close();
} |
Using config constants that you define in the publish settings, you can specify whether certain lines of ActionScript code are compiled or not.
http://help.adobe.com
Setup is done easily in Flash:

Or you can implement it in your ANT build:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <target name="communicator">
<mxmlc file="${SRC_DIR}\coza\d6technology\communicator\communicator.mxml"
output="${BIN_DIR}\communicator.swf"
load-externs="${BASE_DIR}\shellLinkReport.xml"
link-report="${BASE_DIR}\communicatorLinkReport.xml"
debug="${DEBUG}"
default-frame-rate="${FRAME_RATE}"
optimize="true"
static-rsls="true">
<define name="LIBRARY::MDM" value="false"/>
<define name="LIBRARY::MPROJECTOR" value="true"/>
<keep-as3-metadata name="Inject" />
........ |
You are not just restricted to boolean values, although i haven’t tested this, but you can match the constant to a value as shown here: http://www.ericd.net/2009/01/config-constants-in-flash-cs4.html
No Comments » |
ant, config constants, flex |
Permalink
Posted by Kyle Ward
December 3rd, 2010

CIC – Communicator Installer Creator, the AIR/Flex app i created to help our production team create custom versions of the D6 product and its installer, uses a PackageMaker process to create the Mac installer.
As with most Mac installer software i researched, there is no uninstaller option, let alone the option to remove added Application Data or Login items added to system events. So i created a shell script which uses a mix of AppleScript and OSX commands to do such things.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/bin/sh
TITLE="St Peter's Schools"
// stop the process running
osascript -e "tell application \"$TITLE\" to quit"
// removes the "Application Data"
rm -R "$HOME/Library/Application Support/com.d6technology/$TITLE"
//removes the Application
rm -R "/Applications/$TITLE.app"
// removes the startup item
osascript -e "tell application \"System Events\" to delete login item \"$TITLE\"" |
It has not been integrated into production yet, but as a proof of concept it’s there or there about.
No Comments » |
mac, uninstaller |
Permalink
Posted by Kyle Ward
November 17th, 2010
I have multiple swfs in my project that need to be published in a variety of ways. Using ANT i can automate mxmlc, compc, cmd calls which allow me to publish swfs, swcs, extract swfs from swc and many more awesome features.
I found the initial setup of ANT tedious. Here are a few tips for setting up ANT.
Download ANT:
Unzip and copy to your hard drive (like the Flex SDK).
http://ant.apache.org/bindownload.cgi
Make sure you have the Java JDK installed:
Not the JRE else “Unable to locate tools.jar” error.
Download
Set your Enviromental Variables:
ANT_HOME [C:\Program Files\ant]
JAVA_HOME [C:\Program Files\Java\jdk1.6.0_22]
http://www.java.com/en/download/help/path.xml
Place your build.xml and build.properties in your project root:
http://www.adobe.us/devnet/flex/articles/flex_ant_pt1.html
Set path to flexTasks and build.properties in the build.xml:
1 2 3 4 5
| <property file="build.properties" />
<taskdef name="mxmlc" classpath="${FLEX_DIR}/ant/lib/flexTasks.jar" classname="flex.ant.MxmlcTask"/>
<taskdef name="compc" classpath="${FLEX_DIR}/ant/lib/flexTasks.jar" classname="flex.ant.CompcTask"/>
<taskdef name="html-wrapper" classpath="${FLEX_DIR}/ant/lib/flexTasks.jar" classname="flex.ant.HtmlWrapperTask"/> |
http://livedocs.adobe.com/flex/3/html/help.html?content=anttasks_1.html
FlashDevelop plugin:
You can run your build.xml from the CMD or a .bat file.
Most IDEs provide ways to use your ANT file [FlexBuilder, FDT, IntelliJ]
http://code.google.com/p/fd-ant-plugin
No Comments » |
ant, compc, mxmlc, toptips |
Permalink
Posted by Kyle Ward
November 1st, 2010
Whilst profling i noticed that one of my mx:Module would not be cleared from memory.
After an elimination process i found mx:Style to be the guilty party:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <mx:DateChooser xmlns:mx="http://www.adobe.com/2006/mxml"
weekDayStyleName="weekDayStyle">
<mx:Style>
.weekDayStyle {
fontWeight: bold;
...
}
</mx:Style>
<mx:Script>
<![CDATA[
private function styleWeekDay():void
{
var style:Object = iStyleSheetM.getStyle(".dateChooserWeekDay");
var declaration:CSSStyleDeclaration = styleManager.getStyleDeclaration(".weekDayStyle");
declaration.setStyle("fontWeight", style.fontWeight);
....
}
]]>
</mx:Script>
</mx:DateChooser> |
(My modules are styled from an external css file that gets loaded once after the applications startup and then gets implemented as you’ll see above. ie the default values in the script block get replaced by the values from the external css file.)
Remove the mx:Style block and the mx:Module would be collected.
But i need the style and therefore i found a solution:
1 2 3 4 5
| public function shutdown():void
{
styleManager.clearStyleDeclaration(".weekDayStyle", true);
...
} |
Perhaps i should use a better way to style my mx:Module, but at least this is a solution for now.
No Comments » |
flex, modules, robotlegs, style |
Permalink
Posted by Kyle Ward