<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Kevin Hoyt</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/" />
<modified>2007-03-21T01:42:32Z</modified>
<tagline></tagline>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34</id>
<generator url="http://www.movabletype.org/" version="3.16">Movable Type</generator>
<copyright>Copyright (c) 2007, khoyt</copyright>
<entry>
<title>Apollo File API Overview</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/03/apollo_file_api.cfm" />
<modified>2007-03-21T01:42:32Z</modified>
<issued>2007-03-19T15:41:09Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.13400</id>
<created>2007-03-19T15:41:09Z</created>
<summary type="text/plain">I was recently given the opportunity to present an introduction to the Apollo file API&apos;s at Apollo Camp. The event itself was a huge success with an eager and inventive crowd devouring code well into the evening. During Kevin Lynch&apos;s...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Apollo</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>I was recently given the opportunity to present an introduction to the <a href="http://labs.adobe.com/technologies/apollo/">Apollo</a> file API's at <a href="http://apollocamp.eventbrite.com/">Apollo Camp</a>.  The event itself was a huge success with an eager and inventive crowd devouring code well into the evening.  During Kevin Lynch's keynote, he mentioned that it should take Flex developers only a few minutes to get their applications into Apollo.  But what comes next?  </p>]]>
<![CDATA[<p>Wikipedia has an extensive definition for the term "computer file" which has a couple interesting sentences.</p>

<p>A computer file is a piece of arbitrary information, or resource for storing information, that is available to a computer program and is usually based on some kind of durable storage. A file is durable in the sense that it remains available for programs to use after the current program has finished. Computer files can be considered as the modern counterpart of the files of printed documents that traditionally existed in offices and libraries, which are the source of the term. (<a href="http://en.wikipedia.org/wiki/Computer_file">Wikipedia</a>)</p>

<p>Having a durable storage area that lives on after my application has ended is a big leap forward from web applications.  At its core, it is Apollo's local file access that enables occasionally connected computing (OCC) for the web developer.  It also opens the door for a new breed of applications developed using web technologies, which up to this point had required a round-trip to a server.</p>

<p>The file API in Apollo allows developers the ability to:<ul><li>Create and delete files and directories<br />
<li>Copy and move files and directories<br />
<li>List the contents of directories<br />
<li>Get system information on files and directories<br />
<li>Read and write binary files<br />
<li>Read and write text files<br />
<li>Serialize and deserialize ActionScript objects<br />
</ul>The Apollo API's include a new package, flash.filesystem.*, which includes only three new classes.  It is these classes that make all this local file access possible.  If you intend to develop Apollo applications, you should become very familiar with these classes, which are: File, FileMode and FileStream.</p>

<p><img alt="filesystem.jpg" src="http://weblogs.macromedia.com/khoyt/files/filesystem.jpg" width="600" height="450" /></p>

<p>As you might have figured out, the File class is a representation of a file or directory on the local system.  It includes the functionality to get a directory listing, find out the size of a file, when it was created and last modified and more.  The FileMode class sets the stage for you to tell Apollo how it is that you want to access the designated file or directory.  The FileStream class is the powerhouse containing all the methods for reading and writing data - for performing the actual IO operations.</p>

<p>If you're familiar with the ByteArray class that's already in ActionScript, then you'll feel right at home with the FileStream object.</p>

<p>Now wait just a minute.  Before you go off reading and writing files like a cowboy in the Wild West, you'll want to stop and consider that Apollo allows you to deliver applications across multiple operating systems (OS).  Not all operating systems represent file locations in the same fashion.  If you create a file at "C:\Documents and Settings\joe\My Documents\test.txt" what does that mean to a Mac?  What does "/Users/Documents/test.txt" mean to a PC?</p>

<p>The File class in Apollo has numerous properties that represent common file system locations in a manner that abstract the specific operating system.  </p>

<table width="600">
<tr><td>File.appStorageDirectory</td><td>Log files, cache files, preferences files</td></tr>
<tr><td>File.appResourceDirectory</td><td>User's install directory</td></tr>
<tr><td>File.currentDirectory</td><td>Launch directory; useful for command-line arguments</td></tr>
<tr><td>File.desktopDirectory</td><td>User's desktop directory</td></tr>
<tr><td>File.documentsDirectory</td><td>My Documents (Win), Documents (Mac)</td></tr>
<tr><td>File.userDirectory</td><td>User's home directory</td></tr>
</table>

<p>Not to be worried though, if you still want to access files using a native path, you can certainly do that - just be prepared for the results.  Above and beyond the common directory abstractions, Apollo also provides a means to access system resources as URI's.  Take a quick look at the following code snippet and notice the difference between the output of the native path and the URL properties.</p>

<p>trace( File.documentsDirectory.nativePath );<br />
// C:\Documents and Settings\joe\My Documents<br />
// /Users/joe/Documents</p>

<p>trace( File.userDirectory.url );<br />
// file:///C:/Documents%20and%20Settings/joe<br />
// file:///Users/joe</p>

<p>This additional abstraction for local file access has also extended within Apollo to offer two additional URI schemas: app-storage and app-resource.  </p>

<table width="600">
<tr><td>app-storage</td><td>var log:File = File.appStorageDirectory;<br>log = log.resolve( “test.txt” );<br>trace( log.url );<br>// app-storage:/log.txt</td></tr>
<tr><td>app-resource</td><td>var install:File = new File();<br>install.url = “app-resource:/”;<br>install = install.resolve( “hello-world.xml” );<br>trace( install.url );<br>// app-resource:/hello-world.xml</td></tr>
</table>

<p>This example also shows the basis for the common series of steps that you'll take whenever you want to access the local file system.  There's the declaration of the file object, followed by a call to the File.resolve() method.  This call returns a File object that you can use for the remainder of your file access.  It's pretty clear that a good amount of consideration went into local file access options.  The various abstractions also create a great foundation for extension in future releases.  </p>

<p>I know, I know, you're getting anxious.  Before we head to the boilerplate code that we’ll use for every file operation, there's one last consideration of which we need to be aware.  Apollo offers two different ways to read a file - synchronous and asynchronous.  You can probably make a logic leap as to what the differences between the two are, but what does that mean to Apollo specifically?</p>

<p>When you choose to use the synchronous approach to working with the file system, you effectively choose to block any additional user interaction until the file is processed.  It also turns out that this requires less code, which I've personally found very handy when writing smaller data files.  </p>

<p>By comparison, asynchronous methods run in the background, and allow other ActionScript processes to take place at the same time.  This is especially effective for those situations where the file you're reading is larger than 1 Mb.  You'll want to use the asynchronous methods whenever there might be a delay in reading the file contents.  Another example might be reading a relatively small file across a slow network.  </p>

<p>Using the asynchronous methods also means having event listeners registered for the events you want to know about.  This could be an indication that the file is open and ready for processing, or information that a certain number of bytes has been read into the buffer (i.e. random access).  Using the asynchronous methods also means having more code in the form of event handlers.</p>

<p>There are six steps that are common to almost every file access routine you’ll ever write for Apollo.</p>

<p>// Setup a File object<br />
var myFile:File = File.appStorageDirectory;<br />
myFile = myFile.resolve( "contacts.xml" );</p>

<p>// Instantiate a FileStream object<br />
var myStream:FileStream = new FileStream();</p>

<p>// Set the appropriate event listeners if needed<br />
stream.addEventListener( Event.COMPLETE, doReadData );</p>

<p>// Open the file in the required mode<br />
stream.openAsync( myFile, FileMode.READ );</p>

<p>// Various read operations in an event handler</p>

<p>// Close the file when you're done with it<br />
stream.close();</p>

<p>The first step is to setup the file or directory that you want to access.  This can be done using the File properties mentioned earlier, or the URI abstractions.  Once you've resolved the file you'll need to create a FileStream object.  This is the object that does all the work of actual file IO.  </p>

<p>If you're going to be opening a file for asynchronous access, you'll want to register some event handlers next - before you open the file or start working with its bytes.  When you open the file you will call either FileStream.open() or FileStream.openAsync() which are indicative of synchronous and asynchronous file access respectively.  You'll also need to reference which type of access you will be using (i.e. read, write, append, update).</p>

<p>Once you've got that setup, you can read and write at your leisure using any of the various methods on the FileStream object.  These include coverage for everything from least significant bit (endian), reading single bytes, number values, strings and so on.  When you're done with the file, don’t forget to clean up after yourself and close the file using the FileStream.close() method.</p>

<p>I put together a number of examples that show file access from a variety of use-cases.  The <a href="http://weblogs.macromedia.com/khoyt/files/file-api.zip">source code</a> for all those examples, as well as the <a href="http://weblogs.macromedia.com/khoyt/files/fileapi.air">AIR file</a> is available for download.  I've also recorded a narration of my original <a href="http://mmse.acrobat.com/fileapi/">presentation and slides</a> from the Apollo Camp presentation.</p>

<p>I've also put together a <a href="http://mmse.acrobat.com/p19924825/">Connect recording</a> that walks through what each demo is, how it works, and what it does.  The examples start with basic text IO in the form of a minimalist text editor.  There's a simple contact manager application that's repeated twice in the examples - once using XML as the data store and another using ActionScript object serialization.  I’ve also included a very basic hex editor (viewer really) and an Exif data viewer for demonstrations of binary file access.  </p>

<p><img alt="file-api-screen.jpg" src="http://weblogs.macromedia.com/khoyt/files/file-api-screen.jpg" width="600" height="466" /></p>

<p>A bonus example I didn't get a chance to finish all the way is capturing a PNG from the web cam and saving it to disk.  The capture, PNG writing and PNG reading all work, but the UI lacks polish.  This example also shows how to use a directory listing, which is how the application knows what PNG files are available.  You're welcome to play with this example, though it has been commented out in the AIR.</p>]]>
</content>
</entry>
<entry>
<title>Presenting CRUD at 360Flex</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/03/presenting_crud.cfm" />
<modified>2007-03-03T00:26:21Z</modified>
<issued>2007-03-03T00:22:28Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.13282</id>
<created>2007-03-03T00:22:28Z</created>
<summary type="text/plain">Everybody seems to be blogging about their presentations and/or presence at 360Flex, so I thought I&apos;d join the mix. I&apos;m actually in San Jose right now, but headed home for the weekend in an hour or so. I&apos;ll be returning...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Everybody seems to be blogging about their presentations and/or presence at 360Flex, so I thought I'd join the mix.  I'm actually in San Jose right now, but headed home for the weekend in an hour or so.  I'll be returning on Sunday night ready to network, present and otherwise have fun with fellow Flex developers.  My topics are "5 Minute CRUD with FDS" and "Flex with Java".</p>]]>
<![CDATA[<p>The "5 Minute CRUD" presentation is among my favorite, and my most well received.  I remember walking Ted Patrick through it during his first week at Adobe.  It must have struck a nerve because almost a year later to the day, he asked me to present it at 360Flex.  </p>

<p>The presentation starts with the more common XML-oriented CRUD, moves to using remote objects, and then ends with building out a data management infrastructure.  Data storage techniques will include both a relational database and a flat XML file.  I've arranged to give a sneak peak of some of the future of Data Services as well.</p>

<p>The intention of the presentation is to compare and contrast the features of Data Services while understanding the value it can bring to the development process.  It's all code (Java) with the exception of the slide with my name/email and a quick architecture slide.  <br />
If time permits, I'd like to side-step CRUD and talk about messaging as well.</p>

<p>The second presentation on "Flex with Java" is a bit more open-ended.  I could go a number of directions, and since the presentation isn't until the of the day on Wednesday, I have time to change it up.  I could stick to the more traditional XML-oriented side of the house and talk J2EE presentation technologies (JSP, servlets), frameworks (Spring and Hibernate), or integration topics (file upload, JMS).</p>

<p>I'm open to suggestions here, so if you have some input I'd be happy to hear it here in comments, or you can track me down at the event.</p>]]>
</content>
</entry>
<entry>
<title>On Flexing the 1040 (US tax form)</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/02/on_flexing_the.cfm" />
<modified>2007-02-26T17:49:52Z</modified>
<issued>2007-02-26T17:21:05Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.13240</id>
<created>2007-02-26T17:21:05Z</created>
<summary type="text/plain">Let me preface this post by saying that perception is reality. That is to say that sometimes all you really need to do is instill the vision of what&apos;s possible, and the rest will take care of itself. In the...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Let me preface this post by saying that perception is reality.  That is to say that sometimes all you really need to do is instill the vision of what's possible, and the rest will take care of itself.  In the software world we call this a "demo".  Setting vision and demonstrating the possibilities of Adobe software is something I do on a daily basis.  With that in mind, I was recently tasked to come up with a Flex version of the IRS Form 1040 (annual taxes for those outside the United States).</p>]]>
<![CDATA[<p>I've never been classically training in information architecture or experience design, but it is something I find that I have a penchant for developing.  Given that I come from a background of desktop technologies, it should be no surprise that I tend to apply this metaphor to my applications - it also happens to be something that's well suited to RIA.  My first line of business then, was to familiarize myself with the form itself, and to understand how it is that users interact with it currently.</p>

<p>When I headed to the IRS web site and opened the Form 1040, I did so using Acrobat Reader 8.  I thought to myself that there are a lot of fields here, and that in general the PDF version does a pretty good job of displaying it all.  You can turn on highlighting of the fields you have to fill out.  You can merrily tab along all day.  There's even a place to create attachments, which is something the 1040 asks for repeatedly.</p>

<p>Then I came to the "Pages" view containing the thumbnails of the PDF.  This was particularly not helpful.  Two pages with lots of garbage on them left me at a loss for context (where am I in the overall form).  The "How To" section told me all about Acrobat Reader, but nothing about the 1040, which is really where I needed the help.  To get that help I'd have to open another PDF and then toggle between the two, getting lost along the way.</p>

<p>This is where inspiration struck.  Acrobat Reader is relatively unintelligent about these areas because it has to deal with all variety of documents.  Some forms might be related to tax, but yet others might have interactive 3D diagrams for uses in manufacturing.  It suffers content specificity (usability) for abstraction - and understandably so.  What if Acrobat Reader knew this was a 1040?  What then would happen if the "Pages" were of the sections of the form, rather than the pages of the document?  What if the "How To" contained context-sensitive help relative to the fields on the form?  What if rather than reading, I was able to get video/audio help from an IRS representative?</p>

<p><a href="/khoyt/files/f1040.swf"><img alt="f1040-small.jpg" src="http://weblogs.macromedia.com/khoyt/files/f1040-small.jpg" width="660" height="433" /></a></p>

<p>Before I get into the details of what I built, why and how, let's go back to the "perception is reality" thing.  I am one guy.  My timeframe here was a single week.  My already full schedule was also not going to magically clear itself, so I had to fit in development wherever I could.  To that end, this is a demo.  There are lots of fun features, but precious little actual functionality.  Bugs run rampant.  My list of features that didn't get done is almost as long as what did.  Fundamentally however, it does set the vision for the group that requested the work.</p>

<p><b>Dynamic Form Sections via XML</b></p>

<p>The first thing to know is that while the 1040 was the main topic of interest, it was expected that after I was done, the demo would live on and need to be repurposed by others.  For this I leveraged dynamically generation of the form itself.  There's a single XML file which describes the form and that is loaded when the application first starts.  When you see "Accessing form..." in the demo, the XML is loaded and the UI is being constructed at runtime.  </p>

<p>Again, perception is reality.  The user perceives that the some fashion of network calls are happening and is happy to wait, when in actuality the application is burning your CPU to instantiate all the form line items.  This is one of my favorite usability tricks.  I also wasn't going to create the 75+ line items by hand, and have a never-ending support job on my hand every time somebody wanted a new form.  Change the XML, change the form - done.</p>

<p>I should also mention that it's possible to have an XML representation of a PDF, and in theory this same source could potentially be used to drive either UI.  It also stands to reason that additional UI could be added to the application to allow the user to select from any variety of supporting forms, which is one of the features I didn't get to.</p>

<p><b>Real-time Thumbnail Views</b></p>

<p>Great, I've loaded the XML and built the UI at runtime.  What about my main objective however of making taking Acrobat Reader metaphors and making them context sensitive?  How was I going to have thumbnails of the form sections when the application doesn't ever really know what the form looks like?  For this I turned to the Bitmap API in the Flash Player, grabbing the screen shots of the forms once they are created and scaling them down to a thumbnail view.  </p>

<p>Perception is reality though, right?  How do I prove out, or show, that the thumbnails are truly dynamic during the demonstration?  I added a few event listeners to my form line items (which are actually instances of a general-purpose line item component), and then grabbed new "screen shots" of the sections whenever a form was changed.  Doing so with every keystroke seemed a bit overkill however, so I wait for a change and a focus loss.  </p>

<p>Try it - edit a field and then tab off it and watch the thumbnail get updated.  You can also navigate to the various form sections by clicking on a thumbnail.  By the way, I've locked the form fields to accept only numeric data - love that client-side intelligence.  Conversely, I didn't have time to get to the "cents" field, so only the whole dollar fields work.</p>

<p><b>Attachments</b></p>

<p>One of the things I noticed about the verbiage of the 1040 was that it often called for attaching additional forms.  I thought it was annoying to have to read that and then go hunting down the UI for attachments.  I wanted to place context in an otherwise generic Acrobat Reader.  I know what the form is, and I know that the user will be queued to attach files via the verbiage "Attach".  </p>

<p>That little line item component I mentioned earlier is smart enough to pick up on the "Attach" verbiage.  For there it replaces that text with a paperclip icon.  Users can then click on the icon and open a file attachment dialog.  The attachment pane in the application will also open if it isn't already.  </p>

<p>Don't worry, I don’t actually upload your attached files (this is a demo after all), so go ahead and try it.  The application limits the types of forms you can upload to TXT, DOC or PDF.  I also took the time to create a custom item renderer to show the respective icon for the type of file attached.  If you select a file from the list you can also remove it.  And of course, going to the attachment section directly works too if you don’t need the contextual icon.</p>

<p><b>How To</b></p>

<p>With regards to parsing verbiage, the 1040 also says to "see page" for help repeatedly.  This is that aforementioned file you'd have to find, open and toggle between.  In keeping with the mission of adding context, the application parses out wherever it encounters "see page" and creates an icon.  Just like the "attach" icon, the help icon can be clicked, which will take you to the "How To" section and present context-sensitive help - in this case, video help.  </p>

<p>Okay, so I took the opportunity to inject a bit of humor into the demonstration.  Yes, that's me in my office acting like a secret agent.  What can I say?  I was on a "Men in Black" kick at the time!  If the angle looks funny, that's because I'm 6' 7" and had to slouch way down in my chair for my webcam.</p>

<p>I didn't have time to record the actual help for every line, so I created three videos - line 21, line 32 and line 44.  Line 44 is used as a catch-all, so if you click on any other line item that isn't 21 or 32, you'll actually get the video for line 44.  The video here is delivered progressively (actually downloaded).  Ideally, it'd be delivered as streaming video from the Flash Media Server.  </p>

<p><b>Live Help</b></p>

<p>So long as a streaming server might be in place, why not offer live help for the consumer as well?  If you select the "Live" option from the "How To" panel, you'll find a screen that echoes back your webcam.  If you don't have a webcam, you'll have to image your pretty face in that black box.  With FMS in place, it wouldn't be your face there, but a customer service representative (CSR), eagerly waiting to walk you through the complexity of filing your taxes.</p>

<p>Almost assuredly not every person in the United States filing taxes has a webcam, so I needed a way to allow the user to interact with the CSR.  As I've encountered many times through countless e-seminar presentations, text chat performs wonderfully at this task.  If you enter a message and click "Send" you'll get a three second pause and then your message echoed back to you.  </p>

<p>Again, part of my thought process was around distribution of the demonstration, and I wanted to avoid a never ending support situation.  In a deployed scenario, this type of messaging is a perfect fit for Flex Data Services (FDS).  Enabling application sharing through FDS would also be an attractive feature that would allow a CSR to fill out the form remotely. </p>

<p>If you click on the back button in the "How To" section, or the "Home" button, you'll find yourself back at the original screen where we get to watch video of me being corny.  The last type of help I decided to surface in the application was context sensitive by way of mouse click.  </p>

<p>If you click the "Context" option at the top of the list, your mouse will turn into a cursor with a question mark.  You can click anywhere in the form to make this go away.  Clicking on a line item doesn't actually do anything other than remove the cursor in the demonstration.  It does however set the precedent for the empowering the consumer to get their own help in the same context as many other desktop applications.</p>

<p><b>Missing In Action</b></p>

<p>I've talked about the line item component a few times.  It is driven by an XML node, smart enough to know how to parse out verbiage, raises events for user help and attachments, and can even take lightweight HTML for the label.  In my opinion however, this is amongst the weakest parts of the demonstration from an architectural point of view.</p>

<p>There's a number of more complex line items on the 1040 that my little line item component just can't handle.  At least, not in it's current form.  There's also a limit to the screen resolution that this display mechanism presents.  You'll notice for example that if your screen resolution is small enough, the labels will flow right on into the fields.  </p>

<p>If I was going to expand on this demonstration, the line item would be the first place I'd start - allow the XML to describe a more complex line and then to be able to wrap the line where the label is long enough to bump into the field.  It should also be pretty obvious that I'm actually missing a number of sections for this exact shortcoming. </p>

<p><b>Moving Ahead</b></p>

<p>You may or may not be fond of my interpretation, and I respect that completely.  One thing I've encountered though is that there's a distinct shortage of Flex-based RIA (or any RIA really) that account for complex data entry.  When they do, they automatically default to the classic desktop metaphors.  This isn't something I'm against, but I believe that we've yet to tap into potential of RIA for alternative data entry for enterprise applications.  This demonstration however, is hopefully something that instills at least some degree of vision as to where developers might be able to go in the future.</p>

<p>I should also mention that this demonstration stops short at collecting the information.  Clearly this data isn't going to be processed outright by a computer and spit out your refund check.  At some point a human will need to review the content and make sure everything adds up.  That infers some fashion of workflow that needs to be put in place.  A perfect fit for LiveCycle Workflow.</p>

<p>Perhaps rather than submit the information electronically, you want to print it out and put it in the mail.  Does that mean that somebody on the other end is going to have to spend countless hours re-keying all this data?  What's to say that you're going to mail the form to the IRS?  Maybe once you've filled it out, you want to take it to H&R Block (or the likes).  Putting this data into a 2D barcode (PDF 417) a la LiveCycle Barcode would be the perfect fit.</p>

<p>There's of course going to need to be some fashion of security involved with this form.  I don't want my tax information readable by just anybody.  I can also expect that the IRS is going to want to know that I am accountable for the information I provided via signature - digital signature perhaps.  Enter into the mix LiveCycle Security.  </p>

<p>What if the form evolves and as the issuing institution, I want to be able to control or outright revoke who sees what version of the form?  Enter LiveCycle Policy Server.</p>

<p>You see, in the big picture here, going all the way back to setting vision, I think it's important that developers see Adobe for the broader spectrum of solutions that it can provide.  Sure, there's a great "boxed" product company that offers world-class software like Photoshop and Dreamweaver, but Adobe also offers the infrastructure solutions necessary to support developers building their own world-class software.</p>

<p>While there's undoubtedly a long way for Adobe to go on the whole to make this type of vision a reality, I think it's safe to suggest that is the direction it will go in the near-term.  The Adobe/Macromedia acquisition has been final for just over a year at this point.  That's precious little time to bring this entire vision together. What will Adobe's solution offering look like a year from now?</p>]]>
</content>
</entry>
<entry>
<title>Data Synchronization Visualization</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/02/data_synchroniz.cfm" />
<modified>2007-02-28T17:00:02Z</modified>
<issued>2007-02-19T04:39:13Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.13171</id>
<created>2007-02-19T04:39:13Z</created>
<summary type="text/plain">Among the many valuable features of Adobe Flex Data Services is the ability to keep client-side applications in sync with their appropriate data-structures on the server. While this generally means relational databases and lists or tables of data on the...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Among the many valuable features of Adobe Flex Data Services is the ability to keep client-side applications in sync with their appropriate data-structures on the server.  While this generally means relational databases and lists or tables of data on the client, it doesn't always have to be that way.  I recently came across an interesting scenario, which afforded me the luxury of building an application that represented client-side data outside of a list.</p>]]>
<![CDATA[<p>You can pick any number of potential uses for this type of scenario.  Maybe there's a police chase and in which the movement and history are being tracked and analyzed in a database.  Maybe the aircraft in your fleet are reporting their position and you want to see all those aircraft as icons on a map, in real-time as they report.  Maybe you’re a mission commander evaluating field readiness and you need to know where combat assets are located at this very moment.  </p>

<p>The bottom line is that some object is being tracked and its location needs to be monitored in real-time across any given number of client applications. </p>

<p>The downside to being able to develop something like this is that I don't actually have anything reporting to a server.  No information is being stored in a database and the only person who needs to know about it is me.  In order to simulate this, I built two separate applications.  </p>

<p>The first application acts as a viewport into data that will change over time.  It does little more than show where everything in the database is located.  It also summarizes the view, telling the end user how many items are reporting, when the last report arrived at the client and offering the traditional tabular display of data as an alternative view.  I built a "map" component that shows the items being tracked as blue dots.</p>

<p><img alt="viewer.gif" src="http://weblogs.macromedia.com/khoyt/files/viewer.gif" width="660" height="495" /></p>

<p>The second part of the application leverages the exact same "map" component for the purposes of being able to visualize the data, but it also acts as an emulator that causes data to change.  There's a timer control to dictate how often the data is being updated, and a numeric stepper to specify how many items should be reporting.  For every iteration of the timer, this part of the application makes random changes to items being tracked.  This forces an update in the database and subsequent propagation of the new values out the "viewport" applications.</p>

<p><img alt="manager.gif" src="http://weblogs.macromedia.com/khoyt/files/manager.gif" width="660" height="495" /></p>

<p>The real bonus here is that thanks to Flex Data Services, all the synchronization happens automatically.  Furthermore, changes to the data don't happen by RPC calls to specific endpoints, but rather to client side data object in a collection.  When the changes occur, Flex Data Services (FDS) automatically sends a list of the changes made out to the server.  The server then synchronizes and/or commits those changes into a database, and propagates the changes out to all the clients.</p>

<p>From the developer perspective, there's no need to know where RPC endpoints are located.  There's no need to invent a way for all the clients to check-in for the most recent data on a regular basis.  There's no need even to worry about network connectivity, or how the connection is made.  Firewall?  No problem, FDS can automatically failover to HTTP polling.  The abstraction that FDS affords allows developers to focus on the visualization and in adding new features to the applications - and in turn not having to think about all the infrastructure and plumbing.</p>

<p>I've packaged this sample up and made the <a href="http://weblogs.macromedia.com/khoyt/files/fds-map.zip">source available</a> should you like to download it and see just how simple all this really becomes thanks to FDS.  The example has been built on Christophe Coenraets' recently released <a href="http://coenraets.org/blog/2007/01/flex-test-drive-server-for-java-developers-tomcat-based/">FDS Test Drive Server</a> that's based on Tomcat.  You can download that tutorial, unzip the archive and be up and running with FDS in minutes.  There's no invasive installation or database configuration, just a single start-up batch file and tons of invaluable tutorials.</p>

<p>To add this example to the mix you'll need to take a few additional steps as follows:</p>

<ul>
<li>Add the assetsdb.script entries to the db/flexdemodb.script file </li>
<li>Note: The SQL statements in assetsdb.script need to be grouped with their respective statements in the flexdemodb.script file (i.e. CREATE with CREATE, ALTER with ALTER, and INSERTs at the bottom with the other INSERTs)</li>
<li>Put the poc folder found in java/classes into the webapps/ROOT/WEB-INF/classes directory</li>
<li>Copy the destination entry from flex/data-management-config.xml into webapps/ROOT/WEB-INF/flex/data-management-config.xml</li>
<li>Put all the remaining files in the flex directory in a "map" directory in webapps/ROOT</li>
</ul>

<p>At this point you can start the Tomcat installation as instructed in the tutorial (bin/startup.bat).  You'll probably want to open the manager view first which is the "manager.mxml" file you just put in the map directory.  Then you'll want to create a new browser window (or tab) and open the "viewer.mxml" file.  As the manager application changes the data randomly, those changes are put into the database and propagated out the viewer instances.  Don't forget that the manager is a viewer too, leveraging the same "map" component as the viewer.</p>]]>
</content>
</entry>
<entry>
<title>Thoughts on Accordion Usability</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/02/thoughts_on_acc.cfm" />
<modified>2007-02-19T14:56:46Z</modified>
<issued>2007-02-19T03:32:35Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.13170</id>
<created>2007-02-19T03:32:35Z</created>
<summary type="text/plain">It&apos;s no big secret that I&apos;m not a particularly big fan of the accordion control. In almost every case I encounter, the use for the accordion is to provide an alternative view to stepping through complex forms. While it can...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>It's no big secret that I'm not a particularly big fan of the accordion control.  In almost every case I encounter, the use for the accordion is to provide an alternative view to stepping through complex forms.  While it can certainly be made to accommodate this use-case, it has to be one of the most abused applications of the container.  What's worse is that I fear we'll see a lot more of it in the not too distant future.</p>]]>
<![CDATA[<p>Let's take a common complex form that many of us here in the United States are very familiar with as an example - the <a href="http://www.irs.gov/pub/irs-pdf/f1040.pdf?portlet=3">Internal Revenue Service (IRS) Form 1040</a>.  The basic 1040 as pulled from the IRS web site has no fewer than thirteen different sections (nine on the conservative side).  Let's stop and think about this then for a second as it relates to the accordion.  What does the accordion look like with thirteen sections in it?<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,14,0" width="660" height="562" id="bigacc.swf"><br />
  <param name="flashvars" value="versionChecked=true"><br />
  <param name="src" value="http://weblogs.macromedia.com/khoyt/files/bigacc.swf"><br />
  <embed pluginspage="http://www.macromedia.com/go/getflashplayer" width="660" height="562" flashvars="versionChecked=true" src="http://weblogs.macromedia.com/khoyt/files/bigacc.swf" name="bigacc.swf" /><br />
</object><br />
I've only had to complete the few sections here to get the point across.  The first section fills in nicely.  The second section leaves copious amounts of extra space lying around.  My favorite however is the fourth section, in which I've run out of room and stopped after only nine fields.  The actual Form 1040 goes on for another nine fields - the "Tax and Income" section is the longest with 23 fields.  The "one size fits all" approach of the accordion creates this white space feast or famine situation.</p>

<p>On the positive side, the accordion does fundamentally provide contextual information to the user.  We always know where we are and how much we've got left to go.  Is that really the best way to display the content?  Should we just shove our forms into Flex and everything else will just magically improve?  What are some of the alternative displays we might choose for this type of complex form?  </p>

<p>When I find myself struggling for how to implement something in Flex, I ask myself "How is it accomplished in the day-to-day applications I encounter on the desktop?"  To be fair, this question in its own right is somewhat flawed because what we really want is something rich and engaging.  We like to think of this as desktop applications in the context of RIA, but it's really just falling back on an earlier metaphor.  But I digress...</p>

<p>Just how is a complex form displayed in a desktop application?  It may seem elusive at first, but we see them every time we install a new application - wizards.  The parts that are broken about complex forms on the web aren't "Next" and "Previous" but rather the waits and refreshes that accompany the approach.  With RIA however we can offer instantaneous feedback.  Let's apply the "wizard" metaphor to a complex form, and throw in a splash of Flash for emphasis.<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,14,0" width="452" height="522" id="filmstrip.swf"><br />
  <param name="flashvars" value="versionChecked=true"><br />
  <param name="src" value="http://weblogs.macromedia.com/khoyt/files/filmstrip.swf"><br />
  <embed pluginspage="http://www.macromedia.com/go/getflashplayer" width="452" height="522" flashvars="versionChecked=true" src="http://weblogs.macromedia.com/khoyt/files/filmstrip.swf" name="filmstrip.swf" /><br />
</object><br />
From a usability perspective this is better and worse.  While the forms aren't crowded by the container itself any longer, we've lost most of our context.  Where are we in the form?  A little extra UI chrome can bring this out to the user - something for which we now have space.  Perhaps a menu bar (ButtonBar in Flex) across the top of the form?  Maybe thumbnails of the various form sections?  In fact, you now have enough space to take it forwards to RIA and include context-sensitive video help.<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,14,0" width="660" height="562" id="wizard.swf"><br />
  <param name="flashvars" value="versionChecked=true"><br />
  <param name="src" value="http://weblogs.macromedia.com/khoyt/files/wizard.swf"><br />
  <embed pluginspage="http://www.macromedia.com/go/getflashplayer" width="660" height="562" flashvars="versionChecked=true" src="http://weblogs.macromedia.com/khoyt/files/wizard.swf" name="wizard.swf" /><br />
</object><br />
For the record here, I didn't come up with the blur effect on forms.  This is actually how a form in one of our demos is transitioned (thanks to Adobe's Experience Design team).  The effect has been very popular in customer demonstrations, and I've had many people ask me how it is accomplished.  I've even had one colleague suggest that I build a framework for the behavior.  Suffice to say it isn't that complex, and I've <a href="http://weblogs.macromedia.com/khoyt/files/accordion-to-wizard.zip">attached the source</a> (<a href="http://www.ketnerlake.com/work/accordion-to-wizard-video.zip">video files</a>) if you’d like to see for yourself.</p>

<p>I didn't come up with the page thumbnails either - you can see that in Adobe Acrobat Reader.  Once again I go to the desktop for inspiration.  What I did come up with however is a way to generate the thumbnails at runtime based on the forms.  What?  Yup, whenever navigation occurs from one form to another, the thumbnail gets updated dynamically at runtime.  Credit here goes to the bitmap features in the Flash Player.  The <a href="http://weblogs.macromedia.com/khoyt/files/accordion-to-wizard.zip">source</a>  (<a href="http://www.ketnerlake.com/work/accordion-to-wizard-video.zip">video files</a>) for that is also included in the example.</p>]]>
</content>
</entry>
<entry>
<title>Yet Another Webcam Barcode Scanner</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/01/yet_another_web.cfm" />
<modified>2007-01-22T14:50:08Z</modified>
<issued>2007-01-21T17:27:55Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.12958</id>
<created>2007-01-21T17:27:55Z</created>
<summary type="text/plain">Let me be clear right up front - I didn&apos;t come up with this idea. In fact, I&apos;ve seen no fewer than three other web-cam barcode scanner implementations. This first one I saw was shortly after the release of Flash...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Let me be clear right up front - I didn't come up with this idea.  In fact, I've seen no fewer than three other web-cam barcode scanner implementations.  This first one I saw was shortly after the release of Flash Player 8 with the introduction of the bitmap API's.  You can still use this version and access it as a component on <a href="http://en.barcodepedia.com/">Barcodepedia</a>.  <a href="http://renaun.com/flex2/BarcodeReader/BarcodeReader.html">Renaun Ericsson</a> has also created a web-cam barcode scanner using ActionScript 3 complete with a Flex 2 user interface.  I also ran across an implementation on the <a href="http://blog.webqem.com.au/playground/barcodeFP9/BarcodeReader.html">webqem blog</a>.</p>]]>
<![CDATA[<p>None of these projects however provides source code, so I set out to build one myself.</p>

<p>I started off by searching the web for any existing code that I might leverage.  I found a couple C# write-ups on <a href="http://www.codeproject.com/csharp/barcodeimaging2.asp">parsing barcodes</a>, but they both assumed a clean image.  Next I headed to SourceForge, where I found a <a href="http://sourceforge.net/projects/jbcode/">project written in Java</a>.  There was precious little documentation in the project however, so I rounded my knowledge out with an <a href="http://www.wikihow.com/Read-12-Digit-UPC-Barcodes">article on WikiHow</a>.  Once I had everything working, I started tweaking the code to maximize accuracy.</p>

<p>If you're interested in how this is accomplished, the general process looks something like this:</p>

<ul>
<li>Attach Camera to VideoDisplay</li>
<li>Start a Timer to sample (scan) at regular rates</li>
<li>Capture the scan area to a BitmapData object</li>
<li>Take samples from across the image</li>
<li>Convert composite sample to grayscale</li>
<li>Clear out noise through an unsharp mask</li>
<li>Process sample to collect average grey threshold</li>
<li>Walk across sample with threshold to determine "lines"</li>
<li>Determine through averaging the width of a "line"</li>
<li>Combine line groups to extract individual units</li>
<li>Map units to numbers</li>
<li>Run a check-sum on the barcode to determine accuracy</li>
<li>Convert accurate UPC to ISBN</li>
<li>Request Amazon product details using ISBN</li>
<li>Request Flickr images based on author's name as tags</li>
</ul>

<p>The result is relatively accurate, but there's a long way to go.  First I'd like to look at detecting the barcode itself for cropping.  Secondly I'd like to make the scanner smarter about what it sees - which might be early blocks of dark color that aren't lines, and even to <a href="http://www.codeproject.com/useritems/Deskew_an_Image.asp">deskew</a> the sampled image.  Finally I want to add extensibility which would separate the image processing from the barcode matching (making it easy to add custom barcode types).</p>

<p>I'm a big fan of using web cameras for data capture - especially as it relates to barcode symbology.  Web cameras are becoming commonplace and CCD sensor quality is constantly improving.  Virtually everything has a barcode on it, and of course there are numerous tools for generating barcodes (including <a href="http://www.adobe.com/products/server/barcodedpaperforms/">Adobe LiveCycle</a>).  </p>

<p>To me, this functionality, since it is possible with Flash, should be openly available to developers.  Ideally this might be rolled into a <a href="http://www.riaforge.org">RIAForge</a> project, so it can be contributed to and improved by the community.  For now however, here's an <a href="http://weblogs.macromedia.com/khoyt/files/barcode.swf">example application</a> and the <a href="http://weblogs.macromedia.com/khoyt/files/barcode-scanner.zip">source code</a>.</p>

<p><b>Disclaimer</b></p>

<p>As mentioned above, this demonstration while relatively accurate, is far from perfect.  There are many optimizations that could be made to enhance accuracy and/or speed.  Your web camera may not have the required resolution to provide adequate image quality since I have not made these additional optimizations.  </p>

<p>For best results, set the focus on your web camera to as close a focusing point as possible.  Also try to ensure that the left edge of the barcode itself is the only color shift after the start of the image (on the left).  Scan lines should be as perpendicular to the barcode lines as possible.  The surface of the barcode and the surface of the camera should be as parallel as possible.</p>

<p>I have image sharpening completely maxed out here, which means that in some cases, a slight blur on the barcode is better than perfectly clear.  A good scanning technique will involve moving your web camera closer to and away from the barcode gradually.  While the scanner will pull any valid UPC or EAN barcode, I've tightened the event to fire only when book barcodes are read (including a check digit).  In the example application, I’m also only testing against the Amazon US store.</p>

<p><img alt="Barcode Scanner" src="http://weblogs.macromedia.com/khoyt/files/barcode-scanner.jpg" width="660" height="495" /></p>

<p>(These are all books I'm taking to the library soon - if you see something you'd like, please let me know.)<br />
</p>]]>
</content>
</entry>
<entry>
<title>Context Menus Revisited</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/01/context_menus_r.cfm" />
<modified>2007-01-12T21:09:10Z</modified>
<issued>2007-01-12T20:47:39Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.12868</id>
<created>2007-01-12T20:47:39Z</created>
<summary type="text/plain">After encountering a security sandbox limitation in my previous example, I update the post with a scaled-down set of images that are accessed from the same domain. I&apos;ll say more on that topic later. Then I got a comment from...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>After encountering a security sandbox limitation in my previous example, I update the post with a scaled-down set of images that are accessed from the same domain.  I'll say more on that topic later.  Then I got a comment from <a href="http://huwebdev.blogspot.com">Brian Ferris</a> saying that he was confused by my post as it was contradictory to <a href="http://livedocs.macromedia.com/flex/2/langref/flash/ui/ContextMenu.html">the documentation</a>.  Brian quoted the documentation which has the following to say about context menus.</p>]]>
<![CDATA[<p>&lt;snip&gt;<br />
In Flex, only top-level components in the application can have context menus. For example, if a DataGrid control is a child of a TabNavigator or VBox container, the DataGrid control cannot have its own context menu.<br />
&lt;/snip&gt;</p>

<p>As it turns out that this is the exact same snippet of documentation that initially sent me down the wrong path.  When I read this I thought to myself that I must still have to use the original Flash 7 means of tracking mouse movements for nested objects.  As we now know, this isn't the case at all, but rather Flex exposes a context menu property on every interactive object. </p>

<p>To use this property you simply create a ContextMenu object and assign it to the contextMenu property of the control in which you're interested.  The only caveat I've found so far is to be aware of when the various parts of your UI are created.  For example, if you do indeed have a context menu on a DataGrid that's in a VBox that's further in a TabNavigator, when does that DataGrid get created?  </p>

<p>If the DataGrid is on the first tab, it'll get created with the rest of the main UI.  However if the DataGrid is on the second tab, using the default creation policy, it won't get created until that tab is made active.  If you're trying to assign a context menu to the DataGrid on the second tab at Application.creationComplete, then there's nothing there yet to which you can assign.  The solution is simply to watch for DataGrid.creationComplete before you assign the context menu (you can create it whenever you want).</p>

<p>At the end of this post is an example that is in direct contradiction to the documentation.  In fact, I've even gone the extra mile to ensure that it contradicts the entire scenario.  </p>

<p>The UI itself doesn't really do anything, but it's a far more bare-bones example of using context menus on nested controls.  You'll find a context menu on the DataGrid on the second tab.  In fact, there's two - one for if there's no item selected, and one for when there is an item selected, and they are changed dynamically at runtime.  There's also a context menu on the Button that's below the DataGrid on the second tab.  </p>

<p>The attached <a href="http://weblogs.macromedia.com/khoyt/files/nested-context.zip">source</a> for this is far more straight-forward than the image slicing/extracting example in the previous post.  That reminds me to tell you about the security sandbox problem.  </p>

<p>You probably heard that Flickr (and others) moved their cross-domain policy files recently.  This is no big deal once you know where they moved it to, and you can still access their API.  This wasn't the problem with my previous sample.  </p>

<p>The problem with the previous sample has to do with my application trying to copy pixel-level data from images that were loaded from Flickr's server farm.  The security sandbox looks at bitmap operations such as BitmapData.draw() as entering the realm of cross-domain, and therefore limits access.  Without being able to put additional policy files on Flickr's server farm, I was out of luck.  </p>

<p>To get around this problem, I had to change the application to load images from the same domain as the application itself.  If you download the source from that post, you'll still be getting the original example that target's Flickr’s servers.  I've opted to not upload the alternative source, but if you want it, just let me know.  They are fundamentally the same save that the images aren't as "interesting".<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,14,0" width="660" height="543" id="boxgrid.swf"><br />
  <param name="flashvars" value="versionChecked=true"><br />
  <param name="src" value="http://weblogs.macromedia.com/khoyt/files/boxgrid.swf"><br />
  <embed pluginspage="http://www.macromedia.com/go/getflashplayer" width="660" height="543" flashvars="versionChecked=true" src="http://weblogs.macromedia.com/khoyt/files/boxgrid.swf" name="boxgrid.swf" /><br />
</object></p>]]>
</content>
</entry>
<entry>
<title>Flex 2 Context Menus</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/01/flex_2_context.cfm" />
<modified>2007-01-12T05:26:03Z</modified>
<issued>2007-01-11T23:47:08Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.12865</id>
<created>2007-01-11T23:47:08Z</created>
<summary type="text/plain">One of the first tips I give to Flash developers getting into Flex for the first time is to forget what they know about Flash. I was helping a customer with a proof of concept application the other day, and...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>One of the first tips I give to Flash developers getting into Flex for the first time is to forget what they know about Flash.  I was helping a customer with a proof of concept application the other day, and got bit by not following my own advice when the requirement to have context menus came up.  This feature has been available since Flash Player 7, but I wasn't familiar with how to implement it on Flash Player 9 with Flex 2.  After burning several hours trying it the Flash 7 way, I landed at the Flash 9 way.</p>]]>
<![CDATA[<p>[UPDATE: Due to security sandbox limitations, <a href="http://weblogs.macromedia.com/khoyt/files/flickrextract.swf">here on the blog</a>, you won't be seeing exotic images from Flickr's most interesting, but rather a small sampling of rather bland imagery I've selected from my personal library.  The problem with Flickr isn't the policy file to access the Flickr API's, but rather the permissions to physically copy bitmap data from images loaded from Flickr into my SWF served here from MXNA.  The bits in the source archive remain unchanged from the original Flickr version.  You can download the <a href="http://weblogs.macromedia.com/khoyt/files/flickr-extract.zip">source</a> and run the example locally to enjoy interesting Flickr content.  Content aside, this post is really about context menus anyways, so my boring photos will have to suffice.]</p>

<p>The Flash 7 way means following a restriction that only top-level elements can have context menus.  That means that if you have a screen that's done as a component, only that component can have a context menu, and not the control inside of that component.  The way around this is to track roll-over and roll-out events.  Those events can be bubbled to the component level where it can change the context menu respectively.</p>

<p>One trick to this is that when the context menu is activated, a roll-out even is triggered.  This means that when a context menu item is selected, and the event listener goes to back to the sub-control that last triggered the roll-over, but that sub-control no longer exists in that state.  The way around this problem is to track at the top-level if there's a context menu.  If there is, then don't trigger a roll-out and don't mess with the context menu.</p>

<p>Again, this is all the Flash 7 way, and the Flash 9 way with Flex 2 is much easier and far more robust.  </p>

<p>I found that using the Flash 7 way inside the Flex 2 framework, worked pretty consistently.  When it didn't work though, it brought the Flash Player and the entire browser crashing down.  With Flash Player 9 a browser crash should never occur, so I was clearly doing something horribly wrong.  After spending a long time looking over the debugging information however, I was at a loss.</p>

<p>Eventually I learned that with Flex 2 every interactive object gets its own context menu property.  All you have to do as a developer is assign a context menu to that property and you're done.  The Flex Framework takes care of monitoring which interactive object is active and what context menu should be displayed.  Of course if I had ignored the temptation to use what I thought I knew, and had actually referenced the documentation, I would have seen the context menu property front and center just about everywhere.</p>

<p>The customer's requirement was pretty simple.  There were defined hot-spots over an image that needed to respond to right-clicks by presenting a single, common, context menu.  Having been bit by not following my own advice however, I decided that I need to push this area of my knowledge quite a bit further.  I set out with a concept that would allow me to explore context menus, and this is where I landed:</p>

<p><img alt="extracts.jpg" src="http://weblogs.macromedia.com/khoyt/files/extracts.jpg" width="660" height="528" /></p>

<p>Essentially, when the application starts, it makes a request out to Flickr to get the list of the most interesting photos (the top 100).  I initially wanted to show hot-spots over the images wherever there were notes.  It turns out however that precious few interesting photos get notes, so I just forced some random ones of my own.  You can right-click over the note hot-spots and extract a single note or all the notes on the image.  You can also click over the image and select to extract all the notes on that image.  Once you have extracted notes, you can drag-and-drop them to move them around.  You can also right-click over an extracted note to remove it outright.  </p>

<p>What exactly is an "extracted note"?  Well, you'll just have to <a href="http://weblogs.macromedia.com/khoyt/files/flickrextract.swf">try the application</a> see what I mean.  </p>

<p>This could obviously be extended quite a bit, and I've really just touched the surface.  You could add a context menu item that triggers free transforms of the extracted notes as an example.  There are also a number of optimizations that could be made.  For example, you might pick up after the rotation effect is done playing and apply smoothing.  Also rather than have hundreds of image sprites hanging around, you might choose to composite them into one single large bitmap that overlays the entire screen.  </p>

<p>As for me, I got the context menu experience I was wanting, so I'm on to the next project.  The <a href="http://weblogs.macromedia.com/khoyt/files/flickr-extract.zip">source is available</a> should you want to run this application locally, study the source, or make the suggested improvements.</p>]]>
</content>
</entry>
<entry>
<title>Image Processing Algorithms</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2007/01/image_processin.cfm" />
<modified>2007-01-02T17:25:58Z</modified>
<issued>2007-01-02T16:56:13Z</issued>
<id>tag:weblogs.macromedia.com,2007:/khoyt//34.12810</id>
<created>2007-01-02T16:56:13Z</created>
<summary type="text/plain">Image processing algorithms have long been one of my favorite areas of study. It&apos;s the genesis for a number of my Central examples (i.e. EXIF data and hex editor), so you can only imagine that I&apos;m super-excited about Apollo. Of...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Image processing algorithms have long been one of my favorite areas of study.  It's the genesis for a number of my Central examples (i.e. <a href="http://weblogs.macromedia.com/khoyt/archives/2005/11/actionscript_3_1.cfm">EXIF</a> data and <a href="http://weblogs.macromedia.com/khoyt/archives/2004/12/centralflex_hex.cfm">hex editor</a>), so you can only imagine that I'm super-excited about Apollo.  Of course manipulating bitmap data has been possible in ActionScript since Flash Player 8, and has only gotten better (due to performance) in Flash Player 9.  Taking this to the extreme (perhaps) is <a href="http://www.fauxto.com">Fauxto</a>.</p>]]>
<![CDATA[<p>Now while I generally try to keep opinion out of my blog posts, and stick to technical details, I have a few words about Fauxto.  </p>

<p>I want to say right up front that I think the concept is great - an image editor done using Flex.  What worries me about Fauxto is the ultimate goal.  I haven’t heard many details about where they are heading, but I have heard a lot of people talking about how Fauxto has "layers like Photoshop".  If the goal is to be Photoshop, then I'm really worried about how well Fauxto will be received in the long term.</p>

<p>Let me be clear here that I'm talking mostly about the business model.  Photoshop caters to the high-end design professional.  <a href="http://www.corel.com">Paint Shop Pro</a> general targets those with more finite needs and on a more limited budget.  <a href="http://www.gimp.org">Gimp</a> finds it's origins in *nix world.  What of Fireworks though?  It has layers, but caters to the web professional specifically with image optimization, page composition, navigation wizards and other features.  Then there are countless other image editors that focus really well on a specific use-case such as <a href="http://www.iconedit.com/">icon creation</a>, <a href="http://www.coffeecup.com/image-mapper/">image maps</a>, etc.</p>

<p>My statement to the folks behind Fauxto would be simply to be very clear about what your goal is, and to not get distracted by the other countless possibilities.  </p>

<p>Does the world really need another Photoshop, Paint Shop Pro, Gimp or Fireworks?  I’ve heard hints about a model similar to YouTube, which sounds good so far.  YouTube brought video for the web to the masses.  If Fauxto can bring image editing to the masses as a service (SaaS), I think they may be onto something.  But then do the masses need layers like Photoshop?  Maybe, maybe not, but be careful Fauxto; focus...</p>

<p>In the spirit of Fauxto however, here are a couple image processing algorithms I've implemented recently for one of my projects - grayscale and unsharp mask.  I didn't see them in Fauxto's filters so maybe those folks will look to add them.  Perhaps another developer out there will enjoy learning from the <a href="http://weblogs.macromedia.com/khoyt/files/ipsnippets.zip">source code</a>.  To give credit where credit is due, the inspiration for how to implement the unsharp mask comes from Jerry Huxtable's <a href="http://www.jhlabs.com/ip/filters/index.html">Java image filters</a> (but with a distinctly Flash twist).<br />
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,14,0" width="640" height="480" id="ipsnippets.swf"><br />
  <param name="flashvars" value="versionChecked=true"><br />
  <param name="src" value="http://weblogs.macromedia.com/khoyt/files/ipsnippets.swf"><br />
  <embed pluginspage="http://www.macromedia.com/go/getflashplayer" width="640" height="480" flashvars="versionChecked=true" src="http://weblogs.macromedia.com/khoyt/files/ipsnippets.swf" name="ipsnippets.swf" /><br />
</object></p>]]>
</content>
</entry>
<entry>
<title>Borders, Corners and Shadows, Oh My!</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2006/11/borders_corners.cfm" />
<modified>2006-11-29T17:07:27Z</modified>
<issued>2006-11-29T16:41:30Z</issued>
<id>tag:weblogs.macromedia.com,2006:/khoyt//34.12602</id>
<created>2006-11-29T16:41:30Z</created>
<summary type="text/plain">Ever have the problem of getting a UI composite and wondering how you are going to implement it? I had one such example come across an internal Flex questions list the other day. I&apos;ve been helped countless times by the...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Ever have the problem of getting a UI composite and wondering how you are going to implement it?  I had one such example come across an internal Flex questions list the other day.  I've been helped countless times by the list, so I try to at least put some thought into every question that comes across.  This one however had screenshots of the problem inline with the question.  It caught my attention and I couldn't help but think that "we should be able to do that with Flex."</p>]]>
<![CDATA[<p>The challenge was to provide an embossed look to a user-selected portion of the user interface.  There were places where some corners were rounded and others were not.  Along the edge of the selection region were also different color lines for horizontal and vertical orientation.  The embossed feel needed to be maintained evenly across control/containers as well.  </p>

<p>Here's a Captivate recording of the final result to give you an idea of what needed to be accomplished:<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,14,0" width="660" height="543" id="borders-oh-my.swf"><br />
  <param name="flashvars" value="versionChecked=true"><br />
  <param name="src" value="http://weblogs.macromedia.com/khoyt/files/borders-oh-my_skin.swf"><br />
  <embed pluginspage="http://www.macromedia.com/go/getflashplayer" width="660" height="543" flashvars="versionChecked=true" src="http://weblogs.macromedia.com/khoyt/files/borders-oh-my_skin.swf" name="borders-oh-my.swf" /><br />
</object><br />
While Flex does provide for having rounded corners via CSS, it doesn't give you the ability to specify which corners, or to have corners of varying radius's.  The CSS options are also limited to a single border color (in most cases).  If you're like me this means you're looking at making a skin.  I prefer programmatic skinning where I can, and in this case of just a few lines and a fill, it seemed to add the least weight.</p>

<p>Using a programmatic skin gets a lot of this problem out of the way - or so it seems.  </p>

<p>How about that embossed look?  You might think that this would be a simple DropShadowFilter with the "inner" property set to "true".  The problem with this is that the inner option is applied to the inside of the DisplayObject.  That means our nicely drawn border lines are going to be replaced by the shadow, which will start at the edges of our DisplayObject.  </p>

<p>To get around this problem I stacked visual effects.  I first created a programmatic skin for just the border lines and rounded corners.  I applied that skin to one container.  Then I made another skin that made the same lines, but also filled the space.  I placed the second, filled, skin on another container which was then placed under the first container (z-order).  Finally the filter is applied to the lower of the two containers.</p>

<p>You might think that this would be enough, but there's another problem that the filter introduces.</p>

<p>Given the filled the dimensions of lower container, the inner shadow isn't going to be carried nicely over to any other components - remember that we need multiple components to look like they're part of the same selected area.  This is especially important as the shadow goes to wrap itself around corners of "connecting" components.  </p>

<p>To address this problem I had the skin draw the connecting edges to include the corners, and then to extend to "overlap" any connecting area.  Then I applied a mask to the entire component, and intentionally left out the space that was extended as an overlap.  This let the shadow be applied to everything, including the extended connecting edge, but only revealed those parts we were interested in displaying visually.</p>

<p>As it turns out, as I went to implement this solution, I came up with at least two different ways to address the problems that surfaced.  Since I had already completed this approach however, I decided to stick with it.  I have no doubt that this could be further refined.</p>

<p>I built in some fun states to allow the "button" to have different [complex] views depending on user selection.  Again with hindsight being what it is, I could have parameterized the different states as children components.  This would have allowed for more reusability.  I was really only interested in the embossed part though, and it's time to move on to the next project.</p>

<p>I'm guessing that following all of this is probably pretty challenging.  We're looking at layered programmatic skins with filters and masking.  That's a lot to say not to mention to understand with limited visuals.  Well, it's <a href="http://weblogs.macromedia.com/khoyt/files/borders-oh-my.zip">source code</a> to the rescue then, which you should feel free to play with and explore.  I've also posted the <a href="http://weblogs.macromedia.com/khoyt/files/bugs.swf">application</a> itself which for your viewing pleasure.</p>]]>
</content>
</entry>
<entry>
<title>Flex: Association Viewer</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2006/11/flex_associatio.cfm" />
<modified>2006-11-10T00:14:14Z</modified>
<issued>2006-11-09T22:55:09Z</issued>
<id>tag:weblogs.macromedia.com,2006:/khoyt//34.12477</id>
<created>2006-11-09T22:55:09Z</created>
<summary type="text/plain">This week, one of my colleagues in the Technical Sales organization asked me about a particular type of visualization. He needed to be able to display what essentially amounted to boxes and curved lines that connected those boxes with associations....</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>This week, one of my colleagues in the Technical Sales organization asked me about a particular type of visualization.  He needed to be able to display what essentially amounted to boxes and curved lines that connected those boxes with associations.  I figured this was an interesting project, I had a few hours to spare while traveling this week, and thought I would give it a try.  I have written up a little of the project and provided code and the application itself with which you can play.</p>]]>
<![CDATA[<p><img alt="viewer.png" src="http://weblogs.macromedia.com/khoyt/files/viewer.png" width="620" height="460" /></p>

<p>One of the statements I found interesting about the initial inquiry was an attempt to shoehorn this type of display into the Flex DataGrid.  The project was being built by enterprise developers, and the data was coming from an immense database, so Flex seems like a good fit.  Of course when we have data in Flex, what do we do with it?  We put it in a DataGrid!  Not so fast!</p>

<p>This is definitely a little "outside of the box" for what we normally see with Flex applications.  It is also a good case to show that at the end of the day, Flex is Flash, and inherits many expressive traits.  Folks like Ely Greenfield have done an excellent job of dispelling the myth that Flex is all buttons and forms.  I think this just adds to that argument.  It's important to remember the creative roots of Flex when developing applications on the framework.</p>

<p>There were probably a half-dozen ways to deal with the original screen comp I received (sorry, not available in the interest of the customer).  The boxes were ultimately to be lined up in a "grid" or table alignment.  My first thought then was to use the Grid container.  As I got further along though, it seemed like it would just be easier to manually figure out where these boxes belonged.  It is conceivable that a custom layout manager could also be arranged.  </p>

<p>For my "proof" application, I chose a random layout placing boxes at random x and y coordinates.</p>

<p>While drag and drop is already provided for us on list-based controls, this was a job for a custom implementation.  I thought about using the old-school approach to drag and drop initially (MovieClip.startDrag() and MovieClip.stopDrag()).  Since I wasn't really interested in moving the boxes however, just in creating relationships between them, I eased up a little and went with the Flex DragManager.  This turned out to be easier and more robust in the long run.</p>

<p>Yet again, I could have chosen to draw the lines any number of ways, but I decided to treat them as display objects.  I subclassed Canvas, added some properties and I was on my way.  In retrospect, I think I would try and subclass something even more lightweight in the future for maximum performance.  I drew the lines by getting a reference to the graphics object available on every display object.  The hardest part was figuring out the anchor for the Graphics.curveTo() method.</p>

<p>References complete, it was time to add some fun.  I added some color changes in reaction to mouse movements on the boxes first.  Then I thought it'd be fun to be able to click on the lines and see the references in more detail.  The tricky part here was that the mouse wanted to listen to the entire DisplayObject initially.  To get around this I added a UIComponent to the Canvas, did the drawing on that, and then assigned it as the Canvas.hitArea.  Now I had lines the interacted with the mouse, to include handling click events.</p>

<p>I employed a little trick of drawing two lines to broaden the sensitivity to the mouse.  The first line has an alpha value of zero (0) and is ten pixels wide.  The second line has a designated color and is only three pixels wide.  When your mouse comes into contact with the first line, even though it is invisible, it counts as the hitArea and the mouse reacts (triggering color changes).  You might think of this technique as "feathering" in a graphics application.</p>

<p>To finish things off I added a few extra controls for clearing and resetting the application and some motion to draw you eyes to key events.  I can think of at least another dozen features I would like to add, but alas, this project's time is up and the next one is closing in fast.  The source is <a href="http://weblogs.macromedia.com/khoyt/files/rviewer.zip">attached</a> and you can play with the application <a href="http://weblogs.macromedia.com/khoyt/files/rviewer.swf">here</a> as well.  Don't forget to click on the lines to see the references (my favorite part)!</p>]]>
</content>
</entry>
<entry>
<title>Flex to REST CFC Endpoint</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2006/08/flex_to_rest_cf.cfm" />
<modified>2006-08-18T17:41:37Z</modified>
<issued>2006-08-18T17:26:20Z</issued>
<id>tag:weblogs.macromedia.com,2006:/khoyt//34.11726</id>
<created>2006-08-18T17:26:20Z</created>
<summary type="text/plain">Sean Corfield recently published a ColdFusion Component (CFC) that can act as a REST endpoint. I had read a previous post by Sean that talked about this component, and asked him if I could take a look at it. With...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Sean Corfield recently published a ColdFusion Component (CFC) that can act as a REST endpoint.  I had read a previous post by Sean that talked about this component, and asked him if I could take a look at it.  With certain disclosures in mind, Sean let me play with the component, and while he's using it for Java-to-CF connectivity, I'm using it for Flex-to-CF connectivity.</p>]]>
<![CDATA[<p>You might be wondering why one you would expose CF to Flex as REST if Flex can talk to CF directly already in a number of ways (including the more efficient remoting).  For me it wasn't so much about Flex as a consumer, that's just what I had on hand, and the technology with which I am most familiar.  The potential side effect is that Flex can consume my server-side application API in the same fashion as everything else.</p>

<p>Regardless of the potential value (or not), here's a walk-through of a simple example using Sean's CFC REST endpoint from Flex.</p>

<p>The first part is to have a CFC to call.  I have a generic "Greeting" CFC that I use for simple tests/demonstrations.  You can think of it as an OO "Hello World" that has a function for a "hello" greeting and a function for a "goodbye" greeting.  Each function takes a single argument – the name of the person to greet.  The code for the CFC is as follows, and Sean's "endpoint.cfc" is in the same directory.</p>

<p>&lt;cfcomponent name="Greeting" displayname="Greeting" hint="Generic greeting component for testing"&gt;</p>

<p>&nbsp;&nbsp;&lt;cffunction<br />
&nbsp;&nbsp;&nbsp;&nbsp;name="hello" <br />
&nbsp;&nbsp;&nbsp;&nbsp;displayname="hello" <br />
&nbsp;&nbsp;&nbsp;&nbsp;hint="Says hello to the provided user name" <br />
&nbsp;&nbsp;&nbsp;&nbsp;access="remote" <br />
&nbsp;&nbsp;&nbsp;&nbsp;output="false" <br />
&nbsp;&nbsp;&nbsp;&nbsp;returntype="string"&gt;<br />
	<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;cfargument <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name="name" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;displayName="name" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type="string" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hint="The name of the user to greet"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;required="true" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;cfreturn "Hello, " & name & "!" /&gt;<br />
		<br />
&nbsp;&nbsp;&lt;/cffunction&gt;</p>

<p>&nbsp;&nbsp;&lt;cffunction <br />
&nbsp;&nbsp;&nbsp;&nbsp;name="goodbye" <br />
&nbsp;&nbsp;&nbsp;&nbsp;displayname="goodbye" <br />
&nbsp;&nbsp;&nbsp;&nbsp;hint="Says goodbye to the provided user name" <br />
&nbsp;&nbsp;&nbsp;&nbsp;access="remote" <br />
&nbsp;&nbsp;&nbsp;&nbsp;output="false" <br />
&nbsp;&nbsp;&nbsp;&nbsp;returntype="string"&gt;<br />
			<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;cfargument <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name="name" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;displayName="name" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type="string" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hint="The name of the user to greet" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;required="true" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;cfreturn "Goodbye, " & name & "!" /&gt;<br />
		<br />
&nbsp;&nbsp;&lt;/cffunction&gt;<br />
	<br />
&lt;/cfcomponent&gt;</p>

<p>The Flex front-end to this component simply asks the user for a string, and expects that the value is a person’s name (though it can be anything).  It gets interesting when the button to submit the values is clicked.  In short what happens is that an HTTPService instance is used to POST XML content to the "endpoint.cfc".  When a response is returned, I simply display the value in an Alert control.</p>

<p>The HTTPService instance in this case is configured for the behavior the REST endpoint expects.  It points to the CFC with a query string value of "rest", and expects to make a POST request.  I've also specified the content type to be XML rather than form name/value pairs.  E4X makes handling the formatting of the request and, and the response itself a walk in the park.  </p>

<p>&lt;mx:HTTPService <br />
&nbsp;&nbsp;id="svcGreeting"<br />
&nbsp;&nbsp;url="http://[your_domain_here]/work/endpoint.cfc?method=rest"<br />
&nbsp;&nbsp;method="POST" <br />
&nbsp;&nbsp;contentType="application/xml"<br />
&nbsp;&nbsp;resultFormat="e4x"<br />
&nbsp;&nbsp;useProxy="false"<br />
&nbsp;&nbsp;result="doGreeting( event )" /&gt;</p>

<p>If you haven't played around with E4X in ActionScript 3 yet, you're really missing out.  The ability to treat XML as a native data type gives you some very powerful functionality.  In the case of this REST example, the CFC expects the name of the CFC to be invoked as the root XML packet node.  That root node is also expected to have an operation attribute that specifies what function you're going to call the on the designated CFC.  Adding sub-nodes on the root packet, even deeply nested nodes, is just a matter of "dotting-down" and assigning a value.</p>

<p>Note that the XML object itself is provided to the argument of the service call.  That XML object as a string will be the content data.  Also notice the distinct lack of having to use quotes to establish nodes, or strange "child" methods/arrays.  Yeah E4X!</p>

<p>public function doSend( event:MouseEvent ):void<br />
{<br />
&nbsp;&nbsp;var params:XML = new XML( <work.Greeting /> );<br />
				<br />
&nbsp;&nbsp;btnSend.enabled = false;<br />
				<br />
&nbsp;&nbsp;params.@operation = cmbGreeting.selectedLabel;<br />
&nbsp;&nbsp;params.name.value = txtName.text;<br />
				<br />
&nbsp;&nbsp;svcGreeting.send( params );<br />
}</p>

<p>In this example I'm passing a simple value and getting a simple value in return.  I've since gone on to use Sean's CFC for complex structures and arrays.  In the case of a simple value I can use the descendant notation to pull the only "value" node in the response packet.  For an array of structures, I use the same notation, but specify the "map" node, which is used for each structure.<br />
 <br />
btnSend.enabled = true;<br />
Alert.show( svcGreeting.lastResult..value );</p>

<p>Sean's REST endpoint CFC now allows Flex to talk to CF in the same fashion as would his original intention – Java.  Others using PHP, Ruby, .NET or any other XML-capable language would also access the endpoint in the same fashion.  It’s a really powerful means of exposing an entire CFC API in a consistent manner.  The complete source for my example is <a href="http://weblogs.macromedia.com/khoyt/files/flex-cfc-rest.zip">attached to this post</a>.</p>]]>
</content>
</entry>
<entry>
<title>Merging RSS Feeds with Query of Queries</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2006/06/merging_rss_fee.cfm" />
<modified>2006-06-02T03:50:10Z</modified>
<issued>2006-06-02T03:31:24Z</issued>
<id>tag:weblogs.macromedia.com,2006:/khoyt//34.11098</id>
<created>2006-06-02T03:31:24Z</created>
<summary type="text/plain">One of my all-time favorite features in ColdFusion is &quot;query of queries&quot;. I have yet to see this functionality duplicated as thoroughly, or as easily, in any other language outside of SQL itself. Of course the limitation with SQL is...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>ColdFusion</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>One of my all-time favorite features in ColdFusion is "query of queries".  I have yet to see this functionality duplicated as thoroughly, or as easily, in any other language outside of SQL itself.  Of course the limitation with SQL is that it generally operates on relational data stored in a relational database.  The query of queries functionality changes that for ColdFusion developers.</p>]]>
<![CDATA[<p>I'm a pretty blog-centric fellow.  I rely on blogs to keep me up to date on the rapidliy changing world of technology, and on what it is that Adobe's amazing community of developers is up to each week.  I also publish a few blogs.  I have this one for work, but I also have several personal ones.  It’s a great way to distribute and share information across my family which is widely geographically distributed.</p>

<p>As you likely know, most blogs have an XML format called RSS that is often used to describe content in a generic form that can be read by other programs that understand RSS and/or XML in general.  There are a few versions of RSS, and there's also the emerging ATOM format.  XML handling is also another great feature of ColdFusion.  By comparison, in some other mainstream languages this is still amazingly painful.</p>

<p>Recently I decided that I'd like to merge two blogs with related content into one blog.  I was publishing content too slowly to really need them both, but by combining them I could give the impression that I was very active.  In my case one blog was managed by Blogger and published to my personal domain.  The other blog wasn't really even a blog at all, but my Flickr photostream.  Flickr can make your photostream available as an RSS feed.</p>

<p>There was the basis for this little exercise - two blogs, both with RSS feeds, to be merged and sorted by date.  Normally this would be quite the chore, but after some thought it occurred to me that RSS was giving me a neutral way of describing the content.  The two feeds looked like identical relational database tables.  If I could build a table of each feed, I could run a SQL statement on them to join them together (technically a union).</p>

<p>This is when the solution hit me smack in the face.  Use CFHTTP to read the RSS feeds individually, parse the XML content, generate a ColdFusion query objects, fill the query objects with data and run the SQL to put them together and sort them.  In the end, not only would I have merged XML structures from different sources and sorted them, but I would also have native CF query object which would be ideal for looping/output.</p>

<p>What I ended up with was something that looked like the following code snippet (non-pertinent information removed).  </p>

<p>&lt;!--- Grab and parse Flickr RSS feed ---&gt;<br />
&lt;cfhttp url="#flickr#" /&gt;<br />
&lt;cfset doc = XmlParse( CFHTTP.FileContent ) /&gt;</p>

<p>&lt;!--- Build query object with RSS feed data ---&gt;<br />
&lt;cfset photos = QueryNew( "source, title, link, description, publish", "VarChar, VarChar, VarChar, VarChar, Date" ) /&gt;</p>

<p>&lt;cfloop index="sub" from="1" to="#ArrayLen( doc.rss.channel.item )#" step="1"&gt;</p>

<p>&nbsp;&nbsp;&lt;!--- Extract the publish date string as date/time ---&gt;<br />
&nbsp;&nbsp;&lt;cfset publish = ParseDateTime( doc.rss.channel.item[sub].pubDate.XmlText ) /&gt;	<br />
	<br />
&nbsp;&nbsp;&lt;!--- Insert new row into query ---&gt;<br />
&nbsp;&nbsp;&lt;cfset rows = QueryAddRow( photos ) /&gt;<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( photos, "source", "flickr" ) /&gt;		<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( photos, "title", doc.rss.channel.item[sub].title.XmlText ) /&gt;	<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( photos, "link", doc.rss.channel.item[sub].link.XmlText ) /&gt;<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( photos, "description", description ) /&gt;		<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( photos, "publish", publish  /&gt;			<br />
&lt;/cfloop&gt;</p>

<p>&lt;!--- Print results to screen ---&gt;<br />
&lt;cfdump var="#photos#" /&gt;</p>

<p>&lt;!--- ****************************** ---&gt;</p>

<p>&lt;!--- Grab and parse Blogger RSS feed ---&gt;<br />
&lt;cfhttp url="#blogger#" /&gt;<br />
&lt;cfset doc = XmlParse( CFHTTP.FileContent ) /&gt;</p>

<p>&lt;!--- Build query object with ATOM feed data ---&gt;<br />
&lt;cfset posts = QueryNew( "source, title, link, description, publish", "VarChar, VarChar, VarChar, VarChar, Date" ) /&gt;</p>

<p>&lt;cfloop index="sub" from="1" to="#ArrayLen( doc.rss.channel.item )#" step="1"&gt;<br />
&nbsp;&nbsp;&lt;!--- Extract the publish date string as date/time ---&gt;<br />
&nbsp;&nbsp;&lt;cfset publish = ParseDateTime( doc.rss.channel.item[sub].pubDate.XmlText ) /&gt;		<br />
&nbsp;&nbsp;&lt;cfset updated = doc.rss.channel.item[sub].updated.XmlText /&gt;<br />
&nbsp;&nbsp;&lt;cfset offset = Mid( updated, Len( updated ) - 3, 1 ) /&gt;<br />
&nbsp;&nbsp;&lt;cfset publish = DateAdd( "h", offset, publish ) /&gt;<br />
	<br />
&nbsp;&nbsp;&lt;!--- Insert new row into query ---&gt;<br />
&nbsp;&nbsp;&lt;cfset rows = QueryAddRow( posts ) /&gt;<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( posts, "source", "blogger" ) /&gt;		<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( posts, "title", doc.rss.channel.item[sub].title.XmlText ) /&gt;<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( posts, "link", doc.rss.channel.item[sub].link.XmlText ) /&gt;<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( posts, "description", doc.rss.channel.item[sub].description.XmlText ) /&gt;		<br />
&nbsp;&nbsp;&lt;cfset success = QuerySetCell( posts, "publish", publish ) /&gt;			<br />
&lt;/cfloop&gt;</p>

<p>&lt;!--- Print results to screen ---&gt;<br />
&lt;cfdump var="#posts#" /&gt;</p>

<p>&lt;!--- Query of query to merge feed data ---&gt;<br />
&lt;cfquery dbtype="query" name="merger"&gt;<br />
&nbsp;&nbsp;SELECT * <br />
&nbsp;&nbsp;FROM photos<br />
&nbsp;&nbsp;UNION<br />
&nbsp;&nbsp;SELECT *<br />
&nbsp;&nbsp;FROM posts<br />
&nbsp;&nbsp;ORDER BY publish DESC<br />
&lt;/cfquery&gt;</p>

<p>&lt;!--- Print merged data to screen ---&gt;<br />
&lt;cfdump var="#merger#" /&gt;</p>

<p>I don't know how particularly useful this is for anybody else, but I was proud of the little exercise, and felt it was worth sharing.  If you do find it handy, please let me know.  For me, it was simply amazing just how productive this actually was thanks to ColdFusion.  The entire gathering, parsing, populating and merging of both feeds is less than 70 lines of code including comments and spacing.</p>]]>
</content>
</entry>
<entry>
<title>CSS Positioning with Flex 2</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2006/06/css_positioning.cfm" />
<modified>2006-06-01T16:43:48Z</modified>
<issued>2006-06-01T16:17:53Z</issued>
<id>tag:weblogs.macromedia.com,2006:/khoyt//34.11092</id>
<created>2006-06-01T16:17:53Z</created>
<summary type="text/plain">Among the countless new features offered by Flex 2 is constraints-based layout. If you haven&apos;t had a chance to explore the use of constraints I encourage you to spend some time with the approach. I was a skeptic at first...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flex</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>Among the countless new features offered by Flex 2 is constraints-based layout.  If you haven't had a chance to explore the use of constraints I encourage you to spend some time with the approach.  I was a skeptic at first myself, but have since come to really enjoy the lightweight results (as compared to flow-based layout which generally involves deep nesting of boxes to achieve complex layouts).  At the core of constraints-based layout is a series of properties that allow you to specify positioning and anchoring of your controls and containers.</p>]]>
<![CDATA[<p>To be clear, flow-based layout and constraints-based layout aren't mutually exclusive.  Combining the two for their strengths lends itself to rapid development using Flex Builder's design view.</p>

<p>I was curious about these constraints properties, so one day I looked them up in the language reference.  What I found is that they weren't properties at all!  The constraints I had been putting inline were actually styles.  This meant that I could externalize them and leverage an external CSS to control the appearance of my user interface.  Take the following code and screenshot as a starting point.</p>

<p>&lt;mx:Application layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml"&gt;<br />
	<br />
&nbsp;&nbsp;&lt;mx:Panel <br />
&nbsp;&nbsp;&nbsp;&nbsp;x="10" <br />
&nbsp;&nbsp;&nbsp;&nbsp;y="10" <br />
&nbsp;&nbsp;&nbsp;&nbsp;width="274" <br />
&nbsp;&nbsp;&nbsp;&nbsp;height="148" <br />
&nbsp;&nbsp;&nbsp;&nbsp;layout="absolute" <br />
&nbsp;&nbsp;&nbsp;&nbsp;title="Login"&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Label x="10" y="12" text="Username:" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:TextInput x="85" y="10" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Label x="10" y="42" text="Password:" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:TextInput x="85" y="40" displayAsPassword="true" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:ControlBar&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Button label="Login" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/mx:ControlBar&gt;</p>

<p>&nbsp;&nbsp;&lt;/mx:Panel&gt;<br />
	<br />
&lt;/mx:Application&gt;</p>

<p><img alt="constraints1.jpg" src="http://weblogs.macromedia.com/khoyt/files/constraints1.jpg" width="478" height="490" /></p>

<p>At first pass, when you look at the screen and code nothing seems obviously wrong or lacking.  When you take a closer look however, you start to see some shortcomings of how this UI has been put together.  You might notice for example, that the login dialog is always going to be at the upper-left of the application.  We'd probably like that to be centered in the application based on screen resolution.</p>

<p>The login dialog has also been made specifically to fit the size of the TextInput controls.  There's no width information on the TextInput controls, so they will default to 150 pixels.  What would happen if I needed to add another field to the login and the preceding label was longer than the existing username and password labels?  </p>

<p>This would force me to put the TextInput further to the right.  To maintain alignment, I'd then have to revisit the other TextInput controls and align them further to the right as well.  All this pushing to the right would mean that the Panel would need to be wider.  Wouldn't it be easier if the contents of the Panel would just automatically align themselves within the confines of that container?</p>

<p>Constraints let me solve these types of problems very easily.  They also let me do so entirely through Flex Builder's design view.  Let's revisit the code and screenshot with constraints added.</p>

<p>&lt;mx:Application layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml"&gt;<br />
	<br />
&nbsp;&nbsp;&lt;mx:Panel <br />
&nbsp;&nbsp;&nbsp;&nbsp;width="275" <br />
&nbsp;&nbsp;&nbsp;&nbsp;height="150" <br />
&nbsp;&nbsp;&nbsp;&nbsp;horizontalCenter="0" <br />
&nbsp;&nbsp;&nbsp;&nbsp;verticalCenter="0"		<br />
&nbsp;&nbsp;&nbsp;&nbsp;layout="absolute" <br />
&nbsp;&nbsp;&nbsp;&nbsp;title="Login"&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Label left="10" top="12" text="Username:" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:TextInput left="85" right="10" top="10" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Label left="10" top="42" text="Password:" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:TextInput left="85" right="10" top="40" displayAsPassword="true" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:ControlBar&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Button label="Login" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/mx:ControlBar&gt;</p>

<p>&nbsp;&nbsp;&lt;/mx:Panel&gt;<br />
	<br />
&lt;/mx:Application&gt;</p>

<p><img alt="constraints2.jpg" src="http://weblogs.macromedia.com/khoyt/files/constraints2.jpg" width="478" height="490" /></p>

<p>Now my dialog will stay centered in the application regardless of screen resolution.  Additionally, the username and password Label and TextInput controls will also now stay where they are relative to the Panel regardless of the size of the Panel itself.  As a side effect, this has also allowed me to round the numbers for the width and height of the Panel (used to be 274x148, and is now 275x150).  Because the controls will now resize themselves appropriately these subtle changes become much easier to make.</p>

<p>Notice that all the X and Y properties are also no longer present, as the UI is now relative to other parts of the application.</p>

<p>There's still one thing that bugging me about the UI though, and that's the "Login" button itself which is aligned (by default) to the left in the ControlBar.  Most operating systems align control buttons to the bottom right of a dialog.  This is easy enough to change though, right?  The ControlBar defaults to an HBox layout.  While we could tell it to use constraints, this layout is working great for us as-is, save that pesky alignment.</p>

<p>Luckily for us, there's a "horizontalAlign" style on the ControlBar container.  I can flip that style inline, right on the tag, or I can put it in a Style block elsewhere in the source code.  Most of the times we'll pull our styles to a Style block, but then we'll go one step further as well.  We don't like embedding all those styles inside the application itself, so we'll externalize it to a CSS file.  Now all our changes can be made in one centralized place.</p>

<p>What about those constraints though?  Didn't I mention that those were styles too?  They are, and can be externalized in the same CSS.  Let's take a look at the application source code and screenshot one more time.</p>

<p>&lt;mx:Application layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml"&gt;<br />
	<br />
&nbsp;&nbsp;&lt;mx:Style source="constraints3.css" /&gt;<br />
	<br />
&nbsp;&nbsp;&lt;mx:Panel <br />
&nbsp;&nbsp;&nbsp;&nbsp;width="275" <br />
&nbsp;&nbsp;&nbsp;&nbsp;height="150" <br />
&nbsp;&nbsp;&nbsp;&nbsp;layout="absolute" <br />
&nbsp;&nbsp;&nbsp;&nbsp;title="Login"&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Label text="Username:" styleName="userlabel" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:TextInput styleName="userinput" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Label text="Password:" styleName="passlabel" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:TextInput displayAsPassword="true" styleName="passinput" /&gt;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:ControlBar&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;mx:Button label="Login" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/mx:ControlBar&gt;</p>

<p>&nbsp;&nbsp;&lt;/mx:Panel&gt;<br />
	<br />
&lt;/mx:Application&gt;</p>

<p><img alt="constraints3.jpg" src="http://weblogs.macromedia.com/khoyt/files/constraints3.jpg" width="478" height="490" /></p>

<p>The screenshot is almost identical to the previous examples save that our "Login" button is now aligned to the right - whew!  The code has changed only a little as well, and in a good way.  In place of exact constraints there's now style names given to the controls where appropriate.  All those pesky constraints that were tied directly to their specific control are now gone.  Actually they are still there and it's obvious that they are still being applied, but they're now externalized into the CSS file.  It's in that CSS file where the magic really takes place, so let's get a closer look.</p>

<p>ControlBar {<br />
&nbsp;&nbsp;horizontal-align: right;<br />
}</p>

<p>Label {<br />
&nbsp;&nbsp;left: 10;	<br />
}</p>

<p>Panel {<br />
&nbsp;&nbsp;horizontal-center: 0;<br />
&nbsp;&nbsp;vertical-center: 0;	<br />
}</p>

<p>TextInput {<br />
&nbsp;&nbsp;left: 85;			<br />
&nbsp;&nbsp;right: 10;			<br />
}</p>

<p>.userlabel {<br />
&nbsp;&nbsp;top: 12;<br />
}</p>

<p>.userinput {<br />
&nbsp;&nbsp;top: 10;<br />
}</p>

<p>.passlabel {<br />
&nbsp;&nbsp;top: 42;<br />
}</p>

<p>.passinput {<br />
&nbsp;&nbsp;top: 40;	<br />
}</p>

<p>The first thing you should notice is that I've used CSS selectors where appropriate to specify styles for those controls en masse.  When you get to the TextInput block, you'll see that I've defined not fonts or colors, but left and right constraints.  Since I want all my TextInput controls to be aligned vertically, and to maintain the same width (relation to the edges of the container), it makes sense to apply that styling at the block level.  Managing the constraints for the TextInput's relation to the top of the container is done in a CSS class statement.  </p>

<p>The best part of all of this is the cascading nature of CSS.  The "left" and "right" constraints on the TextInput block are also inherited with the class statements used to specify the "top".  We've been looking at the TextInput, but the same is also done with the Label selector and class statements.  These are applied back in the MXML by using a "styleName" property on the controls.  </p>

<p>The CSS selectors and class statements can also include font, color and other styling information.</p>

<p>Using the stylistic approach to constraints provides me with some pretty impressive capabilities.  Let's say that for whatever reason we decided that the Panel should actually be in the upper-left of the application.  I can go into the CSS, exchange "vertical-center" and "horizontal-center" for "left" and "top" values and be done.  An even better example might be if we want to rearrange the order of the Label and TextInput controls.  </p>

<p>Simply by modifying the CSS I can completely change the order in which these controls appear.  It could be as simple as vertical arrangement where I wanted "Password" to come before "Username", but I could also put the Label controls on the right side of the TextInput controls.  No hunting and pecking for inline properties, just simple CSS changes.  A quick couple of double-clicks in the Flex Builder design view to change the labels to reflect their new positioning, and the rest is up to your imagination!  </p>

<p>All the <a href="http://weblogs.macromedia.com/khoyt/files/flex-2-css-p.zip">source code</a> for these iterations is attached.<br />
 <br />
ControlBar {<br />
&nbsp;&nbsp;horizontal-align: right;<br />
}</p>

<p>Label {<br />
&nbsp;&nbsp;right: 10;	<br />
}</p>

<p>Panel {<br />
&nbsp;&nbsp;left: 10;<br />
&nbsp;&nbsp;top: 10;	<br />
}</p>

<p>TextInput {<br />
&nbsp;&nbsp;left: 10;			<br />
&nbsp;&nbsp;right: 85;<br />
}</p>

<p>.userlabel {<br />
&nbsp;&nbsp;top: 42;<br />
}</p>

<p>.userinput {<br />
&nbsp;&nbsp;top: 40;<br />
}</p>

<p>.passlabel {<br />
&nbsp;&nbsp;top: 12;<br />
}</p>

<p>.passinput {<br />
&nbsp;&nbsp;top: 10;	<br />
}</p>

<p><img alt="constraints4.jpg" src="http://weblogs.macromedia.com/khoyt/files/constraints4.jpg" width="478" height="490" /></p>]]>
</content>
</entry>
<entry>
<title>Flash Lite 1.1: Blood Pressure Tracker</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/khoyt/archives/2006/04/flash_lite_11_b.cfm" />
<modified>2006-04-20T23:18:07Z</modified>
<issued>2006-04-20T23:05:13Z</issued>
<id>tag:weblogs.macromedia.com,2006:/khoyt//34.10770</id>
<created>2006-04-20T23:05:13Z</created>
<summary type="text/plain">If you follow my blog you&apos;ll no doubt be under the impression that I am all about Flex. For the most part, this is true, and as a Sr. Product Specialist here at Adobe, specifically for the Flex product, I...</summary>
<author>
<name>khoyt</name>


</author>
<dc:subject>Flash Lite</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/khoyt/">
<![CDATA[<p>If you follow my blog you'll no doubt be under the impression that I am all about Flex.  For the most part, this is true, and as a Sr. Product Specialist here at Adobe, specifically for the Flex product, I spend the majority of my time in that wonderful world.  Occasionally though I'll head out to other technologies provided by Adobe and give them a whirl.  Sometimes this is driven by customer interests/demand, but others are purely exploratory in nature.  Such is the case with the following Flash Lite 1.1 application - Blood Pressure.</p>]]>
<![CDATA[<p>I've always struggled with hypertension.  I have the blessing of genetics to thank for that as both my parents manage their blood pressure with medication.  Much like the now popular pharmaceutical commercials, hypertension doesn't discriminate about age, weight or physical fitness.  While certainly these factors can play a role, one might be the perfect human specimen physically, and still have high blood pressure.  Even as a soldier in the US Army, in peak fitness, running several miles every day, with a body fat percentage nearing single digits, I had to keep my blood pressure in check.</p>

<p>One way to manage hypertension is to be aware of it, and how your body exhibits those stressors.  This most commonly takes the form of simply logging what your blood pressure is at various intervals throughout the day or week.  Obviously this could be done on paper, but I'd leave it somewhere, my wife might throw it away, or my daughter would use it as the foundation for her next work of [scribble] art.  Excel might be an answer, and there are even desktop applications for this purpose, but I don't want to have to power up my laptop every time I want to record my blood pressure.</p>

<p>It then occurred to me that I almost always have my [Flash Lite enabled] phone with me, and that I could write an application to support my efforts.  That application could keep the data on a remote server.  Then I wouldn't have to worry about it, and I could potentially expose a larger set of functionality through a Flex application.  This is the genesis for my Blood Pressure application.  </p>

<table width="100%">
  <tr>
    <td><img alt="Main screen" src="http://weblogs.macromedia.com/khoyt/files/bp-main.gif" width="176" height="208" /></td>
    <td><img alt="Blood pressure reading" src="http://weblogs.macromedia.com/khoyt/files/bp-pressure.gif" width="176" height="208" />
</td>
    <td><img alt="Date of reading" src="http://weblogs.macromedia.com/khoyt/files/bp-date.gif" width="176" height="208" /></td>
  </tr>
</table>

<p>At first glance this is a pretty simple application.  You can add blood pressure readings, view a list of historical readings, and update or delete readings.  Doing this with what essentially amounts to Flash 4 ActionScript however was a very sizable task.  Remember that I'm storing all my data on a remote server (powered by ColdFusion MX 7) through loadVariables() calls.  No fancy SOAP or even XML here, just name/value query string values.</p>

<p>When a data request is made, there are no events or other notifications; I simply had to build that myself.  When the user wants to page down through what could potentially be several years of historical information, I have to manually account for where they are in the overall dataset.  I use a scrollbar to indicate the overall number of records versus the user's current position, and this too had to be invented.  A list control to show selected fields from the data objects also had to be invented.  </p>

<p>Outside of the UI elements, there's a ton of processing on the fields in the UI that occurs.  Think about the fact that readings are recorded with date and time information, but that no Date object exists in Flash 4.  Dealing with leap years meant porting a JavaScript routine I found on the web to ActionScript - Flash 4 ActionScript.  I also had to be able to assemble/disassemble date values to coordinate data communication with the server.  When the users moves the months from February to March to ... I adjust the day of the week (spelled out) to reflect their new selection.  None of this existed, and all of it had to be written from scratch.</p>

<p>You might then understand how the decision to post the source on my blog has pained me so much.  It's been a ton of work, but work from which I'll likely never use fully due to some constraints that I'll mention in a moment.  My thought then is that perhaps the community can benefit from my pains and in studying how it is I went about creating a data-centric, internet-connected, Flash Lite 1.1 application.  With that being said, <a href="http://weblogs.macromedia.com/khoyt/files/bp-v1.zip">attached to this blog entry</a> is my Blood Pressure application.</p>

<p>You know how when you set out to learn about a specific technology, that there are always pitfalls of which you were initially unaware?  Such is the case with Blood Pressure.  Most notably is that Flash Lite 1.1 looks at URL's as distinct entities.  I have a "list.cfm" an "update.cfm" and so on for the various actions needed by the application.  Flash Lite 1.1 looks at those as different destinations, and requests the user's approval before sending the data.  This can be very aggravating when you just want to make a new entry.</p>

<p>In looking back, it'd be better to have a single "bloodpressure.cfm" or the likes that I could control through query string arguments such as "?action=update".</p>

<p>The other limitation comes from being able to uniquely identify the user.  Rather than deal with a login system, I figured that I'd rely on the phone number.  If you're like me and you take your phone number with you from phone to phone, then it would consistently identify your data.  Besides, who's ever going to use this besides me?  Well it turns out that when Flash Lite 1.1 goes to access the phone number, it has to, once again, get approval from the user.  </p>

<p>Note to self (does anybody remember Parker Lewis Can't Lose?): next time use a login authentication scheme.  </p>

<p>A note to those of you that put this one your phone for a test spin: I do record the phone number and store it in my database on my server.  I have no intention of sharing this information with anybody, and quite frankly I'm not sure I'll ever even look at it.  That being said however, it is a file on the Internet and could potentially be susceptible to a hacker.  If you have a problem with using your phone number in this fashion, then I suggest that you avoid running this application on your phone.  The emulator however uses a dummy phone number, which should work great.  All I ask is that you not delete any data that you didn't create.</p>

<p>In the end, all these additional prompts really almost make the application unbearable to use, so I haven't.  It's just been sitting around for months now, collecting digital dust.  As I pick up my next Flash Lite 1.1 project, I find myself referring back to the code.  It occurs to me that if I am referencing the code, then there's likely others out there that can benefit as well.  In the spirit of open source, I hereby set <a href="http://weblogs.macromedia.com/khoyt/files/bp-v1.zip">Blood Pressure</a> free unto the community.</p>

<p>I started a Flash Lite 2 version not too long ago.  It's got a much improved UI and adds charting of your data (a la the Drawing API).  I've even started on a Flex 1.x and subsequently Flex 2 version with far more substantial capabilities.  Will I send those off as well?  Perhaps one day, but for now I encourage you to explore Blood Pressure, it's substantial code, and to provide me with feedback should you go so far as to run it.  I provide not guarantees about the condition of this software, but would love to hear from those bold enough to give it a try. </p>]]>
</content>
</entry>

</feed>