<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>joeberkovitz.com</title>
	<atom:link href="http://joeberkovitz.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://joeberkovitz.com/blog</link>
	<description>Just another WordPress weblog</description>
	<pubDate>Tue, 30 Dec 2008 15:57:34 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<item>
		<title>Going Back to Cali</title>
		<link>http://joeberkovitz.com/blog/2008/12/30/going-back-to-cali/</link>
		<comments>http://joeberkovitz.com/blog/2008/12/30/going-back-to-cali/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 15:57:34 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=131</guid>
		<description><![CDATA[Although not exactly the Cali represented in LL Cool J&#8217;s immortal deadpan number.  (Also check out the wonderful sax solo at the end, playing a minor 3rd up from the key of the tune.)
On Friday, I fly to San Francisco, rent a car, drive to San Rafael, meet spouse who is already there, and then [...]]]></description>
			<content:encoded><![CDATA[<p>Although not <em>exactly</em> the Cali represented in<a href="http://www.youtube.com/watch?v=IC7iIttp6cY"> LL Cool J&#8217;s immortal deadpan number</a>.  (Also check out the wonderful sax solo at the end, playing a minor 3rd up from the key of the tune.)</p>
<p>On Friday, I fly to San Francisco, rent a car, drive to San Rafael, meet spouse who is already there, and then we&#8217;ll spend 6 glorious days moseying around the wilds of the Mendocino County and northern Marin coastlines.  Goodbye, work, for a while.  I predict there will be some kind of trip report!</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/12/30/going-back-to-cali/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Live (or not so live) on The Flex Show</title>
		<link>http://joeberkovitz.com/blog/2008/12/19/live-or-not-so-live-on-the-flex-show/</link>
		<comments>http://joeberkovitz.com/blog/2008/12/19/live-or-not-so-live-on-the-flex-show/#comments</comments>
		<pubDate>Fri, 19 Dec 2008 01:48:35 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Music]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=127</guid>
		<description><![CDATA[Starting today, you can catch me on episode 63 of The Flex Show, in which the effervescent John Wilker and Jeffry Houser interview yours truly about Noteflight, Flex, and I forget what else &#8212; it was taped a few weeks ago, which feels more like several years given the wealth of activity that was packed [...]]]></description>
			<content:encoded><![CDATA[<p>Starting today, you can catch me on <a href="http://www.theflexshow.com/blog/index.cfm/2008/12/17/Flex-Show-Episode-63-Interview-with-Joe-Berkovitz-of-Noteflightcom">episode 63 of The Flex Show</a>, in which the effervescent John Wilker and Jeffry Houser interview yours truly about Noteflight, Flex, and I forget what else &#8212; it was taped a few weeks ago, which feels more like several years given the wealth of activity that was packed into it.  I think I might take a listen right now, to find out the exact manner in which I embarrassed myself.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/12/19/live-or-not-so-live-on-the-flex-show/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Flash &#8220;Clipboard&#8221; using Local Shared Objects</title>
		<link>http://joeberkovitz.com/blog/2008/12/12/clipboard-using-local-shared-objects/</link>
		<comments>http://joeberkovitz.com/blog/2008/12/12/clipboard-using-local-shared-objects/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 17:48:57 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=117</guid>
		<description><![CDATA[I spent a good part of yesterday implementing a new global clipboard feature for Noteflight using local shared objects or LSOs.  These cookie-like constructs are often used to persist application-specific data across multiple sessions, so that when you close an application down and then restart it later, it resumes in the same state you left [...]]]></description>
			<content:encoded><![CDATA[<p>I spent a good part of yesterday implementing a new global clipboard feature for Noteflight using <a href="http://www.adobe.com/products/flashplayer/articles/lso/">local shared objects</a> or LSOs.  These cookie-like constructs are often used to persist application-specific data across multiple sessions, so that when you close an application down and then restart it later, it resumes in the same state you left it.  What I haven&#8217;t seen much of (and haven&#8217;t done before myself) is use LSOs to communicate data between completely different instances of the same application running <em>at the same time</em>.  It does work, and seems to work well.</p>
<p>Noteflight is a Flash-based music notation editor, and one of the most often-requested features has been the ability to cut, copy and paste between different documents.  These &#8220;clipboard&#8221; operations already worked within a single session editing a single document.  However, the clipboard contents did not survive across edits to a series of documents,  nor could they transfer between different documents open in different windows.  In effect, each copy of the application had its own private copy of the clipboard, initialized to emptiness.  Not surprisingly, users don&#8217;t like these limitations.</p>
<p>It seemed clear that LSOs would be a good vehicle for this enhancement.  We would write the clipboard to an LSO on every cut or copy, and read it out of the same LSO before every paste.  This would not be exactly like a real native system clipboard (since it would be separate from the system clip that contains text, images, etc.) but for the purposes of Noteflight it would seem a lot like one.  The challenges we expected to solve (and did) were as follows:  serialization, keeping LSOs small, handling LSO failure gracefully, and application version skew.  There were of course a couple of major surprises, too!</p>
<p><strong>Serialization</strong>.  All LSOs are stored in files, and must serialize their data.  They do so using the <a href="http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf">AMF3</a> protocol. ActionScript 3 defines how one can manage the serialization of arbitrary Objects using the [RemoteClass] and [Transient] metadata tags (be sure to look those up if you are thinking of serializing objects in a Flex application).  I&#8217;ve used them before, but the special problem here was that the clipboard data structures had already been designed and were quite complex, with a number of potential references to objects sitting &#8220;out in the application&#8221;.  Serializing any of those would result in lots of irrelevant data getting &#8220;dragged in&#8221; to the LSO and bloating it, so they&#8217;d have to be marked as transient.  It would be also necessary to make sure that each and every class requiring a [RemoteClass] tag received it.  Getting all this right in a short amount of time seemed unlikely.</p>
<p>Fortunately I had plenty of existing code to serialize the objects in the clipboard to XML and back, since Noteflight persists musical scores as XML.  So I used Flash&#8217;s handy <tt>IExternalizable</tt> interface to take advantage of this.  This is a great technique that allows you to decide how your objects will be serialized.  Basically, what I did was kind of like this:</p>
<pre>[RemoteClass]
public class AppClipboard implements IExternalizable
{
  private var _data:AppData;  // contents of the clipboard...

  public function writeExternal(output:IDataOutput):void
  {
    output.writeObject(XmlWriter.toXML(_data).toXMLString());
  }

  public function readExternal(input:IDataInput):void
  {
    _data = XMLReader.fromXml(new XML(input.readObject()))
  }
}</pre>
<p>(Note the [RemoteClass] tag &#8212; you still need it even if you use IExternalizable, or Flash won&#8217;t reconsititute the class of your object when you read it back in again.)</p>
<p>With this code written,  when you setting one of your shared object&#8217;s <tt>data</tt> properties to an AppClipboard, like this:</p>
<pre>  mySO.data.contents = myAppClipboard;</pre>
<p>then the writeExternal() method is implicitly used to serialize that object.  Same deal goes when reading the shared object back in: readExternal() gets used.</p>
<p>Next challenge:</p>
<p><strong>Keeping the data size low.</strong> since there is a default 100K limit on LSO storage.  XML has its disadvantages, and verbosity is certainly one of them.  I needed to compress my serialized objects somehow.  I found a nice way to do that, which works for any serializable objects at all (whether you use IExternalizable or not).  Here&#8217;s the &#8220;write side&#8221; of the technique:</p>
<pre>
  var so:SharedObject = getClipboardSO();
  var bytes:ByteArray = new ByteArray();
  bytes.writeObject(_clipboard);   // write our object to a ByteArray
  bytes.compress();    // compress the ByteArray
  so.data.contents = bytes;   // and write the ByteArray instead
  so.data.version = NotationXmlReader.CURRENT_VERSION;
  so.data.creationTime = _clipboardCreationTime;
  so.flush();
</pre>
<p>The &#8220;read side&#8221; works similarly:</p>
<pre>
  var so:SharedObject = getClipboardSO();
  if (so != null
      &#038;&#038; so.data.version == CURRENT_VERSION
      &#038;&#038; (_clipboard == null
          || _clipboardCreationTime < so.data.creationTime))
  {
      var bytes:ByteArray = so.data.contents as ByteArray;
      bytes.uncompress();
      _clipboard = bytes.readObject() as AppClipboard;
      _clipboardCreationTime = new Date().getTime();

      // Flush the object after reading it so it doesn't get cached!
      so.flush();
  }
</pre>
<p>Here you can see the <strong>version skew</strong> detection, as well as a guard against using a &#8220;stale&#8221; shared clipboard that is actually older than the local version.  That can happen if the &#8220;write side&#8221; fails to save an LSO due to size limitations, in which case we have to <strong>degrade gracefully</strong> and use the local clipboard instead of the stale shared one.   This means that a single instance will still behave consistently even if it fails to transfer data to other instances.</p>
<p>Surprise #2: note the call to <tt>so.flush()</tt> on the read side.  I did not expect to have to flush() a SharedObject after <em>reading</em> it.  However, before putting this flush in, I found that the player would cache the SharedObject and refuse to check to see if it had been updated when reloading it by calling <tt>SharedObject.getLocal()</tt>.  This caused clipboard-style transfer of data between different application windows to fail sporadically.  It took a long time to figure this one out.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/12/12/clipboard-using-local-shared-objects/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Minimal Apache/Rails configuration on small virtual server</title>
		<link>http://joeberkovitz.com/blog/2008/11/23/minimal-apache-rails-on-small-virtual-server/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/23/minimal-apache-rails-on-small-virtual-server/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 15:31:55 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=114</guid>
		<description><![CDATA[As I&#8217;ve mentioned before I&#8217;m running a couple of WordPress blogs and a Rails application on Slicehost, using the smallest slice size of 256 MB RAM.  Apart from Rails, this is a typical LAMP setup with Ubuntu Hardy Heron, Apache2-prefork, MySQL 5.x, PHP5.  It took a little while for me to find a [...]]]></description>
			<content:encoded><![CDATA[<p>As I&#8217;ve mentioned before I&#8217;m running a couple of WordPress blogs and a Rails application on <a href="http://www.slicehost.com">Slicehost</a>, using the smallest slice size of 256 MB RAM.  Apart from Rails, this is a typical LAMP setup with Ubuntu Hardy Heron, Apache2-prefork, MySQL 5.x, PHP5.  It took a little while for me to find a robust Apache and Rails configuration, though.  The out of the box Apache2 config would periodically eat up all the swap space and die.  So my hope here is to save others some newbie-sysadmin headaches.</p>
<p><strong>Apache2.</strong>  Apache2 prefork is configured to keep a certain number of processes running to respond to HTTP requests that come in.  These processes are reused across a number of requests and thus tend to grow over time in their memory consumption to reach the largest amount of RAM demanded by any page served.  When using mod_php, the RAM consumption is related to PHP application resources, in this case WordPress.  I found that my Apache processes generally were in the 20m range for resident memory size (the RSS column in the &#8216;top&#8217; display).  With the out-of-box Apache2 configuration allowing as many as 15-20 processes, that meant that any large batch of concurrent requests (such as those originating from a search bot) would totally nail my machine.  So the most important change I wound up making was to reduce the number of processes:</p>
<pre>
&lt;IfModule mpm_prefork_module&gt;
    StartServers          3
    MinSpareServers       3
    MaxSpareServers       3
    ServerLimit          10
    MaxClients           10
    MaxRequestsPerChild   1000
&lt;/IfModule&gt;
</pre>
<p>This generally causes me to see around 5-6 processes running, with the possibility of as many as 10.</p>
<p>A number of folks have suggested I run nginx or lighttpd, which I&#8217;m sure would be a great idea, but I was strapped for time and in a mood to stick with things that have lots of online recipes and that I already somewhat understood.</p>
<p><strong>Rails</strong>.  Various approaches are available here as well. At first I was running the mod_passenger module, but I found this gave me a few 30m processes as opposed to the single 50m process I could get by running a single mongrel.  So now I&#8217;m running a single mongrel and it&#8217;s working fine.</p>
<p><strong>MySQL</strong>.  Haven&#8217;t tuned this much yet, but I&#8217;m not seeing any problems.</p>
<p><strong>WordPress</strong>.  Caching is enabled on the advice of a number of people that this will decrease MySQL resource consumption.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/23/minimal-apache-rails-on-small-virtual-server/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Flexcover 0.81 is out</title>
		<link>http://joeberkovitz.com/blog/2008/11/18/flexcover-081-is-out/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/18/flexcover-081-is-out/#comments</comments>
		<pubDate>Tue, 18 Nov 2008 15:12:22 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=112</guid>
		<description><![CDATA[A quick update: Alex Uhlmann and I have just released the latest Flexcover edition on our Google Code Project.  This release supports the newly announced Flex 3.2 SDK, Flex Builder 3.0.2 and AIR 1.5.
]]></description>
			<content:encoded><![CDATA[<p>A quick update: <a href="http://weblogs.macromedia.com/auhlmann/">Alex Uhlmann</a> and I have just released the latest Flexcover edition on our <a href="http://code.google.com/p/flexcover/">Google Code Project</a>.  This release supports the newly announced Flex 3.2 SDK, Flex Builder 3.0.2 and AIR 1.5.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/18/flexcover-081-is-out/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Vote for sampled audio to not crash IE7</title>
		<link>http://joeberkovitz.com/blog/2008/11/17/vote-for-sampled-audio-to-not-crash-ie7/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/17/vote-for-sampled-audio-to-not-crash-ie7/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 11:55:27 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=109</guid>
		<description><![CDATA[Turns out there&#8217;s a nasty bug in sampled audio playback in the newly released Flash 10 player.  Found by Tyler Wright of Legato Media, this bug takes down your entire IE7 browser if you open simultaneous windows with Flash content, one of which is playing back audio using the new SampleDataEvent API.  This [...]]]></description>
			<content:encoded><![CDATA[<p>Turns out there&#8217;s a nasty bug in sampled audio playback in the newly released Flash 10 player.  Found by Tyler Wright of Legato Media, this bug takes down your entire IE7 browser if you open simultaneous windows with Flash content, one of which is playing back audio using the new <tt>SampleDataEvent</tt> API.  This is a crippling problem for any ambitious Flash content on the web incorporating dynamic audio.</p>
<p>Fortunately, we now have the prospect of an American President who can speak in intelligible sentences&#8230;  which means that you can turn all of your positive energy to getting Adobe to fix this bug.  Please vote on it at:</p>
<p><a href="https://bugs.adobe.com/jira/browse/FP-985">https://bugs.adobe.com/jira/browse/FP-985</a></p>
<p>Future generations thank you!  (Future generations of what, you may ask?)</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/17/vote-for-sampled-audio-to-not-crash-ie7/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Flexcover upgrade for Flex 3.2.0 SDK is looking good</title>
		<link>http://joeberkovitz.com/blog/2008/11/11/flexcover-upgrade-for-flex-320/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/11/flexcover-upgrade-for-flex-320/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 02:29:56 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=106</guid>
		<description><![CDATA[Alex and I &#8212; lately, to be honest, it&#8217;s mostly Alex &#8212; have been working on the forthcoming upgrade release of Flexcover, the code coverage instrumentation tool for Flex/AS3.  I&#8217;m feeling pleased because I finally merged up the modifications to the Flex SDK compiler to the 3.2.0 branch, in preparation for an expected release [...]]]></description>
			<content:encoded><![CDATA[<p>Alex and I &#8212; lately, to be honest, it&#8217;s mostly Alex &#8212; have been working on the forthcoming upgrade release of <a href="http://code.google.com/p/flexcover/">Flexcover</a>, the code coverage instrumentation tool for Flex/AS3.  I&#8217;m feeling pleased because I finally merged up the modifications to the Flex SDK compiler to the 3.2.0 branch, in preparation for an expected release of a new Flex Builder in the MAX timeframe.</p>
<p>The merge went smoothly and the 3.2.0 compiler seems to work like a champ &#8212; well, at least, it does everything that the 3.0.x version did.  What&#8217;s more, a sneak peek at Flex Builder 3.2 revealed that they&#8217;ve fixed an irksome bug in the Flex Compiler project options dialog, and it&#8217;s now possible to enable and disable coverage instrumentation using the compiler options field.</p>
<p>That&#8217;s just the part I did.  Alex has been busy working on some very nice changes to the CoverageViewer, which should greatly reduce the performance problems people were seeing during data collection before.  We&#8217;ve also made it much easier to merge reports from multiple test runs.  A few more fixes are needed but things are looking up&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/11/flexcover-upgrade-for-flex-320/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Host of Broken Dreams</title>
		<link>http://joeberkovitz.com/blog/2008/11/06/host-of-broken-dreams/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/06/host-of-broken-dreams/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 16:15:02 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=100</guid>
		<description><![CDATA[This site has been up and down like a yo-yo since Friday.  All is better, though now that I&#8217;ve moved this domain and the Noteflight blog to a new hosting company: Slicehost.  Slicehost seems very cool &#8212; they offer what seems at first like a bare-bones service (VPS hosting starting with a minimal [...]]]></description>
			<content:encoded><![CDATA[<p>This site has been up and down like a yo-yo since Friday.  All is better, though now that I&#8217;ve moved this domain and the Noteflight blog to a new hosting company: <a href="http://www.slicehost.com">Slicehost</a>.  Slicehost seems very cool &#8212; they offer what seems at first like a bare-bones service (VPS hosting starting with a minimal Ubuntu Linux distro, no one-click installs or control panels).  But it&#8217;s not so bare-bones once you realize that Slicehost provides really, really clear how-to articles that make it very straightforward to set up all the same stuff that you&#8217;d normally get from a more standard hosting service.  And when you&#8217;re done doing what these articles explain, you understand how it all works: a great benefit.  And you&#8217;ve got total control over the system you build, with root access and all.  No one can @#$% with it.  For an example of being @#$%ed with, you may continue reading.  <span id="more-100"></span></p>
<p>My previous hosting company &#8212; referred to obliquely in the title of this post &#8212; blew up in this past week, to the point where I had to make an abrupt decision to pull everything off their servers.  Here&#8217;s more or less what happens, starting Friday:</p>
<ul>
<li>With no warning, my Virtual Private Server account is moved to a new domain name and static IP.  (You might wonder what the meaning of &#8220;static IP&#8221; is under these circumstances.)</li>
<li>The old VPS instance continues running and is still accessible at its name and IP, so I assume everything is fine.  However, all activity on that instance (including SVN commits) are written to a separate disk not associated with the new VPS.</li>
<li>Those of my sites which are running on the new VPS instance break, because the new instance is misconfigured and can&#8217;t reach the DB server.  Also its postfix install turns out to be broken due to bad permissions setup.  So the new VPS is basically hosed.</li>
<li>I wait over 48 hours for support to return my emails while my sites are down.  I do not even receive an auto-reply for almost 36 hours.</li>
<li>The same backup cron job is running on both VPS instances, unbeknownst to me.  The job on the new instance backs up stale data that overwrites on the backups from the old VPS (which is still in use, because I haven&#8217;t been told yet which is the &#8220;real&#8221; instance).</li>
<li>Support fixes the new VPS so it can reach the DB server, and the old VPS is removed.  I switch all remaining services to the new VPS but start the process of pulling out.</li>
<li>Support tells me that I was mistakenly charged for a hosting plan along with the VPS account, cancels the hosting plan, and credits my account with the prepaid balance.  With the disappearance of the hosting plan, all my databases and user accounts promptly disappear before I can back them all up and migrate them elsewhere.  All sites down again.</li>
<li>Support reinstates the hosting plan.  I pull everything remaining over to Slicehost and get it running again there.</li>
</ul>
<p>It&#8217;s sad, because this hosting provider used to be a good deal, and delivered exactly what I needed at the point when I first started using them.  I wish I could say the same today. </p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/06/host-of-broken-dreams/feed/</wfw:commentRss>
		</item>
		<item>
		<title>David Coletta at Boston Flex Users Group 11/11</title>
		<link>http://joeberkovitz.com/blog/2008/11/06/david-coletta-at-boston-flex-users-group-1111/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/06/david-coletta-at-boston-flex-users-group-1111/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 13:17:24 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=98</guid>
		<description><![CDATA[A quick squib here to note that my friend David Coletta will be talking about building unified codebases for AIR and Flex at the November Boston Flex User Group meeting.
Go see David.  Go see David.  Go see David.
Is there anything about &#8220;Go see David&#8221; that you don&#8217;t understand?  He&#8217;s a dynamic, intelligent and very, very [...]]]></description>
			<content:encoded><![CDATA[<p>A quick squib here to note that my friend <a href="http://colettas.org">David Coletta</a> will be talking about building unified codebases for AIR and Flex at the November <a href="http://bostonfug.org/">Boston Flex User Group meeting</a>.</p>
<p>Go see David.  Go see David.  Go see David.</p>
<p>Is there anything about &#8220;Go see David&#8221; that you don&#8217;t understand?  He&#8217;s a dynamic, intelligent and very, very informative speaker.  Hope to see you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/06/david-coletta-at-boston-flex-users-group-1111/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Strongly Typed Proxies in AS3</title>
		<link>http://joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/</link>
		<comments>http://joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 12:00:43 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/</guid>
		<description><![CDATA[Something I&#8217;ve often wanted in AS3 is a strongly typed proxy: an object that implements a known interface with typed methods, but where every method results in the invocation of some method like invokeMethod(methodName:String, args:Array).  AS3 does have a Proxy class, but unlike Java&#8217;s class of the same name, an AS3 Proxy doesn&#8217;t implement [...]]]></description>
			<content:encoded><![CDATA[<p>Something I&#8217;ve often wanted in AS3 is a <em>strongly typed proxy</em>: an object that implements a known interface with typed methods, but where every method results in the invocation of some method like <code>invokeMethod(methodName:String, args:Array)</code>.  AS3 does have a <code>Proxy</code> class, but unlike Java&#8217;s class of the same name, an AS3 <code>Proxy</code> doesn&#8217;t implement any particular interface.  One can extend Proxy into a subclass that has an interface, but by that time the Proxy superclass isn&#8217;t delivering any real value.  The AS3 <code>Proxy</code>  has been designed for loose, dynamic typing &#8212; which after all is one of the strengths of the ActionScript/ECMAScript languages.</p>
<p>Why use a strongly typed proxy?  A common use of such a proxy is to create a &#8220;smart wrapper&#8221; around some underlying object with a known interface that looks and acts (and code-hints) exactly like the underlying thingamabob, but does some other stuff around every method call or property access.  You might want a smart wrapper that logs or records all the function calls (as well as executing them).  You might want a wrapper that does a try/catch around every call.  You might want a wrapper that serializes the call over a stream to some remote destination.</p>
<p>(If this sounds like what some call &#8220;aspect-oriented programming&#8221;, well, it is similar to one aspect of aspect oriented programming :-)</p>
<p>Anyway, we can&#8217;t use AS3&#8217;s Proxy to solve this problem, so what to do?  We&#8217;ll start with a simple approach, but make it more general.  If our interface looked like this:</p>
<pre>
public interface ISmashable
{
    function smash(force:Number):String;
}</pre>
<p>and we wanted to create a smart wrapper that logged all function calls around any ISmashable implementation, we might create something like this:</p>
<pre>
public class SmashableLoggingProxy implements ISmashable
{
    private var _smashable:ISmashable;
    public function SmashableProxy(smashable:ISmashable)
    {
        _smashable = smashable;
    }

    public function smash(force:Number):String
    {
        trace("smash():", force);
        var result:String = _smashable.smash(force);
        trace("    result:",result);
        return result;
    }
}</pre>
<p>Then, if we did something like <code>var proxy:ISmashable = new SmashableProxy(realSmashable);</code> we could treat the resulting <code>proxy</code> as an ISmashable everywhere in our application,  Every time we called, say <code>smash(5)</code> method on <code>proxy</code>, not only would <code>realSmashable.smash(5)</code> be called but we&#8217;d see some nice trace output as well.<br />
If you have the time to create a lot of wrapper methods like this (or write a fancy code generator to save the trouble), that&#8217;s fine.  Another way to go, however would be to create a &#8220;generic&#8221; smart wrapper base class: <span id="more-92"></span></p>
<pre>
public class SmartProxy
{
    private var _obj:Object;
    private var _functionNames:Dictionary;

    public function SmartProxy(obj:Object)
    {
        _obj = obj;

        // set up Dictionary that goes from functions in this wrapper to function names
        _functionNames = new Dictionary();
        var typeInfo:XML = describeType(this);   // returns metadata for subclass interface
        for each (var functionInfo:XML in typeInfo.method)
        {
            var name:String = functionInfo.@name;
            _functionNames[this[name]] = name;
        }
    }

    protected function handleInvocation(args:Object):*
    {
        // 'callee' is a special AS3-defined property of an 'arguments' object
        // that provides the Function which was called
        var functionName:String = _functionNames[args.callee];
        return applyFunction(functionName, args);
    }

    protected function applyFunction(functionName:String, args:Object):*
    {
        // This looks up the name of the function that was called, uses it to
        // obtain the Function in the underlying object as a property, and calls it.
        return (_obj[functionName] as Function).apply(_smashable, args);
    }
}</pre>
<p>Now extend this to implement our interface:</p>
<pre>
public class SmashableProxy extends SmartProxy implements ISmashable
{
    public function SmashableProxy(smashable:ISmashable)
    {
        super(smashable);  // sounds like a Nintendo game, eh?
    }
    public function smash(force:Number):String
    {
        return handleInvocation(arguments);  // arguments is a special AS3 language keyword!
    }

    // (if our interface had other functions, they would all have the same body!)
}</pre>
<p>The above SmashableProxy acts exactly like the underlying object.  What&#8217;s the point?  Well, given a base class of this kind, one can create smart wrappers of any variety with very little additional effort:</p>
<pre>
public class SmashableLoggingProxy extends SmashableProxy
{
    public function SmashableProxy(smashable:ISmashable)
    {
        super(smashable);
    }

    override protected function applyFunction(functionName:String, args:Object):*
    {
        trace(functionName, "():", args);
        var result:String = super.applyFunction(functionName, args);
        trace("result:",result);
        return result;
    }
}</pre>
<p>The astute reader may notice that logging is generic, and wonder if it should be handled in the SmartProxy, not in this subclass.  So a further extension of this idea might  introduce a separate <em>invocation handler</em> that can supply generic handling for all method invocations,  and is a property of the SmartProxy.  Java in fact has exactly such a class for its Proxies.</p>
<p>In another post soon, I&#8217;ll describe how this fits into the testing strategy for Noteflight, which has a large automated test suite of recorded UI actions.  We use this suite to validate the program before every checkin &#8212; it is a very complex editor, and it&#8217;s all too easy to fix one thing and break another, so the test suite makes sure we don&#8217;t do that!</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
