<?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>Uncarved &#187; Tutorials</title>
	<atom:link href="http://uncarved.prometheas.com/category/tutorials/feed" rel="self" type="application/rss+xml" />
	<link>http://uncarved.prometheas.com</link>
	<description>An ongoing tension of potential, or how i learned to stop worrying and embrace the iterations.</description>
	<lastBuildDate>Mon, 08 Aug 2011 05:14:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>A Secret Agent Trick</title>
		<link>http://uncarved.prometheas.com/2010/04/secret-agent-trick.html</link>
		<comments>http://uncarved.prometheas.com/2010/04/secret-agent-trick.html#comments</comments>
		<pubDate>Wed, 14 Apr 2010 23:44:40 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Check it out]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iPod Touch]]></category>
		<category><![CDATA[multi-tasking]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=569</guid>
		<description><![CDATA[I recently discovered a neat little "trick" on my iPad (and iPhone): I've stumbled upon a way to listen to music streaming from Internet radio stations while I do "other things," like check my email, take photos, or write text messages.]]></description>
			<content:encoded><![CDATA[<p>I recently discovered a neat little &#8220;trick&#8221; on my iPad (and iPhone): I&#8217;ve stumbled upon a way to listen to music streaming from Internet radio stations while I do &#8220;other things,&#8221; like check my email, take photos, or write text messages.</p>

<p>While <a href="http://mashable.com/2010/04/08/iphone-4-0-os-multitasking/">iPhone OS 4.0</a> — due out this summer — will finally deliver the long-requested ability to allow users to listen to their Pandora or Last.fm radio streams in the &#8220;background&#8221; by virtue of its new &#8220;multi-tasking&#8221; capabilities, the solution I&#8217;ve stumbled upon works (in slight variations) <em>today</em> with any device running iPhone OS 3.x.</p>

<p>Although this little trick won&#8217;t work with Pandora, since you <em>must</em> be using a Pandora client to stream their music, you can use it with any radio station which exposes its MP3 or AAC music stream via a <a href="http://en.wikipedia.org/wiki/PLS_&#40;file_format]&#41;">multimedia playlist file</a> URL  (which will typically end in <code>.pls</code>); basically any radio station you&#8217;ll find on <a href="http://www.live365.com">Live 365</a>, <a href="http://www.somafm.com">Soma FM</a>, and more.</p>

<p>I&#8217;m a fan of Soma FM&#8217;s <a href="http://somafm.com/secretagent48.pls">Secret Agent</a> radio station, so we&#8217;ll use that for our example; feel free to try this out for any station you like.</p>

<p>The process is super easy, but slightly different between <a href="#handhelds">the handheld iPhone OS devices</a> (eg, iPhone and iPod Touch) and <a href="#ipad">iPads</a> (for which it&#8217;s actually a bit spiffier), so I&#8217;ll take you through the steps for doing it on each one.</p>

<p><a id="handhelds"></a></p>

<h2>iPhone / iPod Touch</h2>

<p>Launch Mobile Safari, and head to the following URL:</p>

<p>http://somafm.com/secretagent48.pls</p>

<p>You&#8217;ll see the following:</p>

<div class="figure"><img class="figure" src="http://uncarved.prometheas.com/wp-content/uploads/2010/04/photo-4.jpg" border="0" alt="" width="320" height="480" />
<span class="caption">Safari fetches the PLS file URL</span></div>

<p>Once the playlist file is loaded, Safari will find the URL of the music stream, and start playing the music, and you&#8217;ll see this:</p>

<div class="figure"><img class="figure" src="http://uncarved.prometheas.com/wp-content/uploads/2010/04/photo-5.jpg" border="0" alt="" width="320" height="480" />
<span class="caption">Safari has started playing the audio stream</span></div>

<p>Now — click the Home button and, say, check in on your email. Note that the music continues to play.</p>

<p>Isn&#8217;t <em>that</em> fantastic?</p>

<p>Just one caveat, though: you won&#8217;t be able to browse other websites in Safari until you click the &#8220;Done&#8221; button (top left), which — as you might expect — causes the music to stop playing.</p>

<p>One workaround is to use an alternative browser, like <a href="http://itunes.apple.com/app/icab-mobile-web-browser/id308111628?mt=8">iCab</a>, <a href="http://itunes.apple.com/app/opera-mini-web-browser/id363729560?mt=8">Opera Mini</a>, or any of a number of other web browsers (some paid, some free) available in the App Store.</p>

<p><a id="ipad"></a></p>

<h2>iPad</h2>

<p>Things get a little cooler on the iPad. The steps to get you listening to the music stream are the same, but we can do a few more things once the music starts playing on the iPad.</p>

<p>Once the music starts to play, you&#8217;ll see this:</p>

<div id="attachment_565" class="wp-caption alignnone" style="width: 310px"><a href="http://uncarved.prometheas.com/wp-content/uploads/2010/04/photo-3.png" rel="lightbox[569]" title="Screenshot of Safari playing the audio stream"><img src="http://uncarved.prometheas.com/wp-content/uploads/2010/04/photo-3-300x225.png" alt="Screenshot of Safari playing the audio stream" title="Screenshot of Safari playing the audio stream" width="300" height="225" class="size-medium wp-image-565" /></a><p class="wp-caption-text">Safari playing the audio stream</p></div>

<p>Note one key difference to note, however: unlike the iPhone&#8217;s Mobile Safari app, the iPad&#8217;s Mobile Safari <em>continues to show you the browser chrome</em> up top.</p>

<p>For starters, this means that you may continue browsing other websites in Safari on the iPad by simply tapping the tabs icon at the top:</p>

<div id="attachment_566" class="wp-caption alignnone" style="width: 310px"><a href="http://uncarved.prometheas.com/wp-content/uploads/2010/04/tabs.png" rel="lightbox[569]" title="Safari&#039;s tabs manager"><img src="http://uncarved.prometheas.com/wp-content/uploads/2010/04/tabs-300x225.png" alt="A screenshot of Safari&#039;s tabs manager" title="Safari&#039;s tabs manager" width="300" height="225" class="size-medium wp-image-566" /></a><p class="wp-caption-text">Change tabs or create new ones.</p></div>

<p>What&#8217;s more  you can actually create a bookmark for the radio station, so you can quickly listen any time:</p>

<div id="attachment_567" class="wp-caption alignnone" style="width: 310px"><a href="http://uncarved.prometheas.com/wp-content/uploads/2010/04/bookmarking.png" rel="lightbox[569]" title="Bookmarking"><img src="http://uncarved.prometheas.com/wp-content/uploads/2010/04/bookmarking-300x225.png" alt="Screenshot of Bookmarking" title="Bookmarking" width="300" height="225" class="size-medium wp-image-567" /></a><p class="wp-caption-text">Create bookmarks for your favorite stations</p></div>

<p>But — and this is where I started to get <a href="http://www.youtube.com/watch?v=PDXEgBh0TF0" target="_blank">a little verklempt</a> — it gets just slightly more fantastic: <em>you can bookmark it to your Home Screen</em>.</p>

<div id="attachment_568" class="wp-caption alignnone" style="width: 310px"><a href="http://uncarved.prometheas.com/wp-content/uploads/2010/04/homescreen.png" rel="lightbox[569]" title="Creating a Home Screen bookmark"><img src="http://uncarved.prometheas.com/wp-content/uploads/2010/04/homescreen-300x225.png" alt="A screenshot of creating a Home Screen bookmark" title="Creating a Home Screen bookmark" width="300" height="225" class="size-medium wp-image-568" /></a><p class="wp-caption-text">Now I can fire up Secret Agent FM from my Home Screen, just like Pandora or Last.fm.</p></div>

<p>Looks like the folks at Soma FM went the extra mile to specify a Home Screen icon for their website. Your mileage will vary with the availability of your favorite station&#8217;s dedicated icon for your Home Screen, however, depending on the site publisher.</p>

<p>Meanwhile, go forth and enjoy streaming some music while you&#8217;re sending those texts or reading the Times.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2010/04/secret-agent-trick.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://somafm.com/secretagent48.pls" length="0" type="audio/x-scpls" />
		</item>
		<item>
		<title>Bizarro HowTo: Write CSS Like a Total Douche Bag</title>
		<link>http://uncarved.prometheas.com/2009/08/bizarro-howto-write-css-like-a-total-douche-bag.html</link>
		<comments>http://uncarved.prometheas.com/2009/08/bizarro-howto-write-css-like-a-total-douche-bag.html#comments</comments>
		<pubDate>Tue, 04 Aug 2009 04:48:11 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[bizarro]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[humor]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=441</guid>
		<description><![CDATA[We&#8217;re half way through 2009. All the major browser vendors are shipping products with really great rendering engines now. Usage of the much-maligned Internet Explorer 6 has plummeted to the 15% neighborhood (stats vary, but they all show &#60; 20%). The days that Web developers dreamed about — seemingly, at the time, against all odds [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re half way through 2009. All the major browser vendors are shipping products with really great rendering engines now. Usage of the much-maligned Internet Explorer 6 has <a href="http://www.w3schools.com/browsers/browsers_stats.asp">plummeted</a> to the 15% neighborhood (stats vary, but they all show &lt; 20%).</p>

<p>The days that Web developers dreamed about — seemingly, at the time, against all odds — for about half a decade are nigh upon us with this progression.</p>

<p>Although much work remains to be done before all browsers can be universally relied upon to render HTML in a consistent and relatively uniform manner, the Web development community can at least now <em>begin</em> breathing a sigh of relief about having finally gotten some of the worst of it behind us.</p>

<p>But has anyone ever stopped to think about the folks that actually get off on making other people&#8217;s jobs difficult? Clean <a href="http://www.w3.org/TR/REC-html40/present/styles.html">style sheets</a>? <a href="http://en.wikipedia.org/wiki/Progressive_enhancement">Progressive Enhancement</a>? <a href="http://en.wikipedia.org/wiki/Semantic_web">Semantic Web</a>?</p>

<p>How do you suppose <em>they</em> feel right now? Whether it&#8217;s sadism or nostalgia, they&#8217;ve got feelings, too.</p>

<p>To them, I say with reassurance: <em>fret not</em>!</p>

<p>For them, I offer here three fabulous pointers for writing CSS like a total douche bag:</p>

<ol>
<li><p><strong>Use the same IDs for more than one element in an HTML document</strong>. The HTML spec is very explicit about not doing this, so you can absolutely bet that — some time down the line — some other developer tasked to add some jQuery or Prototype enhancements to your page will totally get screwed.</p></li>
<li><p><strong> Sprinkle your IE 6 &#8220;hacks&#8221; <em>directly into</em> and all throughout your primary CSS files</strong>. Do <em>not</em> separate these IE 6 optimizations out from your <code>main.css</code> file into <code>main_ie6.css</code>. Coding your site to standards first will only make it easier to phase out this pollution when IE 6 finally drops off the planet. To ensure you really nail this one, you should be previewing the site in IE 6 <em>from the very beginning</em> of your development efforts. In fact, I could even recommend you develop the site&#8217;s HTML and CSS in IE 6 exclusively first, <em>then</em> go back and apply hacks to make it work in the rest of the more standards-compliant browsers&#8230; in fact Firefox 3.x and Safari 4.x both include really great developer tools to help you figure out which &#8220;standards compliancy hacks&#8221; you&#8217;ll need to use to keep the site from looking completely fucked in those browsers.</p></li>
<li><p><strong>Use CSS style and ID names like <code>next_alignright_blue</code> or <code>registration_form_gray</code></strong>. The more you mix styling cues directly into these names, the more you&#8217;ll be able to laugh and laugh and laugh and <em>laugh</em> when those &#8220;next&#8221; links need to be green when the site&#8217;s holiday theme feature gets finished after Thanksgiving. Honestly: what&#8217;s funnier than knowing that <code>next_alignright_blue</code> will render green links? And, if you&#8217;re truly lucky, maybe a usability audit of the site might conclude that the &#8220;next&#8221; links should <em>not</em> get jammed to the right, but should appear adjacent to their associated &#8220;previous&#8221; link.</p></li>
<li><p><strong>Avoid <a href="http://www.w3.org/TR/CSS2/selector.html#descendant-selectors">descendant selectors</a> like the plague</strong>. The only thing that these will ever afford you is the opportunity to minimize the number of IDs and class names. Where will your opportunity for laughs come when elements can be targeted by JavaScript enhancements using a syntax like this:</p>

<pre><code>    [#!javascript]
    $('#sidebar .panel .description a.more').click( ... );
</code></pre>

<p>instead of:</p>

<pre><code>    [#!javascript]
    $('#sidebar_videos_panel a.more').click( ... );
    $('#sidebar_widgets_panel a.more').click( ... );
    $('#sidebar_uploads_panel a.more').click( ... );
    $('#sidebar_archives_panel a.more').click( ... );
</code></pre>

<p>The first example allows some other developer to continue to leverage the selector code to enhance the &#8220;more&#8221; link, should another <code>.panel</code> element with a qualifying like in its <code>.body</code> element, rather than having to explicitly add another line.</p></li>
</ol>

<p>And so I hope I&#8217;ve demonstrated that there&#8217;s simply no reason to mindlessly progress into the hegemony of maintainability, efficiency, and sanity for your colleagues. Not when you can utilize simple little techniques like these.</p>

<p>With your efforts, we can squander much of this hard-earned potential for progress! If you have other douchey ideas you&#8217;d like to share, please leave them in comments.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/08/bizarro-howto-write-css-like-a-total-douche-bag.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Single Pear</title>
		<link>http://uncarved.prometheas.com/2009/07/a-single-pear.html</link>
		<comments>http://uncarved.prometheas.com/2009/07/a-single-pear.html#comments</comments>
		<pubDate>Fri, 24 Jul 2009 16:17:06 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Tabula Quasi-Rasa]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[MacPorts]]></category>
		<category><![CDATA[Pear]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[system administration]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=431</guid>
		<description><![CDATA[I&#8217;ve just invested several hours trying to get my system to use the Pear libraries from MacPorts rather than the Pear libraries I had installed years ago using the command line installer, as described here. This is largely because I&#8217;m happy to let the MacPorts package manager take care of upgrading my software, and making [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just invested several hours trying to get my system to use the Pear libraries from <a href="http://macports.org">MacPorts</a> rather than the Pear libraries I had installed years ago using <a href="http://pear.php.net/go-pear">the command line installer</a>, as described <a href="http://clickontyler.com/blog/2008/01/how-to-install-pear-in-mac-os-x-leopard/">here</a>. This is largely because I&#8217;m happy to let the MacPorts package manager take care of upgrading my software, and making sure all inter-dependencies are looked after.</p>

<p>The command line installer adds files to the traditional <code>/usr/local</code> directory, while the MacPorts package manager adds the files to <code>/opt/local</code>.</p>

<p>And from there, troubles arose. <span id="more-431"></span></p>

<p>The truth is, I&#8217;d forgotten about the <code>/usr/local</code> pear install, until I&#8217;d noticed something peculiar trying to setup a <a href="http://symfony-project.org">Symfony</a> project I&#8217;m working on. Attempting to run one of its command line tasks, I got a fatal error from PHP, reading:</p>

<pre><code>  [#!shell]
  $ ./symfony cc

  Warning: require_once(/opt/local/lib/php/symfony/autoload/sfCoreAutoload.class.php): failed to open stream: No such file or directory in /Users/yanni/Sites/Hosts/breadbreaker.dev/config/ProjectConfiguration.class.php on line 3

  Fatal error: require_once(): Failed opening required '/opt/local/lib/php/symfony/autoload/sfCoreAutoload.class.php' (include_path='.:/opt/local/lib/php') in /Users/yanni/Sites/Hosts/breadbreaker.dev/config/ProjectConfiguration.class.php on line 3
</code></pre>

<p>The file paths for the <code>require</code> statement in the <code>ProjectConfiguration.class.php</code> file were generated on my home computer, which was configured to use the MacPorts pear, which installs Symfony at <code>/opt/local/lib/php</code>.</p>

<p>So I thought to check which pear installation I was using:</p>

<pre><code>  [#!shell]
  $ which pear
  /opt/local/bin/pear
</code></pre>

<p>Huh. That&#8217;s&#8230; actually (correctly) the MacPorts one. Next, I thought to check where my Symfony package was installed:</p>

<pre><code>  [#!shell]
  $ which symfony
  /usr/local/bin/symfony
</code></pre>

<p>&#8220;Ah!&#8221; I thought with relief at the promise of closure, &#8220;It&#8217;s using a version of Symfony I&#8217;d installed before I&#8217;d installed MacPorts&#8217; pear.&#8221; Then I thought I&#8217;d confirm that I still had the old version of pear laying around:</p>

<pre><code>  [#!shell]
  $ find /usr/local -name pear
  /usr/local/bin/pear
  /usr/local/share/pear
  /usr/local/share/pear/pear.old/symfony/plugins/sfPropelPlugin/lib/vendor/propel-generator/pear
  /usr/local/share/pear/symfony/plugins/sfPropelPlugin/lib/vendor/propel-generator/pear
</code></pre>

<p>I&#8217;d found it. I only wanted to keep a single version of pear libraries on my system (under MacPorts), so I proceeded to uninstall the Symfony package from <code>/usr/local</code> and install it explicitly into MacPorts&#8217; own <code>/opt/local</code>.</p>

<pre><code>  [#!shell]
  $ sudo /usr/local/bin/pear uninstall symfony/symfony
  uninstall ok: channel://pear.symfony-project.com/symfony-1.1.3

  $ sudo /opt/local/bin/pear install symfony/symfony
  downloading symfony-1.2.8.tgz ...
  Starting to download symfony-1.2.8.tgz (2,695,461 bytes)
  ..........................done: 2,695,461 bytes
  install ok: channel://pear.symfony-project.com/symfony-1.2.8
</code></pre>

<p>I then proceeded to confirm that Symfony was now installed somewhere within the <code>/opt/local</code> directory branch:</p>

<pre><code>  [#!shell]
  $ which symfony
  /usr/local/bin/symfony
</code></pre>

<p>It wasn&#8217;t. I then tried to rename the pear files in <code>/usr/local</code> so that they wouldn&#8217;t be found, but that didn&#8217;t work either. I Googled far and wide, and found my lead in the Pear Documentation website&#8217;s <a href="http://pear.php.net/manual/en/installation.shared.php">article about shared hosting</a>.</p>

<p>I had configured my <code>.pearrc</code> file to explicitly look for installed pear libraries in <code>/usr/local</code>. This setting was even being honored by the pear in <code>/opt/local</code>.</p>

<p>I renamed my <code>~/.pearrc</code> file to <code>~/.pearrc.old</code> and attempted to install the Symfony package again. Pear complained about an unknown installation source, which meant I had to &#8220;discover&#8221; Symfony&#8217;s <a href="http://pear.php.net/manual/en/guide.users.commandline.channels.php">pear channel</a>. Once I&#8217;d done this, Symfony installed to the correct location!</p>

<p>Finally, I just dumped the old pear installation under <code>/usr/local</code> and the file now named <code>~/.pearrc.old</code>, and was fully transitioned to the MacPorts pear.</p>

<p>How do you like <em>them</em> apples?</p>

<h3>Lessons</h3>

<ul>
<li>Ensure that you&#8217;re executing the correct pear script (on Unix, use <code>which</code> to determine absolute path of the script being used)</li>
<li>Verify that your <code>php.ini</code> file has got the correct pear installation path in its include path.</li>
<li>If you encounter some wonkiness with the inclusion of pear libraries, make sure there isn&#8217;t some <code>.pearrc</code> file with vestigial configuration settings messing with you.</li>
</ul>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/07/a-single-pear.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Habits of Effectively Exploiting Twitter</title>
		<link>http://uncarved.prometheas.com/2009/06/habits-of-effectively-exploiting-twitter.html</link>
		<comments>http://uncarved.prometheas.com/2009/06/habits-of-effectively-exploiting-twitter.html#comments</comments>
		<pubDate>Thu, 04 Jun 2009 07:42:53 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Business Sense]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[social media]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=400</guid>
		<description><![CDATA[Yet another article offering insights and recommended practices to help you exploit Twitter's social opportunities, specifically for your company, organization, or development of your own career.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve lately been involved in a number of conversations about the value proposition of Twitter as a publishing platform to anyone interested in developing a public persona for a company, an organization, or even one&#8217;s own career identity. What follows are ideas that have repeatedly surfaced during these conversations, as well as a handful of links I&#8217;ve been amassing from my reading, as well as links friends and colleagues have shared with me.</p>

<h3>Some Terms</h3>

<p>Throughout this post, for the purpose of simplicity, I will use the term <em>brand</em> to apply to all types of public personae, whether organization or personality.</p>

<p>I will also be speaking about a brand&#8217;s <em>domain of interest</em>, by which I intend to refer to the plurality of whatever industries and/or disciplinary fields that are relevant to the brand. I&#8217;ll use it in this singular form as a blanket concept, covering <em>all topics</em> of interest to the brand.</p>

<p>Finally, I&#8217;ll be using the term <em>market</em> to refer to any and all entities to whom a brand seeks (largely competitively) to offer a value proposition, and who interest — in whole or in part — in the brand&#8217;s domain of interest. In the case of a company, their <em>market</em> is naturally their customers, clients, etc. In the context of an organization, its <em>market</em> may be composed of the members it seeks to attract, or the community that it seeks to serve. Finally, a <em>market</em> for an individual&#8217;s own brand can consist of one&#8217;s prospective employers, clients, students, an educational institution, or grant or fellowship for which he or she may wish to apply.</p>

<h3>Why Even Bother With Twitter?</h3>

<p>Before I get into the any of the <em>how</em>, let&#8217;s invest a moment to get on the same page with respect to the <em>why</em>, since the means must be evaluated against whether or not they advance your efforts towards the desired ends.</p>

<p>This is material that&#8217;s been covered the world over around the Web, so I&#8217;ll keep this concise:</p>

<p>The goals are <em>currency</em> and <em>reputability</em>.</p>

<p><em>Currency</em> here refers to the state of maintaining continuing familiarity with the ideas and topics relevant to the conversations <em>presently taking place</em> in the brand&#8217;s domain of interest. Currency helps a brand focus its efforts to remain relevant to its market, and is maintained by consuming incoming information.</p>

<p><em>Reputability</em> refers to the brand&#8217;s reputation within the context of its market. Its measure exists only in the eyes of the brand&#8217;s prospective market, so it can only be built and developed with public action. On Twitter, this means publishing, or <em>tweeting</em>.</p>

<p>And so the value-proposition that participation in the Twittersphere offers a brand is that it can help the brand stay at the top of its game, and give the market a sense of the brand&#8217;s voice, relevance, and even competitive acumen.</p>

<p>But how can a brand engage with Twitter to realize these goals?</p>

<p><span id="more-400"></span></p>

<h3>Currency Through Consumption</h3>

<p>We&#8217;ve already covered the idea that keeping current with one&#8217;s domain of interest equates to consuming relevant information.</p>

<p>The trick, of course, is ensuring the &#8220;relevant&#8221; part — there&#8217;s just so much &#8220;information&#8221; vying to get attention, it gets difficult both to know which sources to pay attention to, and to discover new sources worth following.</p>

<h4>Basics: Follow to Consume</h4>

<p>Crafting a good set of accounts to follow is the most fundamental way you can use Twitter to keep abreast with the various conversations taking place in your brand&#8217;s domain of interest.</p>

<ol>
<li><p><strong>Follow liberally</strong>. Especially when you first start. Remember that one of the great things about Twitter is that it&#8217;s <em>real easy to unfollow</em>. Unlike joining a mailing list, you never have to worry about not being able to unsubscribe from notifications, etc.</p>

<p>So, if you come to realize that a blog you love has a Twitter feed, follow it. When you stumble upon someone that seems to be making great tweets (eg, you find they get re-tweeted often), follow them. When you attend a great lecture and find out the speaker has a Twitter account, follow them. If some organization that&#8217;s relevant to your domain of interest has a Twitter feed, follow them. Did you just learn that someone new is following you? Review their recent tweets and consider following them as well. Get the picture?</p></li>
<li><p><strong>Periodically identify people to <em>unfollow</em></strong>. That is, you should consider if anyone&#8217;s just been tweeting about how they hate being stuck in traffic, or how they fear they&#8217;ll never learn to say &#8220;no&#8221; to dessert.</p>

<p>The more people you follow, the more effort you&#8217;ll find it takes for you to focus on the information that is relevant to you. This might mean giving Ashton Kutcher or Oprah a pass. Or not, if their work interests you.</p></li>
</ol>

<p>Your goal, over time, is to compile a list of people, publications, organizations, etc. to follow that consistently put out useful material — ones that share relevant links, post meaningful insights, etc. Of course, very few will be all great all the time, but you get the gist: keep the signal-to-noise ratio leaning much more heavily towards <em>signal</em> than <em>noise</em>.</p>

<h4>Advanced: Trends, Hash Tags, and More</h4>

<p>Apart from the relatively passive act of following particular users, it is possible to engage in alternative, more engaged modes of consumption on Twitter.</p>

<ol>
<li><p><strong>Check out Shared Links</strong>. This may sound obvious at first, but it&#8217;s worth mentioning explicitly. Note that most URLs are shortened (more later), so the link&#8217;s immediate value may not be apparent from the link itself.</p></li>
<li><p><strong>Note Hashtags</strong>. A hashtag is any word in a tweet that starts with the <code>#</code> symbol, such as <code>#politics</code> or <code>#superbowl</code>. Hashtags are used to define certain words in a tweet as keywords, much like <a href="http://en.wikipedia.org/wiki/Tag_%28metadata%29">tags</a> on Flickr or a blog.</p>

<pre><code>- &lt;strong&gt;Hashtag Links&lt;/strong&gt;. Many Twitter client applications (though notably not Twitter itself) render hashtags within tweets as clickable links. Clicking a hashtag's link in such a cases will produce a global Twitter search results page, listing the most recent tweets containing the hashtag in question — this can be an excellent way to hunt down links to additional information about a topic someone has tweeted about.

- &lt;strong&gt;Hashtag Searches&lt;/strong&gt;. Hashtags can be searched for, as well. A hashtag search can offer different results than a non-hashtag search because hashtags declare _intentional classification_. Searching for "calculus", for example, may yield results which include tweets complaining about how difficult someone's homework is, but searching for "#calculus" will show only tweets whose authors have declared to be _about calculus_.
</code></pre></li>
<li><p><strong>Check in on Trends</strong>. &#8220;Trends&#8221; are basically terms that are used with a high frequency on Twitter, within a given window of time (say the last 2 hours, 24 hours, etc).</p>

<p>Trend terms on Superbowl Sunday may include the best (or worst) player in the game, the company that aired the best commercial, etc; while trend terms on New Year&#8217;s Eve may include <em>champaign</em>, <em>resolution</em>, <em>resolve</em>, <em>happy</em>, <em>healthy</em>, and <em>midnight</em>.</p>

<p><a href="http://mashable.com/2009/04/04/twitter-trends/">Mashable has a list of various tools</a> for checking in on Twitter trends, from websites, to apps for your mobile phone.</p></li>
<li><p><strong>Hashtag Trends</strong>. You can even follow <a href="http://hashtags.org/trends/today">trends of hashtag assignments</a>.</p></li>
</ol>

<p>As you might expect, the basic and advanced activities feed each other. Exploring hashtags will occasionally introduce you to new users potentially worth following, and following interesting users will introduce you to new hashtag topics.</p>

<p>Because of the way these modes of consumption relate to each other, the consuming information on Twitter carries a very different (and potentially greater) value proposition than, say, following the headlines on your favorite news sites or blog using an RSS reader, since Twitter subscriptions give you the chance to learn about someone&#8217;s work before the mainstream news sources even get their act together to pick up on it.</p>

<h3>Reputability Through Publishing</h3>

<p>Now let&#8217;s get into the tips for making the most of your publishing activities, to give you that street cred you&#8217;re looking for. Let&#8217;s start with these very basic guidelines:</p>

<ol>
<li><p><strong>Public Isn&#8217;t Private</strong>. Keep your tweets topical. Remember that you&#8217;re on Twitter to build a <em>brand</em>, whether this brand is your company, organization, or yourself. I would even <em>especially</em> emphasize this point then the brand is yourself. You&#8217;re tweeting to pimp your brand&#8217;s relevancy to, mastery of, and involvement whatever its domain of interest may be.</p>

<pre><code>- _Do_ personalize the wording on your tweets. It's even usually appropriate to proclaim emphatic love or strong distaste for things in your tweets, _as long as these things are somehow relevant to your domain of interest_. This cultivates and expresses your _editorial voice_, which makes reading your tweets more interesting; no-one likes to read sterile posts, after all.

- _Do not_ make the mistake of using your brand's Twitter account to air your laundry by posting about deeply personal stuff. If you wanna tell the world that your mother is annoying, or that your boyfriend is a douche bag, go update your Facebook status. Or create a separate, _personal_ Twitter account, if you simply must tweet it.
</code></pre>

<p>Again, if you&#8217;re not using Twitter to build a brand, this piece of advice doesn&#8217;t apply&#8230; but then, why exactly are you still reading this article&#8230;?</p></li>
<li><p><strong>Stay on Topic</strong>. Keep the majority of your tweets relevant, at least in some way, to the brand&#8217;s domain of interest. It&#8217;s absolutely acceptable to bend the rules of &#8220;relevancy&#8221; from time to time — again: a <em>little</em> variety or deviation will spice up your feed with a bit of personality. And <em>consistent</em> deviations can add layers to the brand (particularly an individual&#8217;s personal brand), but exercise care with that and try to hit 90% on-topic or better, if you can.</p></li>
<li><p><strong>Share Your Discoveries</strong>. Did you have an interesting conversation? Tweet the conclusion, conundrum, or topic. Share the links of any interesting article or website you encounter that is relevant to your brand&#8217;s domain of interest.</p></li>
<li><p><strong>Share Your Work</strong>. Do you have a blog? Make sure you tweet links to your posts. Did you get some press mention? Post a tweet about the experience, and follow it up with a link when it gets published online.</p></li>
<li><p><strong>Shorten Your URLs</strong>. Use services such as <a href="http://tr.im">http://tr.im</a>, <a href="http://is.gd">http://is.gd</a>, or <a href="http://tinyurl.com">http://tinyurl.com</a> to reserve as many of the 140 allowed characters in a tweet for use in your message.</p></li>
<li><p><strong>Engage</strong>. The greatest potential value from a social medium like Twitter is derived from the act of engagement.</p>

<pre><code>- &lt;strong&gt;Reply&lt;/strong&gt;. When someone says something interesting or posts a good link, reply to them.

- &lt;strong&gt;Consult&lt;/strong&gt;. Are you stuck on some complex or nuanced question? Ask your followers.

- &lt;strong&gt;Challenge&lt;/strong&gt;. Or perhaps just come up with a great rhetorical, thought provoking one? Pose it to the folks following you.
</code></pre></li>
<li><p><strong>Mentions</strong>. A <em>mention</em> is simply the inclusion of another user&#8217;s Twitter name, prefixed with the <code>@</code> symbol, in one of your tweets. Here&#8217;s an example tweet with a mention:</p>

<blockquote>
  <p>Meeting with <a href="http://twitter.com/luvinspoonfuls">@luvinspoonfuls</a> today to discuss recipe software.</p>
</blockquote>

<p>Twitter automatically turns those into links that point to the twitter profile of the mentioned user, so mentions can be a powerful cross-promotional tool. As a rule of thumb, whenever you&#8217;re talking about someone who also has a presence on Twitter, make sure you include a mention for their Twitter user, <em>even if the message is addressed to a third party</em>. They&#8217;ll thank you, and more than likely mention you later.</p></li>
<li><p><strong>Re-tweeting</strong>. A re-tweet (or RT) is the act of posting someone else&#8217;s tweet verbatim, in such a way that it includes attribution of its source. RTing is great because it accomplishes a few different things:</p>

<pre><code>- It's a mention, and therefore carries promotional value for the original author

- Pimping other users with RTs casts you in a more social light to your followers, and helps reassure them that the brand is, in fact, participating in a dialogue, rather than just beaming self-promotional messages blindly out into the cosmos.
</code></pre></li>
<li><p><strong>Use Hashtags</strong>. Categories the topics of your tweets with hashtags. Note that some hashtags can even be funny, like <code>#painfullyobvious</code> or <code>#wtf</code>. I like to hashtag inline, when I can, as in the following example (which also includes a mention):</p>

<blockquote>
  <p>Awesome new #website: <a href="http://data.gov">http://data.gov</a> &#8211; I&#8217;m really impressed with the <a href="http://twitter.com/whitehouse">@whitehouse</a>&#8230; Now THAT&#8217;S #technology in #government !!! #amazing</p>
</blockquote></li>
</ol>

<p>The key to building a reputation for a brand on Twitter is constructive participation in the community of users who share interest in the brands domain of interest.</p>

<h3>Conclusions</h3>

<p>These are the basic activities for building the strength of your brand on Twitter. I omitted certain ideas that may be relevant only to corporate brands, etc, but it&#8217;s really all about ways to engage in a dialog with your brand&#8217;s market.</p>

<p>I should note, also, that participating in the so-called Twittersphere is only a <em>small</em> (if potential-packed) part of the brand building social media publishing equation. I would also recommend maintaining a blog of some sort — ideally on the brand&#8217;s own website — to which longer-form content can occasionally be published; 140 characters isn&#8217;t a hell of a lot of opportunity to effectively convince people that you know your shit.</p>

<p>Finally, have fun! Get out there and meet people — engage them in person. Share your energy and ideas with them, and listen to the thoughts and insights they respond with. There&#8217;s no substitute for a lively conversation over a beverage.</p>

<h3>Further Reading</h3>

<ul>
<li><a href="http://mashable.com/2009/04/20/twitter-strategy/">http://mashable.com/2009/04/20/twitter-strategy/</a> &#8211; 7 ways of approaching Twitter publishing</li>
<li><a href="http://mashable.com/2009/05/20/twitter-personal-brand/">http://mashable.com/2009/05/20/twitter-personal-brand/</a> &#8211; how to build your brand</li>
<li><a href="http://twittley.com/">http://twittley.com/</a> &#8211; a Twitter-integrated version of digg (pimp your links)</li>
<li><a href="http://www.techcrunch.com/2009/05/25/viralheats-real-time-social-measurement-tool-analyzes-content-on-twitter-youtube-and-more/">http://www.techcrunch.com/2009/05/25/viralheats-real-time-social-measurement-tool-analyzes-content-on-twitter-youtube-and-more/</a> &#8211; analytics for advanced Twitter publishing activity</li>
</ul>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/06/habits-of-effectively-exploiting-twitter.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using the HP Mini Netbook: Pimping the Mini&#8217;s MIE: Adding Flock</title>
		<link>http://uncarved.prometheas.com/2009/05/pimping-the-minis-mie-adding-flock.html</link>
		<comments>http://uncarved.prometheas.com/2009/05/pimping-the-minis-mie-adding-flock.html#comments</comments>
		<pubDate>Thu, 21 May 2009 06:39:29 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[General Thoughts]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flock]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[HP Mini]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MIE]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=339</guid>
		<description><![CDATA[I broke down and hacked my MIE. But just a teeny bit, though: I simply installed the Flock browser and added it to the application launcher. I needed to know it could be done.]]></description>
			<content:encoded><![CDATA[<p>I broke down and hacked my MIE. But just a teeny bit, though: I simply installed the Flock browser and added it to the application launcher.</p>

<p>I needed to know it could be done.</p>

<p>Having satisfied my need to see the proof-of-concept, I intend to return to using the non-hacked configuration (by disabling what I&#8217;ve done) for a little while longer, while I complete a review period during which I use the computer with only the applications found on the default system.</p>

<p>That said, I <em>will</em> mention that am rather pleased with the initial results of my efforts in hacking this thing.</p>

<p>Once I&#8217;m done assessing its performance and capability as configured in its &#8220;out-of-the-box&#8221; mode, I intend to hack the hell out of MIE. Maybe I&#8217;ll even manage to fix the damned issue I&#8217;m encountering with the <code>Mail</code> widget on the home screen that HP&#8217;s customer support facilities have <em>utterly failed</em> at helping me resolve&#8230; but I&#8217;ll get into the saga of HP&#8217;s epic failures at customer support in a future post.</p>

<p><span id="more-339"></span></p>

<h2>Installing Flock</h2>

<p>Head over to the <a href="http://flock.com">Flock website</a> and download Flock. Unless you&#8217;ve changed the default settings, Firefox will download the file to your desktop.</p>

<p>Fire up a terminal, <code>cd</code> to your Desktop (or whichever directory your Firefox is configured to save its download to) and type:</p>

<pre><code>  [#!shell]
  $ sudo tar -C /opt -xjvf flock-*.linux-i686.tar.bz2
</code></pre>

<p>Test if flock works from the command line:</p>

<pre><code>  [#!shell]
  $ /opt/flock/flock-browser
</code></pre>

<p>If Flock launched properly, it&#8217;s installed properly. Next, we want to get the command to launch flock accessible from your <code>PATH</code> by adding a symlink to it in <code>/usr/local/bin</code>:</p>

<pre><code>  [#!shell]
  $ sudo ln -s /opt/flock/flock-browser /usr/local/bin/flock
</code></pre>

<p>Test if the symlink works:</p>

<pre><code>  [#!shell]
  $ flock
</code></pre>

<p>If Flock launched, then our command line installation steps are complete.</p>

<h2>Adding Flock to the Launcher</h2>

<p>The next several steps will cover how we get the nice Flock icon in the <em>Internet</em> tab of the application launcher, which initially looks like this:</p>

<p><img src="/wp-content/uploads/2009/05/mie-launcher-default-state-300x168.png" alt="MIE Launcher default state.png" border="0" width="300" height="168" /></p>

<h3>Backing Up the Original Settings</h3>

<p>First, let&#8217;s backup our launcher&#8217;s current setup; the wise hacker always keeps a copy of the original configuration in case something gets hosed.</p>

<p>To create this backup, type the following into your terminal:</p>

<pre><code>  [#!shell]
  $ sudo cp -r /etc/xdg/menus /etc/xdg/menus.original
</code></pre>

<p>If we ever want to restore to our defaults, we need simply type:</p>

<pre><code>  [#!shell]
  $ sudo mv /etc/xdg/menus /etc/xdg/menus.hosed
  $ sudo cp -r /etc/xdg/menus.original /etc/xdg/menus
</code></pre>

<p>This reversion will keep whatever changes you made to the config files you accidentally hosed, in case you want to try to copy your hacks back, one by one.</p>

<h3>Creating an Application Entry File for Flock</h3>

<p>Create the file <code>/usr/local/share/applications/flock.desktop</code> and set its contents as follows:</p>

<pre><code>  [#!ini]
  [Desktop Entry]
  Name=Flock
  Comment=Flock Web Browser
  Exec=flock
  GenericName=Flock Web Browser
  Icon=/opt/flock/icons/mozicon128.png
  Path=
  StartupNotify=true
  Terminal=0
  TerminalOptions=
  Type=Application
  Categories=Application;Network;
</code></pre>

<p>Note that we&#8217;re creating our Application Entry file in <code>/usr/local/share</code> rather than <code>/usr/share</code>. This is because this is the recommended practice for items added manually by the user in Unix-like operating systems.</p>

<h3>Adding the Application to an Existing Tab</h3>

<p>Let&#8217;s add Flock to the launcher&#8217;s <em>Internet</em> tab.</p>

<p>Open <code>/etc/xdg/menus/applications.menu</code> file, and make the following change:</p>

<pre><code>  [#!xml]
  &lt;Menu&gt;
    &lt;Name&gt;Internet&lt;/Name&gt;
    &lt;!-- ... other nodes ... --&gt;
    &lt;Layout&gt;
      &lt;Filename&gt;firefox.desktop&lt;/Filename&gt;
      &lt;Filename&gt;thunderbird.desktop&lt;/Filename&gt;
      &lt;Filename&gt;pidgin.desktop&lt;/Filename&gt;
      &lt;Filename&gt;skype.desktop&lt;/Filename&gt;

      &lt;!-- We're adding this line --&gt;
      &lt;Filename&gt;flock.desktop&lt;/Filename&gt;

    &lt;/Layout&gt;
  &lt;/Menu&gt;
</code></pre>

<p>Save your file, then go to the application launcher. You should now see the following:</p>

<p><img src="/wp-content/uploads/2009/05/mie-launcher-with-flock-installed-300x169.png" alt="MIE Launcher with Flock installed.png" border="0" width="300" height="169" /></p>

<p>I won&#8217;t cover <em>replacing</em> Firefox as the default browser here, nor will I get into how to add tabs to the launcher — I&#8217;m not ready to get into all that just yet. Rest assured, however, that I&#8217;ll definitely get there once I dive headlong into my hacking activities.</p>

<p><a href="http://myhpmini.com/forum/viewtopic.php?f=10&#038;t=837&#038;start=0">The material</a> I based this entire endeavor on is from HP&#8217;s Mini forum — check it out!</p>

<p>Good hacking, amigos.</p>

<p class="update"><span class="date">24 May</span>: HP has got the Mini&#8217;s <em>fora</em> back up and running, so I&#8217;ve updated the URL to the material, and removed the Google Cache link.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/05/pimping-the-minis-mie-adding-flock.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>sfPropelLazyHydrationIteratorPlugin — Lazy Hydration, Made Concise</title>
		<link>http://uncarved.prometheas.com/2009/05/lazy-hydration-made-concise.html</link>
		<comments>http://uncarved.prometheas.com/2009/05/lazy-hydration-made-concise.html#comments</comments>
		<pubDate>Wed, 13 May 2009 05:49:06 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[announcement]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[laziness]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Propel]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=310</guid>
		<description><![CDATA[sfPropelLazyHydrationIteratorPlugin lets you utilize Propel 1.2's "lazy hydration" technique of iterating a database query without dealing with its lower level Creole APIs.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been working on <a href="http://www.symfony-project.org/">Symfony</a> / <a href="http://propel.phpdb.org/">Propel</a> projects that deal with particularly large data sets. In such cases, Propel&#8217;s documentation recommends a &#8220;lazy hydration&#8221; approach.</p>

<p>This &#8220;lazy hydration&#8221; of Propel&#8217;s looks like this:</p>

<pre><code>  [#!php]
  // query all the author entities as a Creole ResultSet
  $rs = AuthorPeer::doSelectRS( new Criteria() );

  while( $rs-&gt;next() )
  {
    $author = new Author();
    $author-&gt;hydrate( $rs );
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>The code above does the following:</p>

<ol>
<li>it queries the database for all records in the <code>author</code> table, and loads it into a <a href="http://creole.phpdb.org/">Creole</a> <code>ResultSet</code> object.</li>
<li>enters a loop, iterating over each result (ie, table row) in the <code>ResultSet</code>, and with each of its records, it:

<ol>
<li>creates a new, empty Author object</li>
<li>hydrates the empty object with the data in the <code>ResultSet</code>&#8216;s current row</li>
<li>writes the author&#8217;s last and first name to the output buffer</li>
</ol></li>
</ol>

<p>In this way, only one <code>Author</code> instance is in use at any given time. Each iteration discards the previous instance and creates a new one.</p>

<p>But I hate it — it&#8217;s ugly and unwieldy.</p>

<p>This overt use of the <code>ResultSet</code> object is an awkward practice when using an ORM. The primary design goal of ORMs is to allow the developer to work at a higher level of abstraction than SQL queries and database result sets.</p>

<p>So what <em>should</em> it look like? <span id="more-310"></span></p>

<p>Assuming you&#8217;re <em>not</em> worried the query&#8217;s results might chew up all system&#8217;s RAM, the Propel API lets you get the job done like this:</p>

<pre><code>  [#!php]
  foreach( AuthorPeer::doSelect( new Criteria() ) as $author )
  {
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>For starters, this is a more concise block of code.</p>

<p>Secondly, this block of code focuses more directly on classes that are directly relevant to your application&#8217;s business logic.</p>

<p>Unfortunately, for all the theoretical loveliness it espouses, it consumes considerably more RAM since the data from each record of <code>author</code> table is loaded into unique instances of <code>Author</code> objects, which are all dumped into an array.</p>

<p>If the database only has ten authors, you won&#8217;t have any problems finding the RAM to instantiate all ten <code>Author</code> objects.</p>

<p>If you have <em>tens of thousands</em> of <code>author</code> records, on the other hand, it might be challenging enough to allocate enough RAM to store the entirety of the raw data generated by the database query, let alone to load that data into tens of thousands of <code>Author</code> object instances.</p>

<p>Propel&#8217;s &#8220;lazy hydration&#8221; approach sacrifices a little concision in return for some resource efficiency.</p>

<p>But I was writing <em>many dozens</em> of blocks of code like this, and seeing what is essentially the same lines of code dutifully repeated all over the place started to wear on me. I was even nesting these iterations, winding up with variable scopes that simultaneously contained variables named <code>$authors_rs</code>, <code>$books_rs</code>, and <code>$whatever_else_rs</code>.</p>

<p>I got fed up, so I decided to fix it.</p>

<p>I had started thinking about some other Symfony classes that managed to abstract Propel API quirks, and found inspiration in the <code>sfPropelPager</code> class. I decided to encapsulate all that into the sfPropelLazyHydrationIterator class, which implements PHP&#8217;s <code>Iterator</code> interface to provide the best of both worlds.</p>

<p>Let&#8217;s start simply:</p>

<pre><code>  [#!php 1]
  // create a sfPropelLazyHydrationIterator
  $authors = new sfPropelLazyHydrationIterator('Author', new Criteria());

  foreach( $authors as $author )
  {
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>The constructor requires two arguments: the name of the Propel model class, and a Criteria object. Internally, the object queries the database to retrieve a <code>ResultSet</code>. Using this object in a <code>foreach()</code> loop iterates through the database results using the same lazy hydration technique we looked at earlier.</p>

<p>Let&#8217;s take a look at a slightly more complex scenario, which uses a Propel 1.2 <code>Connection</code> for an in-transaction query:</p>

<pre><code>  [#!php 1]
  // let's add a transaction to the mix
  $con = Propel::getConnection();
  $con-&gt;begin();

  try
  {
    // do some stuff to author records within the transaction...

    $authors = new sfPropelLazyHydrationIterator( 'Author', new Criteria(), $con );
    foreach( $authors as $author )
    {
      echo sprintf('%s, %s', $author-&gt;getFirstName(), $author-&gt;getLastName());
      $author-&gt;setLastAccessedOn( 'now' );
      $author-&gt;save( $con );
    }

    $con-&gt;commit();
  }
  catch (SqlException $sqle)
  {
    $con-&gt;rollback();
  }
</code></pre>

<p>But how does this all happen? Let&#8217;s look at an abbreviated version of this class:</p>

<pre><code>  [#!php 1]
  class sfPropelLazyHydrationIterator
  implements Iterator
  {
    private $modelClassName;
    private $resultSet;

    /**
     * Contstructor.
     *
     * @param string $model_class_name
     * @param Criteria $c
     * @param Connection $con
     * @param string $peer_name
     */
    public function __construct( $model_class_name, $c, $con=null, $peer_name=null )
    {
      $this-&gt;modelClassName = $model_class_name;
      $this-&gt;modelPeerName  = empty($peer_name) ? $this-&gt;modelClassName.'Peer' : $peer_name;
      $this-&gt;resultSet      = call_user_func(array($this-&gt;modelPeerName, 'doSelectRS'), $c);
    }

    /**
     * Implements Iterator::current()
     */
    public function current()
    {
      if (false !== $this-&gt;resultSet-&gt;getIterator()-&gt;current())
      {
        return $this-&gt;createAndHydrateCurrent();
      }

      return false;
    }

    /**
     * Implements Iterator::next()
     */
    public function next()
    {
      if (false !== $this-&gt;resultSet-&gt;getIterator()-&gt;next())
      {
        return $this-&gt;createAndHydrateCurrent();
      }

      return false;
    }

    // ... other Iterator methods

    /**
     * Returns a hydrated instance of the appropriate model class, using
     * the row data at the ResultSet's current pointer position.
     *
     * @return mixed
     */
    protected function createAndHydrateCurrent()
    {
      $object = new $this-&gt;modelClassName();
      $object-&gt;hydrate( $this-&gt;resultSet );
      return $object;
    }

  }
</code></pre>

<p>The real work happens in the constructor and <code>createAndHydrate()</code> method. The latter is called by the <code>Iterator</code> interface implementations of the <code>next()</code> and <code>current()</code> methods (included in the code excerpt above).</p>

<p>This class is available in its entirety as part of the <a href="http://www.symfony-project.org/plugins/sfPropelLazyHydrationIteratorPlugin">sfPropelLazyHydrationIteratorPlugin</a>, which I have already published to the Symfony plugins site. The plugin is not, at the time of this writing, available as a PEAR package, but I intend to sort that out in the coming days.</p>

<p><strong>Please note</strong>: the sfPropelLazyHydrationIterator presently only works with Propel 1.2.</p>

<h3>Getting <em>Really</em> Lazy</h3>

<p>And finally, let&#8217;s surrender fully to the laziness within — let&#8217;s look at super concision. We&#8217;ll add a new method to the <code>AuthorPeer</code> class:</p>

<pre><code>  [#!php 1]
  class AuthorPeer extends BaseAuthorPeer
  {

    /**
     * Returns a sfPropelLazyHydrationIterator to allow iteration over retrieved
     * database results, utilizing "lazy hydration".
     *
     * @param Criteria $c
     * @param Connection $con
     * @return sfPropelLazyHydrationIterator
     */
    public static function doSelectLazy( $c, $con=null )
    {
      return new sfPropelLazyHydrationIterator('Author', $c, $con);
    }

    // ... other peer methods ...
  }
</code></pre>

<p>Now, we can iterator over all <code>author</code> records like so:</p>

<pre><code>  [#!php 1]
  foreach( AuthorPeer::doSelectLazy(new Criteria()) as $author )
  {
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>Whoever said you couldn&#8217;t have your cake <em>and</em> eat it obviously wasn&#8217;t terribly determined to be as lazy as possible.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/05/lazy-hydration-made-concise.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stop Installing Windows</title>
		<link>http://uncarved.prometheas.com/2009/04/stop-installing-windows.html</link>
		<comments>http://uncarved.prometheas.com/2009/04/stop-installing-windows.html#comments</comments>
		<pubDate>Sat, 11 Apr 2009 10:51:44 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=149</guid>
		<description><![CDATA[My brother and I had been suffering from a chronic affliction for roughly the last decade. You see, every year or so, we&#8217;d have to reinstall Windows on the PCs in our father&#8217;s office. The reasons for the re-installation ranged from viruses, to a hosed registry, and even hard drive failures; the poor man&#8217;s PCs [...]]]></description>
			<content:encoded><![CDATA[<p>My brother and I had been suffering from a chronic affliction for roughly the last decade. You see, every year or so, we&#8217;d have to reinstall Windows on the PCs in our father&#8217;s office. The reasons for the re-installation ranged from viruses, to a hosed registry, and even hard drive failures; the poor man&#8217;s PCs have seen it all.</p>

<p>It was a cycle that looked something like this:</p>

<ol>
<li>the computer starts behaving strangely (random crashes of applications or the system, mysterious prolonged lock-ups, etc)</li>
<li>my brother or I get called in to diagnose</li>
<li>we discover the problem</li>
<li>we attempt to fix</li>
<li>sometimes the problem is resolved, but other times it&#8217;s necessary to reinstall</li>
<li>we attempt to backup the most recent data (if it&#8217;s not somehow corrupted), or use the latest weekly backup</li>
<li>boot the Windows installation disk</li>
<li>clear the hard drive</li>
<li>install Windows</li>
<li>activate our copy of Windows</li>
<li>install anti-virus software</li>
<li>install the latest Windows Service Packs, as well as any other security updates</li>
<li>install the necessary software</li>
<li>restore the backed up data files</li>
<li>wait for the cycle to start again</li>
</ol>

<p>Some folks reading this far might argue that we should have moved him off Windows a long time ago, and saved ourselves the trouble. Why not just give him a Mac or install Linux and put the worries aside?</p>

<p>Unfortunately, it&#8217;s not that simple.</p>

<p>He <em>needs</em> to run Windows because he runs his business on an accounting software package called PeachTree. The fact that alternatives exist is immaterial; all the business data is already stored in there, Dad and his book keepers know how to use it, and nobody involved feels like learning some other convoluted accounting software.</p>

<p>Windows simply cannot be removed from the equation.</p>

<p>Unfortunately, we were trapped in what seemed like an interminable cycle. It had practically reached the point where my brother and I developed the capability to do the job drawing purely on muscle memory to lead us through.</p>

<p>But muscle-memory or not, <em>installation demands time</em>.</p>

<p>Even after the Windows installer itself would do its job, we would then have to download and apply the most recent Service Packs, install his software, and reconfigure his desktop so that everything is &#8220;in the right place.&#8221;</p>

<p>In our case, the reinstallation process would typically consume about a full 8-hour workday, and occasionally more if there are network connectivity issues or other mishaps. Naturally, since both my brother and I have day to day responsibilities of our own, the effort would always wind up consuming one of our weekend or holiday days.</p>

<p>It happened again in February of 2009&#8230; specifically, on my brother&#8217;s birthday weekend. My father took the family out for a birthday brunch, after which my brother and I accompanied him to his office to do the dirty work.</p>

<p>But this time, a new strategy occurred to me: <em>surrender</em>.</p>

<p>I decided to accept the eventuality that Windows will, in time, shit the bed on us. This has all happened before, and it will all happen again. It may be some sort of malware, or just a badly-written (but perfectly legitimate) installer that hoses your registry.</p>

<p>Once I&#8217;d accepted this, and the denial had melted away, my goals changed from protecting Windows from malware to <em>working out how to make the restore suck less</em>.</p>

<p>Since we&#8217;d managed to get them in the weekly practice of making weekly backups of their business data, the worst part about restoring their computers was simply investing the time it takes wait out all the damned progress bars of the process. Installer after installer would run, many needing an attentive human present to click &#8220;OK&#8221; or to accept license agreements.</p>

<p>The faster we could get from empty hard drive to functional Windows system, and the less attentive effort it required of anyone, the better everyone&#8217;s life would become <em>ever more</em>.</p>

<p>The goal was to reduce the restore process to a simple file copy.</p>

<p>And with this thought, I suddenly knew what had to be done: all we needed was a bunch of free software (and a RAM upgrade for one of the computers), and <em>we could install and configure Windows—and all of his software—for the last time, ever</em>.</p>

<p>We erased the hard drives of his PCs and installed <a href="http://ubuntu.com/">Ubuntu Linux</a> on all of them. We then installed Sun&#8217;s free and open source <a href="http://en.wikipedia.org/wiki/Virtual_machine">virtualization software</a>, called <a href="http://virtualbox.org/">VirtualBox</a>, and carried out our routine installation and configuration of Windows — and all the necessary software — into a virtual machine.</p>

<p>We added free <a href="http://getdropbox.com/">DropBox</a> account service to the picture, just to bulletproof the backup strategy for his business data.</p>

<p>Once everything was installed and properly configured, we stopped the VirtualBox virtual machine and created a master backup copy of the new virtual machine&#8217;s hard drive image file. This master copy of the hard drive image now contained a <em>fully-configured, pristine version of Windows</em>.</p>

<p>Moving forward, a full Windows restoration process for the accounting PC can be conducted over a lunch, instead of the course of a full workday.</p>

<p>And because Windows is running in a virtual machine, we&#8217;ve even managed to reduce the amount of time that would be required to replace the entire machine: simply wipe its hard drive, install Linux on it, copy over the Windows virtual machine&#8217;s hard drive image, and we&#8217;re up and running with all of our user settings and latest business data in place. And because Windows only ever &#8220;sees&#8221; the virtualized &#8220;hardware&#8221; presented by VirtualBox, it won&#8217;t require a reactivation.</p>

<p>I should finally note that the accounting machine is used as a fulltime Windows machine. That is, from the moment of startup, VirtualBox is launched, and the Windows desktop is used in full-screen mode, with nary a though given to the Linux environment, until they&#8217;re ready to shut the machine down.</p>

<p>So from now on, when Windows <em>does</em> eventually punk out in one of its many—and, at times, even <em>innovative</em>—ways, we&#8217;ll be ready.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/04/stop-installing-windows.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

