<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mark Alldritt&#039;s Journal &#187; FaceSpan</title>
	<atom:link href="http://blog.latenightsw.com/?feed=rss2&#038;cat=10" rel="self" type="application/rss+xml" />
	<link>http://blog.latenightsw.com</link>
	<description>Just another developer weblog</description>
	<lastBuildDate>Mon, 07 May 2012 23:57:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>FaceSpan 5 (Mark&#8217;s Misadventure)</title>
		<link>http://blog.latenightsw.com/?p=637</link>
		<comments>http://blog.latenightsw.com/?p=637#comments</comments>
		<pubDate>Sun, 06 May 2012 04:38:48 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>
		<category><![CDATA[Late Night Software]]></category>

		<guid isPermaLink="false">http://blog.latenightsw.com/?p=637</guid>
		<description><![CDATA[A review of my failed FaceSpan 5 project and a chance to try the software out.]]></description>
			<content:encoded><![CDATA[<p>Back in May 2009 I made the <a href="http://blog.latenightsw.com/?p=50">difficult decision to abandon FaceSpan 5</a>. This was a wrenching period in my life and it has taken a long time to recover.  The failure of this project seriously stressed my relationship with a couple of good friends and cost me a lot of money and time.  At last I feel like I have enough distance to begin to talk about what was accomplished and the mistakes I made. </p>

<p>I am a self-funded Indie (lone) developer.  I made a number of classic business blunders on the FaceSpan 5 project.  I broke the golden rule: <strong>never (never!) rewrite a software product</strong>.  I massively underestimated the effort required to complete the product.  I set off without having sufficient resources to complete the project.  Because I took so long to complete my work, the market moved on &#8212; AppleScript&#8217;s importance to the customers I intended to target declined.  Some may argue that the market was never really there to provide a return for a product of this complexity.  Finally, I didn&#8217;t pull the plug soon enough.  Hindsight its great.</p>

<p>Not all was lost.  <em>Some</em> of the code I developed for FaceSpan 5 found a home in <a href="http://blog.latenightsw.com/?cat=18">Script Debugger 5</a>.</p>

<h2>A Little History</h2>

<p>Many years previously I developed FaceSpan 3 under contract for its owner. As part of that effort I became impressed with FaceSpan&#8217;s power and simplicity. FaceSpan 3 was successful, for a development tool, and even received an Apple Design Award at that year&#8217;s Worldwide Developers Conference.  Sadly, after my involvement with the product ended, FaceSpan fell into disrepair and did not make the leap to Mac OS X. FaceSpan&#8217;s developer finally produced FaceSpan 4 which was to little to late and not as successful as hoped for.</p>

<p>I acquired FaceSpan 4 in 2006 and, after a period where I tried to fix the most serious issues with the product, I concluded that FaceSpan 4&#8242;s dependance on AppleScript Studio was its core problem.  FaceSpan 4 had great integration of a visual UI bilder and coder editor, but lacked a good runtime environment and debugging.</p>

<p>Work on FaceSpan 5 began in 2007 with the aim of freeing FaceSpan from AppleScript Studio and restoring the classic FaceSpan&#8217;s attractiveness. By the time I stopped FaceSpan&#8217;s development I believe I was well on my way to achieving my aims. Two great Mac developers helped me with the project:</p>

<ul>
<li>Adrian Ruigrok, who now works for Apple, developed much of the FaceSpan 5 IDE code.</li>
<li>Matt Neuburg acted as a sounding board for my ideas and developed the initial FaceSpan 5 documentation.</li>
</ul>

<p>The project turned out to be too ambitious given my resources.  Additionally, FaceSpan revealed a number of AppleScript issues and problems in Apple&#8217;s Cocoa Scripting framework which I was ultimately unable to overcome.</p>

<h2>What Is (Was) FaceSpan?</h2>

<p>FaceSpan 5 was an integrate tool for building Cocoa applications using AppleScript.  Many people saw similarities to Apple&#8217;s HyperCard.  FaceSpan provided a visual UI builder, an AppleScript editor, an AppleScript debugger and a runtime environment designed to take the best advantage of AppleScript&#8217;s strengths and provide a collection services and UI widgets out of which applications can be built.  Matt wrote this <a href="http://blog.latenightsw.com/?page_id=565">description of FaceSpan 5</a> back when the project was active.</p>

<p><img src="http://blog.latenightsw.com/wp-content/uploads/2012/05/FaceSpan5.png" alt="FaceSpan 5 Project Window" /></p>

<p>The FaceSpan 5 runtime environment wrapped Apple&#8217;s Cocoa Frameworks in a sanitized and simplified AppleScript focused programming interface.  This allowed one to build fully Cocoa-native applications using AppleScript without having to learn anything about Cocoa.  The intent was for Cocoa to be an implementation detail rather than the programming interface.</p>

<p>We&#8217;ll never know if the FaceSpan 5 approach was actually better than the <a href="http://developer.apple.com/legacy/mac/library/documentation/AppleScript/Conceptual/StudioBuildingApps/StudioBuildingApps.pdf">AppleScript Studio</a> interface offered by Apple.  My hope was that FaceSpan&#8217;s approach was actually simpler, and not simply a substitution of one complicated programming interface for another.</p>

<p>Since FaceSpan 5 was abandoned there have been several developments in the area of AppleScript GUI tools.  Firstly, Apple transitioned from AppleScript Studio to <a href="http://developer.apple.com/library/mac/#releasenotes/ScriptingAutomation/RN-AppleScriptObjC/_index.html">AppleScriptObjC</a>.  Shane Stanley has released his <a href="http://www.macosxautomation.com/applescript/apps/runner.html">ASObjC Runner</a> which can display progress dialogs.  And then there is the long lived <a href="http://www.24usoftware.com/AppearanceOSAX">Appearance OSAX</a> from 24U Software.</p>

<h2>The Last Build</h2>

<p>When I stopped developing FaceSpan 5, a lot of people came out of the woodwork looking for a copy of the software.  I was not willing to make the software available at that time, but I am now.  I&#8217;m doing this now because I think it might be interesting for those of you who were/are curious about what I was working on to get a chance to play with the product.  </p>

<p>Keep in mind that this build predates the release of Xcode 4 and there are some interesting similarities.  Apple had to be developing parts of Xcode 4 during the same period so its fascinating to me how common ideas arrise in different places.</p>

<p>Before you download the software, please keep the following conditions in mind:</p>

<ul>
<li>This is <strong><a href="http://en.wikipedia.org/wiki/Alpha_software#Alpha">Alpha-Stage</a></strong> software.  This means that it is buggy and its not feature or UI complete.  Expect it to crash and fail.  If you stick to the examples included with the documentation, you should be okay.  </li>
<li><strong>THE FACESPAN SOFTWARE IS PROVIDED AS-IS FOR EVALUATION PURPOSES ONLY.  USE AT YOUR OWN RISK</strong>.</li>
<li><strong>PLEASE DO NOT FILE BUG REPORTS</strong>.  I&#8217;m not going to produce another build.</li>
<li><strong>PLEASE DO NOT ASK ME TO OPEN SOURCE THE PROJECT</strong>.  This product shares a lot of code with my Script Debugger product and I&#8217;m not willing to release the code.</li>
<li><strong>RTFM</strong>.  Seriously, you are on your own.</li>
<li>The software should run on Snow Leopard (10.6) or Lion (10.7).  I have no idea if it will work on Mountain Lion (10.8) or beyond.</li>
</ul>

<p>View <strong><a href="http://blog.latenightsw.com/wp-content/uploads/facespan_beta/index.html">Matt Neuburg&#8217;s Alpha Documentation</a></strong>.  More <a href="http://blog.latenightsw.com/?page_id=568">FaceSpan 5 information and screencasts</a>.</p>

<p>Download <strong><a href="http://www.latenightsw.com/archives/FaceSpan5.dmg">FaceSpan 5.0</a></strong>.</p>

<p><strong><a href="http://blog.latenightsw.com/?cat=10">FaceSpan 5 Blog Posts</a></strong>.</p>

<p>To get you going, check out this post: <a href="http://blog.latenightsw.com/?p=569">Dock Icon Changer</a>.</p>

<p>Have Fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=637</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>FaceSpan 5 Development Suspended</title>
		<link>http://blog.latenightsw.com/?p=50</link>
		<comments>http://blog.latenightsw.com/?p=50#comments</comments>
		<pubDate>Tue, 05 May 2009 16:15:37 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>
		<category><![CDATA[Late Night Software]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blog/?p=50</guid>
		<description><![CDATA[I must reluctantly announce that I am suspending FaceSpan 5 development.]]></description>
			<content:encoded><![CDATA[<p>I must reluctantly announce that I am suspending FaceSpan 5 development.  I want to thank you all, particularly those that have contributed their time and effort to help me move FaceSpan 5 forward.</p>

<p>The just released FaceSpan 5.0d70 build will continue to run and has no expiry dates built in.  The projects you build with it should continue to execute.</p>

<p>My reasons for suspending FaceSpan development are many.  Chief among them are that I keep missing every deadline I have set for myself.  I am now over 2 years into this project and I cannot clearly see how to wrap development up so that I have a product to sell.  I also am feeling that in the time it has taken me to do this work, the world has moved on and AppleScript-based UIs are not going to be relevant in the marketplace.  The Web, Flash and other technologies are moving much faster than AppleScript or I can match.  Additionally, there many technical limitations in AppleScript and Cocoa Scripting that I keep having to hack around in order to make FaceSpan usable.</p>

<p>All of this has left me feeling burnt out and I need some perspective.  So I&#8217;m going to down-tools on FaceSpan for an indefinite period of time.  I&#8217;m hoping that I can find a way to revive or reuse the work I&#8217;ve done at some point in the future, but I have no specific plans at this time.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=50</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQLite Demo</title>
		<link>http://blog.latenightsw.com/?p=177</link>
		<comments>http://blog.latenightsw.com/?p=177#comments</comments>
		<pubDate>Tue, 05 May 2009 16:01:03 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>
		<category><![CDATA[Late Night Software]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=177</guid>
		<description><![CDATA[A number of people on the FaceSpan 5 mailing list have asked for an example project that shows how to use the SQLite plugin to make data persist within FaceSpan. This FaceSpan example attempts to address this request. The demo presents a simple form in a window, and allows the user to enter data, update, [...]]]></description>
			<content:encoded><![CDATA[<p>A number of people on the FaceSpan 5 mailing list have asked for an example project that shows how to use the SQLite plugin to make data persist within FaceSpan.</p>

<p>This FaceSpan example attempts to address this request.  The demo presents a simple form in a window, and allows the user to enter data, update, add and remove records.</p>

<p><a href='http://blog.latenightsw.com/wp-content/uploads/2009/05/sqlitedemo.zip'>SQLiteDemo</a> (120Kb)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=177</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testing Pre-Release Software</title>
		<link>http://blog.latenightsw.com/?p=174</link>
		<comments>http://blog.latenightsw.com/?p=174#comments</comments>
		<pubDate>Wed, 10 Dec 2008 15:00:21 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=174</guid>
		<description><![CDATA[By Shane Stanley Testing pre-release software involves some interesting, and sometimes nerve-wracking, decisions. In most cases the best way to test is with a real job, but committing a large job to alpha software can involve a leap of faith. You have to weigh up what happens if it doesn&#8217;t work out, what the alternatives [...]]]></description>
			<content:encoded><![CDATA[<p>By Shane Stanley</p>

<p>Testing pre-release software involves some interesting, and sometimes nerve-wracking, decisions. In most cases the best way to test is with a real job, but committing a large job to alpha software can involve a leap of faith. You have to weigh up what happens if it doesn&#8217;t work out, what the alternatives are, and even how much faith you have in the developer involved.</p>

<p>Several months back I took on a fairly large project, and this was the process I was going through. In some ways it was a straight-forward scripting job, but what complicated things was the need for a bit of user interface, plus the amount of code likely to be involved. I looked at the options: a series of applets with death-by-display-dialog, or the potential maintenance headache of AppleScript Studio. FaceSpan 5 was at least worth considering, even though it was a long way off release.</p>

<p>I&#8217;d already written a fair bit of code in the form of a couple of applets, so the first thing to try was to bring them into FaceSpan and see how much effort was involved.</p>

<p>The process was surprisingly easy, as was adding the basic UI I needed. I could see that things would get more complicated if I wanted to implement non-modal elements such as sheets, with a much more event-oriented approach required, but my immediate goal was to try to get the main basic dialog working. My first impression was one of comfort: the editing and debugging environment were largely similar to Script Debugger, if a little undeveloped in some areas (we&#8217;re still talking early development software). So far, so good.</p>

<p>I started running the resulting Facespan 5 apps, and got my second surprise: performance. The apps were mainly targeting InDesign and Illustrator, both of which have a script menu or panel. Anyone who has scripted them knows that there&#8217;s a big difference in how fast things happen when scripted from the menu/panel versus an external application.Â </p>

<p>But the FaceSpan 5 apps were driving both InDesign and Illustrator more like they were being run from a menu/panel: InDesign stuff happened much faster than when driven from a normal AppleScript applet, and with Illustrator the difference was massive &#8212; almost an order of magnitude. This was a big plus for this project.</p>

<p>By now the amount of code was growing, and I had to look at how to manage it. The traditional AppleScript way is to save handlers in libraries, and load them into variables at launch time.Â </p>

<p>But libraries involve issues like where to store them, and when it comes to debugging they&#8217;re a bit like black boxes. That&#8217;s fine when you have well developed code in them, but it can be inconvenient on a project where you&#8217;re developing both the library code and the main code at the same time, and the requirements are changing. You end up doing things like putting handlers inside scripts until you have them debugged, and then juggling them &#8212; the code management issues start to make the code writing a lot harder.</p>

<p>I was hoping for a better approach, and FaceSpan 5 had it in the bag &#8212; objects called bags that are nothing more than containers for holding code.</p>

<p>The advantages of using bags soon became apparent because of another FaceSpan 5 feature, delegation. So I could put some of my &#8220;library&#8221; handlers in a bag, delegate the bags containing the main code to this library bag, and call the handlers without having to jump through the hoop of loading the bag into a global variable and referencing it that way from then on &#8212; I just call dosSomething(), and if there in no doSomething() handler in the bag where it&#8217;s called, it just looks further up its delegation chain until it finds one.Â </p>

<p>There are a couple of gotchas, but using bags like this really helped me focus on the code, especially at the stage where I was rearranging things and moving stuff about. As a bonus, doing it this way reduces launch time because there&#8217;s no need to load slabs of code first &#8212; they don&#8217;t get loaded until called, and not at all if they&#8217;re not called.</p>

<p>The other big advantage of using bags is in debugging: you can step through your script, in and out of handlers in other bags, seemlessly. And having a series of smaller bags of code that you can easily switch back and forth between, without having to worry about what&#8217;s in what file or bundle, makes managing a larger project so much simpler. It&#8217;s hard to explain, but it seemed to make it easier to arrange the code to reflect how it all interacted.</p>

<p>I still have a wish list, and I still occassionally copy chunks of code into Script Debugger for debugging. At the same time, I&#8217;m also moving smaller projects that could happily be done as applets into FaceSpan, largely for the performance gain. And there&#8217;s still lots of stuff in FaceSpan I haven&#8217;t started exploring. But so far I&#8217;m a very happy, and enthusiastic, &#8220;tester&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=174</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AppleScript Speed Boost</title>
		<link>http://blog.latenightsw.com/?p=173</link>
		<comments>http://blog.latenightsw.com/?p=173#comments</comments>
		<pubDate>Sun, 13 Jul 2008 15:07:18 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=173</guid>
		<description><![CDATA[We have discovered that AppleScirpt code runs faster in the FaceSpan runtime than it does in Apple&#8217;s applet/droplet environment. Â One of our testers has found that he has been able to dramatically improve the performance of several of his AppleScript applets by simply transplanting their code into a FaceSpan project. FaceSpan 5.0 provides two template [...]]]></description>
			<content:encoded><![CDATA[<p>We have discovered that AppleScirpt code runs faster in the FaceSpan runtime than it does in Apple&#8217;s applet/droplet environment. Â One of our testers has found that he has been able to dramatically improve the performance of several of his AppleScript applets by simply transplanting their code into a FaceSpan project.</p>

<p>FaceSpan 5.0 provides two template projects (Applet and Droplet) to make this transition simpler.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=173</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Displaying Lists &#8211; Part 2</title>
		<link>http://blog.latenightsw.com/?p=574</link>
		<comments>http://blog.latenightsw.com/?p=574#comments</comments>
		<pubDate>Thu, 13 Sep 2007 18:29:42 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=48</guid>
		<description><![CDATA[In my first Displaying Lists post, I described how to use an HTML view to display a list of values formatted using a CSS stylesheet. This time I&#8217;ll use an XSL stylesheet to convert the XML data into HTML for display. The advantage of using XSL over CSS is that you can restructure the incoming [...]]]></description>
			<content:encoded><![CDATA[<p>In my first <a href="http://blog.latenightsw.com/?p=17">Displaying Lists</a> post, I described how to use an HTML view to display a list of values formatted using a CSS stylesheet.  This time I&#8217;ll use an XSL stylesheet to convert the XML data into HTML for display.</p>

<p>The advantage of using XSL over CSS is that you can restructure the incoming XML data in any way you like.  For instance, with CSS, you are stuck with the order of XML elements, but with XSL you can re-order them.  Additionally, the XSL stylesheet can incorporate additional HTML markup, such as column headings.</p>

<p>Here&#8217;s a fairly simple XSL stylesheet that converts the XML into an HTML table, complete with headings.</p>

<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"&gt;
  &lt;xsl:output method="html"/&gt;

  &lt;xsl:template match="doc"&gt;
        &lt;html&gt;
        &lt;head&gt;
            &lt;title&gt;&lt;xsl:value-of select="@name"/&gt;&lt;/title&gt;
            &lt;link rel="stylesheet" type="text/css2" href="foo.css"/&gt;
        &lt;/head&gt;
        &lt;body&gt;
          &lt;table width="100%" border="0" cellpadding="0" cellspacing="0"&gt;
            &lt;tr&gt;
              &lt;td&gt;
                &lt;table width="100%" border="0" cellspacing="1" cellpadding="0"&gt;
                  &lt;tr&gt;
                    &lt;td height="15" width="140" nowrap="yes"&gt;
                      &lt;table width="100%" height="15" border="0" cellpadding="0" cellspacing="0"&gt;
                        &lt;tr&gt;
                          &lt;td class="tablehead"&gt;Name&lt;/td&gt;
                        &lt;/tr&gt;
                      &lt;/table&gt;
                    &lt;/td&gt;
                    &lt;td height="15" width="140" nowrap="yes"&gt;
                      &lt;table width="100%" height="15" border="0" cellpadding="0" cellspacing="0"&gt;
                        &lt;tr&gt;
                          &lt;td class="tablehead"&gt;Modification Date&lt;/td&gt;
                        &lt;/tr&gt;
                      &lt;/table&gt;
                    &lt;/td&gt;
                    &lt;td height="15" nowrap="yes"&gt;
                      &lt;table width="100%" height="15" border="0" cellpadding="0" cellspacing="0"&gt;
                        &lt;tr&gt;
                          &lt;td class="tablehead"&gt;Path&lt;/td&gt;
                        &lt;/tr&gt;
                      &lt;/table&gt;
                    &lt;/td&gt;
                  &lt;/tr&gt;

                  &lt;xsl:apply-templates/&gt;

                &lt;/table&gt;
              &lt;/td&gt;
            &lt;/tr&gt;
          &lt;/table&gt;
        &lt;/body&gt;
        &lt;/html&gt;

  &lt;/xsl:template&gt;

  &lt;xsl:template match="row"&gt;

        &lt;xsl:variable name="rowStyle"&gt;
            &lt;xsl:choose&gt;
                &lt;xsl:when test='(position() mod 2) = 1'&gt;oddRow&lt;/xsl:when&gt;
                &lt;xsl:otherwise&gt;evenRow&lt;/xsl:otherwise&gt;
            &lt;/xsl:choose&gt;
        &lt;/xsl:variable&gt;

        &lt;tr valign="top"&gt;&lt;xsl:attribute name='class'&gt;&lt;xsl:value-of select='$rowStyle'/&gt;&lt;/xsl:attribute&gt;
          &lt;td height="14" width="140" class="tabletext"&gt;
            &lt;xsl:value-of select="./name"/&gt;
          &lt;/td&gt;
          &lt;td height="14" width="140" class="tabletext"&gt;
            &lt;xsl:value-of select="./date"/&gt;
          &lt;/td&gt;
          &lt;td height="14" width="100%" class="tabletext"&gt;
            &lt;xsl:value-of select="./path"/&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
  &lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;
</pre>

<p>And here&#8217;s the AppleScript code that generates the XML data, and displays it in an HTML view.  Its very similar to the CSS example.  The key difference is the inclusion of the <em>&lt;?xml-stylesheet type=&#8221;text/xsl&#8221; href=&#8221;foo.xsl&#8221;?&gt;</em> directive in the XML data which directs the HTML view to apply the <em>foo.xsl</em> stylesheet to the data before displaying it.</p>

<pre>
on didInvokeListFinderFiles(theObject)
    local rsrcsFolder, theNames, theURLs, theDates, theXML

    set rsrcsFolder to POSIX path of (get my application's resources folder)

    try
        --  Generate XML listing the files in the top Finder window
        tell application "Finder" to Â¬
            set {theNames, theURLs, theDates} to {name, URL, modification date} of items of first window

        set theXML to {"&lt;?xml version="1.0"?&gt;"}
        set end of theXML to "&lt;?xml-stylesheet type="text/xsl" href="foo.xsl"?&gt;" -- associated a XSL stylesheet with this XML document
        set end of theXML to "&lt;doc&gt;"
        repeat with i from 1 to length of theNames
            set end of theXML to "  &lt;row&gt;"
            set end of theXML to "    &lt;name&gt;" &#038; (item i of theNames) &#038; "&lt;/name&gt;"
            set end of theXML to "    &lt;path&gt;" &#038; (item i of theURLs) &#038; "&lt;/path&gt;"
            set end of theXML to "    &lt;date&gt;" &#038; (item i of theDates) &#038; "&lt;/date&gt;"
            set end of theXML to "  &lt;/row&gt;"
        end repeat
        set end of theXML to "&lt;/doc&gt;"

        --  Convert the list of strings we have accumulated into one long string that we can display
        set AppleScript's text item delimiters to {return}
        set theXML to theXML as string

        --  A this point we end up with an XML document looking something like this:
        --
        --  &lt;?xml version="1.0"?&gt;
        --  &lt;?xml-stylesheet type="text/xsl" href="foo.xsl"?&gt;
        --  &lt;doc&gt;
        --    &lt;row&gt;
        --      &lt;name&gt;AbstractConnection.h&lt;/name&gt;
        --      &lt;path&gt;file://localhost/Users/mall/Desktop/connection/trunk/AbstractConnection.h&lt;/path&gt;
        --      &lt;date&gt;Friday, July 13, 2007 4:59:01 PM&lt;/date&gt;
        --    &lt;/row&gt;
        --    &lt;row&gt;
        --      &lt;name&gt;AbstractConnection.m&lt;/name&gt;
        --      &lt;path&gt;file://localhost/Users/mall/Desktop/connection/trunk/AbstractConnection.m&lt;/path&gt;
        --      &lt;date&gt;Friday, July 13, 2007 4:59:01 PM&lt;/date&gt;
        --    &lt;/row&gt;
        --    ...
        --  &lt;/doc&gt;

        --  Display the XML in an HTML view using an XSL stylesheet to make it look like a nice pretty table.
        tell my htmlView
            set value MIME type to "text/xml" -- makes the HTML view treat the string as XML rather then HTML
            set value base URL to (path to resource "foo.xsl") -- tells the HTML view where the resources are (stylesheets, CSS &#038; gifs)
            set value to theXML -- apply the XSL stylesheet and display the resulting HTML
        end tell
    on error errMsg
        display alert "No Finder Window" message "Please open a Finder window to list." buttons "OK" over my window
    end try
end didInvokeListFinderFiles
</pre>

<p>When you put all this together in FaceSpan, here&#8217;s what it looks like:</p>

<p><img id="image49" src="http://blog.latenightsw.com/wp-content/uploads/2007/09/xsl.jpg" alt="xsl.jpg" /></p>

<p><a href="http://blog.latenightsw.com/wp-content/uploads/2007/09/displayxmlxsl.zip">Display XML (XSL) Example Project</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=574</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Coming from FaceSpan 3</title>
		<link>http://blog.latenightsw.com/?p=573</link>
		<comments>http://blog.latenightsw.com/?p=573#comments</comments>
		<pubDate>Fri, 07 Sep 2007 18:57:17 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=47</guid>
		<description><![CDATA[A few messages on the FaceSpan 5 Alpha mailing list have described the difficulties FaceSpan 3 users face when trying to get up and running with FaceSpan 5. I&#8217;m going to use this blog post to collect a summary of the differences between FaceSpan 5 and FaceSpan 3. This list will no doubt grow over [...]]]></description>
			<content:encoded><![CDATA[<p>A few messages on the FaceSpan 5 Alpha mailing list have described the difficulties FaceSpan 3 users face when trying to get up and running with FaceSpan 5.</p>

<p>I&#8217;m going to use this blog post to collect a summary of the differences between FaceSpan 5 and FaceSpan 3.  This list will no doubt grow over time as we learn more about how best to program FaceSpan 5.</p>

<p>So here we go:</p>

<ol>
<li><p>The names of many properties have changed.  When the FaceSpan 5 dictionary settles down, I&#8217;ll prepare a table that maps the old FaceSpan 3 names to the new FaceSpan 5 names.  Until then, you&#8217;ll have to use the FaceSpanKit dictionary to find the new names.</p></li>
<li><p>You can safely ignore FaceSpan 5&#8242;s delegates when starting out with FaceSpan 5.  FaceSpan 3 message dispatching is identical to FaceSpan 5&#8242;s default way of dispatching events (i.e. upwards the containment hierarchy: view -> window -> application).</p></li>
<li><p>FaceSpan 3 allowed you to reference any view from any other view.  This allowed you to say things like <em>text view &#8220;myViewName&#8221;</em> in any other view&#8217;s script and FaceSpan would search the window for you.</p>

<p>In FaceSpan 5, you have to explicitly reference the window using <em>my window</em>&#8216;s text view &#8220;myViewName&#8221; (or more directly: my window&#8217;s myViewName).</p></li>
<li><p>There are no storage items.  However, you can simulate storage items using <em>Bag</em> objects.  Just create <em>Bag</em> instances at the application level in the IDE.  You can then use the <em>Bag</em>&#8216;s <em>persistent data</em> property to store information that should be retained between application runs.</p></li>
</ol>

<p>&#8230;more later</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=573</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>LAMEncoder, Spawn of FaceSpan!</title>
		<link>http://blog.latenightsw.com/?p=572</link>
		<comments>http://blog.latenightsw.com/?p=572#comments</comments>
		<pubDate>Mon, 27 Aug 2007 22:24:15 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=46</guid>
		<description><![CDATA[FaceSpan 5 is under development. That means it isn&#8217;t finished. But it also means that to some degree â€” indeed, to a rather impressive degree â€” it is finished. It isnâ€™t all there, but there is certainly something there. And that something is remarkably viable. To illustrate this, I took advantage of FaceSpan 5 to [...]]]></description>
			<content:encoded><![CDATA[<p>FaceSpan 5 is under development. That means it isn&#8217;t finished. But it also means that to some degree â€” indeed, to a rather impressive degree â€” it <em>is</em> finished. It isnâ€™t all there, but there is certainly <em>something</em> there. And that something is remarkably viable. To illustrate this, I took advantage of FaceSpan 5 to do the very thing FaceSpan 5 is intended to do â€” to write a complete, useful, â€œshippableâ€ application. In fact, Iâ€™ve actually â€œshippedâ€ this application, which is called LAMEncoder, and you can download it (<a href="http://pages.sbcglobal.net/mattneub/downloads/LAMEncoder.zip">here</a>) and try it out.</p>

<p>The very fact that I was able to do this should serve as an indication of just how rich and how powerful FaceSpan 5 is already, even in its current state.</p>

<h3 id="glasshalfemptyglasshalffull">Glass half empty, glass half full</h3>

<p>There are actually two main areas in which FaceSpan 5 isnâ€™t finished yet:</p>

<ul>
<li><p><strong>The IDE</strong>. By this I mean the environment in which you work as you develop your application. For example, you can drag a button into a window to tell FaceSpan that there should be a button at this location in this window. But, so far in FaceSpanâ€™s growth, no guidelines appear to show you when the button is at the correct position (a certain number of pixels from the edge of the window, or aligned with other widgets in the window), and you canâ€™t yet double-click on the button to change its title (you have to work in FaceSpanâ€™s â€œinspectorâ€ palettes). Also, when youâ€™re debugging, certain powerful Script Debugger features, such as breakpoints, arenâ€™t yet implemented in FaceSpan.</p></li>
<li><p><strong>The â€œwidgetâ€ repertoire</strong>. Certain standard interface elements that lots of people would like to use just arenâ€™t there yet, or are present only in rudimentary form. </p></li>
</ul>

<p>Despite these current limitations, the actual process of developing LAMEncoder was wonderfully fast and easy. In fact, Iâ€™d have to say (not without a certain amount of prejudice, to be sure) that FaceSpan 5 is already shaping up to be the best application development environment Iâ€™ve ever used. The IDE has <em>enough</em> functionality, and we have <em>enough</em> interface widgets in place, that weâ€™ve passed a certain tipping point of usability and usefulness.</p>

<p>Indeed, I can specify for you quite precisely what tipping point it is. Very early on, when FaceSpan 5 was just a gleam in Markâ€™s eye, he posed me a challenge: At some point, he hoped, there would come a day when I would tell him that Iâ€™d rather develop using FaceSpan than any other development environment. That day is here. Not since HyperCard has an IDE felt so satisfying and easy to me. In a future article, Iâ€™d like to write more about that, using the organization and development of the LAMEncoder code to illustrate.</p>

<p>In <em>this</em> article, though, Iâ€™ll just describe the finished product, LAMEncoder itself, particularly with regard to its interface. This (and using LAMEncoder itself, of course) should give you an idea of just how powerful FaceSpan is, even now.</p>

<h3 id="thelamegame">The LAME game</h3>

<p>So. What does LAMEncoder do? It encodes WAV and AIFF files to MP3 using the freeware LAME encoding engine. I prefer LAME to iTunesâ€™ MP3 encoding engine. But LAME is a command-line tool, and I can never remember the commands. LAMEncoderâ€™s purpose is to remember and construct those commands for you. You hand it some WAV or AIFF files, and set the parameters the way you want them. Then you press the Convert button, and LAMEncoder uses the LAME engine to encode the files to MP3.</p>

<p>If this sounds familiar, it should. The idea comes straight from the LAME Encode Automator action developed starting on p. 452 of my <a href="http://www.oreilly.com/catalog/applescpttdg2/">AppleScript book</a>. That Automator action wraps an AppleScript script in â€œjust enough interfaceâ€ to make it convenient and powerful. LAMEncoder wraps the same functionality in even more interface â€” enough interface to constitute a full-fledged, stand-alone application.</p>

<p>Hereâ€™s the main window:</p>

<p><img id="shot1" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder1.png" alt="shot1" title="" /></p>

<p>In the screen shot above, notice the tooltip. All the interface widgets have tooltips, and, like this one, many of them are dynamic &#8211; they change depending on the situation. Here, the tooltip is explaining why the file list area is blank. Once we hand LAMEncoder some files to convert, the tooltip will automatically read differently (as we shall see later).</p>

<p>There are three ways to hand LAMEncoder some files to convert. One way is to press the Add File button in the toolbar at the top of the window. When you do, a standard Open File dialog appears:</p>

<p><img id="shot2" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder2.png" alt="shot2" title="" /></p>

<p>In the above screen shot, Iâ€™ve selected an AIFF file. Now Iâ€™ll press Add. The Open File dialog closes and the selected file appears in the list:</p>

<p><img id="shot3" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder3.png" alt="shot3" title="" /></p>

<p>Notice that the Clear and Convert buttons have become enabled as well. They were disabled before, because, with nothing in the file list, there was nothing useful they could do.</p>

<p>Another way to add files to the list is to press the Add Folder button in the toolbar. When you do this, a standard Choose Folder dialog appears:</p>

<p><img id="shot4" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder4.png" alt="shot4" title="" /></p>

<p>When I choose the â€œwavsâ€ folder and click Add, any AIFF or WAV files in that folder are added to the list:</p>

<p><img id="shot5" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder5.png" alt="shot5" title="" /></p>

<p>Naturally, the toolbar isnâ€™t the only place to access the Add File and Add Folder functionality; after all, the user could hide the toolbar, or even customize it to remove those buttons. So the same functionality is also present in the menu, complete with keyboard shortcuts:</p>

<p><img id="shot10" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder10.png" alt="shot10" title="" /></p>

<p>The third way of adding files, not illustrated here, is to drag them from the Finder into the list.</p>

<h3 id="htmlviewbenefits">HTML View benefits</h3>

<p>At this point we should pause to answer a burning question that Iâ€™m sure youâ€™re racking your brains over right now: what the heck is this interface widget in which the file list appears? It clearly is not a standard Table View. And that makes sense, because the Table View is one of the important interface widgets that hasnâ€™t been written into FaceSpan 5 yet.</p>

<p>This was probably the biggest limitation of the FaceSpan 5&#8242;s current state that I faced when writing LAMEncoder. It meant that I had to find a workaround means of displaying a scrolling list of the files the user wanted to encode. The workaround was to use FaceSpanâ€™s HTML View widget. Yes, that area in the middle of the window is actually a Web browser! LAMEncoder structures the list of files as HTML and hands that HTML to the HTML View widget.</p>

<p>An HTML View widget is a powerful animal in FaceSpan. To see how powerful, take a look at this next screen shot:</p>

<p><img id="shot6" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder6.png" alt="shot6" title="" /></p>

<p>The above screen shot displays the tooltip for the HTML View when the list actually contains some files. Notice that it has changed from the tooltip we saw earlier. Notice also that it claims we can click on a file name to play that file. Letâ€™s try it! We click on the last file in the list, and a dialog appears:</p>

<p><img id="shot7" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder7.png" alt="shot7" title="" /></p>

<p>You canâ€™t hear it, of course, but in that screen shot the dialog really is playing the WAV file. That part is easy, because FaceSpan has a Movie View widget; the dialogâ€™s interface is nothing but a movie controller, and QuickTime knows how to play AIFF and WAV files. But how is it possible that you can click in the list of files in order to play a file? Well, as I said, an HTML View widget is a powerful thing in FaceSpan. One of the powerful things it can do is intercept the userâ€™s request to navigate to a link. The names of the files are links. So when the user clicks on the name of a file, thatâ€™s a link navigation request; the HTML View hears about this, and instead of actually navigating to anything, it hands the information about the link over to the file-playing dialog, which opens and plays the file.</p>

<p>Incidentally, the power of an HTML View is also why we can drag and drop a file from the Finder in order to add it to the list. This is quite remarkable, because in general, drag-and-drop is one of the things that isnâ€™t implemented yet in FaceSpan! But an HTML View is its own little world, and it already knows how to respond to drag-and-drop. When it does, this counts as navigation (basically, it counts as an attempt to open a file). In LAMEncoder, the HTML View intercepts this attempt, and instead of navigating anywhere, it effectively hands the file over to the Add File button.</p>

<h3 id="encodinginaction">Encoding in action</h3>

<p>So now that weâ€™ve created a list of files to convert, letâ€™s actually convert the files in the list. First, we use the â€œConversion parametersâ€ area of the window to set up how the conversion will be performed. In this next screen shot, Iâ€™ve decided to use CBR (constant bitrate) encoding, and Iâ€™ve entered a bitrate value of 320 for very high quality:</p>

<p><img id="shot8" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder8.png" alt="shot8" title="" /></p>

<p>Notice that the text above the popup menu has changed from <code>lame --preset standard</code> to <code>lame --preset cbr 320</code>. That text represents the command-line parameters that will actually be sent to LAME to perform the encoding. The change in the text happens automatically as you play with the â€œConversion parametersâ€ interface.</p>

<p>Furthermore, however you set the â€œConversion parametersâ€ interface is automatically remembered by LAMEncoder when you quit, by being written into the applicationâ€™s user defaults (its Preferences .plist file); when you start up LAMEncoder again, that information is fetched from the user defaults and the â€œConversion parametersâ€ interface appears just the way you left it when you quit. That sort of thing, which adds a nice professional touch to our application, is extremely easy in FaceSpan.</p>

<p>Anyway, now we press the Convert button. The Terminal opens and LAME is started, with the files and conversion parameters that we specified in LAMEncoderâ€™s window:</p>

<p><img id="shot9" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder9.png" alt="shot9" title="" /></p>

<p>That may seem a little nerdy, but for that very reason I like it. LAME provides nice progress feedback as it runs in the Terminal, so it makes sense to me to hand over the actual conversion process to the Terminal and let LAME do its thing. Meanwhile, LAMEncoder itself is free for further use; having handed off the correct command to the Terminal, it returns instantly and sits idle. The user can even quit LAMEncoder at this point, while the Terminal chugs merrily along, encoding the files.</p>

<h3 id="finishingtouches">Finishing touches</h3>

<p>Now Iâ€™d like to point out a few of the finishing touches in the LAMEncoder interface that give it a full-fledged, â€œprofessionalâ€ application quality. First, thereâ€™s a standard About dialog:</p>

<p><img id="shot11" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder11.png" alt="shot11" title="" /></p>

<p>All the underlined blue terms are links that the user can click to go to the relevant Web pages. </p>

<p>LAMEncoder also has a second About dialog, which properly attributes the LAME engine and provides the text of the LGPL agreement under which it can be used in an application. Thatâ€™s required, because LAMEncoder actually includes a copy of the LAME engine inside itself:</p>

<p><img id="shot12" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder12.png" alt="shot12" title="" /></p>

<p>(Incidentally, the above window is the only part of LAMEncoder containing an interface widget that isnâ€™t really built into FaceSpan. The scrolling Text View containing the text of the LGPL is implemented through a â€œplug-inâ€, which is essentially a bundle of Objective-C code. Eventually, the Text View will be a native FaceSpan widget.)</p>

<p>Next, LAMEncoder has some preferences that the user can set. When you choose Preferences from the LAMEncoder menu, the preferences dialog appears:</p>

<p><img id="shot13" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder13.png" alt="shot13" title="" /></p>

<p>As you can see, we have two preferences here.</p>

<ul>
<li><p>First, using radio buttons, the user can decide whether to use the LAME engine built into LAMEncoder, or to use a copy of the LAME engine that may already be installed on the userâ€™s computer. This is because itâ€™s possible to compile LAME yourself, possibly using settings optimized for your processor, and we wouldnâ€™t want to prevent a user who has done so from using that specially compiled LAME.</p></li>
<li><p>Second, having chosen the second radio button, it is also necessary to press the Set button and tell LAMEncoder where that on-disk copy of the LAME engine is. In this case, Iâ€™ve specified a bogus location; there is no copy of LAME on my desktop. If I press the second radio button and try to dismiss the preferences dialog, Iâ€™ll get an error alert:</p>

<p><img id="shot14" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder14.png" alt="shot14" title="" /></p>

<p>The preferences dialog then opens again, forcing me either to use LAMEncoderâ€™s internally provided LAME engine or to specify a location where there really is a copy of the LAME engine on my hard disk.</p></li>
</ul>

<p>Finally, like any good application, LAMEncoder provides online help:</p>

<p><img id="shot15" src="http://pages.sbcglobal.net/mattneub/LAMEncoder/lameEncoder15.png" alt="shot15" title="" /></p>

<p>The user chooses from the Help menu, and the online help appears (in this case, itâ€™s a page of HTML, and opens in the userâ€™s default browser).</p>

<h3 id="futuredirections">Future directions</h3>

<p>So much for LAMEncoder itself. There are two kinds of future directions Iâ€™d like you to be thinking about.</p>

<p>First, there are future directions for LAMEncoder. Now that this version of LAMEncoder is finished, itâ€™s easy to add further features. For example, right now LAMEncoder implements only the <code>--preset</code> subset of LAME commands (because those are the only ones I really use). It would be easy to add even more LAME commands, making LAMEncoder an even more powerful, complete front-end interface to LAME.</p>

<p>Second, there are future directions for FaceSpan 5 â€” and for you. If LAMEncoder is the kind of application FaceSpan 5 can create right now, think what kinds of application it will be able to generate in the future. Clearly, this is an application development tool worth watching. Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=572</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GraphX Plugin</title>
		<link>http://blog.latenightsw.com/?p=571</link>
		<comments>http://blog.latenightsw.com/?p=571#comments</comments>
		<pubDate>Mon, 13 Aug 2007 14:41:40 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=45</guid>
		<description><![CDATA[The recent FaceSpan 5.0d42 build includes a graphing plugin based on Chad Weider&#8217;s GraphX framework. Chad&#8217;s framework provides three graphing views: curve, histogram and scatter plot. As always when creating FaceSpan plugins from Cocoa frameworks, the tough part is converting the Cocoa APIs into a simple to use AppleScript syntax. In the case of these [...]]]></description>
			<content:encoded><![CDATA[<p>The recent FaceSpan 5.0d42 build includes a graphing plugin based on Chad Weider&#8217;s <a href="http://blog.oofn.net/projects/graphx">GraphX</a> framework.  Chad&#8217;s framework provides three graphing views: curve, histogram and scatter plot.</p>

<p>As always when creating FaceSpan plugins from Cocoa frameworks, the tough part is converting the Cocoa APIs into a simple to use AppleScript syntax.  In the case of these graphing views, I have substituted the &#8216;Data Source&#8217; based APIs with a simple event for the curve view, and a <em>value</em> property that accepts a list of values to be graphed (a list of reals for the histogram and a list of x-y points for the scatter plot).</p>

<p>Here&#8217;s how it all looks running in a FaceSpan-built application:</p>

<p><img id="image44" src="http://blog.latenightsw.com/wp-content/uploads/2007/08/graphx.jpg" alt="graphx.jpg" /></p>

<p>The code for the curve view looks like this:</p>

<pre>
--
--  CT curve uses this event handler to get the data to be graphed
--
on CT get y value theCTCurve for theXValue
    return theXValue * theXValue * theXValue + 1.0
end CT get y value
</pre>

<p>The event is called repeatedly by the curve view to generate the data to be graphed.</p>

<p>The code for the histogram looks like this:</p>

<pre>
on initialize theResponder
    --  CT histogram needs a list of reals to graph
    set theData to {}

    repeat with i from (x axis minimim) to (x axis maximum)
        set end of theData to random number from 1 to 10
    end repeat
    set value to theData

end initialize
</pre>

<p>Here I simply generate a random series of values and assign them to the view&#8217;s <em>value</em> property.  The plugin does the rest.</p>

<p>And finally, the code for the scatter plot looks like this:</p>

<pre>
on initialize theResponder
    --  CT scatter plot requires a list of points (x, y pairs) to graph...

    set yValue to 1.0
    set theData to {}

    repeat with i from (x axis minimim) to (x axis maximum)
        set end of theData to {i, yValue}
        set yValue to yValue + (random number from 0 to 2.0)
    end repeat
    set value to theData

end initialize
</pre>

<p>Again, I simply generate a random series of point values and assign them to the view&#8217;s <em>value</em> property.  The plugin does the rest.</p>

<p>The sources for the plugin are included in the FaceSpan 5.0d42 SDK.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=571</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Forking Scripts</title>
		<link>http://blog.latenightsw.com/?p=570</link>
		<comments>http://blog.latenightsw.com/?p=570#comments</comments>
		<pubDate>Mon, 06 Aug 2007 19:14:01 +0000</pubDate>
		<dc:creator>Mark Alldritt</dc:creator>
				<category><![CDATA[FaceSpan]]></category>

		<guid isPermaLink="false">http://www.latenightsw.com/blogfs5/?p=43</guid>
		<description><![CDATA[One of the precepts of FaceSpan programming is that your event handlers should run as quickly as possible to avoid blocking the FaceSpan user interface. However, this is at odds with how AppleScript is commonly used to orchestrate the actions of other applications. One generally begins a long process that involves directing one or more [...]]]></description>
			<content:encoded><![CDATA[<p>One of the precepts of FaceSpan programming is that your event handlers should run as quickly as possible to avoid blocking the FaceSpan user interface.</p>

<p>However, this is at odds with how AppleScript is commonly used to orchestrate the actions of other applications.  One generally begins a long process that involves directing one or more applications to complete a task.  Even if the AppleScript code is short, it may have to wait for another application to complete a lengthy operation.</p>

<p>The question becomes how best to accomplish this kind of AppleScript automation in FaceSpan.  One answer is forking.  This involves breaking the long-running portion of your project&#8217;s AppleScript code out into a separate script, and then running that script in its own Unix task.  However, you want to do this in a way that keeps all the benefits of running AppleScript code within the FaceSpan environment (delegation, access to the UI, etc.).</p>

<p>The answer is to use AppleScript&#8217;s parent property to link the forked script back to the FaceSpan responder (e.g. a <em>button</em>) that forked it.  Here&#8217;s a simple example of a long running AppleScript that uses this technique:</p>

<pre>
using terms from application "Forking" -- the name of the FaceSpan project
    property parent : application "Forking"'s pushMe
    --  From this point onward, all commands and property access is directed
    --  at the "pushMe" button.  Note that this includes scripting addition
    --  commands!

    on doSomethingTimeConsuming()
        delay 1
    end doSomethingTimeConsuming

    try
        --  Simulate a long-running AppleScript task
        repeat with i from 1 to 10
            reportProgress(i) -- tell the main app how far we have gotten
            doSomethingTimeConsuming()
        end repeat

        --  To send commands to the process running this script rather than
        --  the main FaceSpan application, you must do the following:
        tell current application to current date

        --  Report back to the main application that we are finished
        reportAllDone()

        --  Prove that this code can be written as if its running in FaceSpan:
        display alert "Done" ¬
            message "I've finished wasting some time" ¬
            buttons "OK" ¬
            over my window
    on error errMsg
        set responderName to get my name
        display alert "Runtime Error" ¬
            message "Error in " &#038; responderName &#038; "'s forked script: " &#038; errMsg ¬
            buttons "OK" ¬
            over my window
    end try
end using terms from
</pre>

<p>This code is saved as a standard AppleScript compiled script using Script Editor/Script Debugger in a file within the FaceSpan project&#8217;s bundle.</p>

<p>Now you are ready to fork the script from FaceSpan:</p>

<pre>
on action theObject
    set enabled to false

    --  Fork off a process running an AppleScript that thinks its running in
    --  the context of this object (button)...
    set theCommand to "osascript " &#038; ¬
        quoted form of (POSIX path of (path to resource "fork.scpt"))
    tell (make new task ¬
        with properties {command:theCommand, auto delete:true})
        start
    end tell
end action

--  Subroutines that the forked script can call to tell the main application
--  what's going on:
on reportProgress(theProgress)
    set title to "Progress: " &#038; theProgress
end reportProgress

on reportAllDone()
    set title to "Push Me"
    set enabled to true
end reportAllDone
</pre>

<p>Notes:</p>

<ul>
<li>since the forked script runs in a FaceSpan task, you could use the task&#8217;s &#8216;task did end&#8217; event to discover when the forked script completes instead of the reportAllDone() subroutine.</li>
<li>if you need to abort the forked script for some reason (e.g. the user pressing a Cancel button), you can tell the FaceSpan task to stop.</li>
</ul>

<p>This seems like such an important thing to be able to do that I&#8217;m working on integrating this capability directly into the FaceSpan runtime for a future build.</p>

<p><strong>UPDATE</strong>: The FaceSpan 5.0d42 build provides this capability with the new <em>fork</em> command.  The fork command accepts an AppleScript script object that is executed in a seperate process, thus allowing for long-running operations that don&#8217;t block the UI.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.latenightsw.com/?feed=rss2&#038;p=570</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.518 seconds -->

