<?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>Saturnboy &#187; Code</title>
	<atom:link href="http://saturnboy.com/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://saturnboy.com</link>
	<description>Code, Work, and Life</description>
	<lastBuildDate>Wed, 28 Jul 2010 13:20:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>SuperTextInput &#8211; Building a Custom Component in Flex 4</title>
		<link>http://saturnboy.com/2010/07/supertextinput-building-a-custom-component/</link>
		<comments>http://saturnboy.com/2010/07/supertextinput-building-a-custom-component/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 18:59:29 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[custom component]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1489</guid>
		<description><![CDATA[I&#8217;ve been building a lot of Flex 4 custom components lately, including a sliding drawer, a multiple content area container, and now SuperTextInput. Nor will this be that last, because I think I have a few more in me. I thought it would be useful to spend some time in the details, explaining The Flex [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been building a lot of Flex 4 custom components lately, including a <a href="http://saturnboy.com/2010/06/drawer-component-flex-4/">sliding drawer</a>, a <a href="http://saturnboy.com/2010/07/multiple-content-area-containers/">multiple content area container</a>, and now SuperTextInput.  Nor will this be that last, because I think I have a few more in me.  I thought it would be useful to spend some time in the details, explaining <i>The Flex 4 Way</i> and how I try to walk the path.</p>
<p>SuperTextInput is a prompting, clearable <code>TextInput</code> extension in Flex 4.  It&#8217;s just an enhanced version of the default <code>TextInput</code> control, and as such, it follows a fairly standard pattern of custom component creation.</p>
<h3>Enhanced Component Pattern</h3>
<p>It&#8217;s almost too stupid to call this a pattern, but it&#8217;s <b>so</b> common in custom component creation that I&#8217;ll run with it.  Also, I&#8217;ve found it to be worthwhile to distinguish between adding new functionality to a component already present in the framework (aka an enhanced component) versus creating a truly custom component.</p>
<p class="bottom">The enhanced component pattern is just two simple steps:</p>
<ol>
<li><b>Extend</b> &ndash; extend some default component and add some new functionality</li>
<li><b>Skin</b> &ndash; make it look good</li>
</ol>
<p>In my version of reality, these steps carry equal weight, because almost all worthwhile functionality in Flex touches the UI in some fashion, so the design and UX (the look-and-feel, it&#8217;s usability, the integration into the rest of the app, etc.) are critical. Don&#8217;t forget or skimp on step #2 because it&#8217;s all the client, team, customer ever sees.</p>
<h3>A Prompting TextInput</h3>
<p>Since SuperTextInput has two new pieces of functionality (the prompt and the clear button), I&#8217;ll split them apart, and consider each part separately.  First, the prompt is merely the text you see when the <code>TextInput</code> is empty.  It often becomes a space saving label, because it can be used to tell the user what goes into the <code>TextInput</code> without costing the UI any screen real estate.</p>
<p>Thinking more about the prompt, we want the prompt text to be visible initially, but it should disappear when the user clicks (or tabs) to the control, and only returns when the control loses focus and is still empty.  So this tells us that we need to communicate both the prompt text and it&#8217;s visibility to our skin.  The prompt text can just be a simple <code>Label</code> <code>SkinPart</code>, but it&#8217;s visibility is complicated enough that it makes sense to add a new <code>prompting</code> <code>SkinState</code>.</p>
<p class="bottom">Here&#8217;s a functioning <code>PromptingTextInput</code> custom component (which is simply the prompting code lifted from <code>SuperTextInput.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">package components <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">events</span>.<span style="color: #006600;">FocusEvent</span>;
    <span style="color: #0066CC;">import</span> mx.<span style="color: #006600;">events</span>.<span style="color: #006600;">FlexEvent</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">Label</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">TextInput</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">events</span>.<span style="color: #006600;">TextOperationEvent</span>;
&nbsp;
    <span style="color: #66cc66;">&#91;</span>SkinState<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;prompting&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PromptingTextInput <span style="color: #0066CC;">extends</span> TextInput <span style="color: #66cc66;">&#123;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> promptDisplay:Label;
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _prompt:<span style="color: #0066CC;">String</span> = <span style="color: #ff0000;">''</span>;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _focused:<span style="color: #0066CC;">Boolean</span> = <span style="color: #000000; font-weight: bold;">false</span>;
&nbsp;
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> PromptingTextInput<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for programmatic changes to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>FlexEvent.<span style="color: #006600;">VALUE_COMMIT</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for user changes (aka typing) to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>TextOperationEvent.<span style="color: #006600;">CHANGE</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>Bindable<span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">get</span> prompt<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">String</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">return</span> _prompt;
        <span style="color: #66cc66;">&#125;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">set</span> prompt<span style="color: #66cc66;">&#40;</span>value:<span style="color: #0066CC;">String</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_prompt <span style="color: #66cc66;">!</span>= value<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                _prompt = value;
                <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>promptDisplay <span style="color: #66cc66;">!</span>= <span style="color: #000000; font-weight: bold;">null</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                    promptDisplay.<span style="color: #0066CC;">text</span> = value;
                <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> textChangedHandler<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:Event<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> focusInHandler<span style="color: #66cc66;">&#40;</span>event:FocusEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">focusInHandler</span><span style="color: #66cc66;">&#40;</span>event<span style="color: #66cc66;">&#41;</span>;
            _focused = <span style="color: #000000; font-weight: bold;">true</span>;
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
        override protected <span style="color: #000000; font-weight: bold;">function</span> focusOutHandler<span style="color: #66cc66;">&#40;</span>event:FocusEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">focusOutHandler</span><span style="color: #66cc66;">&#40;</span>event<span style="color: #66cc66;">&#41;</span>;
            _focused = <span style="color: #000000; font-weight: bold;">false</span>;
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == promptDisplay<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                promptDisplay.<span style="color: #0066CC;">text</span> = prompt;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">String</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>prompt.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span> <span style="color: #66cc66;">&amp;&amp;</span> <span style="color: #0066CC;">text</span>.<span style="color: #0066CC;">length</span> == <span style="color: #cc66cc;">0</span> <span style="color: #66cc66;">&amp;&amp;</span> <span style="color: #66cc66;">!</span>_focused<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                <span style="color: #b1b100;">return</span> <span style="color: #ff0000;">'prompting'</span>;
            <span style="color: #66cc66;">&#125;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #0066CC;">super</span>.<span style="color: #006600;">getCurrentSkinState</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>In addition to the <code>promptDisplay</code> <code>SkinPart</code> and the new <code>prompting</code> <code>SkinState</code>, there is a lot of other stuff going on in the above code.  First, as is typical with data-driven <code>SkinPart</code>s, we back the <code>promptDisplay</code> with a good old <code>prompt</code> property.  The net is the fairly common pattern of: check if the <code>SkinPart</code> is not null, then do something to it.  So in the <code>prompt</code> setter, we assign the incoming value to the private <code>_prompt</code> variable, then check if <code>promptDisplay</code> is available and if yes, set it&#8217;s <code>text</code> property.  The setter does the job of updating the prompt, but only once everything is happily running.  In order to get the data to the skin initially, we must use the <code>partAdded()</code> override to pass the local prompt to the <code>promptDisplay</code>&#8216;s <code>text</code> property.  And that&#8217;s it for the prompt text.</p>
<p>The prompt visibility part requires lots of event watching, and also <code>SkinState</code> stuff because we made the choice to push visibility via the <code>prompting</code> <code>SkinState</code>.  First, we wire up both the programmatic text change events and the user text change events to a handler, <code>textChangedHandler()</code>, that does nothing more than invalidate the state.  <code>TextInput</code> change events are a <a href="http://stackoverflow.com/questions/283497/capturing-user-input-from-flex-textinput-control-which-event-to-use">little wacky</a>, but the code works fine.  Next, instead of wiring the focus events to another handler (as seen in this <a href="http://www.andymcintosh.com/?p=207">prompting <code>TextInput</code> component</a> by Andy McIntosh), we simply override the protected handlers in the parent and add our focus-tracking logic directly.  Finally, we override <code>getCurrentSkinState()</code> to do the work of figuring out whether or not the prompt should be displayed.</p>
<p class="bottom">A skin for <code>PromptingTextInput</code> is now trivial because our component does the work of pushing the important information to the skin.  If we ignore all the pretty stuff, the skin is very simple:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SparkSkin</span> ...<span style="color: #7400FF;">&gt;</span></span>
    ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;prompting&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichEditableText</span> id=<span style="color: #ff0000;">&quot;textDisplay&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> id=<span style="color: #ff0000;">&quot;promptDisplay&quot;</span> includeIn=<span style="color: #ff0000;">&quot;prompting&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SparkSkin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>We add the <code>prompting</code> <code>State</code> to the list of states and also add the <code>promptDisplay</code> <code>Label</code> component.  By using the standard inline state syntax, <code>includeIn=&quot;prompting&quot;</code> our <code>Label</code> is shown only in the <code>prompting</code> state.</p>
<h3>A Clearable TextInput</h3>
<p>The second piece of SuperTextInput functionality is the clear button.  The clear button appears when the <code>TextInput</code> has a value, and when clicked, it clears that value (which re-displays the prompt).  Again, there are two pieces of information the need to be communicated to the skin to create the clear button functionality: the button itself and it&#8217;s visibility.  In this case, since the visibility is so simple (on if <code>TextInput</code> has a value, otherwise off), we&#8217;ll just punt and manage it directly in the component.  Therefore, the only a <code>Button</code> <code>SkinPart</code> for the clear button will be pushed to the skin.</p>
<p class="bottom">Here&#8217;s a functioning <code>ClearableTextInput</code> custom component (which is simply the clear button code lifted from <code>SuperTextInput.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">package components <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">events</span>.<span style="color: #006600;">Event</span>;
    <span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">events</span>.<span style="color: #006600;">MouseEvent</span>;
    <span style="color: #0066CC;">import</span> mx.<span style="color: #006600;">events</span>.<span style="color: #006600;">FlexEvent</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #0066CC;">Button</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">TextInput</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">events</span>.<span style="color: #006600;">TextOperationEvent</span>;
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ClearableTextInput <span style="color: #0066CC;">extends</span> TextInput <span style="color: #66cc66;">&#123;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> clearButton:<span style="color: #0066CC;">Button</span>;
&nbsp;
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> ClearableTextInput<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for programmatic changes to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>FlexEvent.<span style="color: #006600;">VALUE_COMMIT</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for user changes (aka typing) to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>TextOperationEvent.<span style="color: #006600;">CHANGE</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> textChangedHandler<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:Event<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>clearButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                clearButton.<span style="color: #0066CC;">visible</span> = <span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">text</span>.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> clearClick<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:MouseEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">text</span> = <span style="color: #ff0000;">''</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == clearButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                clearButton.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clearClick<span style="color: #66cc66;">&#41;</span>;
                clearButton.<span style="color: #0066CC;">visible</span> = <span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">text</span> <span style="color: #66cc66;">!</span>= <span style="color: #000000; font-weight: bold;">null</span> <span style="color: #66cc66;">&amp;&amp;</span> <span style="color: #0066CC;">text</span>.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partRemoved<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partRemoved</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == clearButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                clearButton.<span style="color: #006600;">removeEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clearClick<span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>After the <code>PromptingTextInput</code>, the <code>ClearableTextInput</code> is a little more straightforward.  First, we have the <code>clearButton</code> <code>SkinPart</code> and it&#8217;s <code>clearClick()</code> event handler.  Wiring the handler function to the button is done in the <code>partAdded()</code> override, and un-wiring in the <code>partRemoved()</code> override.  Next, button visibility is managed by watching for both programmatic text change events and user text change events.  The handler, <code>textChangedHandler()</code>, sets the button as visible when the control has text in it.</p>
<p>As I mentioned above, I decided against pushing the <code>clearButton</code>&#8216;s visibility down to the skin via a <code>SkinState</code>, and instead chose to manage it inside the component by setting <code>clearButton.visible</code> directly.  I tend to favor the <code>SkinState</code> method when more than one thing needs to change in the skin or if I need advanced visuals (like transitions).  If I need to do just one thing and I don&#8217;t care about visuals, I&#8217;ll do it inside the component.  The two examples here aren&#8217;t the best to illustrate the two options, but that&#8217;s my general thought process when building a custom component and custom skin.</p>
<p class="bottom">A skin for <code>ClearingTextInput</code> is super trivial.  Again, ignoring all the pretty stuff, the skin is:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SparkSkin</span> ...<span style="color: #7400FF;">&gt;</span></span>
    ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichEditableText</span> id=<span style="color: #ff0000;">&quot;textDisplay&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Button</span> id=<span style="color: #ff0000;">&quot;clearButton&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SparkSkin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Just add the <code>clearButton</code> <code>Button</code> and position it.</p>
<h3>Fusion, Glorious Fusion</h3>
<p>The fusion process of creating <code>SuperTextInput</code> from <code>PromptingTextInput</code> and <code>ClearableTextInput</code> is nothing more than copy and paste.  <code>SuperTextInput</code> has lots of uses, but my favorite is to use it to capture text input to filter a list.  It also works great as a search box, or in any smart form UI.  Enjoy.</p>
<p class="bottom">Here&#8217;s the finished product showing all three custom components skinned and ready for action (view source enabled):</p>
<div id="flashcontent-supertextinput">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/super_text_input/SuperTextInput.html">SuperTextInput</a> (<a href="http://saturnboy.com/proj/flex4/super_text_input/srcview/SuperTextInput.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/super_text_input/SuperTextInput.swf', 'flashcontent-supertextinput', '240', '94', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/07/supertextinput-building-a-custom-component/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building Flex 4 Containers with Multiple Content Areas</title>
		<link>http://saturnboy.com/2010/07/multiple-content-area-containers/</link>
		<comments>http://saturnboy.com/2010/07/multiple-content-area-containers/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 22:48:18 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[custom component]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1454</guid>
		<description><![CDATA[Back in the days of Flex 3, if you wanted multiple content areas in your main application, you&#8217;d need to arrange some set of containers (Canvas, HBox, VBox) in the app and fill them with content. It was just your basic Flex 3 development process. The danger, of course, is that you are mixing content [...]]]></description>
			<content:encoded><![CDATA[<p>Back in the days of Flex 3, if you wanted multiple content areas in your main application, you&#8217;d need to arrange some set of containers (<code>Canvas</code>, <code>HBox</code>, <code>VBox</code>) in the app and fill them with content.  It was just your basic Flex 3 development process.  The danger, of course, is that you are mixing content with presentation, aka bad separation of concerns.  Today, with the power of Flex 4 skins, we can avoid this issue by moving the presentation layer into a skin (or set of skins).  And thus, we can do a much better job achieving a happy level of separation of concerns.</p>
<h3>The Flex 3 Way</h3>
<p class="bottom">To give a concrete example, I&#8217;ll build a blog layout (yes, another blog layout) with a header, footer, sidebar, and main content areas.  But before we get started, let&#8217;s review the old Flex 3 way:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:HBox</span> id=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Image</span> source=<span style="color: #ff0000;">&quot;@Embed('assets/logo.png')&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> id=<span style="color: #ff0000;">&quot;body&quot;</span> width=<span style="color: #ff0000;">&quot;800&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;main content&quot;</span> width=<span style="color: #ff0000;">&quot;600&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:VBox</span> id=<span style="color: #ff0000;">&quot;sidebar&quot;</span> x=<span style="color: #ff0000;">&quot;600&quot;</span> width=<span style="color: #ff0000;">&quot;200&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;Sidebar&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;sidebar content&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:VBox</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:VBox</span> id=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;2010 saturnboy&quot;</span> styleName=<span style="color: #ff0000;">&quot;footer&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:VBox</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The above code comes from a previous post, <a href="http://saturnboy.com/2009/02/designing-in-flex/">Designing in Flex 3</a>, but has been modified to make sense here.  You&#8217;ve got you basic blog design: a box for the header, footer, and body, where body is subsequently is divided into a main content area and a sidebar.</p>
<h3>The 3-in-4 Way, aka The Wrong Way</h3>
<p>The unfortunate next step in a Flex developer&#8217;s evolution is what I like to call the Flex 3-in-4 way.  This is a the way of neanderthals,  which is to say, it is an evolutionary dead end.  If you ever have the bad luck to see 3-in-4 code, you can be sure you are dealing with a novice Flex 4 developer.  In general, the 3-in-4 way consists of making the simple transcription: <code>Canvas</code> &rarr; <code>Group</code>, <code>HBox</code> &rarr; <code>HGroup</code>, <code>VBox</code> &rarr; <code>VGroup</code>.  But the most damning tipoff of a 3-in-4 developer is the assertion that one is now a Flex 4 developer and the learning curve wasn&#8217;t all that bad.  While I do think Flex 4 is more of an evolutionary release than a revolutionary release, it&#8217;s different enough.  And it is particularly different on the design side of the framework, how it handles skins, layout, etc.</p>
<p class="bottom">If we just transcribe the above example, we get some classic 3-in-4 code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:HGroup</span> id=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;Multi Content Area Example&quot;</span> styleName=<span style="color: #ff0000;">&quot;header&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:HGroup</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;body&quot;</span> width=<span style="color: #ff0000;">&quot;800&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;main content&quot;</span> width=<span style="color: #ff0000;">&quot;600&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:VGroup</span> x=<span style="color: #ff0000;">&quot;600&quot;</span> width=<span style="color: #ff0000;">&quot;200&quot;</span> styleName=<span style="color: #ff0000;">&quot;sidebarBox&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;Sidebar&quot;</span> styleName=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;sidebar content&quot;</span> styleName=<span style="color: #ff0000;">&quot;sidebar&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:VGroup</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Group</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:VGroup</span> id=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;2010 saturnboy&quot;</span> styleName=<span style="color: #ff0000;">&quot;footer&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:VGroup</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>*Barf*, please <b>not</b> do this.  This code has all the same issues as the Flex 3 code in the first example, and moreover it is a slap in the face of <i>The Flex 4 Way</i> and all of its improvements.</p>
<h3>The Flex 4 Way</h3>
<p>Yes, there is a Flex 4 Way and it looks like this.</p>
<p class="bottom">First, we rewrite the main app using a custom container.  Ignoring the specifics of the custom container for a moment, here is the re-written main app (minus some clutter):</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:headerContent</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;Multi Content Area Example&quot;</span> styleName=<span style="color: #ff0000;">&quot;header&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:headerContent</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:sidebarContent</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichText</span> left=<span style="color: #ff0000;">&quot;0&quot;</span> right=<span style="color: #ff0000;">&quot;0&quot;</span> styleName=<span style="color: #ff0000;">&quot;sidebar&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:content</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span> fontSize=<span style="color: #ff0000;">&quot;20&quot;</span><span style="color: #7400FF;">&gt;</span></span>Sidebar<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span><span style="color: #7400FF;">&gt;</span></span>sidebar content<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:content</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:RichText</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:sidebarContent</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:footerContent</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;2010 saturnboy&quot;</span> styleName=<span style="color: #ff0000;">&quot;footer&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:footerContent</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichText</span> left=<span style="color: #ff0000;">&quot;0&quot;</span> right=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:content</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span> fontSize=<span style="color: #ff0000;">&quot;30&quot;</span><span style="color: #7400FF;">&gt;</span></span>Content<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span><span style="color: #7400FF;">&gt;</span></span>main content<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:content</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:RichText</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>As you can see, the main app is now a nice set of semantic buckets, one for each of the content areas.  Header stuff goes in the <code>headerContent</code> bucket, footer stuff goes in the <code>footerContent</code> bucket, etc.</p>
<h3>Building a Multi Content Area Container</h3>
<p>Second, we need to create a custom container with the nice set of semantic buckets used in the above code.  This is achieved by following a straightforward formula:</p>
<ol>
<li><b>Extend SkinnableContainer</b> &ndash; Extend <code>SkinnableContainer</code> or some child class.  In our sample app, our custom container extends <code>Application</code> (which extends <code>SkinnableContainer</code>).</li>
<li><b>Add Buckets</b> &ndash; add some content buckets (in the form of <i>xxx</i><code>Content</code>) as <code>Array</code>s.  These become the MXML tags used to bucket components together.  Each content bucket has a public getter, but most importantly a public setter that accepts an incoming <code>Array</code> of <code>IVisualElement</code>s and uses the magical <code>mxmlContent</code> property to assign it to the associated <code>SkinPart</code>.</li>
<li><b>Add SkinParts</b> &ndash; add some matching SkinParts (in the form of <i>xxx</i><code>Group</code>) as spark <code>Group</code>s.  There are used in the custom skin to display the content.  Also, I usually set <code>required=&quot;false&quot;</code> to make everything optional.</li>
<li><b>Add partAdded() &amp; partRemoved()</b> &ndash; override the new Flex 4 skinning lifecycle methods to wire the incoming content to the outgoing <code>SkinPart</code>.</li>
</ol>
<p class="bottom">The custom component code is actually easier to follow then the description.  Here is a custom container with only one additional content bucket, <code>sidebarContent</code>, and its matching <code>SkinPart</code>, <code>sidebarGroup</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">package containers <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">Group</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">Application</span>;
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MainApp <span style="color: #0066CC;">extends</span> Application <span style="color: #66cc66;">&#123;</span>
        <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> sidebarGroup:Group;
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _sidebarContent:<span style="color: #0066CC;">Array</span> = <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span>;
&nbsp;
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> MainApp<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>ArrayElementType<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;mx.core.IVisualElement&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">get</span> sidebarContent<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">Array</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">return</span> _sidebarContent;
        <span style="color: #66cc66;">&#125;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">set</span> sidebarContent<span style="color: #66cc66;">&#40;</span>value:<span style="color: #0066CC;">Array</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            _sidebarContent = value;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>sidebarGroup<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                sidebarGroup.<span style="color: #006600;">mxmlContent</span> = value;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == sidebarGroup<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                sidebarGroup.<span style="color: #006600;">mxmlContent</span> = _sidebarContent;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partRemoved<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partRemoved</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == sidebarGroup<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                sidebarGroup.<span style="color: #006600;">mxmlContent</span> = <span style="color: #000000; font-weight: bold;">null</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Following the four steps: we extend <code>Application</code>, have a <code>sidebarContent</code> bucket and its associated <code>sidebarGroup</code> <code>SkinPart</code>, and override <code>partAdded()</code> and <code>partRemoved()</code> to wire everything together.</p>
<h3>Skinning a Multi Content Area Container</h3>
<p>Skinning in Flex 4 is awesome, and like everyone says, it&#8217;s easily one of the best new features in the framework.  While I find the skinning process fairly straightforward, I would never call it trivial, mostly due to the depth and flexibility of the skinning system.</p>
<p>We need a custom skin for our custom multi content area component.  This is probably the 10% case for skinning, but it&#8217;s also the coolest.  In my experience, an average Flex 4 app has many <code>Button</code> skins (like 10 or even 20), a few default component skins (skins for <code>List</code>, <code>DropDownList</code>, <code>TextInput</code>, etc.), and maybe only two or three skins for custom components.</p>
<p>The skin itself is nothing special.  To display our custom component&#8217;s <code>SkinPart</code>s, we simply include a <code>Group</code> with the matching <code>id</code> attribute.  For example, our skin will include a <code>&lt;s:Group id="sidebarGroup" /&gt;</code> to display the <code>sidebarGroup</code> <code>SkinPart</code>.  Just rinse, wash, repeat, to add all of our custom content areas in the container to the skin.</p>
<p class="bottom">Here is a trivial skin:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Skin</span> ... <span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [HostComponent(&quot;containers.MainApp&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span> 
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:VGroup</span> left=<span style="color: #ff0000;">&quot;40&quot;</span> right=<span style="color: #ff0000;">&quot;40&quot;</span> top=<span style="color: #ff0000;">&quot;40&quot;</span> bottom=<span style="color: #ff0000;">&quot;40&quot;</span> gap=<span style="color: #ff0000;">&quot;20&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;headerGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;contentGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;sidebarGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;footerGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:VGroup</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Skin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>In this trivial skin, we just shove all the content groups (including <code>SkinnableContainer</code>&#8216;s default <code>Group</code>, <code>contentGroup</code>) into a <code>VGroup</code>.  Also note, we correctly set <code>HostComponent</code> to our custom container.  If you are thinking, &quot;Hey, this skin looks similar to the Flex 3 and 3-in-4 example code, just minus the content&quot; that&#8217;s exactly the point.</p>
<p class="bottom">Lastly, we wire out skin to our custom component via CSS:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">containers|MainApp <span style="color: #00AA00;">&#123;</span>
    skinClass<span style="color: #00AA00;">:</span>ClassReference<span style="color: #00AA00;">&#40;</span><span style="color: #ff0000;">'skins.TrivialAppSkin'</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>Using <code>skinClass</code> to wire a skin to a component is <b>so</b> 2009.  The sample app has its CSS inline, but in any real app I&#8217;ll always put this in an external file.</p>
<h3>Conclusion</h3>
<p>After this, there&#8217;s really not much more to say.  You can certainly create a more complicated arrangement of the multiple content areas by making a more complicated skin.  I&#8217;ve done exactly this in the final sample, which includes three different skins and a skin switcher (click 1, 2, or 3 to switch skins).</p>
<p>&raquo; <a href="http://saturnboy.com/proj/flex4/multi_content_area/MultiContentArea.html">view MultiConentArea sample</a> (view source enabled)</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/multi_content_area/MultiContentArea.html">MultiContentArea</a> (<a href="http://saturnboy.com/proj/flex4/multi_content_area/srcview/MultiContentArea.zip">download</a>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/07/multiple-content-area-containers/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Drawer Component in Flex 4</title>
		<link>http://saturnboy.com/2010/06/drawer-component-flex-4/</link>
		<comments>http://saturnboy.com/2010/06/drawer-component-flex-4/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 04:31:09 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[custom component]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[flexlib]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1418</guid>
		<description><![CDATA[I needed a good way to have a large settings panel with a minimal visual impact. The obvious answer is to hide or minimize or collapse the settings panel when not in use. I thought about using Flexlib&#8216;s WindowShade component (which I&#8217;ve dicussed in detail in Styling Flexlib&#8217;s WindowShade), but why reuse something when you [...]]]></description>
			<content:encoded><![CDATA[<p>I needed a good way to have a large settings panel with a minimal visual impact.  The obvious answer is to hide or minimize or collapse the settings panel when not in use.  I thought about using <a href="http://code.google.com/p/flexlib/">Flexlib</a>&#8216;s WindowShade component (which I&#8217;ve dicussed in detail in <a href="http://saturnboy.com/2009/03/styling-flexlib-windowshade/">Styling Flexlib&#8217;s WindowShade</a>), but why reuse something when you can reinvent the wheel?  Plus, it always helps to hone my Flex 4 custom component kung-fu.  So, I chose to implement a simple sliding drawer component from scratch as a Flex 4 component.</p>
<p class="bottom">The Drawer component is a vanilla container (it actually extends <code>SkinnableContainer</code>), so it will happily take any spark component for its children.  Before I dive into my implementation, let&#8217;s check out the finished drawer component in action (view source enabled):</p>
<div id="flashcontent-drawer" style="background-color:#eee">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p> Just click on the handle to open and close the drawer.</p>
<h3>Extending <code>SkinnableContainer</code></h3>
<p>The Drawer component itself, is just pure AS3, but the demo above uses a few MXML skins to achieve the desired look-and-feel.  This is a pretty standard pattern that I see during Flex 4 development, so expect it when you write your own custom components.</p>
<p class="bottom">We&#8217;ll review the component implementation in two steps.  First, we focus on the skin state management aspect of the drawer.  Here&#8217;s the relevant code (taken from <code>Drawer.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #66cc66;">&#91;</span>SkinState<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;opened&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
<span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Drawer <span style="color: #0066CC;">extends</span> SkinnableContainer <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _opened:<span style="color: #0066CC;">Boolean</span> = <span style="color: #000000; font-weight: bold;">false</span>;
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">get</span> opened<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">Boolean</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">return</span> _opened;
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">set</span> opened<span style="color: #66cc66;">&#40;</span>value:<span style="color: #0066CC;">Boolean</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_opened <span style="color: #66cc66;">!</span>= value<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            _opened = value;
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    override protected <span style="color: #000000; font-weight: bold;">function</span> getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">String</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #66cc66;">&#40;</span>opened ? <span style="color: #ff0000;">'opened'</span> : <span style="color: #0066CC;">super</span>.<span style="color: #006600;">getCurrentSkinState</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
    ...
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The <code>Drawer</code> component can either be closed (the default) or opened.  To model theses states, we use the <code>normal</code> state from the superclass to represent the closed drawer, and add a new <code>opened</code> <code>SkinState</code> to represent the opened drawer.  We just expose a simple <code>opened</code> boolean property with a custom getter and setter, and then override the <code>getCurrentSkinState()</code> method.  It&#8217;s important to remember the states we are talking about are skin states, and not <i>component</i> states (see <a href="http://saturnboy.com/2009/09/flex4-component-states-skin-states/">Flex 4 Component States vs. Skin States</a> for the difference).</p>
<p class="bottom">Second, we focus on the action of opening and closing the drawer.  Here&#8217;s the relevant code (taken from <code>Drawer.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Drawer <span style="color: #0066CC;">extends</span> SkinnableContainer <span style="color: #66cc66;">&#123;</span>
    ...
    <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> openButton:<span style="color: #0066CC;">Button</span>;
&nbsp;
    <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> clickHandler<span style="color: #66cc66;">&#40;</span>event:MouseEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        opened = <span style="color: #66cc66;">!</span>opened;
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == openButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            openButton.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clickHandler<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    override protected <span style="color: #000000; font-weight: bold;">function</span> partRemoved<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partRemoved</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == openButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            openButton.<span style="color: #006600;">removeEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clickHandler<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The <code>Drawer</code> component includes a simple spark button, as an optional <code>SkinPart</code>, that is used to initiate the state change.  The <code>partAdded()</code> and <code>partRemoved()</code> methods are overridden to manage and adding and removing of the button&#8217;s click event handler.  And lastly, the <code>clickHandler()</code> method flips between skin states by toggling the <code>opened</code> boolean property.</p>
<h3>Usage</h3>
<p class="bottom">Using the <code>Drawer</code> is the same as any container.  In MXML, just put any child components you want between the container&#8217;s open and close tags:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:Drawer</span> ... skinClass=<span style="color: #ff0000;">&quot;skins.DrawerSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- components go here --&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:Drawer</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Here we also apply the <code>DrawerSkin</code> to our container.</p>
<h3>Skins</h3>
<p class="bottom">The <code>DrawerSkin</code> is responsible for creating the desired look-and-feel and generally making the <code>Drawer</code> component look cool.  Here are the interesting parts of the skin:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Skin</span> ...<span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [HostComponent(&quot;containers.Drawer&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;opened&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
   ...
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Button</span> id=<span style="color: #ff0000;">&quot;openButton&quot;</span> ...</span>
<span style="color: #000000;">            skinClass=<span style="color: #ff0000;">&quot;skins.DrawerOpenButtonSkin&quot;</span></span>
<span style="color: #000000;">            skinClass.opened=<span style="color: #ff0000;">&quot;skins.DrawerCloseButtonSkin&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;contentGroup&quot;</span> ... includeIn=<span style="color: #ff0000;">&quot;opened&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Skin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The <code>DrawerSkin</code> has three skin states, <code>normal</code> and <code>disabled</code> are inherited from <code>SkinnableContainer</code>, but <code>opened</code> is our custom skin state.  The skin also includes the optional <code>openButton</code> <code>SkinPart</code>, which itself uses two custom buttons skins, one for the open drawer and one for the closed drawer.  Lastly, note that the container&#8217;s content is only displayed when the skin is in the <code>opened</code> state via the newfangled inline state syntax: <code>includeIn=&quot;opened&quot;</code>.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/drawer/Drawer.html">Drawer</a> (<a href="http://saturnboy.com/proj/flex4/drawer/srcview/Drawer.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/drawer/Drawer.swf', 'flashcontent-drawer', '520', '340', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#eeeeee', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/06/drawer-component-flex-4/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Metrics and the AIR Install Badge</title>
		<link>http://saturnboy.com/2010/05/metrics-air-install-badge/</link>
		<comments>http://saturnboy.com/2010/05/metrics-air-install-badge/#comments</comments>
		<pubDate>Wed, 19 May 2010 15:21:01 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[AIR]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[flexmonkey]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1405</guid>
		<description><![CDATA[The AIR Install Badge is a very handy little flash application for delivering AIR applications to your users via the web. The badge allows your users to download and install both your application and the Adobe AIR runtime. Additionally, the install badge will automatically prompt users to upgrade if a previously installed version is detected. [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.adobe.com/devnet/air/articles/badge_for_air.html">AIR Install Badge</a> is a very handy little flash application for delivering AIR applications to your users via the web.  The badge allows your users to download and install both your application and the Adobe AIR runtime.  Additionally, the install badge will automatically prompt users to upgrade if a previously installed version is detected.  At <a href="http://www.gorillalogic.com/">Gorilla Logic</a>, we use the AIR Install Badge on the <a href="http://www.gorillalogic.com/flexmonkey/download">FlexMonkey download page</a> (free registration required).</p>
<p>Alas, flash is opaque to analytics.  We have no idea what our users are doing inside the AIR Install Badge application.  Are they installing? Or upgrading?  No problem, we just need to write some code&#8230;</p>
<h3>The Code</h3>
<p>Using flash&#8217;s <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html">ExternalInterface</a>, we can manually push the data out of flash and into javascript.  Once we have the data in javascript, we have total control.  One option is to <a href="http://blog.creoff.net/using-google-analytics-with-adobe-air-install-badge/">use google analytics to store our badge data</a>.  In the case of FlexMonkey, we send the badge data along with the user&#8217;s credentials to our CRM platform, <a href="http://www.salesforce.com/">SalesForce.com</a>.</p>
<p class="bottom"><b>Step 1:</b> First, open <code>AIRInstallBadge.as</code> and add this to the top:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">external</span>.<span style="color: #006600;">ExternalInterface</span>;</pre></div></div>

<p class="bottom"><b>Step 2:</b> Next, add the <code>ExternalInterface</code> call to the top of the <code>handleActinClick()</code> function in <code>AIRInstallBadge.as</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">protected <span style="color: #000000; font-weight: bold;">function</span> handleActionClick<span style="color: #66cc66;">&#40;</span>evt:MouseEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>action == <span style="color: #ff0000;">'install'</span> <span style="color: #66cc66;">||</span> action == <span style="color: #ff0000;">'upgrade'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #808080; font-style: italic;">//send data to js</span>
        ExternalInterface.<span style="color: #0066CC;">call</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'badgeJS'</span>,action<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
    ...
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Since I only care about the <code>install</code> or <code>upgrade</code> actions, I&#8217;ll only send those out to javascript.  Re-compile the badge and deploy.</p>
<p class="bottom"><b>Step 3:</b> Last, add the <code>badgeJS()</code> javascript callback to the page containing the badge and do whatever you want with the incoming badge data:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> badgeJS<span style="color: #009900;">&#40;</span>action<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">//do metrics here...</span>
    <span style="color: #000066;">alert</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'badge action='</span> <span style="color: #339933;">+</span> action<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Conclusion</h3>
<p>With an hour of effort, and a very small amount of code, we&#8217;ve managed to get the useful metrics of installs and upgrades out of the AIR Install Badge and into our analytics engine of choice.  A job well done.</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/05/metrics-air-install-badge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Perfect Gradients for Perfect Buttons</title>
		<link>http://saturnboy.com/2010/05/perfect-gradients-perfect-buttons/</link>
		<comments>http://saturnboy.com/2010/05/perfect-gradients-perfect-buttons/#comments</comments>
		<pubDate>Tue, 11 May 2010 03:21:02 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1334</guid>
		<description><![CDATA[Photoshop does this annoying thing where purely vertical gradients have some horizontal variation. Yes, it&#8217;s usually only plus or minus one bit of color, but it offends! I&#8217;ve battled Photoshop for a while on this, but I just can&#8217;t seem to get exactly what I want out of it. So to make a perfect gradient, [...]]]></description>
			<content:encoded><![CDATA[<p>Photoshop does this annoying thing where purely vertical gradients have some horizontal variation.  Yes, it&#8217;s usually only plus or minus one bit of color, but it offends!  I&#8217;ve battled Photoshop for a while on this, but I just can&#8217;t seem to get <b>exactly</b> what I want out of it.  So to make a perfect gradient, I decided to write some code.  The requirements are simple: given a starting color and a set of deltas, output a perfect gradient.</p>
<p class="bottom">Here are some quick examples:</p>
<div class="span-14 last">
<div class="span-1 comm-idx">1</div>
<div class="span-3">
<img src="http://saturnboy.com/proj/php/perfect_gradient/gradient1.png" alt="gradient1" title="gradient1" width="60" height="100" />
</div>
<div class="prepend-1 span-1 comm-idx">2</div>
<div class="span-3">
<img src="http://saturnboy.com/proj/php/perfect_gradient/gradient2.png" alt="gradient2" title="gradient2" width="60" height="100" />
</div>
<div class="prepend-1 span-1 comm-idx">3</div>
<div class="span-3 last">
<img src="http://saturnboy.com/proj/php/perfect_gradient/gradient3.png" alt="gradient3" title="gradient3" width="60" height="100" />
</div>
</div>
<div class="span-14 last">
<div class="prepend-1 span-3"><b>#000000</b><br />4, 1, 0.25</div>
<div class="prepend-2 span-3"><b>#eeeeff</b><br />-2.2, -1, -0.3</div>
<div class="prepend-2 span-3 last"><b>#ff0099</b><br />-1, 0, 1</div>
</div>
<div class="span-14 last">&nbsp;</div>
<p class="bottom">If we zoom in on example #1, which starts with black (#000000) and has deltas of 4, 1, 0.25, we see the following:</p>
<div class="prepend-1 span-13 last">
<img src="http://saturnboy.com/proj/php/perfect_gradient/gradient-diagram.png" alt="zoomed gradient" title="zoomed gradient" width="252" height="200" />
</div>
<div class="span-14 last">&nbsp;</div>
<p>The diagram shows the first ten rows of the gradient.  The delta values are accumulated with each row, and only the whole part of the resulting color value is used (aka I take the <b>floor</b> of each color bit).  So in this example, using the fractional delta of 0.25 results in exactly one additional blue bit every four rows.  Ahhh, perfect!</p>
<h3>The Code</h3>
<p class="bottom">No need to <a href="http://saturnboy.com/2010/04/the-schizophrenic-programmer/">use some fancy new language</a>, I wrote a simple PHP program to handle commandline input and output a perfect PNG gradient.  The interesting part is the function that generates and saves the gradient:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> build_image<span style="color: #009900;">&#40;</span><span style="color: #000088;">$filename</span><span style="color: #339933;">,</span> <span style="color: #000088;">$w</span><span style="color: #339933;">,</span> <span style="color: #000088;">$h</span><span style="color: #339933;">,</span> <span style="color: #000088;">$color</span><span style="color: #339933;">,</span> <span style="color: #000088;">$delta</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$img</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecreatetruecolor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$w</span><span style="color: #339933;">,</span> <span style="color: #000088;">$h</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$c</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecolorallocate</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$img</span><span style="color: #339933;">,</span> <span style="color: #000088;">$color</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$color</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$color</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$d</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$delta</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$y</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$y</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$h</span><span style="color: #339933;">;</span> <span style="color: #000088;">$y</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #990000;">imagefilledrectangle</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$img</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$y</span><span style="color: #339933;">,</span> <span style="color: #000088;">$w</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$y</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$c</span> <span style="color: #339933;">=</span> <span style="color: #990000;">imagecolorallocate</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$img</span><span style="color: #339933;">,</span>
      clamp<span style="color: #009900;">&#40;</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$color</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      clamp<span style="color: #009900;">&#40;</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$color</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      clamp<span style="color: #009900;">&#40;</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$color</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$d</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$delta</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$delta</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$delta</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #990000;">imagepng</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$img</span><span style="color: #339933;">,</span> <span style="color: #000088;">$filename</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #990000;">imagedestroy</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$img</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The code is straight forward.  First, create the image via <code>imagecreatetruecolor()</code>.  Then, starting with the starting color, draw a one pixel tall rectangle for each row of the image.  The next row&#8217;s color is computed in each iteration by adding the accumulated delta to the starting color.  Finally, output the image as a PNG via <code>imagepng()</code> and free the memory.  The complete php source can be downloaded <a href="http://saturnboy.com/proj/php/perfect_gradient/gradient.php.gz">here</a>.</p>
<h3>Button Time </h3>
<p>Once we have our perfect gradient engine in place, it&#8217;s time to make some perfect buttons.  To achieve the standard <i>glass button</i> look-and-feel, I typically fuse two gradients together: light on the top, dark on the bottom.</p>
<p class="bottom">Here are the two halves of a pretty red button, along with their starting color and deltas:</p>
<div class="span-14 last">
<div class="prepend-1 span-3 quiet">TOP</div>
<div class="prepend-2 span-3 last quiet">BOTTOM</div>
</div>
<div class="span-14 last">
<div class="prepend-1 span-3">
<img src="http://saturnboy.com/proj/php/perfect_gradient/red-top.png" alt="top" title="top" width="100" height="16" />
</div>
<div class="prepend-2 span-3 last">
<img src="http://saturnboy.com/proj/php/perfect_gradient/red-bottom.png" alt="bottom" title="bottom" width="100" height="16" />
</div>
</div>
<div class="span-14 last">
<div class="prepend-1 span-3"><b>#ff8080</b><br />-3,-3,-3</div>
<div class="prepend-2 span-3 last"><b>#d23c3c</b><br />-3,-3,-3</div>
</div>
<div class="span-14 last">&nbsp;</div>
<p class="bottom">And the two commandline invocations of <code>gradient.php</code> to create the gradients:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">php gradient.php 100x16 ff8080 -<span style="color: #000000;">3</span>,-<span style="color: #000000;">3</span>,-<span style="color: #000000;">3</span> top.png
php gradient.php 100x16 d23c3c -<span style="color: #000000;">3</span>,-<span style="color: #000000;">3</span>,-<span style="color: #000000;">3</span> bottom.png</pre></div></div>

<p>If I want my buttons to be sexy, rounded corners are a must.  My favorite photoshop trick to create multiple rounded buttons is to use a rounded alpha-transparent button with each gradient as a clipping mask.  Using a clipping mask is a simple way to guarantee button geometry remains fixed while colors are changed.</p>
<p class="bottom">Here is the layers pane showing the two gradients fused together and used as a clipping mask for the rounded alpha-transparent button:</p>
<div class="prepend-1 span-13 last">
<img src="http://saturnboy.com/proj/php/perfect_gradient/layers-dialog.png" alt="clip mask" title="clip mask" width="220" height="177" />
</div>
<div class="span-14 last">&nbsp;</div>
<p class="bottom">The result is a horizontally stretchable gradient button, that doesn&#8217;t look half bad.  See for yourself:</p>
<div class="prepend-1 span-13 last">
<img src="http://saturnboy.com/proj/php/perfect_gradient/btn-red.png" alt="button" title="button" width="26" height="32" />
</div>
<div class="span-14 last">&nbsp;</div>
<h3>Custom UIButton</h3>
<p class="bottom">The final button asset can be used as desired, but here is a simple Objective-C example since I&#8217;ve been in iPhone world lately:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">UIButton <span style="color: #002200;">*</span>btn <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>UIButton buttonWithType<span style="color: #002200;">:</span>UIButtonTypeCustom<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>btn setFrame<span style="color: #002200;">:</span>CGRectMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">20</span>, <span style="color: #2400d9;">20</span>, <span style="color: #2400d9;">140</span>, <span style="color: #2400d9;">32</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>btn setBackgroundImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;btn-red.png&quot;</span><span style="color: #002200;">&#93;</span>
      stretchableImageWithLeftCapWidth<span style="color: #002200;">:</span><span style="color: #2400d9;">10.0</span>
      topCapHeight<span style="color: #002200;">:</span><span style="color: #2400d9;">0.0</span><span style="color: #002200;">&#93;</span> forState<span style="color: #002200;">:</span>UIControlStateNormal<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>btn setTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;BUTTON&quot;</span> forState<span style="color: #002200;">:</span>UIControlStateNormal<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>btn setTitleColor<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIColor whiteColor<span style="color: #002200;">&#93;</span> forState<span style="color: #002200;">:</span>UIControlStateNormal<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>btn.titleLabel setFont<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIFont boldSystemFontOfSize<span style="color: #002200;">:</span><span style="color: #2400d9;">14</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;</pre></div></div>

<p>Create a new <code>UIButton</code> of type <code>UIButtonTypeCustom</code> and then set the button skin as the <code>backgroundImage</code>.  The horizontal stretchability is due to the <code>stretchableImageWithLeftCapWidth</code> and <code>topCapHeight</code>.</p>
<p class="bottom">Here is a screenshot from the iPhone simulator showing the button in action:</p>
<div class="prepend-1 span-13 last">
<img src="http://saturnboy.com/proj/php/perfect_gradient/screenshot.png" alt="screenshot" title="screenshot" width="326" height="486" />
</div>
<div class="span-14 last">&nbsp;</div>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/php/perfect_gradient/gradient.php.gz">gradient.php</a> &ndash; the perfect gradient engine</li>
<li><a href="http://saturnboy.com/proj/php/perfect_gradient/gradient-button.psd">gradient-button.psd</a> &ndash; the photoshop source for the red button image, including the rounded alpha-transparent button and fused red gradients</li>
<li><a href="http://saturnboy.com/proj/php/perfect_gradient/btn-red.png">btn-red.png</a> &ndash; the red button image</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/05/perfect-gradients-perfect-buttons/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Scraping Google Groups</title>
		<link>http://saturnboy.com/2010/03/scraping-google-groups/</link>
		<comments>http://saturnboy.com/2010/03/scraping-google-groups/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 03:31:31 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[flexmonkey]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1105</guid>
		<description><![CDATA[When we launched the new and improved Gorilla Logic website, we decided to bring all our open source projects together under one roof. In order to migrate all things FlexMonkey back to our website, we need to get our forum data migrated out of Google Groups. Alas, Google doesn&#8217;t provide any way to export data [...]]]></description>
			<content:encoded><![CDATA[<p>When we launched the new and improved <a href="http://www.gorillalogic.com/">Gorilla Logic</a> website, we decided to bring all our open source projects together under one roof.  In order to migrate all things <a href="http://www.gorillalogic.com/flexmonkey">FlexMonkey</a> back to our website, we need to get our forum data migrated out of Google Groups.  Alas, Google doesn&#8217;t provide any way to export data from Google Groups.  The only way to preserve the amazing contributions from the FlexMonkey community was to scrape Google Groups.  So that&#8217;s just what we did.</p>
<p>With a very minimal amount of PHP, I was able to walk the entire FlexMonkey Google Group, scrap all the topics (aka threads) and all the posts inside each thread.  The first step was to build a generic scraper class that grabs an html page (using <a href="http://curl.haxx.se/">cURL</a>) and parses out all unique outbound links.</p>
<p class="bottom">Here&#8217;s the code for the <code>Scraper</code> class:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Scraper <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$links</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$url</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">links</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">//scrape url &amp; store html</span>
        <span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_URL<span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">html</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
         <span style="color: #666666; font-style: italic;">//parse html for all links</span>
        <span style="color: #000088;">$matches</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">preg_match_all</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'#&lt;a.*?href\s*=\s*&quot;(.*?)&quot;.*?&gt;(.*?)&lt;/a&gt;#i'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">html</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$href</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$val</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #666666; font-style: italic;">//unique links</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$href</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">links</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">links</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$href</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$val</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>In the <code>run()</code> method, cURL is used to grab the html.  Next, a regular expression is used to match all outbound links.  The links are are stored in a hash, while making sure they point to unique urls.</p>
<p class="bottom">Built on top of the generic <code>Scraper</code> class is a specialized Google Groups scraper class, aptly named <code>GoogleGroupsScraper</code>.  For a given Google Group, the url of the main page (containing a list of most recent topics) is:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">http://groups.google.com/group/[GROUP]/topics</pre></div></div>

<p class="bottom">And the url of a single topic (aka thread) is:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">http://groups.google.com/group/[GROUP]/browse_thread/thread/[THEAD_ID]#</pre></div></div>

<p>Where <code>[GROUP]</code> is the name of the Google Group, and <code>[THREAD_ID]</code> is some alphanumeric id.  Most importantly, at the bottom of the main page is an <u>Older &raquo;</u> link that points to the next page of topics.  The <code>GoogleGroupsScraper</code> exploits this to spider the entire group, recording topic title and topic url as it walks each page.</p>
<p>Next, each individual topic page is scraped by the <code>GoogleGroupsTopicScraper</code> class and parsed into a list of posts with author name, date, timestamp, etc.  The topic scraper uses various regular expressions to extract and massage the html to extract the different parts of each post.  In particular, the post body needs a lots of work to strip out any Google Groups specific links and code.</p>
<p>Lastly, the topics and their posts are assembled into an XML document with a nice big CDATA block around the post body to preserve the html content.</p>
<p class="bottom">Here&#8217;s some sample output from the scraper:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scrape</span> <span style="color: #000066;">group</span>=<span style="color: #ff0000;">&quot;flexmonkey&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;topic<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>FlexMonkey User Group is now located at www.gorillalogic.com/flexmonkey!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://groups.google.com/group/flexmonkey/browse_thread/thread/fe9ed66bf56db88e#<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;posts<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Stu<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>stu.st...@gorillalogic.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 21:17:52 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265836672<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #339933;">&lt;![CDATA[</span>
<span style="color: #339933;">&lt;p&gt;People of FlexMonkey, &lt;p&gt;We have migrated the FlexMonkey discussion forum to &lt;a href=&quot;http://www.gorillalogic.com/flexmonkey&quot;&gt;http://www.gorillalogic.com/flexmonkey&lt;/a&gt;. Please note that you will need to re-subscribe to the new forum to continue receiving FlexMonkey discussion messages. &lt;p&gt;-Stu &lt;br&gt;</span>
<span style="color: #339933;">]]&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/posts<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/topic<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;topic<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Record button clicks based on Ids instead of names?<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://groups.google.com/group/flexmonkey/browse_thread/thread/4f079b1959374f53#<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;posts<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shilpa<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>shilpa.g...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 9, 2010 23:44:44 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265759084<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;1&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shilpa<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>shilpa.g...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 00:05:44 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265760344<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;2&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Gokuldas K Pillai<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>gokul...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 00:16:34 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265760994<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;3&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shilpa<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>shilpa.g...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 01:18:42 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265764722<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
...</pre></div></div>

<p class="bottom">Finally, there is a very simple PHP driver for the scraper that runs the scraping process:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GoogleGroupsScraper.class.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$scraper</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> GoogleGroupsScraper<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'[GROUP]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$scraper</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">run</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">print</span> <span style="color: #000088;">$scraper</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getXML</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p class="bottom">And you run it as usual:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">php scrape.php &gt; output.xml</pre></div></div>

<p>Just enter the name of the Google Group you wish to scrap, and away you go.  Here are a couple of notes to help you along:</p>
<ol>
<li><code>[GROUP]</code> is the group name as it appears in the url, so no spaces, etc.</li>
<li>It&#8217;s not fast, so be patient, or modify the scraper code to generate some intermediate output.</li>
<li>Via a browser, Google Group displays 30 topics per page, but via PHP &amp; cURL you only get 10.  Probably some Cookie or User Agent magic going on.</li>
<li>Not much error handling.   The error handling that exists isn&#8217;t very good. It will break.</li>
<li>Good luck!</li>
</ol>
<p>Please download the code and use it however you wish.  Hopefully, putting the code online and writing this post will save someone else some time when migrating data off Google Groups.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/gorilla/scraper/GoogleGroupsScraper.tgz">GoogleGroupsScraper.tgz</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/03/scraping-google-groups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Managing Event Listeners in Flex 4</title>
		<link>http://saturnboy.com/2010/03/event-listeners-in-flex-4/</link>
		<comments>http://saturnboy.com/2010/03/event-listeners-in-flex-4/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 04:59:47 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[flex4]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1089</guid>
		<description><![CDATA[Event-driven programming is at the heart of Flex. It also lies close to the heart of insanity for the developer. When an application becomes too loosely coupled, things get painful fast. The perfect storm arrives when you marry an event-driven UI with an event-driven asynchronous backend. Better async testing becomes the least of your problems, [...]]]></description>
			<content:encoded><![CDATA[<p>Event-driven programming is at the heart of Flex.  It also lies close to the heart of insanity for the developer.  When an application becomes too loosely coupled, things get painful fast.  The perfect storm arrives when you marry an event-driven UI with an event-driven asynchronous backend.  <a href="http://saturnboy.com/2010/02/async-testing-with-flexunit4/">Better async testing</a> becomes the least of your problems, and you are constantly trying to figure out who is listening to what, when.</p>
<p>In these cases, I often find that some simple runtime management of event listeners can really help.  To begin, I start with some component whose listeners I want to manage, then I override the <code>addEventListener()</code> and <code>removeEventListener()</code> functions in that component to always keep track of who is actively listening.</p>
<p class="bottom">Here is the basic code that can be added to any component (actually any descendent of <code>EventDispatcher</code> which is basically everything in Flex):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _listeners:<span style="color: #0066CC;">Object</span> = <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>;
&nbsp;
override <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> addEventListener<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>:<span style="color: #0066CC;">String</span>, listener:<span style="color: #000000; font-weight: bold;">Function</span>, useCapture:<span style="color: #0066CC;">Boolean</span>=<span style="color: #000000; font-weight: bold;">false</span>, priority:<span style="color: #0066CC;">int</span>=<span style="color: #cc66cc;">0</span>, useWeakReference:<span style="color: #0066CC;">Boolean</span>=<span style="color: #000000; font-weight: bold;">false</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">super</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>, listener, useCapture, priority, useWeakReference<span style="color: #66cc66;">&#41;</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_listeners.<span style="color: #006600;">hasOwnProperty</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #66cc66;">&#40;</span>_listeners<span style="color: #66cc66;">&#91;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#93;</span> as <span style="color: #0066CC;">Array</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #0066CC;">push</span><span style="color: #66cc66;">&#40;</span>listener<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span>
        _listeners<span style="color: #66cc66;">&#91;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #66cc66;">&#91;</span>listener<span style="color: #66cc66;">&#93;</span>;
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
override <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> removeEventListener<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>:<span style="color: #0066CC;">String</span>, listener:<span style="color: #000000; font-weight: bold;">Function</span>, useCapture:<span style="color: #0066CC;">Boolean</span>=<span style="color: #000000; font-weight: bold;">false</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">super</span>.<span style="color: #006600;">removeEventListener</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>, listener, useCapture<span style="color: #66cc66;">&#41;</span>;
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_listeners.<span style="color: #006600;">hasOwnProperty</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">var</span> listeners:<span style="color: #0066CC;">Array</span> = _listeners<span style="color: #66cc66;">&#91;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#93;</span> as <span style="color: #0066CC;">Array</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>listeners.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&lt;</span>= <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">delete</span> _listeners<span style="color: #66cc66;">&#91;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#93;</span>;
        <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">var</span> idx:<span style="color: #0066CC;">int</span> = listeners.<span style="color: #0066CC;">indexOf</span><span style="color: #66cc66;">&#40;</span>listener<span style="color: #66cc66;">&#41;</span>;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>idx <span style="color: #66cc66;">!</span>= -<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                listeners.<span style="color: #0066CC;">splice</span><span style="color: #66cc66;">&#40;</span>idx,<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>We just store all listeners of a given event type in an array, and store the array as the values in a hash keyed by event type.  When a new listener is added via <code>addEventListener()</code>, we check if any listeners of that event type exist.  If yes, we push the new listener onto the array.  If no, we create a new one-item array containing just the new listener.  The tracking process for <code>removeEventListener()</code> is just the opposite.</p>
<p class="bottom">Once we have all the listener bookkeeping in place, we can add any type of event listener management that we want.  For example, he&#8217;s a <code>removeAllEventListeners()</code> function:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> removeAllEventListeners<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>:<span style="color: #0066CC;">String</span> = <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>.<span style="color: #0066CC;">length</span> == <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">for</span> <span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">var</span> t:<span style="color: #0066CC;">String</span> <span style="color: #b1b100;">in</span> _listeners<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            removeAllEventListeners<span style="color: #66cc66;">&#40;</span>t<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_listeners.<span style="color: #006600;">hasOwnProperty</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>hasEventListener<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">for</span> each <span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">var</span> listener:<span style="color: #000000; font-weight: bold;">Function</span> <span style="color: #b1b100;">in</span> _listeners<span style="color: #66cc66;">&#91;</span><span style="color: #0066CC;">type</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                removeEventListener<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">type</span>, listener<span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Nothing cosmic, as <a href="http://stu-stern.blogspot.com/">my boss</a> likes to say, just walk all the listeners of a given event type and remove them.  If the event type is blank, just use some dirty recursion to walk all the types to remove everything.</p>
<p class="bottom">Here is a sample application which is tracking all the listeners on a <code>Panel</code> component (view source enabled):</p>
<div id="flashcontent-listener-tracker">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p>You can add/remove a custom listener for the <i>foo</i> custom event type using the buttons.  Or hit <i>remove all</i> to clear everything (including the listeners attached by default by the Flex framework).</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/listener_tracker/ListenerTracker.html">ListenerTracker</a> (<a href="http://saturnboy.com/proj/flex4/listener_tracker/srcview/ListenerTracker.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/listener_tracker/ListenerTracker.swf', 'flashcontent-listener-tracker', '320', '150', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/03/event-listeners-in-flex-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Parsing Twitter with RegExp</title>
		<link>http://saturnboy.com/2010/02/parsing-twitter-with-regexp/</link>
		<comments>http://saturnboy.com/2010/02/parsing-twitter-with-regexp/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 11:51:02 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regexp]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1055</guid>
		<description><![CDATA[I needed a very simple Twitter cache for a project I&#8217;m working on. And I was very happy to trade off some realtime accuracy for reliability. In addition to caching the tweets, I also needed to pre-process them into css-able html with clickable links, usernames, and hashtags. The web had a few nice examples of [...]]]></description>
			<content:encoded><![CDATA[<p>I needed a very simple Twitter cache for a project I&#8217;m working on.  And I was very happy to trade off some realtime accuracy for reliability.  In addition to caching the tweets, I also needed to pre-process them into css-able html with clickable links, usernames, and hashtags.  The web had a <a href="http://www.simonwhatley.co.uk/parsing-twitter-usernames-hashtags-and-urls-with-coldfusion">few</a> <a href="http://www.snipe.net/2009/09/php-twitter-clickable-links/">nice</a> <a href="http://snipplr.com/view/28483/regex-to-make-twitter-links-clickable/">examples</a> of how to use regular expressions to parse the raw tweet text, but I decided to take what I liked and do the rest myself.</p>
<h5>Links</h5>
<p class="bottom">Here&#8217;s the PHP code for parsing links out of the raw tweet text:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'@(https?://([-\w\.]+)+(/([\w/_\.]*(\?\S+)?(#\S+)?)?)?)@'</span><span style="color: #339933;">,</span>
     <span style="color: #0000ff;">'&lt;a href=&quot;$1&quot;&gt;$1&lt;/a&gt;'</span><span style="color: #339933;">,</span>
    <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>I only wanted <code>http</code> and <code>https</code> links, with an optional query part <code>(\?\S+)?</code> and an option anchor part <code>(#\S+)?</code>.  The conversion of a text link into an html link is done using back references, which in PHP is <code>$1</code>, <code>$2</code>, etc.  In the expression above, I use <code>$1</code> twice to put the matched link into both the <code>href</code> attribute and the link text.</p>
<h5>Users</h5>
<p class="bottom">Here&#8217;s the PHP code for parsing Twitter usernames:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'/@(\w+)/'</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'&lt;a href=&quot;http://twitter.com/$1&quot;&gt;@$1&lt;/a&gt;'</span><span style="color: #339933;">,</span>
    <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Nothing special, just take the @ and all following word characters (letters, digits, and underscores), and turn it into a user link.</p>
<h5>Hashtags</h5>
<p class="bottom">Here&#8217;s the PHP code for parsing Twitter hashtags:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'/\s+#(\w+)/'</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">' &lt;a href=&quot;http://search.twitter.com/search?q=%23$1&quot;&gt;#$1&lt;/a&gt;'</span><span style="color: #339933;">,</span>
    <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Getting the hashtags right was the most tricky of the three.  I decided to only grab hashtags that were proceeded by one or more spaces.  The real magic is the <code>%23</code> in the query string, which forces a search on the complete hashtag, including the <code>#</code> part.  For example, compare a search for <a href="http://search.twitter.com/search?q=%23flex">#flex</a> to a search for <a href="http://search.twitter.com/search?q=flex">flex</a>.</p>
<h5>The Cache</h5>
<p>The cache is just a simple cron job that periodically queries Twitter and retrieves the latest tweets.  Most importantly, the cache fails gracefully if Twitter is inaccessible, which it does by doing exactly nothing if Twitter is down.  This guarantees that my app always has valid data (when my server is up, the cache is up too), but with the possibility that the data is a little old.</p>
<p class="bottom">Here&#8217;s the notable function in the cache:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> getTweets<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$num</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">//first, get the user's timeline</span>
    <span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_URL<span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;http://twitter.com/statuses/user_timeline/<span style="color: #006699; font-weight: bold;">$user</span>.json?count=<span style="color: #006699; font-weight: bold;">$num</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$json</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$json</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #666666; font-style: italic;">//abort on error</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//second, convert the resulting json into PHP</span>
    <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #990000;">json_decode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$json</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//third, build up the html output</span>
    <span style="color: #000088;">$s</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">//handle any special characters</span>
        <span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">htmlentities</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">text</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">ENT_QUOTES</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'utf-8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">//build the metadata part</span>
        <span style="color: #000088;">$meta</span> <span style="color: #339933;">=</span> <span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'g:ia M jS'</span><span style="color: #339933;">,</span> <span style="color: #990000;">strtotime</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">created_at</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">' from '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">source</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">//parse the tweet text into html</span>
        <span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'@(https?://([-\w\.]+)+(/([\w/_\.]*(\?\S+)?(#\S+)?)?)?)@'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;a href=&quot;$1&quot;&gt;$1&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/@(\w+)/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;a href=&quot;http://twitter.com/$1&quot;&gt;@$1&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/\s#(\w+)/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">' &lt;a href=&quot;http://search.twitter.com/search?q=%23$1&quot;&gt;#$1&lt;/a&gt;'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">//assemble everything</span>
        <span style="color: #000088;">$s</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'&lt;p class=&quot;tweet&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$text</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;br /&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&lt;span class=&quot;tweet-meta&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$meta</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/span&gt;&lt;/p&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$s</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>First, we query the user&#8217;s JSON timeline using <a href="http://curl.haxx.se/">cURL</a>.  Second, we use PHP&#8217;s awesome json_decode function to convert the JSON into objects.  And lastly, we iterate over the tweets and parse everything into our desired HTML output.</p>
<p class="bottom">Here some sample output from <a href="http://twitter.com/saturnboy">my twitter</a> feed:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;p class=&quot;tweet&quot;&gt;Been reading Programming Goggle App Engine. Actually feeling dumber now than before I started. Too much to learn.&lt;br /&gt; 
&lt;span class=&quot;tweet-meta&quot;&gt;2:58pm Feb 14th from &lt;a href=&quot;http://www.tweetdeck.com/&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&nbsp;
&lt;p class=&quot;tweet&quot;&gt;Blog Post :: Async Testing with FlexUnit 4 :: &lt;a href=&quot;http://bit.ly/cGLnaI&quot;&gt;http://bit.ly/cGLnaI&lt;/a&gt;&lt;br /&gt; 
&lt;span class=&quot;tweet-meta&quot;&gt;3:33pm Feb 11th from &lt;a href=&quot;http://www.tweetdeck.com/&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&nbsp;
&lt;p class=&quot;tweet&quot;&gt;Blog Post :: A Better HTML Template for Flex 4 :: &lt;a href=&quot;http://bit.ly/70DLsj&quot;&gt;http://bit.ly/70DLsj&lt;/a&gt;&lt;br /&gt; 
&lt;span class=&quot;tweet-meta&quot;&gt;12:55pm Jan 25th from &lt;a href=&quot;http://www.tweetdeck.com/&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</pre></div></div>

<p>Once I have the output, I can do whatever I want with it: save to disk, stick it in the database, keep it in memory, cache it in <a href="http://memcached.org/">memcache</a>, etc.  In my case, I wanted the simplest possible option, so I chose to write it out as a static html file.</p>
<p>The end.  The rest of the app&#8217;s not ready yet&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/02/parsing-twitter-with-regexp/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Faking Transaction in LCDS 3</title>
		<link>http://saturnboy.com/2010/02/faking-transaction-in-lcds-3/</link>
		<comments>http://saturnboy.com/2010/02/faking-transaction-in-lcds-3/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 11:58:09 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[LCDS]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1000</guid>
		<description><![CDATA[Alas, LCDS 3 doesn&#8217;t support the notion of transaction (in the sense of a Database Transaction). I assume that somewhere deep within the system transactions are used to ensure correctness of data in the db, but none of this is exposed to the user. Fortunately, it is possible to bundle up a bunch of updates [...]]]></description>
			<content:encoded><![CDATA[<p>Alas, <a href="http://www.adobe.com/products/livecycle/dataservices/">LCDS 3</a> doesn&#8217;t support the notion of transaction (in the sense of a <a href="http://en.wikipedia.org/wiki/Database_transaction">Database Transaction</a>). I assume that somewhere deep within the system transactions are used to ensure correctness of data in the db, but none of this is exposed to the user. Fortunately, it is possible to bundle up a bunch of updates on the client and push them all at once to the server. <i>Fake transactions</i>, as I like to call them, are quite useful.  But they can also be dangerous because they are not really transactions (hence the <i>fake</i> part), and don&#8217;t always work as you would hope.</p>
<h5>Fake It</h5>
<p>Faking a tranaction is done using the <code>autoCommit</code> property on a generated service.  According to the <a href="http://help.adobe.com/en_US/LiveCycleDataServicesES/3.0/Developing/index.html">docs</a>, setting <code>autoCommit</code> to <code>false</code> blocks Data Management from pushing any changes to the server until <code>commit()</code> is called manually.</p>
<p class="bottom">Here&#8217;s a <a href="http://help.adobe.com/en_US/LiveCycleDataServicesES/3.0/Developing/WSc3ff6d0ea77859461172e0811f00f7045b-7f83.html#WSc3ff6d0ea77859461172e0811f00f6f23a-7ff7">direct quote</a>:</p>
<blockquote><p>&#8220;&#8230;set a <code>DataService</code> component <code>autoCommit</code> property to false to allow only manual calls to the <code>commit()</code> method. It is important to set <code>autoCommit</code> to <code>false</code> when you are going to make more than one change&#8230;so that the <code>DataService</code> component can batch those changes and send them in one batch to the destination.&#8221;</p></blockquote>
<p class="bottom">So to make life easy, I made a simple static function that does the <code>autoCommit</code> gymnastics:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">public</span> <span style="color: #0066CC;">static</span> <span style="color: #000000; font-weight: bold;">function</span> fakeIt<span style="color: #66cc66;">&#40;</span>service:DataService, func:<span style="color: #000000; font-weight: bold;">Function</span><span style="color: #66cc66;">&#41;</span>:AsyncToken <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">!</span>service.<span style="color: #006600;">autoCommit</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #0066CC;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #0066CC;">Error</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;ERROR: autoCommit is already off.&quot;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>service.<span style="color: #006600;">commitRequired</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #0066CC;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #0066CC;">Error</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;ERROR: another transaction is already open.&quot;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    service.<span style="color: #006600;">autoCommit</span> = <span style="color: #000000; font-weight: bold;">false</span>;
    func<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #000000; font-weight: bold;">var</span> token:AsyncToken = service.<span style="color: #006600;">commit</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    service.<span style="color: #006600;">autoCommit</span> = <span style="color: #000000; font-weight: bold;">true</span>;
    <span style="color: #b1b100;">return</span> token;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>After some error handling, we toggle <code>autoCommit</code> to false, call our function, then commit any updates, toggle <code>autoCommit</code> back on, and return the token.</p>
<h5>Usage</h5>
<p>Using our fake transaction function is straight forward, and typically involves passing in and inline anonymous function.</p>
<p class="bottom">Imagine our favorite example of teams and players, where each team has one-to-many players.  We might choose to perform a sequence of operations to add a new player to an existing team, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">var</span> token:AsyncToken = FakeTransaction.<span style="color: #006600;">fakeIt</span><span style="color: #66cc66;">&#40;</span>
    teamService.<span style="color: #006600;">serviceControl</span>,
    <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #808080; font-style: italic;">//rename the team</span>
        team.<span style="color: #0066CC;">name</span> = <span style="color: #ff0000;">'Denver Nuggetz'</span>;
&nbsp;
        <span style="color: #808080; font-style: italic;">//create player</span>
        <span style="color: #000000; font-weight: bold;">var</span> p:Player = <span style="color: #000000; font-weight: bold;">new</span> Player<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        p.<span style="color: #0066CC;">name</span> = <span style="color: #ff0000;">'Carmelo Anthony'</span>;
&nbsp;
        <span style="color: #808080; font-style: italic;">//wire both side of relationship</span>
        p.<span style="color: #006600;">team</span> = team;
        team.<span style="color: #006600;">players</span>.<span style="color: #006600;">addItem</span><span style="color: #66cc66;">&#40;</span>p<span style="color: #66cc66;">&#41;</span>;
&nbsp;
        playerService.<span style="color: #006600;">createPlayer</span><span style="color: #66cc66;">&#40;</span>p<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
token.<span style="color: #006600;">addResponder</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> AsyncResponder<span style="color: #66cc66;">&#40;</span>successHandler, faultHandler<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>In this case, the fake transaction is used to ensure the team is renamed and the player is added.  Both operations occur together, so it should not be possible to have the new player on the old team, or have the renamed team without the new player.</p>
<h5>Warning! Danger!</h5>
<p>Experience has shown me that fake transactions don&#8217;t always work as one would expect if they were real transactions. Sometimes, particularly when you are manipulating entities already under Data Management, it seems like operations are not really batched but instead executed one at a time.  Thankfully, it appears that LCDS is order preserving, and by that I mean it doesn&#8217;t magically re-order things.  LCDS always executes operations in the order they come in.  I can only recommend you test your application vigorously to ensure what you expect to happen actually happens (<a href="http://flexunit.org/">FlexUnit4</a> is pretty awesome for <a href="http://saturnboy.com/2010/02/async-testing-with-flexunit4/">testing async backends</a>). </p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/wp-content/uploads/2010/01/FakeTransaction.as">FakeTransaction.as</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/02/faking-transaction-in-lcds-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Like Peas and Carrots: LCDS 3 and UTF-8</title>
		<link>http://saturnboy.com/2010/02/lcds-and-utf-8/</link>
		<comments>http://saturnboy.com/2010/02/lcds-and-utf-8/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 17:54:32 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[LCDS]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[UTF-8]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=958</guid>
		<description><![CDATA[I just wrote about how to handle special characters in Flex 4 when written as HTML entities in MXML. Now I&#8217;ve moved my data with the special characters out of MXML and down into a MySQL database. Data access is provided by a vanilla LCDS 3 backend. I now have a very different problem than [...]]]></description>
			<content:encoded><![CDATA[<p>I just wrote about how to handle <a href="http://saturnboy.com/2010/01/special-characters-flex-4/">special characters in Flex 4</a> when written as HTML entities in MXML. Now I&#8217;ve moved my data with the special characters out of MXML and down into a MySQL database.  Data access is provided by a vanilla <a href="http://www.adobe.com/products/livecycle/dataservices/">LCDS 3</a> backend. I now have a very different problem than what I had before: How do I get UTF-8 data out of the database with LCDS and onto the display?</p>
<h5>MySQL and UTF-8</h5>
<p>In theory, LCDS is perfectly happy with special characters and foreign languages (here&#8217;s a link to <a href="http://help.adobe.com/en_US/livecycle/9.0/programLC/langref/charset-codes.html">supported characters sets</a> in LiveCycle ES2). So this time around, our problem has nothing to do with Flex 4 or LCDS, instead it&#8217;s all about the database. For our example, we&#8217;ll skip the pure model driven development route and just start with a simple database with a single <code>players</code> table.</p>
<p class="bottom">Create the database:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> ballerz <span style="color: #993333; font-weight: bold;">DEFAULT</span> CHARACTER <span style="color: #993333; font-weight: bold;">SET</span> utf8 COLLATE utf8_general_ci;
<span style="color: #993333; font-weight: bold;">CREATE</span> USER <span style="color: #ff0000;">'baller'</span>@<span style="color: #ff0000;">'localhost'</span> <span style="color: #993333; font-weight: bold;">IDENTIFIED</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">'password'</span>;
<span style="color: #993333; font-weight: bold;">GRANT</span> <span style="color: #993333; font-weight: bold;">ALL</span> PRIVILEGES <span style="color: #993333; font-weight: bold;">ON</span> ballerz<span style="color: #66cc66;">.*</span> <span style="color: #993333; font-weight: bold;">TO</span> baller@localhost;</pre></div></div>

<p>It is possible to configure MySQL to default to UTF-8 friendly behavior but the <code>CREATE DATABASE</code> command guarantees that the newly created db will be happy.</p>
<p class="bottom">Create the <code>players</code> table:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> players <span style="color: #66cc66;">&#40;</span>
  id int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">,</span>
  name varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Nothing special here, just use <code>VARCHAR</code> for the text fields.  In this case, we only have the player&#8217;s name.</p>
<p class="bottom">Insert some sample data:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Carmelo Anthony&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Chaunçey Billups&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Nenê&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Këñÿõn Martin&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;LeBrøn James&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Mo Williams&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Shaquille O†Neal&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Ænderson Varejao&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> players <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">,</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">&quot;Zýdrunãs Ílgauskãs&quot;</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>I put some extra special characters into the <code>INSERT</code> statements just for fun.</p>
<blockquote class="deeper"><p><b>Digging Deeper:</b> When connecting to MySQL from the commandline you can use the <code>--default-character-set=utf8</code> option to force your terminal to show UTF-8 characters correctly.</p></blockquote>
<h5>LCDS and UTF-8</h5>
<p>Now that the database is correctly setup to handle UTF-8, the rest of the LCDS setup is straight forward (see my getting started <a href="http://saturnboy.com/2009/07/get-started-lcds-mysql-1/">part 1</a> and <a href="http://saturnboy.com/2009/07/get-started-lcds-mysql-2/">part 2</a> posts). Create a new LCDS webapp via copy-and-paste from the template app, then fire up Flash Builder 4 and get to work.  In the Modeler plugin, configure a new RDS connection and just drag-and-drop the players table into the model.</p>
<p class="bottom">Here&#8217;s a screenshot of our LCDS model:</p>
<div class="span-14 last" style="min-height:274px;">
<img src="http://saturnboy.com/wp-content/uploads/2010/01/lcds_utf8_model.png" alt="model" width="391" height="264" />
</div>
<p class="bottom">And here&#8217;s a screenshot of the running app (remember this is backed by LCDS, so no running demo):</p>
<div class="span-14 last" style="min-height:180px;">
<img src="http://saturnboy.com/wp-content/uploads/2010/01/lcds_utf8_screenshot.png" alt="screenshot" width="390" height="170" />
</div>
<p class="bottom">Lastly, the frontend code showing just the highlights:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Application</span> ...</span>
<span style="color: #000000;">        creationComplete=<span style="color: #ff0000;">&quot;complete()&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;!<span style="color: #66cc66;">&#91;</span>CDATA<span style="color: #66cc66;">&#91;</span></span>
<span style="color: #000000;">           private function complete<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:void <span style="color: #66cc66;">&#123;</span></span>
<span style="color: #000000;">                getPlayers.token = playerService.getAll<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;</span>
<span style="color: #000000;">            <span style="color: #66cc66;">&#125;</span></span>
<span style="color: #000000;">        <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Declarations</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:CallResponder</span> id=<span style="color: #ff0000;">&quot;getPlayers&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Ballerz:PlayerService</span> id=<span style="color: #ff0000;">&quot;playerService&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Declarations</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:List</span> </span>
<span style="color: #000000;">            dataProvider=<span style="color: #ff0000;">&quot;{getPlayers.lastResult}&quot;</span></span>
<span style="color: #000000;">            labelField=<span style="color: #ff0000;">&quot;name&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Again, no magic here, I use a simple <code>getAll()</code> query to retrieve the entire <code>players</code> table then feed it into a <code>List</code> via the <code>CallResponder</code>&#8216;s <code>lastResult</code> property.</p>
<h5>Conclusion</h5>
<p>So the moral of our story is: if you correctly configure your database to support UTF-8 and you correctly get UTF-8 data into your tables, then everything just works.  LCDS will transparently get data out of the db and Flex will transparently get it onto the screen.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/lcds/ballerz/Ballerz.tgz">Ballerz.tgz</a></li>
<li><a href="http://saturnboy.com/proj/lcds/ballerz/create_db.sql">create_db.sql</a></li>
<li><a href="http://saturnboy.com/proj/lcds/ballerz/create_tables.sql">create_tables.sql</a></li>
<li><a href="http://saturnboy.com/proj/lcds/ballerz/data.sql">data.sql</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/02/lcds-and-utf-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
