<?xml version="1.0" encoding="UTF-8"?>
<rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Beckism.com</title>
	
	<link>https://ianbeck.webfactional.com</link>
	<description>Fiction, opinions, and more</description>
	<lastBuildDate>Sat, 30 Jan 2010 18:30:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/beckism" /><feedburner:info uri="beckism" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Understanding Espresso actions</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/goWII1wNOSQ/</link>
		<comments>https://ianbeck.webfactional.com/2010/01/espresso_actions/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 18:30:08 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[custom solution]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=348</guid>
		<description>A fair number of people in the Espresso forums ask questions like, &amp;#8220;Is there a shortcut to delete the current line the way there is in Textmate?&amp;#8221;  Usually the answer is, &amp;#8220;No, why don&amp;#8217;t you create one?&amp;#8221;  Yet people remain leery of creating text actions by hand.  I understand that; heck it&amp;#8217;s [...]</description>
			<content:encoded><![CDATA[<p>A fair number of people in the <a href="http://macrabbit.com/espresso/">Espresso</a> forums ask questions like, &#8220;Is there a shortcut to delete the current line the way there is in Textmate?&#8221;  Usually the answer is, &#8220;No, why don&#8217;t you create one?&#8221;  Yet people remain leery of creating text actions by hand.  I understand that; heck it&#8217;s extra work, and who wants that?  What I think most people don&#8217;t realize is that, particularly for text manipulations like deleting the current line, the amount of work is minimal.  All you need is a basic understanding of how Espresso works and the ability to author simple Javascript and XML.</p>
<h4>Anatomy of an action</h4>
<p>Espresso actions come in two parts:</p>
<ol>
<li>The XML definition, which tells Espresso the action&#8217;s title, what Objective-C class to execute when the action is invoked, and additional information like keyboard shortcuts or tab triggers that should invoke the action.</li>
<li>The Objective-C class (or, if using a plugin like <a href="http://onecrayon.com/tea/">TEA</a> or <a href="http://onecrayon.com/spice/">Spice</a>, the script that defines the action&#8217;s logic)</li>
</ol>
<p>Most often, XML action definitions are included with a Sugar (you can make a Sugar for custom text actions simply by adding a <code>.sugar</code> extension to a folder that contains a TextActions folder with the action XML files in it).  If you wish, you can also define action XML files outside of a Sugar by enabling TEA custom user actions in the Advanced pane of the Espresso Preferences (<a href="http://onecrayon.com/tea/docs/preferences/#actions">more info about TEA custom user actions</a>).</p>
<p>As of Espresso 1.1 there isn&#8217;t an in-program GUI for editing actions yet, but hopefully that will come in time.</p>
<h4>Spice up your actions</h4>
<p><a href="http://onecrayon.com/spice/">Spice</a> is an Espresso Sugar that I&#8217;m currently developing that provides access to the Espresso API using Javascript (thanks to <a href="http://inexdo.com/JSCocoa">JSCocoa</a>), and additionally provides a selection of utility classes that allow you to interact with the API without needing to know anything about Objective-C or the JSCocoa bridge.</p>
<p>The benefits of this should be fairly obvious, but there&#8217;s another reason creating actions with Spice is easier than using TEA or Objective-C; not only are the action scripts not compiled, but you don&#8217;t need to relaunch Espresso to see your changes.  When I&#8217;m coding a Spice action, I usually open the Javascript action in Espresso, and then run the action right there on the Javascript when I need to test it.</p>
<p>Although Spice&#8217;s utility classes make creating custom Espresso actions easier, you still need a basic understanding of how the Espresso API works.</p>
<h4>Contexts, ranges, recipes, and snippets</h4>
<p>When a user invokes an action from the Actions menu, Espresso executes the action&#8217;s class and sends it an object representing the <strong>text or file context</strong> (depending on whether you&#8217;re using a text or file action; I&#8217;ll be focusing only on text actions because the file action API is currently underwhelming).  The text context allows you to access the active file&#8217;s text, information about the selection (or selections, since you can select multiple things at once), line information, preferences (like what line ending or indentation is being used), and access to the syntax system.</p>
<p>When you are ready to change some text in the file, your action messages the text context and tells it what to change and how to do it.</p>
<p>As of Espresso 1.1, the easiest actions to create are ones that are invoked by the user, access and change something about the active file&#8217;s text, and then immediately exit.  It&#8217;s possible to do things that are a bit more complicated or on-going, but at the moment Espresso doesn&#8217;t make it easy.</p>
<p>When you&#8217;re working with text, you&#8217;ll mainly be dealing with <strong>ranges</strong>.  A range represents a section of text in the active file and is composed of a location and a length.  Internally Espresso keeps track of text by counting all of the characters in the active file starting at zero, so the range location is the index of the starting character and the length is the number of characters contained within the range.  Typically you&#8217;ll be dealing with selections, so you&#8217;ll have ranges like {0, 10} (the first ten characters in the file) or {100, 30} (characters 100 through 130).  However, it&#8217;s also possible to have ranges like {10, 0}, which represents the cursor location at character index #10 in the file.</p>
<p>A typical text action will fetch the currently selected ranges from Espresso, manipulate the text within them somehow, and then tell Espresso to change the range(s) accordingly.  In order to queue up changes like this, you&#8217;ll use text recipes.</p>
<p><strong>Text recipes</strong> are something that is unique to Espresso, so far as I know.  Basically, you create a recipe and tell it things like &#8220;delete the text in this range&#8221;, &#8220;replace the text in this second range&#8221;, and &#8220;add this text at a third range&#8221;.  You can compose a multiple step recipe without worrying about tracking how ranges will change; for instance, if you add characters to an early range, you don&#8217;t have to adjust the location of later ranges.  Instead, the recipe does that for you when you apply it to the document.</p>
<p>Text recipes allow you to make complex changes to multiple ranges in the active file, but you can instead insert <strong>text snippets</strong>, as well.  A text snippet is a specially formatted string that allows Espresso to create tab stops, mirrored segments, and more after you&#8217;ve inserted it.  Many of the custom actions bundled with Espresso are little more than text snippets; for instance Wrap Selection In Tag merely grabs the selected text and wraps it in a simple snippet that mirrors the HTML element from the opening tag to the closing tag.  You can do some pretty magical-seeming things with very simple actions simply through tricky use of text snippets.  The one downside to keep in mind for text snippets, however, is that you can only insert one at a time (unlike text recipes, you can&#8217;t insert multiple text snippets over discontiguous selections).</p>
<h4>Bringing it all together</h4>
<p>With an understanding of how the Espresso API works and a quick peek at the <a href="http://onecrayon.com/spice/docs/">Spice docs</a>, setting up an action to delete the current line (to take one example) becomes simple enough:</p>
<ol>
<li>First, we&#8217;ll need to define an action in XML, and create a Javascript file with the action logic</li>
<li>In the Javascript, we&#8217;ll need to query the text context to get the range of the current line, and then create a text recipe to delete that range</li>
</ol>
<p>The action XML is easy enough; simply create the file <code>Actions.xml</code> and place it either in a Sugar&#8217;s TextAction folder or in your Espresso Support folder located here:</p>
<p><code>
<pre>~/Library/Application Support/Espresso/Support/TextActions/</pre>
<p></code></p>
<p>The contents of the action XML definition should be this:</p>
<p><code>
<pre>&lt;action-recipes&gt;
    &lt;action id="com.onecrayon.DeleteLine" category="actions.text.generic"&gt;
        &lt;class&gt;Spice&lt;/class&gt;
        &lt;title&gt;Delete Line&lt;/title&gt;

        &lt;setup&gt;
            &lt;script&gt;delete_line&lt;/script&gt;
            &lt;undo_name&gt;Delete Line&lt;/undo_name&gt;
        &lt;/setup&gt;
    &lt;/action&gt;
&lt;/action-recipes&gt;
</pre>
<p></code></p>
<p>(If you wish to add a keyboard shortcut, you can do that with the <code>key-equivalent</code> entity; see the <a href="http://onecrayon.com/spice/docs/spice-xml/">Spice action XML docs</a>.)</p>
<p>If you&#8217;re using the Support folder option, you&#8217;ll need to enable TEA custom user actions in the preferences and restart the program twice.  Otherwise you&#8217;ll need to make sure the Sugar is installed and restart the program once (action XML definitions are loaded when Espresso boots up; unfortunately as of Espresso 1.1 there isn&#8217;t a way to refresh action XML definitions without a relaunch).</p>
<p>Now that you&#8217;ve got the action defined (and showing up in the Actions menu) you can create the Javascript file <code>delete_line.js</code> (referenced in the <code>script</code> element of the action XML).  If you are using a Sugar, it should be located here:</p>
<p><code>
<pre>MySugar.sugar/Support/Scripts/</pre>
<p></code></p>
<p>If you&#8217;re using custom user actions in the Espresso Support folder, you&#8217;ll save it here:</p>
<p><code>
<pre>~/Library/Application Support/Espresso/Support/Scripts/</pre>
<p></code></p>
<p>The simplest way to delete the current line would be this:</p>
<p><code>
<pre>// Deletes the current line

// require() allows you easy modular access to Spice's helper classes
var textContext = require('text_action_context').textContext;
var TextRecipe = require('text_recipe').TextRecipe;

// exports.main is your primary function, run automatically by Spice
exports.main = function() {
    // Grab the range of the current line
    var linerange = textContext.rangeForLine();
    // Run the actual removal
    return new TextRecipe().remove(linerange).apply();
}</pre>
<p></code></p>
<p>First, the script uses the universal <code>require()</code> function to include the Spice utility object <code>textContext</code> (which contains methods for interacting with the Espresso text context) and utility class <code>TextRecipe</code> (which allows access to Espresso text recipes).</p>
<p>Spice&#8217;s utility classes are provided in a modular system that allows you to only require what you need in order to run your action.  Spice modules have the following naming conventions:</p>
<ul>
<li>The module is named for the primary class, converted to lowercase and with underscores between words (so primary class <code>TextActionContext</code> becomes module <code>text_action_context</code>)</li>
<li>Classes are all camel-case with the first letter capitalized (<code>TextActionContext</code>)</li>
<li>Objects (instantiated versions of a class) are camel-case with the first letter lowercase (<code>textContext</code> is an instantiated version of <code>TextActionContext</code>)</li>
</ul>
<p>You can see what a given module exports in the <a href="http://onecrayon.com/spice/docs/">Spice docs</a> (along with full references to the object methods available).  The <code>text_action_context</code> module is one of the few that exports an object as well as the class, since you&#8217;ll never need more than one object for referencing the text context.</p>
<p>Once you&#8217;ve saved the Javascript file, you&#8217;ve officially created your first Espresso action!  You can immediately run the action from the Actions menu, and it will delete the current line.  If you test it out, though, you may notice that the action behaves differently when you delete the final line in the document; instead of removing the line completely, it only removes all the text.  To fix this, you could modify the action like so:</p>
<p><code>
<pre>// Deletes the current line

// require() allows you easy modular access to Spice's helper classes
var textContext = require('text_action_context').textContext;
var TextRecipe = require('text_recipe').TextRecipe;
var Range = require('range').Range;

// exports.main is your primary function, run automatically by Spice
exports.main = function() {
    // Grab the range of the current line
    var linerange = textContext.rangeForLine();
    // If on the last line of the doc, remove the line break prior to the line
    // This isn't strictly necessary, but it's nice to have
    if (textContext.lineNumber() != 1 &#038;&#038; textContext.rangeForLine(textContext.lineNumber() + 1) === false) {
        linerange = new Range(linerange.location - 1, linerange.length + 1);
    }
    // Run the actual removal
    return new TextRecipe().remove(linerange).apply();
}</pre>
<p></code></p>
<p>The only addition is some logic to check if we&#8217;re on the last line of the document, and if so create a custom <code>Range</code> object that includes the linebreak from the previous line.</p>
<h4>Debugging</h4>
<p>As you work on your own custom actions, you will of course run into problems and errors.  The best way to debug is to keep Console.app open (located in your Applications/Utilities folder), since most errors will be output there.  You can also use the globally available <code>system.log('message')</code> to output directly to the console.  Many Spice utility classes also include a <code>log()</code> method to quickly log the contents of an object.</p>
<p>When using Spice, keep in mind that it&#8217;s still under development (at the time of this writing, it&#8217;s at version 1.0 beta 6).  If you run into something that seems buggy or a limitation of the utility classes, please <a href="http://onecrayon.com/about/contact/">let me know</a>.</p>
<h4>Parting thoughts</h4>
<p>Even if you don&#8217;t use Spice, the basic strategy for adding a custom action to Espresso remains the same.  TEA offers several alternative methods to creating text actions (from Python scripts with full access to the API to scripts in arbitrary languages like Ruby or PHP that have more limited capabilities).  Although the basic editor has a nice interface and some great features, I&#8217;ve found that the extensibility of Espresso is what keeps me coming back for more.  A modicum of effort is often all that&#8217;s required to add a custom text action, so there&#8217;s little excuse for not giving it a try if you find yourself missing functionality you&#8217;ve grown used to in other editors.</p>
<p>If you do write any great custom actions, please think about sharing them either via a Sugar, GitHub, or the Espresso forums!  I&#8217;d also love to hear how people are using Spice; I&#8217;m still planning out the additions I want to make now that I&#8217;ve got most of the basic Espresso API for text actions covered by the utility classes, so your input is extremely valuable.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/goWII1wNOSQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2010/01/espresso_actions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2010/01/espresso_actions/</feedburner:origLink></item>
		<item>
		<title>When the formula falters</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/Q1dcmKsO2ms/</link>
		<comments>https://ianbeck.webfactional.com/2009/12/formula_falters/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 15:58:45 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[movies]]></category>
		<category><![CDATA[opinions]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=346</guid>
		<description>My girlfriend and I went to see The Princess and the Frog last night, and it was fun.  Not great, but fun.  Unfortunately Disney has managed to capture the spectacle but little of the soul of past great Disney movies (which is mildly ironic, given the movie&amp;#8217;s setting).  The Princess and the [...]</description>
			<content:encoded><![CDATA[<p>My girlfriend and I went to see The Princess and the Frog last night, and it was fun.  Not great, but fun.  Unfortunately Disney has managed to capture the spectacle but little of the soul of past great Disney movies (which is mildly ironic, given the movie&#8217;s setting).  The Princess and the Frog was exquisitely executed (beautiful animation, great voice acting and characters, high-energy music) but something was missing, a core component that left the movie feeling ever so slightly flat.</p>
<p>My first inclination, comparing the film with my Disney favorites Little Mermaid, Beauty and the Beast, and Aladdin was that Princess and the Frog had used those prior movies as a formula and that was what was jarring.  Upon further thought, though, I realized that the use of a formula wasn&#8217;t the problem; I&#8217;d never noticed before Princess and the Frog made me think about it, but Little Mermaid, Beauty and the Beast, and Aladdin follow strict formulas themselves.  Heck, they&#8217;re practically the same movie:</p>
<ul>
<li>The movie opens, and shortly after introducing the main characters our heroine (or hero, but most of them are female for this particular sampling so for simplicity I&#8217;ll stick with the feminine) is brought to the villain&#8217;s attention.  The villain reveals that the heroine has something that makes them uniquely important to the villain&#8217;s personal goals (Ariel is the key to Triton&#8217;s power, Belle is the only girl worthy of conquest, Aladdin is the only one who can gain the power of the lamp)</li>
<li>Early on, our heroine reveals their core motivation via song (Part of Your World, Belle&#8217;s opening song, One Jump Ahead)</li>
<li>A spectacular musical number reawakens our interest (Under the Sea, Be Our Guest, Friend Like Me)</li>
<li>At some point, the villain has a lone musical number, partially spoken or otherwise not as melodic and memorable (Gaston&#8217;s song being something of an exception, likely because he&#8217;s more of a passive antagonist otherwise so they had to compensate somewhere to make him interesting)</li>
<li>Various filler songs occur here and there, typically to advance the plot</li>
<li>A love song occurs at the primary moment one (or both) of the love interests realize their feelings (or otherwise reach a turning point in their relationship)</li>
<li>A showdown occurs with the villain, the heroine triumphs, and the culmination of their triumph is the marriage to the love interest and achievement of their dreams</li>
</ul>
<p>You can break the formula down even further past the musical numbers to specific characters (villain&#8217;s humorous sidekick, heroine&#8217;s non-human helpers, etc.), but you get the idea.</p>
<p>It wasn&#8217;t that The Princess and the Frog followed a formula, then, that impaired the movie.  In point of fact, the way it nails almost every aspect of the Little Mermaid/etc. formula may well be its greatest strength.  Disney obviously brought a lot of budget and creativity to bear to bring the movie to life in the same vein as their old hits (even making the comparison explicitly in their previews, which is what cued me into comparing the two as I was watching it).  Yet unlike Little Mermaid or Aladdin I didn&#8217;t walk out of the theater wanting to see it again, or utterly captivated by the characters, or excited and eager to tell my friends about the movie.  I came out of the theater and thought, &#8220;Well, that was fun.  Don&#8217;t really need to see it again.&#8221;</p>
<p>I&#8217;ve been pondering, and come to the conclusion that what the Disney movies of the early 90&#8217;s that I remember so fondly had that Princess and the Frog lacks is the spark, the soul, the story that needs desperately to be told.  Without that inspiration, the formula falters, the pieces pull slightly apart, and the viewer is left with the realization that there <em>is</em> a formula and that it isn&#8217;t quite working.</p>
<p>Great movies happen because creative people get excited, and if they&#8217;re lucky they have the budget and direction they&#8217;ll need to create something fantastic.  I think that people got excited about Princess and the Frog, but I don&#8217;t think that it was because of the story that drives the entire project forward.  I think they got excited about the spectacle, the fun characters, and the setting.  And in the end, that made the difference between a film destined to be a classic and one that is merely diverting.</p>
<p>The more near misses I see in the theater the more I&#8217;ve come to believe that story is the driving creative force that must exist for any narrative work to succeed, be it cinema, literature, or otherwise.  Certainly, great characters are a part of the puzzle.  A well-tested formula can help clarify and ease the story&#8217;s delivery.  Talented people well directed can breathe a lot of life into any tale.  But unless these things are born out of a story that needs to be told the pieces won&#8217;t quite snap into place.</p>
<p>The Princess and the Frog is not a story that needed to be told.  It&#8217;s a decent story, an amusing story, a story that pleasantly reinforces our own delusions about ourself and our culture; but it isn&#8217;t a story that needs its telling so badly that it grabs the imaginations of its makers and viewers alike and refuses to let go even once the curtain has closed.</p>
<p>I don&#8217;t know where stories come from, or even how crafted and calculated the Disney movies of yore that I loved might have been behind the scenes.  All I know is that in Princess and the Frog Disney has produced a film that sparkles, amuses, and tweaks gently at the heartstrings yet fails to achieve the vivid life bequeathed by story.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/Q1dcmKsO2ms" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/12/formula_falters/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/12/formula_falters/</feedburner:origLink></item>
		<item>
		<title>Wrap Selection In Link in any program on Mac OS 10.6</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/6f64FmIzpZ4/</link>
		<comments>https://ianbeck.webfactional.com/2009/11/wrap_in_link_mac/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 20:28:27 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[custom solution]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=344</guid>
		<description>The Mac OS X Services menu got a serious bit of love for 10.6, but until now I haven&amp;#8217;t really played around with it.  Today, however, I finally got around to trying it out, and for the first time since I started using OS X years ago, Services are actually becoming useful for me.
The [...]</description>
			<content:encoded><![CDATA[<p>The Mac OS X Services menu got a serious bit of love for 10.6, but until now I haven&#8217;t really played around with it.  Today, however, I finally got around to trying it out, and for the first time since I started using OS X years ago, Services are actually becoming useful for me.</p>
<p>The specific need I wanted to address was my inability to easily insert some common HTML elements (particularly links) in <a href="http://www.hogbaysoftware.com/products/writeroom">WriteRoom</a>.  I&#8217;ve owned WriteRoom for years thanks to a software bundle, but I never had any use for it until I discovered <a href="http://www.hogbaysoftware.com/products/quickcursor/">QuickCursor</a>.  Now I can&#8217;t get enough of it; full screen editing for text fields in Safari is brilliant.</p>
<p>The only thing I haven&#8217;t been happy about was needing to type out every blessed character when I needed light HTML. Although WriteRoom&#8217;s Applescript support does not apparently provide access to selected text, the new Services menu does.</p>
<p>To add HTML link insertion to WriteRoom (or any other text editor that supports Services, for that matter) first boot up Automator and create a new Service workflow:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/11/service_workflow.jpg" alt="service_workflow.jpg" /></p>
<p>By default, Automator will have you processing selected text in any application.  Check the &#8220;Replaces selected text&#8221; checkbox, and if you&#8217;re only going to be using the action in WriteRoom (or similar application) make sure to use the dropdown to target that app and avoid cluttering up your Services menu:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/11/service_config.jpg" alt="service_config.jpg" /></p>
<p>Over at the top right, type &#8220;Applescript&#8221; in the search box to filter the list for the &#8220;Run Applescript&#8221; action (make sure you have the Library highlighted, or it may not show up).  Drag the action into your workflow:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/11/services_action.jpg" alt="services_action.jpg" /></p>
<p>Select everything in the text box, and replace it with this:</p>
<p><code>
<pre>on run {input, parameters}
    set linkDefault to (the clipboard as string)
    set linkDefault to my switchText(linkDefault, "\\\"", "\"")
    set targetLink to do shell script "echo \"" &#038; linkDefault &#038; "\"|sed -E \"s/(mailto:)?(.+@.+\\..+)/mailto:\\2/\""
    if targetLink does not start with "mailto:" then
        set targetLink to do shell script "echo \"" &#038; linkDefault &#038; "\"|sed -E \"s/^(([a-zA-Z0-9-]+\\.)*[a-zA-Z0-9-]+\\.[a-zA-Z]{2,4}(\\/.*)?)/http:\\/\\/\\1/\""
        if targetLink does not start with "http" then
            set targetLink to "http://"
        end if
    end if

    return "&lt;a href=\"" &#038; targetLink &#038; "\"&gt;" &#038; input &#038; "&lt;/a&gt;"
end run

on switchText(fromText, targetText, replaceText)
    set d to text item delimiters
    set text item delimiters to replaceText
    set fromText to fromText's text items
    set text item delimiters to targetText
    tell fromText to set fromText to item 1 &#038; ({""} &#038; rest)
    set text item delimiters to d
    return fromText
end switchText</pre>
<p></code></p>
<p>Save your workflow, and you&#8217;re basically done!  When you select some text in WriteRoom or elsewhere and run the action from the Services menu, it will wrap the text with a link.  It also will check the clipboard to see if there&#8217;s a recognizable email address or URL on it, and if so will use it for the link (otherwise defaults to <code>http://</code>).</p>
<p>For maximum productivity benefits, of course, you&#8217;ll want to visit the System Preferences Keyboard pane and give your new Service action a shortcut; I&#8217;m using <code>control-shift-L</code> since that&#8217;s what I&#8217;m used to from Textmate and Espresso.</p>
<p>Worth noting is the fact that the above Applescript doesn&#8217;t display a dialog box to query you for a URL if it can&#8217;t detect one on the clipboard, so for maximum effect you&#8217;ll want to copy your target URL prior to running the action if possible.  The reason for this minor problem is that the dialogs spawned by my Service action never received focus, and for myself mousing over to give the dialog focus is more work than option arrowing a few times to edit the default URL.</p>
<p>You can, of course, add simple Service actions to surround text in other arbitrary HTML tags, as well.  Simply use an Applescript similar to this instead:</p>
<p><code>
<pre>on run {input, parameters}
	return "&lt;strong&gt;" &#038; input &#038; "&lt;/strong&gt;"
end run</pre>
<p></code></p>
<p>The only major downside that I&#8217;ve found of using Services this way is that it isn&#8217;t as quick as I&#8217;d like. I experimented with using shell scripts or Python instead of Applescript, but there were no significant speed boosts; as best I can tell, however Services is harvesting the selected text and then replacing it afterward is simply a slow process.</p>
<p>I&#8217;d love to hear how other people are leveraging the new 10.6 Services menu! I have the feeling that I&#8217;m just scratching the surface with this script.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/6f64FmIzpZ4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/11/wrap_in_link_mac/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/11/wrap_in_link_mac/</feedburner:origLink></item>
		<item>
		<title>Comparing StoryMill and Scrivener</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/oBkHW-qPeT8/</link>
		<comments>https://ianbeck.webfactional.com/2009/10/storymill_and_scrivener/#comments</comments>
		<pubDate>Sat, 31 Oct 2009 15:38:39 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[opinions]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=337</guid>
		<description>I&amp;#8217;m a long-time user of StoryMill (starting when it was originally called Avenir), but I&amp;#8217;m also something of a software junkie, so when Scrivener came out I tried using it for a few projects.  Particularly now that StoryMill has a timeline view (as of this writing the only Mac creative writing software to implement [...]</description>
			<content:encoded><![CDATA[<p>I&#8217;m a long-time user of <a href="http://www.marinersoftware.com/sitepage.php?page=127">StoryMill</a> (starting when it was originally called Avenir), but I&#8217;m also something of a software junkie, so when <a href="http://www.literatureandlatte.com/scrivener.html">Scrivener</a> came out I tried using it for a few projects.  Particularly now that StoryMill has a timeline view (as of this writing the only Mac creative writing software to implement the feature) and Mariner Software is distributing it, it seems like a more and more people are wondering whether they should use StoryMill or Scrivener.</p>
<p>Well, here it is: my definitive StoryMill vs. Scrivener review.  Although StoryMill is my personal application of choice, there&#8217;s a lot to love (and some things to dislike) about both programs.</p>
<h4>Quick and dirty</h4>
<p>Not everyone wants to wade through my periphrastic meanderings (just discovered that word, and it&#8217;s making me really happy; sorry for sounding like a total vocab snob), so here&#8217;s the quick and dirty:</p>
<ul>
<li>If you primarily write fiction and want a program that will provide you with an easy framework for organizing your writing, you&#8217;ll probably prefer StoryMill.</li>
<li>If you primarily write non-fiction or screenplays or write fiction and want a program that will let you do pretty much whatever the hell you want workflow-wise (with a correspondingly higher level of confusion), you&#8217;ll probably prefer Scrivener.</li>
</ul>
<h4>A broader picture</h4>
<p>As is often the case, the fast and dirty comparison is a bit misleading: either program can help you write fiction or non-fiction.  The reason the fiction/non-fiction comparison is common is because StoryMill is explicitly focused on fiction (and doesn&#8217;t support screenplays at all, since that would steal sales from its companion software <a href="http://www.marinersoftware.com/sitepage.php?page=104">Montage</a>) while Scrivener provides a general writing metaphor that can apply to either genre equally well (with limited support for screenplay formatting and footnotes).</p>
<p>The truth is that regardless of your genre the deciding factor for which software to use will be a matter of style.  StoryMill&#8217;s approach is to provide you with a specific framework for writing and organizing, complemented with a focused group of powerful features.  In contrast, Scrivener is much more flexible and offers a larger number of features that you can pick and choose from to form your workflow.  You can do most of the things in Scrivener that you can in StoryMill (with a few key exceptions), but it will be slightly more effort.</p>
<p>If StoryMill&#8217;s framework makes sense to you and you don&#8217;t have an urgent need for any of the features that are Scrivener-only, then StoryMill will be the easiest environment to write in.  However, for some people the time necessary to set up their own framework in Scrivener is well worth the effort because the program&#8217;s flexibility allows them to write most effectively.</p>
<p>To figure out which style, and thus program, is the best choice for you, you&#8217;ll need to consider two big questions: what metaphors do you use for writing, and what specific features are most important for you?</p>
<h4>StoryMill: a novel framework</h4>
<p>The foundation of StoryMill&#8217;s approach to writing and organizing is the scene.  Scenes in StoryMill are the building blocks which create chapters and ultimately the story itself (it&#8217;s worth noting that you can think of scenes and chapters as whatever content blocks make sense for your story; the names don&#8217;t really limit the function).  Though you&#8217;ll track your characters, locations, and so forth elsewhere, the scenes are where you&#8217;ll tie them together.</p>
<p>StoryMill offers several other types of items like characters, locations, research, and even submission tracking for when you complete the novel, but the scenes are the core of the program.  If working with scenes makes sense to you, and you like the ability to directly relate characters to scenes and organize both in plot order and chronological order (the latter via the timeline feature), then StoryMill will likely appeal.</p>
<p>This scene-centric framework has actually taken a page from Scrivener&#8217;s book in recent updates, as well.  You can use scenes either as an outline (in the Scenes view) or as the actual text of the story (in the Chapters view).  Storing text in scenes can be a little bit confusing (particularly since you can still store text in chapters and use scenes purely for organization if you choose), but this allows you to take advantage of the outline-as-text feature that Scrivener executes with such panache.</p>
<p>StoryMill also has some specific stand-out features that influenced my decision to use it.  For me, annotations are one of the biggest.  In StoryMill, you annotate text by selecting it and choosing &#8220;Annotate&#8221;.  The text turns the standard link blue with underline, and a little window opens up in which you can type the annotation&#8217;s title (defaults to the selected text) and add your annotation.  This is great for a number of reasons:</p>
<ol>
<li>Annotated text is clearly marked, yet the annotations themselves are completely invisible unless you want to see them.</li>
<li>Annotations are rich text, so they can contain just about anything.  This includes images, formatted text, etc.</li>
<li>StoryMill handles annotations intelligently: if you open up the annotations window and start moving through the text with your cursor, the displayed annotation will update based on which linked text the cursor is in.  You can also open the annotations window for a given annotation with a hotkey (no clicking the link required).</li>
</ol>
<p>Some people prefer the margin-notes approach to annotations in Pages, Word, etc., but I find those extremely limiting because if you type more than a sentence or two they become unwieldy, it&#8217;s not always easy to tell what text the annotation applies to, and you can&#8217;t have very many on a page before they get out of control.  The only thing they have over StoryMill&#8217;s annotations is that you can view all of them at once, but in practice I&#8217;ve never found this to matter.</p>
<p>Another big draw for StoryMill is its timeline functionality.  Timelines allow you to view and organize scenes in chronological time, even if the flow of the novel is completely different.  This can be fantastically helpful for preventing plot holes and other inconsistencies, and getting a general overview of the flow of time through your novel can be useful in its own right.  The downside to timeline is that it&#8217;s still a young feature; the interface could use a little refinement and it had a bit of a rocky start thanks to some bugs, but there&#8217;s still nothing comparable out there (aside from dedicated timeline software).</p>
<p>StoryMill has numerous other small features that I can&#8217;t live without, as well: the progress meter is a one that I&#8217;ve surprisingly grown to rely on.  It visually tracks how far along you are for both your session and project word goals.  It also can emit a sound when you hit your session goal, which is really nice feedback if you&#8217;re working in full screen.  Full screen is of course another great feature, although one that&#8217;s available in most writing software these days.  The reason I like StoryMill&#8217;s better than Scrivener&#8217;s is that it&#8217;s truly nothing but you and your writing; no annotations, no floating windows, nothing but the text.  Tags and smart views, export templates, and the project-wide find and replace dialog are other reasons to love StoryMill.</p>
<h4>Scrivener: your digital corkboard</h4>
<p>Scrivener takes a slightly different approach to the writing process.  Where StoryMill provides a framework with carefully designed parts, Scrivener offers the user a beautifully executed corkboard metaphor and then hangs potentially useful features around it.</p>
<p>Scrivener&#8217;s corkboard is where it really shines.  The connection between outline, visual organization of &#8220;index cards&#8221;, and your actual text is simple, sensible, and flexible enough to handle virtually any kind of writing.  Want to break things down into beats, then scenes, then chapters, then acts?  Go for it.  Your only real limit is your creativity.  Scrivener&#8217;s central metaphor additionally captures in a digital format a way of working that instantly makes sense to most people who have written by hand.  This is a definite strength over StoryMill, which takes a more relational database-driven approach to organization and writing that may not be as easy to initially access for some people.</p>
<p>Aside from its elegant central metaphor, Scrivener also offers a slew of useful features.  I encourage you to check out the Scrivener website and free trial to figure out which ones you&#8217;ll care about, but the primary things of interest to me are snapshots (saving multiple versions of a single piece of text), wiki-style links to internal documents, the vastly flexible exporting system, and the simple script-writing formatting tools.</p>
<p>It&#8217;s worth taking a moment to dwell on snapshots.  Although StoryMill is planning to implement similar functionality for their next version, this is a key area where Scrivener is clearly the better choice.  Organizing multiple revisions of the same text in StoryMill is extremely kludgy at the current time, while Scrivener handles it with ease.</p>
<p>Additionally, you can (with a little bit of work) mimic some of StoryMill&#8217;s strengths in Scrivener.  For instance, the Document References could be used to associate characters with scenes.  You can also mimic StoryMill&#8217;s annotations to some extent using wiki-links that open in split views (Scrivener&#8217;s built-in annotations are inline with the text, making them only useful for very short notes to yourself that you don&#8217;t mind reading every time you go back over things).  They&#8217;re not as easy to use as StoryMill annotations, sure, but this kind of flexibility is another of Scrivener&#8217;s strengths.  The menus may be confusing and (to my eye) bloated, but all those disparate features mean that with a little work you can achieve numerous different workflows.</p>
<h4>Beyond the software</h4>
<p>Of course, there&#8217;s more to writing than just the software itself.  Both Scrivener and StoryMill have healthy communities and refreshingly responsive developers.  Scrivener has a larger community (and one more inclined to chat about whatever the heck is on their minds), but you may get a faster response in StoryMill&#8217;s forums simply because there aren&#8217;t as many threads.  Your mileage will doubtless vary, but I highly suggest dropping by the forums for whichever software you&#8217;re leaning toward and asking any questions you have.</p>
<p>An additional concern is interoperability between your writing software and other software on your computer.  Both Scrivener and StoryMill store data in proprietary formats but both also offer flexible ways to export that data.  Which export system you like better will probably depend a lot on what you need to export, but both allow you to get all of your data out of the program without much fuss.  If you&#8217;re trying either software&#8217;s free trial, definitely play with the export system before purchasing it.</p>
<p>Scrivener additionally allows easy editing of text in external programs, which can be nice if you like editing text in WriteRoom, BBEdit, or similar.</p>
<h4>Time to write</h4>
<p>Both StoryMill and Scrivener were created because the developers couldn&#8217;t find a tool that fit their respective needs as authors, and the bottom line for any potential user is you should use whichever program makes it easiest for you to write.</p>
<p>For myself, that program is StoryMill.  Its framework makes sense to me and I&#8217;ve become addicted to its overall slimmed-down focus on the features that matter most (not to mention some specific niceties like rich annotations and timelines).</p>
<p>I can certainly appreciate the draw of Scrivener, however.  Every time I open it I&#8217;m amazed anew at how simple and relevant a metaphor for writing it provides.  StoryMill&#8217;s niggling issues with the separation between outline and text are nonexistent in Scrivener thanks to its solid basis in the idea of a corkboard.  Sure, to get the kind of interconnectivity that StoryMill encourages you have to do a bit more work, but with Scrivener&#8217;s large and helpful community figuring out a document layout and workflow shouldn&#8217;t be too painful.</p>
<p>Ironically, in a few short years we&#8217;ve gone from having no great alternative writing environments to Word and the other word processors to having a difficult choice between two strong contenders (and that&#8217;s discounting the scads of similar but less popular software like <a href="http://bartastechnologies.com/products/copywrite/">CopyWrite</a>, <a href="http://www.jerssoftwarehut.com/AboutJNW.shtml">Jer&#8217;s Novel Writer</a>, <a href="http://www.storyist.com/">Storyist</a>, or <a href="http://www.the-soulmen.com/ulysses/">Ulysses</a>, the program that started it all); no choice has exploded into too much choice.  Hopefully by focusing on which general approach and specific features are most helpful for your workflow you&#8217;ll be able to select the best software for you and get on to what&#8217;s really important: your writing.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/oBkHW-qPeT8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/10/storymill_and_scrivener/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/10/storymill_and_scrivener/</feedburner:origLink></item>
		<item>
		<title>StoryMill and NaNoWriMo</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/uITl-UBhvA8/</link>
		<comments>https://ianbeck.webfactional.com/2009/10/storymill_nanowrimo/#comments</comments>
		<pubDate>Sat, 31 Oct 2009 05:30:48 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[opinions]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=335</guid>
		<description>Although I find my current work as a web designer interesting and occasionally fulfilling, it is not what I want to do the rest of my life.  Since I was a snot-nosed kid in fifth grade, I have instead set my sites on being a novelist.  I know that I&amp;#8217;m capable of writing [...]</description>
			<content:encoded><![CDATA[<p>Although I find my current work as a web designer interesting and occasionally fulfilling, it is not what I want to do the rest of my life.  Since I was a snot-nosed kid in fifth grade, I have instead set my sites on being a novelist.  I know that I&#8217;m capable of writing a novel (learned that thanks to my senior thesis), but up until now my writing has been very haphazard.  I&#8217;ll write on vacations (sometimes) or when the mood strikes, but anyone who has tried to write a novel knows that you&#8217;ll never get anything done doing that.  To write a longer work, writing has to be a habit, and I&#8217;ve been finding it a difficult habit to form.</p>
<p>So this year, I&#8217;ve decided to finally jump on the <a href="http://www.nanowrimo.org/">National Novel Writing Month</a> (NaNoWriMo) bandwagon in the hopes that the experience will help me settle into some good writing habits, like writing every morning instead of poking around listlessly online.  I will, of course, be writing in <a href="http://www.marinersoftware.com/sitepage.php?page=127">StoryMill</a> because I can&#8217;t fathom writing in any other software (and yes, I&#8217;ve tried pretty much all of the ones available for Mac).</p>
<p>But upon opening StoryMill and prepping a new document for the fast upcoming November 1st, I realized that my typical approach to writing in StoryMill simply isn&#8217;t going to work for NaNoWriMo.  In order to finish 50,000 words in 30 days, on top of a full time job and other distractions, I&#8217;m going to need to write, write, write.  Outlining, character backstory, notes on locations, research&mdash;all of these will be distractions that could well prevent me from reaching the goal, and yet all of these things are tasks that I regularly undertake in StoryMill.  In fact, the program encourages it; take a look at its default novel document:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/10/sm_default_doc.jpg" alt="StoryMill's default document setup" /></p>
<p>This is no good at all.  Keeping track of characters, scenes, etc. is certainly useful, but I&#8217;m going for pure word output, and if the option to procrastinate by expanding on my backstory is available, I&#8217;ll probably take it.  So to start, I decided to axe absolutely everything except the generic Tasks view, which I renamed to Notes (to delete and rename these items right click a view in the sidebar and choose Manage Views; then when you&#8217;re done, right click the smart view and choose Remove View):</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/10/sm_slimmed_down.jpg" alt="sm_slimmed_down.jpg" /></p>
<p>I can add those views back in when it comes time to clean things up, and in the meantime I can drop any notes on backstory or whatever into the Notes view as I think of them without feeling any pressure to expand on the ideas.  Will my story have more plot holes and inconsistencies than if I&#8217;d left those views in?  Doubtless.  But darn it, I want to win NaNoWriMo!  I cannot afford distractions.</p>
<p><img class="right" src="http://beckism.com/wp-content/uploads/2009/10/sm_chapter_naming.jpg" alt="sm_chapter_naming.jpg" />Next up, I took a look at the chapters view.  I definitely am going to want to write my text in Chapters (the chapters editing window, which you can get to by double clicking a chapter title in the list area, offers numerous incentives like highlighting and annotations that aren&#8217;t as easy to use in other views).  However, worrying about where my chapter breaks fall is going to slow me down and distract me yet again.  I suppose I could just write in a single long chapter, but it would get difficult to manage quickly.  Instead, I think I&#8217;ll add a new chapter every day.  That way I can not only see how many words I was able to write in retrospect (which could be useful info), but I&#8217;ll have the story broken up into easily skimmable chunks if I need to go back over it to remember someone&#8217;s name or whatever.</p>
<p>Just to prevent any temptation, I also right-clicked on the Timeline button in the toolbar and chose &#8220;Remove Item&#8221;.  Sure, it would never have been activated because I don&#8217;t have a scenes view, but the temptation to add a scenes view would be there.</p>
<p>Last, but certainly not least, I double clicked the Progress Meter and set my goals appropriately:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/10/sm_progress.jpg" alt="sm_progress.jpg" /></p>
<p>And with that, I&#8217;m ready to start writing, as distraction-free as I&#8217;m likely to get.  I&#8217;m sure this system won&#8217;t work for everyone (heck, it might not even work for me; I&#8217;ve yet to test it out), but my hope is that by slimming down StoryMill to the bare essentials I&#8217;ll be able to get my first draft in there as part of reaching the NaNoWriMo goal of 50,000 words, and then I&#8217;ll be able to add features like the scenes view, characters, and locations back when I get ready to revise so that I can start cleaning up plot holes and putting a little more thought into the novel.  Plus, needing to copy and paste all of my text into scenes will be an excellent excuse to read over it all as part of my revision efforts, anyway.</p>
<p>For other NaNoWriMo participants planning to use StoryMill, here&#8217;s a few generic tips to help you out:</p>
<ul>
<li>Full screen will likely be your best friend.  You can enter full screen quickly from just about any part of the program by hitting command-option-F.  Exit full screen by hitting escape.</li>
<li>As I mentioned above, the Chapters window is probably the best editing experience in StoryMill (aside from full screen).  Double click a chapter in the list or sidebar to see what I mean.</li>
<li>If you&#8217;re using a slimmed-down project like I will, you&#8217;ll probably also want to avoid spending much time adding tags to things.  However, if you drop something in the Notes view it would be a good idea to toss a couple quick tags on it to make sorting through things later easier.  For instance, a note about a character could get a &#8220;character&#8221; tag.  Then when it comes time to add the characters view back in you can make a smart view based on notes to filter for all character items and hit the ground running.</li>
</ul>
<p>Good luck to the other NaNoWriMo participants!</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/uITl-UBhvA8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/10/storymill_nanowrimo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/10/storymill_nanowrimo/</feedburner:origLink></item>
		<item>
		<title>I am crap at networking</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/ReMsI8nCTLU/</link>
		<comments>https://ianbeck.webfactional.com/2009/10/crap_at_networking/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 02:51:53 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[personal]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=329</guid>
		<description>I went to the ExpressionEngine Roadshow today where I learned a couple things, was disgusted with EllisLab for their cop-out non-presentation, and awkwardly stood alone in the corner (or, worse, the center of the room) between speeches while people around me did this thing called &amp;#8220;networking&amp;#8221;.
I am such crap at networking.  I&amp;#8217;ve only attended [...]</description>
			<content:encoded><![CDATA[<p>I went to the <a href="http://www.eeroadshow.com/">ExpressionEngine Roadshow</a> today where I learned a couple things, was disgusted with EllisLab for their cop-out non-presentation, and awkwardly stood alone in the corner (or, worse, the center of the room) between speeches while people around me did this thing called &#8220;networking&#8221;.</p>
<p>I am such crap at networking.  I&#8217;ve only attended two conferences so far (An Event Apart and EE Roadshow), but at both I came to the conclusion that the presentations aren&#8217;t what the thing&#8217;s about.  Both times only about half of the presentations were remotely worthwhile, while the others were either senseless cruft or so bogged down by the speaker&#8217;s fear of public speaking and/or inability to write coherently that by the end I just wanted to bang my head into the nearest wall a few times.  Clearly we aren&#8217;t here because web developers are charismatic individuals with a flair for speech-writing.</p>
<p>So I can only assume that it&#8217;s the times in between, the meal times and parties, that people find the real value.  Those times when you&#8217;re expected to wander around, get to know your fellow developers, swap business cards, and talk shop.</p>
<p>Sadly for me, I have no interest in approaching complete strangers and introducing myself.  I&#8217;ve never had this inclination, which is something that puzzles me.  Engage me in conversation, and you&#8217;ll find I&#8217;m not socially awkward: I am, in fact, an intelligent individual with a good sense of humor who loves interacting with people.  Observe me with a group of my friends or family, and you may think me highly extroverted.  Yet drop me in a room full of strangers, and I clam up instantly.  I know these people are passionate about the same things I&#8217;m passionate about, but unless one of them seeks me out I find it hard to think of things to talk about.</p>
<p>I was thinking about this on the bus ride home (I left early, having deduced from fifteen minutes standing around alone that I wasn&#8217;t going to get anything out of the after-party, particularly since I don&#8217;t drink and thus could not take advantage of the free alcohol), and I&#8217;ve finally realized the problem: I&#8217;m a presenter.  A performer.  I&#8217;m damn good at giving a speech and then talking to people about it afterward, but no good at being just another member of the audience, milling around and networking.</p>
<p>Problem being, of course, that in both the EE community and the web development community as a whole, I&#8217;m a nobody.  I haven&#8217;t written any books, or published any extensions, or been hired by Happy Cog so it&#8217;s unlikely anyone is going to invite me to speak anytime soon.</p>
<p>Guess it&#8217;s time to either start the difficult personal work necessary to overcome my awkwardness at initiating social encounters or start submitting topic proposals to my favorite web conference organizers.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/ReMsI8nCTLU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/10/crap_at_networking/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/10/crap_at_networking/</feedburner:origLink></item>
		<item>
		<title>Cinnamon rolls (in five minutes a day)</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/f9jtDwcx9OI/</link>
		<comments>https://ianbeck.webfactional.com/2009/09/cinnamon_rolls/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 05:00:10 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[food]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=327</guid>
		<description>Ever since I was a kid, I&amp;#8217;ve loved cinnamon rolls.  I remember a particularly glorious few days when my family went to visit my aunt and uncle and discovered that their son was working for Cinnabon that summer.  Every evening he&amp;#8217;d bring home left-over Cinnabons and my father and I would eat ourselves [...]</description>
			<content:encoded><![CDATA[<p>Ever since I was a kid, I&#8217;ve loved cinnamon rolls.  I remember a particularly glorious few days when my family went to visit my aunt and uncle and discovered that their son was working for Cinnabon that summer.  Every evening he&#8217;d bring home left-over Cinnabons and my father and I would eat ourselves sick.  Apparently love of gooey cinnamon pastries runs in the blood.</p>
<p>Despite my love affair with cinnamon rolls, however, I have never had the courage to experiment with them before.  In part, it&#8217;s because yeast scares me (my early experiences with yeast bakes turned out poorly, to say the least).  Mainly, it&#8217;s that I&#8217;ve never really had homemade cinnamon rolls that consistently turned out well.  Mom would make them occasionally, but they were hit and miss; sometimes delicious, other times passable.</p>
<p>Fortunately for me, and unfortunately for my cholesterol levels, I have at last braved the cinnamon roll and discovered something wonderful: I make damn fine cinnamon rolls, and they&#8217;re really, really easy.</p>
<p>Like most of my recent excursions into yeast bakes, my cinnamon rolls start with <a href="http://www.artisanbreadinfive.com/">Artisan Bread in Five Minutes a Day</a> (available via <a href="http://www.amazon.com/dp/0312362919/?tag=beckism-20">Amazon</a> or on <a href="http://www.amazon.com/dp/B001TOCAZO/?tag=beckism-20">Kindle</a>).  I cannot recommend this book highly enough; it is a brilliant introduction to bread baking that makes the task not only easy but quick.  Like any baking, it takes a couple tries to figure out exactly how things work, but although my first attempts at recipes and doughs typically don&#8217;t end up quite like I planned, I&#8217;ve only had a single total disaster (my first attempt at naan was carbonized thanks to following the book&#8217;s instructions to heat the skillet on high prior to cooking the bread).  If you&#8217;ve tried and been frustrated with yeast baking before, you&#8217;ll understand what an astonishing track record that is for a beginning baker.</p>
<p>If you have any interest in making fresh bread, go buy the book.  You&#8217;ll need it to make cinnamon rolls my way, anyway, because they rely on the dough recipes and preparation methods that are the core of the book.  Specifically, Artisan Bread in Five provides a Caramel Sticky Buns recipe on page 187, which will be your starting point.  The key is instead of the rigamarole of coating the bottom of the pan and turning things upside down once you finish baking, etc. you&#8217;ll want to use this easy cinnamon filling:</p>
<p><strong>Cinnamon filling</strong><br />
1 cup packed brown sugar<br />
2 1/2 tablespoons ground cinnamon</p>
<p>Mix the brown sugar and the cinnamon together.  You&#8217;ll have enough for 2-3 batches of cinnamon rolls (depending on how liberal you are with the sugar and how large you make the cinnamon rolls), so store it in a tupperware or similarly air-tight container for later.</p>
<p>After you&#8217;ve rolled the dough out into a rectangle as per the sticky bun recipe, spread all of it except for 1/2-1 inch around the edges with softened butter.  I&#8217;m usually a bit more liberal with the butter if I&#8217;m using the master recipe, but particularly if you&#8217;re using brioche dough (which makes the richest, most desert-like cinnamon rolls) you&#8217;ll want to be a bit conservative with the butter.  You just need enough to coat the dough with a thin layer.</p>
<p>Once you&#8217;ve spread the butter, sprinkle it liberally with the cinnamon-sugar mixture.  You want to have enough cinnamon-sugar that you can&#8217;t see any dough or butter peeking through (except for the strip around the edge of the dough, of course).  If you&#8217;re particularly liberal with the cinnamon-sugar, you&#8217;ll likely end up with a sticky goo at the bottom of the rolls similar to the stuff you&#8217;d find in a Cinnabon.  Use a little less, and you&#8217;ll have a more subtly-flavored rolls that&#8217;s a bit cleaner to eat.</p>
<p>Roll and cut the dough as per the sticky bun recipe.  I usually use a greased 9&#215;9 glass pan, and always end up with nine rolls (counting the two end ones) each about 1-2 inches high.  You can, of course, make more or less depending on how much dough you&#8217;ve got and the size of your pan.  Place the rolls in the pan with a little bit of room between each one (they&#8217;ll spread out as they rise), and cover lightly with plastic wrap.</p>
<p>Whether the rolls rise or not will depend on the temperature of your kitchen.  I often need to place a second 9&#215;9 pan filled with hot water under the one with the rolls for 20-40 minutes of the rising time, since my kitchen tends to be cooler.  Ideally, the rolls should rise upwards and outwards both, so that they are just touching their neighbors.</p>
<p>Bake according to the sticky buns recipe, about 40 minutes.  Baking time will fluctuate depending on how large your rolls are, so start peeking around 30 minutes.  Serve warm, preferably with some icing (I leave it to you to find a good icing recipe online; we typically just mix some powdered sugar with water and drizzle it over the warm rolls).</p>
<p>I&#8217;ve tried using brioche dough and the master recipe both, and the cinnamon rolls turn out great either way.  As you would expect, the brioche-based rolls are richer and more buttery, while the dough of the master recipe rolls takes more of a backseat to the filling.  I&#8217;m itching to try the challah dough because it&#8217;s in between the two as far as eggs and butter content goes.</p>
<p>The only downside to this recipe is that it takes roughly two hours from when you decide to make cinnamon rolls and when they&#8217;re ready to eat, thanks to the rising and baking time (even if it&#8217;s passive time, it still makes it hard to make cinnamon rolls for breakfast before work).  If anyone has any ideas for how to prep the rolls in the evening and have them ready to bake in the morning, I would love to hear them.</p>
<p>Even if I never find a way to cut down on the rising and baking time, though, needing to think ahead two hours is a miniscule price to pay considering that the payout is a dish that has warmed, comforted, and delighted me since childhood.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/f9jtDwcx9OI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/09/cinnamon_rolls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/09/cinnamon_rolls/</feedburner:origLink></item>
		<item>
		<title>One Crayon redesigned</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/ZAXXDglnTcc/</link>
		<comments>https://ianbeck.webfactional.com/2009/09/onecrayon_redesign/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 20:21:21 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Adversaria]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[personal]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=324</guid>
		<description>After working on it for the past couple months, I&amp;#8217;m very happy to announce that my freelancing site, One Crayon, has been redesigned from the ground up.
One Crayon now looks several orders of magnitude better than its original design; offers information and documentation for TEA for Espresso, TEA for Coda, and my other projects in [...]</description>
			<content:encoded><![CDATA[<p>After working on it for the past couple months, I&#8217;m very happy to announce that my freelancing site, <a href="http://onecrayon.com/">One Crayon</a>, has been redesigned from the ground up.</p>
<p>One Crayon now looks several orders of magnitude better than its original design; offers information and documentation for <a href="http://onecrayon.com/tea/">TEA for Espresso</a>, <a href="http://onecrayon.com/tea/coda/">TEA for Coda</a>, and my <a href="http://onecrayon.com/products/">other projects</a> in a single unified location; and offers numerous other improvements like a <a href="http://feeds.feedburner.com/onecrayon/">news feed</a> for keeping up to date with general One Crayon news and updates to my various software projects.</p>
<p>I&#8217;m not actively seeking freelance work thanks to a busy full time schedule, but I&#8217;ve been wanting to revitalize One Crayon for a while, not least because I wanted to start migrating some of my sites over to ExpressionEngine and One Crayon seemed like a good place to start.</p>
<p>There are still some rough edges (I&#8217;m looking at you, IE 6) and I haven&#8217;t added my website or writing portfolios, but I hope you&#8217;ll enjoy it anyway!</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/ZAXXDglnTcc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/09/onecrayon_redesign/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/09/onecrayon_redesign/</feedburner:origLink></item>
		<item>
		<title>Text Editor Actions for Espresso</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/YxExo7VYMoI/</link>
		<comments>https://ianbeck.webfactional.com/2009/09/tea_for_espresso/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 00:49:38 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[custom solution]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=319</guid>
		<description>I am extremely happy to announce that my Text Editor Actions for Espresso (or &amp;#8220;TEA&amp;#8221; for short) has at last been released as version 1.0.  Version 1.0 is available for download, or you&amp;#8217;ll also find it bundled in the upcoming Espresso 1.0.7.
So just what the heck is TEA for Espresso?  Simply this:

A selection [...]</description>
			<content:encoded><![CDATA[<p>I am extremely happy to announce that my Text Editor Actions for Espresso (or &#8220;TEA&#8221; for short) has at last been released as version 1.0.  Version 1.0 is <a href="http://github.com/onecrayon/tea-for-espresso/downloads">available for download</a>, or you&#8217;ll also find it bundled in the upcoming Espresso 1.0.7.</p>
<p>So just what the heck is TEA for Espresso?  Simply this:</p>
<ol>
<li>A selection of my favorite text actions, mostly (but not entirely) copied from Textmate</li>
<li>Generic actions that allow you to create variations on TEA&#8217;s bundled functionality to suit your workflow by editing simple XML</li>
<li>A general framework for coding and running text actions in arbitrary languages without needing to create a Sugar or (for third party Sugars) without needing compiled Objective-C classes</li>
</ol>
<p>Espresso&#8217;s Sugar API was already pretty sweet.  TEA makes it that much better by lowering the barrier to creating custom text actions for users and Sugar developers alike.</p>
<p>Documentation for TEA is currently limited to <a href="http://wiki.github.com/onecrayon/tea-for-espresso">info on creating your own actions</a>, so I&#8217;ll walk you through the basic actions included with the plugin.</p>
<p>The vast majority of TEA&#8217;s built-in actions focus on making HTML easier to edit, because editing HTML is most often why I need a text editor.</p>
<h4>Generic text actions</h4>
<p><strong>Spaces To Tabs&#8230;</strong> and <strong>Tabs To Spaces&#8230;</strong><br />
As you might expect, these actions convert the type of indentation in your document or (if it exists) your selected text.  When you run the actions you&#8217;ll be prompted to enter the number of spaces per tabs you wish to use (it defaults to whatever is in your Espresso preferences, so you can just hit enter most of the time).</p>
<p><strong>Trim Line(s)</strong><br />
Trim Line(s) will, when invoked, either trim all of the lines in your selection or the current line the cursor is on (if no selection exists).  Unlike some trim lines actions, TEA&#8217;s Trim Line(s) attempts to be smart about what whitespace it removes:</p>
<ul>
<li>All whitespace at the end of the line will be stripped</li>
<li>Any whitespace at the beginning of the line that isn&#8217;t part of the indentation will be stripped</li>
</ul>
<p>What the latter means is that if in the Espresso preferences you have the program set to use spaces instead of tabs with four spaces per tab, and the beginning of a line has ten spaces, two of the spaces will be stripped.</p>
<p><strong>Select &rarr; Word</strong>, <strong>Select &rarr; Line</strong>, <strong>Select &rarr; Line Contents</strong><br />
As you might expect, these actions select the word under the cursor, the line under the cursor (including leading and trailing whitespace), or the textual contents of the line under the cursor (excluding leading and trailing whitespace), respectively.</p>
<p><strong>Sorting &rarr; Sort Lines (Ascending)</strong> and <strong>Sorting &rarr; Sort Lines (Descending)</strong><br />
As you might expect, these actions sort all lines in the selection (or document, if no selection) in ascending and descending order, respectively.</p>
<p><strong>Sorting &rarr; Randomize Lines</strong><br />
This randomly sorts all lines in the selection (or document, if no selection).</p>
<p><strong>Sorting &rarr; Remove Duplicate Lines</strong><br />
If for some reason you need to strip all duplicate lines from your selection or document, this is the command for you.</p>
<h4>Formatting commands</h4>
<p><strong>Indent New Line</strong> (command-shift-enter)<br />
One of my favorite parts of Textmate is that after creating an HTML tag, I only have to hit enter once to get a perfectly indented tag pair with the cursor in between and bumped in a level.  The fact that Espresso doesn&#8217;t do this irks me greatly, and so this action allows you to force the issue.  Indent New Line will turn this (pipe represents cursor):</p>
<p><code>
<pre>&lt;div>|&lt;/div></pre>
<p></code></p>
<p>Into this:</p>
<p><code>
<pre>&lt;div>
    |
&lt;/div></pre>
<p></code></p>
<p>If you have any text selected when you run the action, the selected text will be moved to the middle line and indented.</p>
<p><strong>Insert Linebreak(s)</strong> (control-enter)<br />
In HTML, Insert Linebreak(s) will insert a break tag (<code>&lt;br /></code>).  In some other contexts (like PHP double quoted strings), it will insert <code>\n</code>.  In Markdown it will insert two spaces and a linebreak.  If you have one or more selections, the tag or textual linebreak will be inserted at the end of each selection.</p>
<p>In case you didn&#8217;t quite catch that, Espresso allows you to have multiple selections (hold down command while you select multiple items with your mouse), and this action will affect all of them.  This is extremely cool, and one of the features that I&#8217;m still learning to use; before now, I&#8217;d never come across a text editor that allowed me to so much as select multiple items at once.  Of course, it isn&#8217;t all that often that you need to append br tags in a whole bunch of places around a document, but what about when you want tags for&#8230;</p>
<p><strong>Strong</strong> (command-B) and <strong>Emphasize</strong> (command-shift-I)<br />
These do about what you&#8217;d expect.  If you have one or more selections, they&#8217;re surrounded with strong or em tags.  If no selection, you get a tag wrapping your cursor.  Incidentally, if you&#8217;re working with a single selection (or no selection) you&#8217;ll get a text snippet with tab stops, so hit the tab key to edit what&#8217;s inside the tag.</p>
<p>A note on Emphasize&#8217;s shortcut; command-I by default is used to show and hide the navigator sidebar, hence this somewhat odd shortcut for italics.  If you wish to switch the shortcuts, you can do so through the System Preferences Keyboard &amp; Mouse controls.</p>
<h4>HTML actions</h4>
<p><strong>Entities &rarr; Convert To Named Entities</strong> (control-&amp;) and <strong>Entities &rarr; Convert To Numeric Entities</strong><br />
Run one of these actions to have the character immediately to the left of the cursor converted from Unicode into an HTML character entity.  If you have one or more selections, all non-ASCII Unicode characters will be converted to entities of the desired variety.  If using named entities, Unicode characters without a named entity will still be converted to their numeric equivalent.  These actions will also convert ampersands (but will ignore ampersands that are already part of an entity).</p>
<p><strong>Entities &rarr; Insert Non-Breaking Space</strong>, etc.<br />
Use these actions to quickly insert the named HTML entity for the given character.</p>
<p><strong>Expand Abbreviation</strong> (control-,)<br />
This action is much like Textmate&#8217;s &#8220;Insert Open/Close Tag (With Current Word)&#8221; which, when I saw it demoed in a screencast, changed my life.  For far too long had I been toiling away, typing out every blessed less than/greater than symbol.  With Expand Abbreviation, I merely type the HTML tag, hit the shortcut, and voil&agrave;.  I have the complete tag ready to go with barely any effort at all.</p>
<p>And the fun doesn&#8217;t stop there!  The reason for the action&#8217;s name change is that Expand Abbreviation is powered by the fantastic <a href="http://code.google.com/p/zen-coding/">zen coding project</a>, so in addition to Textmate&#8217;s functionality Expand Abbreviation offers the full range of zen coding abbreviations and CSS-selector style syntax to create complex markup from very simple declarations.  Here&#8217;s a quick example of zen coding&#8217;s awesomeness:</p>
<p><code>
<pre>div#stuff.things.booyah</pre>
<p></code></p>
<p>Type that, hit control-, and you&#8217;ll end up with this (pipe represents cursor):</p>
<p><code>
<pre>&lt;div id="stuff" class="things booyah">|&lt;/div></pre>
<p></code></p>
<p>Or if you want to do something a little more complicated:</p>
<p><code>
<pre>div#nav+div#content>p.item$*2</pre>
<p></code></p>
<p>Which leads to this:</p>
<p><code>
<pre>&lt;div id="nav">|&lt;/div>
&lt;div id="content">
	&lt;p class="item1">&lt;/p>
	&lt;p class="item2">&lt;/p>
&lt;/div></pre>
<p></code></p>
<p>And that&#8217;s just the tip of the iceberg.  Zen coding offers <a href="http://code.google.com/p/zen-coding/wiki/ZenHTMLSelectorsEn">numerous other selectors</a> and scads of abbreviations for <a href="http://code.google.com/p/zen-coding/wiki/ZenHTMLElementsEn">HTML</a> and <a href="http://code.google.com/p/zen-coding/wiki/ZenCSSPropertiesEn">CSS</a>.  All of them will work with Expand Abbreviation.</p>
<p>You may also, if you need, use the old Textmate-style tag creation where you type out everything in the tag except the carets, highlight it, and run it through Expand Abbreviation to get a full tag.  For instance, this:</p>
<p><code>
<pre>div style="width:100%;"</pre>
<p></code></p>
<p>Once selected and run through Expand Abbreviation leads to this markup:</p>
<p><code>
<pre>&lt;div style="width:100%;">|&lt;/div></pre>
<p></code></p>
<p>If there is no selection, this action will use the current word regardless of where the cursor falls in it (Textmate will only parse to the left of the cursor).</p>
<p><strong>Wrap Selection In Tag</strong> (control-shift-W)<br />
As you might expect, if you select some text and invoke Wrap Selection In Tag, the selection will be wrapped in an HTML tag.  Just like in Textmate, you can type out tag attributes and they won&#8217;t be mirrored to the closing tag, and moving outside the tag is a tab away.</p>
<p><strong>Wrap Selected Lines In Tag</strong> (command-control-shift-W)<br />
This one acts just like Wrap Selection In Tag, except that each line in the selection is wrapped.</p>
<p><strong>Wrap Selection In Link</strong> (control-shift-L)<br />
Unsurprisingly, selecting some text and invoking this command will wrap it in an HTML link tag.  What makes this action more worthwhile than some of the others is that if you have a recognizable link on your clipboard it will be inserted, and there are several tab stops set up to make removing or editing the link&#8217;s title extremely easy.  Unlike Textmate, this action does not attempt to populate the title from the actual webpage&#8217;s title.  I&#8217;ve had Textmate hang while it waits to retrieve the webpage too many times to want to implement that functionality myself.</p>
<p>If you use this action while editing Markdown or Textile, the selection will be wrapped in a Markdown or Textile link rather than an HTML anchor.</p>
<p><strong>Documentation For Tag</strong> (control-H)<br />
If your cursor is inside an HTML tag, you can run Documentation For Tag to have the word under the cursor (or the selection) searched for in <a href="http://htmlhelp.com/reference/html40/">HTMLHelp.com&#8217;s HTML reference</a>.  If the cursor is inside an HTML tag, you&#8217;ll be taken straight to the first result (almost always the correct tag page).  Otherwise, you&#8217;ll get a Google result listing.</p>
<h4>TEA Preferences</h4>
<p><strong>TEA &rarr; Preferences</strong> offers a GUI to modify some TEA-related preferences.  You&#8217;ll need to have a document open in order to access the prefs due to limitations in how Espresso sets up actions.</p>
<p><strong>General Prefs</strong><br />
Checking &#8220;use XHTML by default&#8221; will cause TEA-based snippets that use the <code>$E_XHTML</code> variable to leave it blank.  At some point in the future, TEA will hopefully be more intelligent about detecting whether a document is HTML or XHTML, but for now you&#8217;ll need to control it using this preference.</p>
<p>Similar to Textmate, anything entered in the Custom Shell Variables section of the preferences will be available as an environmental variable to any shell scripts you run through TEA.  For instance, if you add a variable with the name &#8220;MY_CUSTOM_VARIABLE&#8221; and the contents &#8220;I love TEA!&#8221; then wherever you use the shell environmental variable <code>$MY_CUSTOM_VARIABLE</code> you&#8217;ll get &#8220;I love TEA!&#8221;</p>
<p><strong>Actions</strong><br />
If you check &#8220;Enable custom user actions&#8221; you will be able to create custom actions without needing a custom sugar.  This is useful not only for custom TEA-based actions, but for custom actions using third party sugars, as well.</p>
<h4>Beyond the bundle</h4>
<p>If TEA&#8217;s included actions aren&#8217;t enough for you, it&#8217;s extremely easy to add your own custom actions, port actions from Textmate bundles, and otherwise use TEA to jumpstart your own Espresso customizations.  The <a href="http://wiki.github.com/onecrayon/tea-for-espresso">TEA for Espresso wiki</a> has lots of info on this sort of thing, or you can take a look at the <a href="http://github.com/onecrayon/HTMLBundle.sugar">HTMLBundle.sugar&#8217;s source</a> for an example of porting Textmate snippets and bundle items (the HTMLBundle.sugar may also be of use to other folks who want Textmate&#8217;s HTML tab completions, among other things; <a href="http://github.com/onecrayon/HTMLBundle.sugar/downloads">download it here</a>).</p>
<p>I&#8217;m also usually available in the forums or Espresso IRC channel if you have questions about using TEA, feature requests, bug reports, or other comments.  Alternatively if you have a GitHub account, you can file bug reports and feature requests directly into the <a href="http://github.com/onecrayon/HTMLBundle.sugar/downloads">TEA for Espresso Issues tracker</a>.</p>
<p>I hope you enjoy TEA with your Espresso!</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/YxExo7VYMoI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/09/tea_for_espresso/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/09/tea_for_espresso/</feedburner:origLink></item>
		<item>
		<title>The ideal feed reader</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/PuqZV73lZ2Q/</link>
		<comments>https://ianbeck.webfactional.com/2009/07/ideal_feed_reader/#comments</comments>
		<pubDate>Sat, 25 Jul 2009 15:14:03 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[opinions]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=317</guid>
		<description>I have never found a Mac OS X RSS feed reader that, after extended use, I was completely happy with, and this makes me sad because my feed reader is right up there with my email client for regular usage.  Every time a new feed reader comes out, I eagerly try it, am often [...]</description>
			<content:encoded><![CDATA[<p>I have never found a Mac OS X RSS feed reader that, after extended use, I was completely happy with, and this makes me sad because my feed reader is right up there with my email client for regular usage.  Every time a new feed reader comes out, I eagerly try it, am often very happy with it initially, and then inevitably become dissatisfied with its shortcomings after a week or two of use.</p>
<p>I&#8217;ve tried and discarded <a href="http://www.newsfirerss.com/">NewsFire</a>, <a href="http://www.vienna-rss.org/">Vienna</a>, <a href="http://www.newsgator.com/INDIVIDUALS/NETNEWSWIRE/">NetNewsWire</a>, <a href="http://www.thinkmac.co.uk/newsmac/">NewsLife</a>, <a href="http://www.acrylicapps.com/times/">Times</a>, and many others which were on my computer such a short time they don&#8217;t deserve a mention.  None of them fully satisfied my needs.</p>
<p>Most recently, I decided to give <a href="http://feedafever.com/">Fever</a> a try.  Though I highly dislike web apps (I&#8217;ve never found a web app that was remotely as good as its desktop counterparts, mainly thanks to speed and usability issues), I love <a href="http://haveamint.com/">Mint</a> and figured that maybe, just maybe, Shaun Inman would be the one who could write a web app that was actually useable day to day.</p>
<p>Sadly, my hopes were dashed.  Fever is too slow to handle the speed that I can skim through feeds, and has some of the same problems that drove me from NewsFire (like refreshing automatically and losing your place in whatever you&#8217;re viewing after an update).  I find that I never use the &#8220;Hot&#8221; functionality because it is so useless at actually predicting what I&#8217;ll find interesting (partially thanks to my lack of Spark link blogs, but <a href="http://al3x.net/2009/07/18/fever-and-the-future-of-feed-readers.html">others have had similar issues</a>), and as a result Fever for me has turned out to just be a rather unresponsive generic feed reader.</p>
<p>(Side note: I haven&#8217;t been happy with Fever, but I&#8217;d still hesitantly recommend it for some people.  Simply the fact that its capable of standing up with options like NewsFire and NetNewsWire is a big point in its favor if you don&#8217;t mind the Ajaxy slowness.)</p>
<p>Despite my rampant discontent, I still do not want to code a feed reader myself, so on the off chance that someone is trying to make the perfect feed reader, here&#8217;s what it needs.</p>
<p><strong>Make sure keyboard navigation is easy to use.</strong>  This is the part of Fever that I enjoy most. Hit space bar to jump to the next item.  Right arrow opens the item in the browser.  Enter swaps between excerpt and full text.  Left arrow jumps back to the source list to select a different group.  Brilliant.</p>
<p><strong>Allow grouping items by source feed.</strong> NewsFire does this beautifully, but for some reason none of the other feed readers have even attempted it.  I typically want to read or skim items based on which feed they&#8217;re in, and grouping items visually by feed makes it very easy for me to do so.  Sticking the source website in a column, or under the title, or over the title, or next to the title <em>does not work as well</em>.</p>
<p><strong>Don&#8217;t use a three-pane interface.</strong>  Mail is a brilliant application for reading email.  <em>Feeds are not email</em>.  Go use Fever, NewsFire, or Times and find out why designing a great, feed reader-specific workflow is a better plan than rehashing the tired old three-pane news reader.</p>
<p><strong>Settings should be possible to apply per feed, per group, or as application defaults.</strong>  I love that NetNewsWire and Fever both allow me to granularly set behavior preferences for feeds.  Setting refresh rates on a per-feed basis is rarely necessary, but when you need it you&#8217;ve got to have it.  When I was hunting up freelance work, I subscribed to a few Craig&#8217;s List feeds.  I eventually had enough work that the feeds were just noise, so (thanks to NetNewsWire), I stuck them in a group and turned off refreshing for that group.  They were ready for when I needed them in the future, but out of my way for now.</p>
<p><strong>Don&#8217;t sacrifice performance for aesthetics.</strong>  Times, I&#8217;m looking at you.  Times is a beautiful feed reader, with an innovative approach to feed reading, and a great set of features.  I&#8217;d be using it right now if it weren&#8217;t buggier than an anthill.  The somewhat recent 1.1 update fixed a lot of the really annoying bugs, but the program still isn&#8217;t usable.  Maybe in another few point updates.</p>
<p><strong>Don&#8217;t sacrifice aesthetics for performance.</strong>  Hi, NetNewsWire!  To be fair NetNewsWire mitigates this problem somewhat by offering some really top-notch themes, but although the application is certainly solid and obviously has been given a lot of attention to detail, it could still use a bit of the flair of NewsFire, Times, or Fever.  I think there&#8217;s a middle road here, and on that middle road a talented designer and talented developer are collaborating.  Sadly, feed readers appear to be primarily one-man-in-his-basement affairs.</p>
<p><strong>Remember that users will subscribe both to feeds they want to read every word and those they merely want to skim.</strong>  Times and Fever are both best for feeds that you want to focus on every headline.  NewsFire is great for skimming through lots of headlines thanks to its group-by-feed feature.  NetNewsWire is actually pretty good at both, as long as you&#8217;re careful about how you sort feeds into groups.  The problem here is that the needs (and thus best interface) for feeds with lots of signal versus feeds with lots of noise are quite different, yet feed readers invariably only offer a single interface for browsing and accessing feeds (or offer multiple possible interfaces, but you have to switch between them globally for the whole program).  I don&#8217;t know what the perfect solution is here, but I do know that it can only exist if the program recognizes that I have two very different approaches to feed reading and provides options accordingly.</p>
<p>Perhaps I&#8217;ll never see my perfect feed reader, and instead be destined to keep bouncing between substandard options as they release new upgrades and rekindle my hope that maybe this time they&#8217;ll have gotten it right.  Perhaps Mac OS X feed readers simply aren&#8217;t profitable enough to attract the time and care necessary to craft something that does everything I want without being bloated and terrible, and I&#8217;ll eventually just have to suck it up and go with a web app.</p>
<p>But I hope that isn&#8217;t the case.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/PuqZV73lZ2Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/07/ideal_feed_reader/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/07/ideal_feed_reader/</feedburner:origLink></item>
		<item>
		<title>Estimates</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/jZUBH2CXqvA/</link>
		<comments>https://ianbeck.webfactional.com/2009/07/xkcd_estimates/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 14:27:10 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Adversaria]]></category>
		<category><![CDATA[humor]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=313</guid>
		<description>My other favorite time estimator is Stuffit, which back when I still used it would tell me that files would be completely unstuffed anywhere from -16,000 to 1,000,000,000 minutes.  I never was sure how a file could have been unstuffed in negative minutes.  Possibly Stuffit was trying to tell me that it had [...]</description>
			<content:encoded><![CDATA[<p class="center"><a href="http://xkcd.com/612/"><img src="http://beckism.com/wp-content/uploads/2009/07/estimation.png" alt="Estimation" title="They could say 'the connection is probably lost,' but it's more fun to do naive time-averaging to give you hope that if you wait around for 1,163 hours, it will finally finish." /></a></p>
<p>My other favorite time estimator is Stuffit, which back when I still used it would tell me that files would be completely unstuffed anywhere from -16,000 to 1,000,000,000 minutes.  I never was sure how a file could have been unstuffed in negative minutes.  Possibly Stuffit was trying to tell me that it had been unstuffed once before in the past, so why the hell was I opening it again?</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/jZUBH2CXqvA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/07/xkcd_estimates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/07/xkcd_estimates/</feedburner:origLink></item>
		<item>
		<title>Beating the game</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/otMt4JhDUzg/</link>
		<comments>https://ianbeck.webfactional.com/2009/06/beating_the_game/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 15:34:27 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[opinions]]></category>
		<category><![CDATA[video games]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=310</guid>
		<description>Shortly after it came out, I beat Braid, a puzzle platformer initially released for the Xbox 360 as an arcade title and incidentally the single best game I&amp;#8217;ve played in years (it is now also available for Mac and PC).  Braid was a short game (I finished it in one Saturday with lots of [...]</description>
			<content:encoded><![CDATA[<p>Shortly after it came out, I beat <a href="http://braid-game.com/">Braid</a>, a puzzle platformer initially released for the Xbox 360 as an arcade title and incidentally the single best game I&#8217;ve played in years (it is now also available for <a href="http://www.playgreenhouse.com/game/NNONE-000001-01/">Mac and PC</a>).  Braid was a short game (I finished it in one Saturday with lots of play, and a couple hours the following Monday; probably around 6 hours total) but it was one of the most satisfying gaming experiences I&#8217;ve had in a long time.  Braid&#8217;s puzzles all revolve around your ability to affect time, and each one is unique.  No puzzle requires you to travel until you find an appropriate item or hint that makes everything clear.  You could, with patience and a willingness to think outside the box, solve each puzzle sequentially the first time you played the game.  In a world where puzzle and adventure games have mostly devolved into mindless color matching or poking around until you find the hidden lever, Braid is a breath of fresh air.</p>
<p>If you&#8217;d like to get a great feeling for Braid take a moment to read through the <a href="http://braid-game.com/walkthrough/walkthrough.html">Official Braid Walkthrough</a>.  I promise, it won&#8217;t spoil anything.  Quite the contrary.</p>
<p>Early on when I was playing the game, I got frustrated at one of the puzzles and resorted to the internet to find a walkthrough with some pointers.  I stumbled across the official one, read it, and rather sheepishly returned to the game without looking further (incidentally solving the puzzles that I&#8217;d had trouble with after leaving them alone for a while and coming back).</p>
<p>But the day that I beat the game, I cheated for real.  In my defense, one of the puzzles that I sought help-via-walkthrough on was something I probably wouldn&#8217;t have figured out without some sort of hint, dumb luck, or an outside opinion.</p>
<p>For the second puzzle whose solution I looked up, though, I was just being lazy.  I had one puzzle left, as far as I could tell it was impossible, and I wanted to beat the damn game and go to bed.  After reading the solution, I realized that it was far from impossible, that if I had slept on it one more night and come back with a fresh perspective I would doubtless have figured it out for myself, and that I had just cheated myself out of the pleasure of discovering a solution on my own.</p>
<p>Which makes me wonder; when did beating the game become so important to me?</p>
<p>I don&#8217;t really know for sure, but I suspect I have beat maybe only 25% of the video games I&#8217;ve ever played, and most of those I completed before I entered junior high.  This is in part thanks to the fact that my prime game-playing time (high school and college) I spent working for Inside Mac Games where it was more important to play lots of games than to play games to completion.  Even for games that I loved and had a compelling reason to finish (like a few of Spiderweb Software&#8217;s games) I inevitably got interrupted by something new that needed to be played and written up; a few interrupted games I went back to and finished, but many more I simply let fall to the wayside.  The rest of the reason that I have such a rotten record for games that I&#8217;ve beaten compared to when I was young is that I can now afford to just buy a new game if something ends up frustrating or annoying me.  When I was in elementary school, Riven pissed me off more times than I can count.  I constantly came up against impassable obstacles, and there were weeks or more when I would leave the game alone in disgust and frustration.  I couldn&#8217;t afford to buy any other games, though, thanks to my all but non-existant allowance, so I kept coming back to Riven until I finally beat it.</p>
<p>Given my record, beating a game isn&#8217;t high on my list of priorities.  Hell, just looking at my Xbox arcade collection proves that; of the twenty-two I own, I&#8217;ve only beaten two (one of which was Braid).</p>
<p>Which brings me back to the question: why was beating Braid important enough to cheat myself out of further time with it?  I know, both from experience and from the official Braid walkthrough, that the journey is the reward and sometimes all you need is a good night&#8217;s sleep for a puzzle to open up to you.  And I still ruined it.</p>
<p>My temptation is to blame the internet.  The games I remember most fondly are the old LucasArts adventure games (Indiana Jones and the Fate of Atlantis, Sam &#038; Max, Day of the Tentacle, The Dig), and I played them through either before my family had internet, or when walkthroughs were harder to find.  In a way, I couldn&#8217;t find spoilers, so I couldn&#8217;t spoil myself.</p>
<p>That argument, however, is unfair.  The problem isn&#8217;t that walkthroughs exist and are easy to find.  I actually prefer information to be readily available; there&#8217;s nothing worse than having something in a game you can&#8217;t solve that you&#8217;ve been working at for days with no luck, and then being unable to find any information online to help you.  The fault lies somewhere else.</p>
<p>I think the real reason that I became so focused on beating Braid, despite knowing better, was because I have become accustomed to games having some worthwhile content that is then expanded with mountains of filler.  A game of Braid&#8217;s caliber, where every puzzle is lovingly crafted and unique, took me completely by surprise.</p>
<p>And that makes me sad, both because the game industry as a whole is so focused on quantity rather than quality and because I as a gamer have reached a point where I&#8217;m so immured to games without redeemable qualities past the bullet points on their boxes that I unintentionally spoil the few gems that I do come across.</p>
<p>If you have not yet come across Braid, I urge you to learn from my mistakes: don&#8217;t just beat the game; play it.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/otMt4JhDUzg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/06/beating_the_game/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/06/beating_the_game/</feedburner:origLink></item>
		<item>
		<title>Tibia or not tibia…</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/kjaFAONPpX0/</link>
		<comments>https://ianbeck.webfactional.com/2009/05/tibia/#comments</comments>
		<pubDate>Tue, 26 May 2009 02:09:54 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Adversaria]]></category>
		<category><![CDATA[humor]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=304</guid>
		<description>Pete Joison&amp;#8217;s artwork, in all its forms, makes me so very, very happy.</description>
			<content:encoded><![CDATA[<p class="center"><a href="http://blurburger.com/shoebox/toons/toons/tibea.png"><img src="http://beckism.com/wp-content/uploads/2009/05/tibea.jpg" alt="Tibia or not tibia..."  /></a></p>
<p>Pete Joison&#8217;s artwork, in <a href="http://www.blurburger.com/">all</a> <a href="http://tihntoun.com/">its</a> <a href="http://www.petejoison.com/">forms</a>, makes me so very, very happy.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/kjaFAONPpX0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/05/tibia/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/05/tibia/</feedburner:origLink></item>
		<item>
		<title>Adventures with Yahoo Pipes</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/CaBh9S0oi2E/</link>
		<comments>https://ianbeck.webfactional.com/2009/04/yahoo_pipes/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 16:10:45 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=298</guid>
		<description>When I was testing Tumblr as a platform for beckbits, I discovered that their RSS feeds didn&amp;#8217;t offer quite what I was hoping.  Since I was primarily planning to use beckbits as a link blog, I wanted it to work Daring Fireball-style: link items should go straight to the source material, and all other [...]</description>
			<content:encoded><![CDATA[<p>When I was testing <a href="http://www.tumblr.com/">Tumblr</a> as a platform for <a href="http://bits.beckism.com/">beckbits</a>, I discovered that their RSS feeds didn&#8217;t offer quite what I was hoping.  Since I was primarily planning to use beckbits as a link blog, I wanted it to work <a href="http://daringfireball.net/">Daring Fireball</a>-style: link items should go straight to the source material, and all other items should be permalinks back to the site.  I&#8217;ve always thought that was a brilliant design choice on John Gruber&#8217;s part, and I&#8217;ve always been a big believer in integrating aspects of great design that I find around the web into my own projects.</p>
<p>In the hopes that I could take the RSS feed and remix it easily on my own, I turned to <a href="http://pipes.yahoo.com/pipes/">Yahoo Pipes</a>.  Yahoo Pipes provides a relatively easy graphical interface to parse, modify, and combine data streams, JSON, and RSS and spit it back out as RSS, JSON, or PHP serialized code.  I first discovered Pipes when I found someone&#8217;s &#8220;lifestream&#8221;, a website that displayed a list of their activity across numerous different services using Yahoo Pipes.  These kind of RSS feed mashups seem to be the most common use of the service, but the service is quite flexible so it seemed well suited for repurposing Tumblr&#8217;s RSS feed to my own uses.</p>
<p>Over the course of creating the feed, I discovered some interesting features that I feel are worth sharing.  For those of your who are curious about my specific implementation, here&#8217;s the <a href="http://pipes.yahoo.com/pipes/pipe.info?_id=uCxBbzww3hGB9ClS6ycw5g">actual pipe that is powering beckbits</a>.</p>
<h4>Moving data between elements</h4>
<p>Very early on in my exploration of the default Tumblr RSS feed I realized that I was going to need to use the <a href="http://www.tumblr.com/docs/api">Tumblr API</a> if I wanted to get direct access to the various components that make up Tumblr posts.  Of course, the API provides completely different elements than an RSS feed, so one of the main tasks of my pipe is to move data around between elements.</p>
<p>For things with a one-to-one relationship, the &#8220;Rename&#8221; operator typically does the trick.  For instance, using the external site&#8217;s URL for the RSS item link on Tumblr link items was as easy as throwing in a Rename with the rule &#8220;<em>item.link-url</em> renamed to <em>link</em>&#8220;.</p>
<p>But what about when I needed to combine multiple fields into one?  Rename certainly wasn&#8217;t going to help me there, and I couldn&#8217;t find any way to pipe data between operators and string functions.</p>
<p>Fortunately, the Regex operator came to the rescue.</p>
<p>Although I couldn&#8217;t find any documentation for this, the regex module offers a couple great features:</p>
<ul>
<li>If you reference an element in the first column that doesn&#8217;t exist, it will be created.</li>
<li>
<p>You can include the contents of other elements using the &#8220;named backreference&#8221; syntax (<code>${element-name}</code>).  For instance, when I wanted my description element to include both the Tumblr &#8220;quote-text&#8221; and &#8220;quote-source&#8221; elements the &#8220;replacement&#8221; column looked something like this:</p>
<p><code>
<pre>&lt;blockquote&gt;${quote-text}&lt;/blockquote&gt;&lt;p&gt;&lt;cite&gt;${quote-source}&lt;/cite&gt;&lt;/p&gt;</pre>
<p></code>
</li>
</ul>
<h4>Simple conditionals using regex</h4>
<p>Thanks to the fact that everything in a Yahoo pipe is evaluated sequentially, you can use the regex operator to setup simple conditionals.  For instance, regular Tumblr posts have an optional title.  If the title existed, I wanted to use it as my RSS item&#8217;s title; otherwise it should default to a short excerpt of the text.  To accomplish this, I setup the following rules:</p>
<p><strong>Rename</strong><br />
<em>item.regular-title</em> copy as <em>title</em></p>
<p><strong>Regex</strong><br />
In <em>item.title</em> replace <code>(.*)</code> with <code>$1```${excerpt}</code><br />
In <em>item.title</em> replace <code>^```(.*)$</code> with <code>$1</code><br />
In <em>item.title</em> replace <code>^(.+?)```.*</code> with <code>$1</code></p>
<p>The basic idea is to combine two fields into one separated by some delimiter characters that are unlikely to ever show up otherwise.  I chose to use three backticks, since it kept things pretty legible and I rarely use backticks.  If you&#8217;re not comfortable with regex, the rules in order say:</p>
<ol>
<li>Copy regular-title to title (because regular-title might not exist, this may result in an empty title element)</li>
<li>Append <code>```</code> plus the excerpt element to whatever is in the title element</li>
<li>If the title element starts with backticks (<code>^```</code>), replace its contents with whatever follows the backticks (the excerpt)</li>
<li>If the title element starts with one or more characters followed by backticks (<code>^(.+?)```</code>), replace everything with that starting content</li>
</ol>
<h4>Replacing your site feed with a pipe</h4>
<p>Once I&#8217;d created my pipe it was time to replace beckbits&#8217; feed with the pipe, and I discovered that Yahoo Pipes has a serious downside when it comes to using it instead of your default site feed: the pipe&#8217;s output always links back to the pipe page as the feed&#8217;s homepage.  Although this wouldn&#8217;t be a huge deal, it has the unfortunate side effect of causing the favicon associated with your feed to be the Yahoo Pipes favicon, which is extremely non-ideal.  In order to fix this, you actually have to post-process the pipe output.</p>
<p>For myself, I opted to do this by reading in the pipe as serialized PHP and then constructing my own simple RSS feed.  If you&#8217;re interested in doing something similar and would like a starting point, <a href="http://gist.github.com/102081">here&#8217;s the gist of it</a>.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/CaBh9S0oi2E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/04/yahoo_pipes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/04/yahoo_pipes/</feedburner:origLink></item>
		<item>
		<title>Introducing beckbits</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/k4s6AOPFBLE/</link>
		<comments>https://ianbeck.webfactional.com/2009/04/beckbits/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 17:15:06 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[personal]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=296</guid>
		<description>If you ask my supervisor, she&amp;#8217;ll tell you that I&amp;#8217;m the Director of Web Services.  This is bullshit, but it sounds professional and presumably the clients love it.  So that&amp;#8217;s alright.
The truth is, I&amp;#8217;m a problem-solver.  Every day, I sit down at my computer and I solve people&amp;#8217;s problems.  Perhaps the [...]</description>
			<content:encoded><![CDATA[<p>If you ask my supervisor, she&#8217;ll tell you that I&#8217;m the Director of Web Services.  This is bullshit, but it sounds professional and presumably the clients love it.  So that&#8217;s alright.</p>
<p>The truth is, I&#8217;m a problem-solver.  Every day, I sit down at my computer and I solve people&#8217;s problems.  Perhaps the problem is that Client A wants a site that they can update themselves.  Or maybe my coworker needs me to figure out why the heck their code is breaking in some browsers but not others.  And sometimes Client C just has to have a rainbow unicorn spring out of the middle of the page and dance on the user&#8217;s mouse cursor in a paroxysm of misused Javascript.  The problems change day to day and project to project.</p>
<p>I&#8217;ve now been solving problems professionally for over a year and a half, and I&#8217;ve found that in the course of solving problems I often discover information and tools online that are extremely useful for web work.  Up until now, I haven&#8217;t done much with these tidbits aside from occasionally bookmarking them.</p>
<p>No longer!  I am pleased to announce <a href="http://bits.beckism.com/">beckbits</a>, a collection of links, tips, and other tidbits that I discover during my day job and would like to share with other web problem-solvers.  Aside from links to useful resources that I&#8217;ve discovered, I may occasionally post software or productivity tips, links to my most recently completed sites, and other minor items that relate to my work as a web professional.</p>
<p>Enjoy!</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/k4s6AOPFBLE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/04/beckbits/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/04/beckbits/</feedburner:origLink></item>
		<item>
		<title>Encode named HTML entities with Python</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/_clorSWkcLk/</link>
		<comments>https://ianbeck.webfactional.com/2009/03/named_entities_python/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 06:07:19 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=290</guid>
		<description>If you&amp;#8217;re using Python to parse text that&amp;#8217;s going to end up on the web, odds are you need to worry about character entities for Unicode characters.
Obtaining numeric HTML/XML entities is easy enough; I found several different ways to do so in a quick Google search, this being the easiest (text is just an example [...]</description>
			<content:encoded><![CDATA[<p>If you&#8217;re using Python to parse text that&#8217;s going to end up on the web, odds are you need to worry about character entities for Unicode characters.</p>
<p>Obtaining numeric HTML/XML entities is easy enough; I found several different ways to do so in a quick Google search, this being the easiest (<code>text</code> is just an example variable):</p>
<p><code>
<pre>text = text.encode('ascii', 'xmlcharrefreplace')</pre>
<p></code></p>
<p>However, it is significantly more difficult to find a way to encode text as named character entities, which if you&#8217;re ever going to need to look at the markup later is vastly preferable.  After a lot of digging, I discovered some basic logic for named HTML entities in the <a href="http://www.amazon.com/dp/0596007973/beckism-20">Python Cookbook</a>.  After improving on it to make sure that all entities get replaced (even high level ones without named equivalents) I&#8217;ve got something that others may find useful in turn.  Simply place this code into a file called <code>named_entities.py</code> and stick it somewhere that your script can find it (or just stick the code at the top of your file, if you only need it in one place).  Usage info is in the comment at the top of the code.</p>
<p>Please note that this code is for Python 2.x.  Python 3 moved codepoint2name into <a href="http://docs.python.org/3.0/library/html.entities.html">html.entities.codepoint2name</a>, so you&#8217;d need to modify the import.</p>
<p><code>
<pre>'''
Registers a special handler for named HTML entities

Usage:
import named_entities
text = u'Some string with Unicode characters'
text = text.encode('ascii', 'named_entities')
'''

import codecs
from htmlentitydefs import codepoint2name

def named_entities(text):
    if isinstance(text, (UnicodeEncodeError, UnicodeTranslateError)):
        s = []
        for c in text.object[text.start:text.end]:
            if ord(c) in codepoint2name:
                s.append(u'&%s;' % codepoint2name[ord(c)])
            else:
                s.append(u'&#%s;' % ord(c))
        return ''.join(s), text.end
    else:
        raise TypeError("Can't handle %s" % text.__name__)
codecs.register_error('named_entities', named_entities)</pre>
<p></code></p>
<p>One last thing: whether you use numeric or named entities, you&#8217;ll probably want to encode ampersands afterward.  Here&#8217;s the regex that I&#8217;ve been using to do so, and it&#8217;s safe to run on the output of either the named or numeric entity creation code (remember to <code>import re</code> before trying this at home):</p>
<p><code>
<pre>text = re.sub('&#038;(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);)', '&amp;amp;', text)</pre>
<p></code></p>
<p>Enjoy!</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/_clorSWkcLk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/03/named_entities_python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/03/named_entities_python/</feedburner:origLink></item>
		<item>
		<title>Espresso 1.0 released</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/rqGXFemLF1Y/</link>
		<comments>https://ianbeck.webfactional.com/2009/03/espresso_released/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 06:12:02 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[opinions]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=288</guid>
		<description>Espresso 1.0 has officially been released for general consumption, and I&amp;#8217;m extremely proud to announce that TEA for Espresso (coded by yours truly) is bundled with the application!  Espresso is a text editor aimed firmly (for the moment) at the web editing crowd, and offers code folding, a powerful code navigator, FTP synching, Textmate-style [...]</description>
			<content:encoded><![CDATA[<p><a href="http://macrabbit.com/espresso/">Espresso 1.0</a> has officially been released for general consumption, and I&#8217;m extremely proud to announce that TEA for Espresso (coded by yours truly) is bundled with the application!  Espresso is a text editor aimed firmly (for the moment) at the web editing crowd, and offers code folding, a powerful code navigator, FTP synching, Textmate-style text snippets (with tab stops and all that jazz), and an extensible underbelly for extending the program.  It&#8217;s pretty sweet.</p>
<p>That said, I have to admit that my feelings about this release are mixed, and I don&#8217;t think that most people who live in their text editor (including myself) will be able to switch to Espresso full time just yet.  I&#8217;m beginning to think that this may just be how text editors work.  I was completely underwhelmed by Coda when it first came out, too, but after Coda 1.5 I tried it again and started migrating projects to it, and as of 1.6 I&#8217;m using Coda full time.  While some people will find Espresso 1.0&#8217;s friendly and simple editing just what the doctor ordered, I suspect that its wider appeal will not be truly realized for another few point releases.</p>
<p>None of which, of course, answers the question, &#8220;Is Espresso for me?&#8221;  Obviously, you won&#8217;t know until you try it out for yourself, but for those of you who like to have other people do the initial dirty work, here&#8217;s what Espresso is, what it is not, and where it&#8217;s probably headed in the near future.  (Please note that I don&#8217;t have any insider info; I have been participating in the betas since slightly before they went public, however, and would like to think that my guesses are fairly educated.)</p>
<p>In many ways, to understand Espresso you first need to understand what it is not.</p>
<h4>Espresso is not CSSEdit</h4>
<p>Before you so much as think about downloading Espresso, you need to be clear on one thing: Espresso is not CSSEdit.  Yes, you can edit CSS files with Espresso, but it does not offer visual CSS editing, and X-ray and the inspector are nowhere to be seen.  You can override stylesheets, CSSEdit groups are supported in the code navigator, and the CSS text editing is very similar, but if you are expecting CSSEdit plus the ability to edit HTML you will be sorely disappointed.</p>
<p>I&#8217;m going to make a prediction here (and yes, it&#8217;s just a prediction; I have no insider knowledge): I think that Espresso will get X-Ray in a point release.  I think it will probably get the inspector and the ability to jump straight from the Inspector to a style in the CSS.  But I don&#8217;t think it will ever get CSSEdit&#8217;s visual editors.  Why?</p>
<p>Because competing with yourself is stupid.</p>
<p>CSSEdit is the best way to edit CSS (right now, anyway).  Espresso is shooting to be the best way to edit code, no matter what the language.</p>
<p>Perhaps someday MacRabbit might want to merge CSSEdit into Espresso and retire their original flagship product, but don&#8217;t hold your breath.</p>
<p>All that said, I&#8217;m as baffled as the next guy why you can&#8217;t right click a CSS file in Espresso and choose &#8220;Edit in CSSEdit&#8221;.</p>
<h4>Espresso is not Coda</h4>
<p>Particularly when MacRabbit announced Espresso and showed off screenshots of an integrated FTP editor I think a lot of people assumed that Espresso was setting out to be an all-in-one editor to challenge Coda (albeit much more slimmed-down).  &#8220;Hooray!&#8221; cried the masses.  &#8220;Perhaps at last we&#8217;ll have an all-in-one solution with a decent text editor at its core!&#8221;</p>
<p>The masses were a ways off the mark.  Coda attempts to give you every tool you&#8217;re likely to need to edit code.  Espresso tries to give you a fantastic environment for editing web pages with an extensible Sugar architecture to allow you to expand the editor to other languages.  Notice how different those two sentences are.</p>
<p>If you love Coda because of the diverse tools that it gives you, you&#8217;ll probably be underwhelmed by Espresso.  However, if the shortcomings of Coda&#8217;s text editor rub you the wrong way and you don&#8217;t very often find yourself using SVN, books, the terminal, etc., then Espresso might be a wonderful solution to your needs.</p>
<h4>Espresso 1.0 is a foundation</h4>
<p>In many ways, Espresso is building off the legacy of Textmate, if you can say that a piece of software that&#8217;s still nominally developed and actively used has a legacy.  Text snippets with tab stops and mirrored segments directly mimic Textmate&#8217;s snippets and the Sugar syntax system is fairly Textmate-y, as well.  Where Textmate provides extreme flexibility with a correspondingly steep learning curve, Espresso attempts to provide some of the core aspects of that flexibility but focus on providing users with a more polished, CSSEdit-ish application.</p>
<p>Espresso 1.0 is a foundation, a solid feature-set that shows the core capabilities of the program and through its scope and design may give you a good idea of what directions the application is likely to grow.  When I first read MacRabbit&#8217;s descriptions of Espresso I immediately began imagining the possibilities, and every time I launch it I find myself imagining possibilities again.  It has the potential to grow into an application almost as flexible as Textmate, but easier to extend and with a friendlier interface that also happens to offer the core features needed for web development.</p>
<p>Aside from its potential, Espresso 1.0 is a powerful text editor that&#8217;s overly focused on web design with a few rough edges tucked away beneath the overall gleam of its interface.  It&#8217;s better than most of the web-centric offerings, but may not be quite good enough to lure you away from heavy hitters like Textmate, Coda, or the venerable BBEdit.</p>
<p>If you&#8217;re looking for a simple yet powerful web-oriented text editor with a lot of flexibility and promise for growth, I highly recommend giving Espresso a download.  As long as you don&#8217;t go in expecting CSSEdit, Coda, or something that will turn into a magical unicorn and solve all your problems you should be pretty pleased with what you find, even if, like myself, you&#8217;re unlikely to be able to switch to using it full time for your day job until the application is a bit more mature.</p>
<h4>That&#8217;s nice; what about TEA?</h4>
<p>I haven&#8217;t been talking about TEA for Espresso much because although I&#8217;m ecstatic that it was one of the few Sugars chosen to be included in the application, it frankly wasn&#8217;t ready.  I still consider it in beta even if Espresso is out, and because I didn&#8217;t know that it was going to be bundled in the application until the morning the app was released, some of its better features are broken.  Once I&#8217;ve got it in a more mature place, I&#8217;ll definitely brag about it a bit more and offer some examples of how to use it; for now, please give me a shout in the <a href="http://wiki.macrabbit.com/forums/viewthread/160/">Espresso forums</a> if you have any feedback, requests, or bug reports.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/rqGXFemLF1Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/03/espresso_released/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/03/espresso_released/</feedburner:origLink></item>
		<item>
		<title>Tips, tricks, and gotchas for writing bundles with PyObjC</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/ZUhEA-8uF6Q/</link>
		<comments>https://ianbeck.webfactional.com/2009/03/pyobjc_tips/#comments</comments>
		<pubDate>Sat, 21 Mar 2009 16:28:01 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=284</guid>
		<description>Part of the reason that I haven&amp;#8217;t been posting very actively to Beckism.com or Tagamac is that I&amp;#8217;ve recently been getting exceedingly involved in a number of personal projects involving Python.  Python itself is super fantastic and learning it has been a blast, but one project in particular has been causing me undue amounts [...]</description>
			<content:encoded><![CDATA[<p>Part of the reason that I haven&#8217;t been posting very actively to Beckism.com or Tagamac is that I&#8217;ve recently been getting exceedingly involved in a number of personal projects involving Python.  Python itself is super fantastic and learning it has been a blast, but one project in particular has been causing me undue amounts of head-to-desk contact thanks to its reliance on the oh-so-cool but insufficiently documented PyObjC, and I&#8217;d like to share some of the things that I&#8217;ve discovered for other would-be programmers who want to extend their favorite Mac OS X applications with PyObjC powered plugins.</p>
<p>For those of you who prefer source to exposition, the project that I&#8217;ve been working on is TEA for Espresso and you can find the full source code over at the <a href="http://github.com/onecrayon/tea-for-espresso/">TEA for Espresso project on GitHub</a>.  As you may have surmised, it&#8217;s a plugin for the upcoming <a href="http://macrabbit.com/espresso/">Espresso</a> text editor created because I wanted to play with Espresso but am addicted to Textmate-style HTML actions.</p>
<p>My personal preference for Python is to use four spaces rather than a tab for indentation, so keep that in mind if you&#8217;re trying to execute the code samples below and your document is using tabs.</p>
<h4>Using py2app to create semi-standalone code</h4>
<p>Py2app allows you to work completely in Python without ever needing to boot up Xcode and touch Objective-C.  There&#8217;s plenty of information around the web about how to setup a basic py2app setup.py file, but one of the things that I had to discover via trial and error was how to make my code semi-standalone.</p>
<p>Semi-standalone is an option you can enable with py2app that makes your code reliant on the version of Python that is installed with the OS.  By default, py2app tries to bundle any dependencies for your project into your bundle, but if you&#8217;re only distributing the bundle/plugin/app/whatever to people using the same major OS version this makes for about 15 MB minimum of unnecessary junk getting tossed into your bundle.</p>
<p>Turning on semi-standalone is as simple as adding a key to your py2app options dictionary, but what you might not know is that you also need to enable site-packages, as well (which apparently encourages py2app to create the links to Python necessary for getting the bundle up and running, although it&#8217;s only supposed to tell it to include the system and user site-packages in the system path).  So to get a semi-standalone bundle, your code needs to look something like this:</p>
<p><code>
<pre>setup(
    name='My Plugin Bundle',
    plugin = ['MyPluginBundle.py'],
    options=dict(py2app=dict(
        extension='.bundle',
        semi_standalone = True,
        site_packages = True
    )),
)</pre>
<p></code></p>
<p>One of the most frustrating aspects of working with py2app for me was the lack of any decent documentation on the <a href="http://undefined.org/python/py2app.html">main py2app site</a>.  Fortunately, there&#8217;s a much more comprehensive page of documentation available in the <a href="http://svn.pythonmac.org/py2app/py2app/trunk/doc/index.html">MacPython py2app SVN repository</a>, which is where I discovered the site-packages option.</p>
<h4>Automatically including project data files</h4>
<p>Odds are since you&#8217;re using Python you&#8217;ll need to include some arbitrary data files with your application, be they NIB files, extra Python scripts and classes, or whatever else.  However, py2app&#8217;s method of declaring what files you want included with your project is to list them explicitly in a data_files array.  This is a major pain, since every time you add or remove a file you have to remember to edit setup.py.  No thanks.</p>
<p>Fortunately, Python comes with some powerful file system modules that allow you to traipse around your file system, making note of files and folders as you go.  The following code snippet, if included in your setup.py script, will automatically parse through a directory of files and add them to your data_files array without you needing to lift a finger (assuming that you configure the first couple variables to fit your project, that is).  Files that start with a period (hidden files) will be ignored.  If you&#8217;re using SVN, you may also need to add some logic to exclude folders that start with a period (TEA for Espresso is using Git, so this hasn&#8217;t been an issue for me).</p>
<p>The downside to using this code, of course, is that you&#8217;ll need to nest all your files in the directory structure that you want in your final bundle.  So, for example, in order to include something in the Resources folder for TEA for Espresso, I have to nest it in <code>src/Contents/Resources/</code> whereas I otherwise could have placed it in the root project directory.  If you&#8217;re doing a simple project with very few files, it might be more worth your while to define data_files differently.</p>
<p><code>
<pre>import os

# Sets what directory to crawl for files to include
# Relative to location of setup.py; leave off trailing slash
includes_dir = 'src'

# Set the root directory for included files
# Relative to the bundle's Resources folder, so '../../' targets bundle root
includes_target = '../../'

# Initialize an empty list so we can use list.append()
includes = []

# Walk the includes directory and include all the files
for root, dirs, filenames in os.walk(includes_dir):
    if root is includes_dir:
        final = includes_target
    else:
        final = includes_target + root[len(includes_dir)+1:] + '/'
    files = []
    for file in filenames:
        if (file[0] != '.'):
            files.append(os.path.join(root, file))
    includes.append((final, files))

setup(
    name='My Plugin Bundle',
    plugin = ['MyPluginBundle.py'],
    data_files = includes,
    options=dict(py2app=dict(
        extension='.bundle'
    )),
)</pre>
<p></code></p>
<h4>Avoid release statements in Python</h4>
<p>I&#8217;m sure this is extremely obvious for anyone with significant PyObjC experience, but TEA for Espresso lay fallow for over a month after I started it because I couldn&#8217;t get the example plugin ported from Objective-C to Python.  It turns out that almost everything in Objective-C can be easily ported to Python using the simple conversion rules (colons to underscores, etc.; see the <a href="http://pyobjc.sourceforge.net/documentation/pyobjc-core/intro.html">PyObjC intro</a> for more info), <em>except</em> for any calls to release objects.  For instance, here&#8217;s the code that was breaking my project:</p>
<p><strong>Objective-C</strong><br />
<code>[selectedRanges release];</code></p>
<p><strong>Ported into Python</strong> (don&#8217;t do this!)<br />
<code>selectedRanges.release()</code></p>
<p>PyObjC auto-releases absolutely everything, so don&#8217;t port lines like the one above.  They will break your project.  This is actually described in the <a href="http://pyobjc.sourceforge.net/documentation/pyobjc-core/intro.html#reference-counting">PyObjC introduction</a> if you&#8217;d like a more technical explanation; apparently I just missed the significance of it when I read the intro the first time.</p>
<h4>Handling **NSError arguments</h4>
<p>If you&#8217;re implementing a bundle that will be loaded into another application, odds are you&#8217;ll need to implement an Objective-C protocol in Python, and Objective-C functions occasionally have an **NSError parameter.  If you&#8217;re not going to be returning any error information, you can safely ignore the **NSError in your Python code.  The bridge automatically handles it.  If you might return an error, then you may find <a href="http://sourceforge.net/mailarchive/forum.php?thread_name=d2ae22970902020634n4e11770fje703042e807dc2a0%40mail.gmail.com&#038;forum_name=pyobjc-dev">this thread</a> on the PyObjC-dev mailing list useful.</p>
<p>For example, for TEA for Espresso I needed to implement this Objective-C method in Python:</p>
<p><code>
<pre>- (BOOL)performActionWithContext:(id)context error:(NSError **)outError;</pre>
<p></code></p>
<p>Since I&#8217;m never returning any error information, in Python this translates to:</p>
<p><code>
<pre>def performActionWithContext_error_(self, context):</pre>
<p></code></p>
<p>Although woefully out of date in some respects, one of the most useful and understandable sources of information about using **NSError with PyObjC I found was Apple&#8217;s <a href="http://developer.apple.com/cocoa/pyobjc.html">PyObjC for Developing Cocoa Apps</a> page.</p>
<h4>Implementing Objective-C interfaces without a protocol</h4>
<p>An interesting problem that can arise if your bundle is implementing an Objective-C interface (rather than conforming to a protocol) is that when your code is loaded you may find that Objective-C can&#8217;t find your class methods.  To solve this, usually all you need to do is explicitly define the type encoding of your class method.  For instance, TEA for Espresso&#8217;s main bundle class has the following method:</p>
<p><code>
<pre>class TEAforEspresso(NSObject):
    @objc.signature('B@:@')
    def canPerformActionWithContext_(self, context):</pre>
<p></code></p>
<p>The @objc.signature() decorator tells PyObjC that this particular method returns a bool (&#8221;B&#8221;), is an object method (&#8221;@&#8221; means object, and &#8220;:&#8221; means method selector), and accepts one argument which should be a generic object (&#8221;@&#8221; again meaning object).  For a full list of available encoding characters, see the <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html">Objective-C Runtime Programming Guide</a>.</p>
<p>You can find more information about this bit of weirdness over at <a href="http://jimmatthews.wordpress.com/2007/07/12/objcselector-and-objcsignature/">Jim Matthews Blog</a> or, to a very limited extent, in the <a href="http://pyobjc.sourceforge.net/documentation/pyobjc-core/wrapping.html">PyObjC class wrapping documentation</a>.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/ZUhEA-8uF6Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/03/pyobjc_tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/03/pyobjc_tips/</feedburner:origLink></item>
		<item>
		<title>A better bash prompt on Mac OS X</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/_ZKv1YwRVRc/</link>
		<comments>https://ianbeck.webfactional.com/2009/02/better_bash_prompt/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 03:47:04 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=280</guid>
		<description>I have always disliked Terminal.  I got a basic grounding in Unix command-line usage in a C++ class in college, but Terminal still bugs me.  Yes, I can adjust colors and fonts in the preferences, but it isn&amp;#8217;t the background color that bothers me; it&amp;#8217;s the fact that I can never tell my [...]</description>
			<content:encoded><![CDATA[<p>I have always disliked Terminal.  I got a basic grounding in Unix command-line usage in a C++ class in college, but Terminal still bugs me.  Yes, I can adjust colors and fonts in the preferences, but it isn&#8217;t the background color that bothers me; it&#8217;s the fact that I can never tell my prompt apart from my output.</p>
<p>This became particularly aggravating when I recently started using Git.  Git, unfortunately, does not have a great GUI client on the Mac that I&#8217;ve found, so I was doing all my work on the command line and determining where the prompt ended and output began was getting to be a persistent problem.  I also was not happy with the fact that almost any command besides a simple <code>cd</code> or <code>ls</code> was wrapping onto multiple lines; the default Terminal prompt just takes up so much horizontal space.</p>
<p>Fortunately, it is possible to modify your bash prompt, and having trolled the internet and tested various solutions, here&#8217;s what I&#8217;m currently using to distinguish prompt from output:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/02/terminal-prompt.png" alt="My very own terminal prompt" /></p>
<p>Yes, my computer is named Tastefully Delicious.  I myself am not entirely certain how this occurred.</p>
<p>My custom prompt isn&#8217;t perfect, and it&#8217;s certainly a lot more basic than some that you can create, but it does a great job of visually distinguishing between input and output which is exactly what I needed.  Fortunately, it&#8217;s not terribly difficult to enable something like this; although bash prompt examples around the internet range from gibberish to hundreds of lines of cryptic functions that you have to load into your bash session, understanding the basics of a custom bash prompt in order to make your own peace with Terminal is quite simple.</p>
<p>First off, head over to <a href="http://www.ibm.com/developerworks/linux/library/l-tip-prompt/">IBM&#8217;s cheat sheet for bash prompt modification</a>.  This was by far the best reference I found on modifying the prompt, and offers a complete listing of available bash sequences and colors (as an added bonus, it uses a much simpler syntax for colors than some other sites advise).  In my examples below I&#8217;ll be using the specific variables for my personal prompt, but you can of course substitute any bash sequence that you like to make the command line your own.</p>
<p>There are two main parts to customizing your prompt: deciding on the right prompt declaration for you, and then writing it to a file so that it&#8217;s loaded every time you load bash.  The prompt is stored in the PS1 variable in bash, which you can examine like this:</p>
<p><code>echo $PS1</code></p>
<p>To temporarily change the variable (for instance, while testing out various prompts), you&#8217;ll run something like this:</p>
<p><code>export PS1="Your prompt here > "</code></p>
<p>By adding bash sequences to your prompt, you can make it display more interesting information.  For instance, if you wanted to use just the second line of my prompt (what folder you&#8217;re in, what computer you&#8217;re logged into, and what user account you&#8217;re using), you could enter this:</p>
<p><code>export PS1="\W @ \h (\u) \$ "</code></p>
<p>Which would result in a prompt that reads something like this:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/02/somewhat-modified-prompt.png" alt="A somewhat modified prompt" /></p>
<p>You can, of course, use any of the sequences listed on the <a href="http://www.ibm.com/developerworks/linux/library/l-tip-prompt/">IBM reference</a>.  For myself, I found that changing the content of the prompt itself wasn&#8217;t enough (even when I experimented with multi-line prompts); what was really needed was some color.</p>
<p>Colors in bash are rather offputting, but easy enough to use as long as you&#8217;re careful.  The basic format is <code>\e[0m</code> &mdash; "\e[" starts the color code, 0 is the actual color declaration (0 specifically means "reset to default"), and "m" ends the color.  However, in order to make sure bash wraps things right (should they need wrapping) you have to add some backslash-escaped brackets to mark the code as taking up no space on the line:</p>
<p><code>\[\e[0m\]</code></p>
<p>Fun, illegible times.  In the color chart on IBM&#8217;s reference, you can see the various codes associated with different colors.  To setup a specific color combination, separate different numeric color codes with semicolons (so far as I know, order doesn&#8217;t matter).  So if you wanted red text on a black background you would use <code>\[\e[31;40m\]</code> and if you wanted bold green text on a blue background you&#8217;d use <code>\[\e[1;32;44m\]</code> (the number 1 makes the text bolder and/or brighter for use on a dark background).  You can also leave off any of the color codes (to just set the background color without messing with the default text color, for instance).</p>
<p>For my prompt I wanted something more subtle than most of the bash colors provide for, so I set the background of the whole window to light gray in the Terminal preferences, and then used the code <code>\[\e[1;30;47m\]</code> which set the text to the bright variant of black on a white background.  I wasn&#8217;t too happy with the bold text, but fortunately Terminal offers a pair of options to disable bold text and make it &#8220;bright&#8221; which worked perfectly for me:</p>
<p class="center"><img src="http://beckism.com/wp-content/uploads/2009/02/terminal-settings.jpg" alt="Terminal preferences" /></p>
<p>With colors worked out, the last step was adding a horizontal rule (via underscores) to separate out the prompt even more.  My default Terminal window is 80 characters wide, so I just tossed in 80 underscores.  I&#8217;m certain there are ways to get tricky with functions and only output as many underscores as you need to fill the window, but that seemed like more effort (and processing overhead) than it was worth.</p>
<p>So without further ado, my complete custom bash prompt:</p>
<p><code>
<pre>export PS1="\[\e[1m\]________________________________________________________________________________\n\[\e[1;30;47m\]| \W @ \h (\u) \n| => \[\e[0m\]"</pre>
<p></code></p>
<p>There&#8217;s additionally a second level prompt that you may need if you&#8217;re entering a command over multiple lines.  I just duplicated the final line of my original prompt for the secondary one:</p>
<p><code>
<pre>export PS2="\[\e[1;30;47m\]| => \[\e[0m\]"</pre>
<p></code></p>
<p>For both of them, note the &#8220;return to default&#8221; color code at the end; if you don&#8217;t enter that, you&#8217;ll end up with an entire window the color of your prompt, which will likely defeat the purpose.</p>
<p>Once you&#8217;ve found a prompt that you like, you&#8217;ll want to save it so that it automatically loads.  To do this, just add the export commands to a hidden file in your home folder named either &#8220;.bash_profile&#8221; or &#8220;.bashrc&#8221; (I don&#8217;t have any idea what the difference is; I&#8217;m personally using .bash_profile because it already existed in my home folder).</p>
<p>Once you&#8217;ve saved your path to the file, you should forevermore experience a more visually appealing (and possibly informative) bash prompt, hopefully rendering Terminal a less painful program to use.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/_ZKv1YwRVRc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2009/02/better_bash_prompt/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2009/02/better_bash_prompt/</feedburner:origLink></item>
		<item>
		<title>Our first Christmas tree</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/EyKb02W-I8I/</link>
		<comments>https://ianbeck.webfactional.com/2008/12/first_christmas_tree/#comments</comments>
		<pubDate>Tue, 16 Dec 2008 04:32:07 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[personal]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=273</guid>
		<description>My girlfriend&amp;#8217;s and my first Christmas tree together.  Happy!
Sitting on the couch we&amp;#8217;ve got a view of the Christmas tree with the Space Needle standing tall in the window next to it.  I love this apartment.</description>
			<content:encoded><![CDATA[<p class="center"><img src="http://beckism.com/wp-content/uploads/2008/12/first-xmas-tree.jpg" alt="Our first Christmas tree" /></p>
<p>My girlfriend&#8217;s and my first Christmas tree together.  Happy!</p>
<p>Sitting on the couch we&#8217;ve got a view of the Christmas tree with the Space Needle standing tall in the window next to it.  I love this apartment.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/EyKb02W-I8I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2008/12/first_christmas_tree/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2008/12/first_christmas_tree/</feedburner:origLink></item>
		<item>
		<title>Display: block and form legend elements</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/ckO9iOHjal0/</link>
		<comments>https://ianbeck.webfactional.com/2008/12/display_block_legend/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 16:51:47 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=268</guid>
		<description>If you&amp;#8217;ve ever tried to make an HTML form look like the fancy PSD mockup that your graphic designer threw together, you know how much hate forms deserve.  Forms are an integral part of the web, yet making them semantic, accessible, and visually appealing across browsers can be a major bitch.
There&amp;#8217;s lots of information [...]</description>
			<content:encoded><![CDATA[<p>If you&#8217;ve ever tried to make an HTML form look like the fancy PSD mockup that your graphic designer threw together, you know how much hate forms deserve.  Forms are an integral part of the web, yet making them semantic, accessible, and visually appealing across browsers can be a major bitch.</p>
<p>There&#8217;s lots of information scattered about the interwebs about arm-wrestling forms into submission, but I recently ran across an issue that has not, so far as I know, been adequately discussed.  That topic is legends.</p>
<p>No, not like the legend of Jeffrey Zeldman and his big blue ox, although that&#8217;s a good one; I&#8217;m talking about the legend element that attaches to fieldsets in order to let your visitor know what the heck this group of form controls they&#8217;re supposed to fill out pertains to.  Legends, it turns out, are some of the most annoying elements to style you can find.  Not only do they by default have some bizarre formatting applied to them by every browser out there (usually in slightly different ways), but normal styling rules don&#8217;t apply.  <code>Display: block</code>, anyone?  Yeah, ain&#8217;t happening.</p>
<p>Recently I was asked to style a really nicely laid out form; it had everything lined up down the left side, clearly labeled sections, the works.  Except that the headings for each section were occasionally long enough to wrap, and were displayed with many of the same rules as the H3&#8217;s on the page.  Easy enough, I figured, I&#8217;ll just stick <code>display: block</code> and some margins on them.</p>
<p>Which is when I discovered that <code>display: block</code> has no effect on legends in any browser (any browser worth testing in, that is, which means IE 6, IE 7, Firefox 2, Firefox 3, and Safari for my company).  Legends with lots of text in them tend to stretch themselves or, worse, their parent elements out to keep everything on the same line, and even if they&#8217;re supposedly block-level elements with a margin they&#8217;re still treated as inline.  Not cool.  Fortunately, my latent CSS superpowers were activated when I started swearing like a sailor (wish I had a more socially acceptable trigger, but there you go) and I pounded out some CSS that:</p>
<ol>
<li>Forces long legends to wrap in IE, Firefox, and Safari</li>
<li>Encourages legends to act like they know what <code>display: block</code> is all about</li>
</ol>
<p>The code looks like this (or <a href="https://ianbeck.webfactional.com/examples/display_block_legends.html">see it in action</a>):</p>
<p><strong>HTML</strong><br />
<code>
<pre>&lt;fieldset&gt;
    &lt;legend&gt;&lt;span&gt;Legend text&lt;/span&gt;&lt;/legend&gt;
&lt;/fieldset&gt;</pre>
<p></code></p>
<p><strong>CSS</strong><br />
<code>
<pre>legend {
    margin: 0 0 15px;
    float: left;
    white-space: normal;
    *margin-left: -7px;
}

legend span {
    width: 400px;
    display: block;
}</pre>
<p></code></p>
<p>Seem weird?  That&#8217;s because it is.  Here&#8217;s the reasons for the insanity:</p>
<p>If you&#8217;re like me, you&#8217;ll want a margin on your block level elements; in order to get your margin recognized in Firefox 2, you have to put it on the legend element.  Of course, margins won&#8217;t be recognized on inline elements or legends, but since <code>display: block</code> does squat for a legend you have to float the legend left.  For the full <code>display: block</code> effect, of course, there should be a width on the legend, but since Firefox will collapse the legend&#8217;s width down to its content anyway, I left it off.</p>
<p>Instead, the semantically meaningless span gets the width and <code>display: block</code>.  The span not only forces Firefox to bump the legend&#8217;s width out the correct amount, but it also is necessary for long legends to wrap in some browsers.  I&#8217;m using a pixel width mainly because IE 6 requires a different pixel width (more on this later).  Although in a perfect world your legends would not have anything in them other than the legend text, we don&#8217;t live in a perfect world.</p>
<p>Adding <code>white-space: normal</code> to either the span or the legend will fix the wrapping problems in Firefox 3 (I chose to attach it to the legend in the hopes that in fifty years or so I can rid myself of that span with less effort).</p>
<p>The <code>*margin-left: -7px</code> line is a hack to fix an IE-specific problem.  Even with no padding, margin, and <code>left: 0px</code> IE will still indent your legends seven pixels.  The star-property hack targets both IE 6 and 7 (while being ignored by sane browsers) and bumps the legend back over where it should be.  I&#8217;m using the star-property hack here because it makes the source a lot less verbose; however, you should probably migrate that rule into an IE-specific stylesheet behind a conditional comment.</p>
<p>There is also one more IE-specific adjustment that you have to make thanks to the seven pixel indent.  When calculating its box model, IE 6 will determine the width of the legend and add the seven pixel indent before shifting the legend to the left.  Long and short of it is that the parent element will be bumped out seven pixels wider than it should be, so you&#8217;ll need to give the span a width seven pixels less than your target width for IE 6.  For instance, to make the code above work in IE 6 I would add an IE 6 conditional comment with <code>legend span { width: 393px; }</code> inside somewhere.</p>
<p>And that&#8217;s it!  You will, of course, want to be using an intelligent CSS reset (I recommend <a href="http://meyerweb.com/eric/tools/css/reset/">Eric Meyer&#8217;s CSS reset</a>), but otherwise the above CSS should give you a legend element that acts like a block-level element instead of some weird border-loving pseudo-element with wrapping issues.</p>
<p>There are some further gotchas to be aware of if you start playing around with legends.  IE by default colors all legends blue, for instance, and if you want the legend to overlay the fieldset border (or not) you&#8217;ll need to go about things slightly differently.  However, if you&#8217;ve been frustrated by the inability to get your legends to behave like <code>display: block</code> means something, hopefully this snippet will help you out.</p>
<p>As is usually the case, I discovered this particular combination of HTML and CSS by taking previous solutions, mixing them into a putrescent green cocktail, and force-feeding it to my browsers, tweaking the constituent ingredients until they were saying &#8220;Mmm, tasty!&#8221; instead of puking a bunch of crap all over my lovely webpage.  Specifically, John Faulds provided some <a href="http://www.tyssendesign.com.au/articles/css/legends-of-style/">basic concepts and examples for styling legends</a> and Stephanie Sullivan wrote up the <a href="http://www.communitymx.com/blog/index.cfm?newsid=923">strategies for encouraging legend wrapping in Firefox 2 and 3</a>.  Thanks, guys; you rock.</p>
<p>If you want to see the code in action with various permutations for More Pretty, check out this <a href="https://ianbeck.webfactional.com/examples/display_block_legends.html">page o&#8217; examples</a>.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/ckO9iOHjal0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2008/12/display_block_legend/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2008/12/display_block_legend/</feedburner:origLink></item>
		<item>
		<title>Accept text from either LaunchBar or Quicksilver in Applescript</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/ccZ3iNFMiKc/</link>
		<comments>https://ianbeck.webfactional.com/2008/11/accept_text_applescript/#comments</comments>
		<pubDate>Sat, 29 Nov 2008 18:08:16 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=262</guid>
		<description>Here&amp;#8217;s the thing: I absolutely adore LaunchBar.  I use it constantly throughout the day, and if I&amp;#8217;m using a computer without LaunchBar I practically can&amp;#8217;t function because I keep habitually hitting the LaunchBar shortcut and opening Spotlight on accident.  So when I write Applescripts that I want to accept text and do something [...]</description>
			<content:encoded><![CDATA[<p>Here&#8217;s the thing: I absolutely adore <a href="http://www.obdev.com/products/launchbar/">LaunchBar</a>.  I use it constantly throughout the day, and if I&#8217;m using a computer without LaunchBar I practically can&#8217;t function because I keep habitually hitting the LaunchBar shortcut and opening Spotlight on accident.  So when I write Applescripts that I want to accept text and do something with it, I use LaunchBar-specific code.</p>
<p>However, there&#8217;s a large number of people out there who prefer <a href="http://code.google.com/p/blacktree-alchemy/">Quicksilver</a> (link to Google Code project; also see <a href="http://www.blacktree.com/">Blacktree&#8217;s site</a>).  I don&#8217;t know if it&#8217;s for the sexier (if more complicated) interface or just because they&#8217;ve got Quicksilver embedded in their fingers as badly as I&#8217;ve got LaunchBar in mine, but they&#8217;re unlikely to switch anytime soon.</p>
<p>And then there&#8217;s the folks out there who haven&#8217;t discovered the joys of a launcher program and just run Applescripts manually or with something like <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>.</p>
<p>All of which adds up to a bit of a conundrum if you want to share your favorite Applescripts with the world.  Fortunately, with a bit of Googling and some good old trial and error, I&#8217;ve written a simple Applescript template that allows all users, no matter how they like to launch scripts, to use yours.  Without further ado, here&#8217;s the code:</p>
<p><code>
<pre>-- You'll want to rename this function something appropriate
on action_function(someText)
    -- Check to see if we've got text, ask for it if not
    if someText is equal to "" then
        set question to display dialog ("Enter text:") default answer ""
        set someText to text returned of question
    end if
    -- Do whatever your script does here
end action_function

-- Quicksilver tie-in code
using terms from application "Quicksilver"
    on process text qsText
        my action_function(qsText)
    end process text
end using terms from

-- LaunchBar tie-in function
on handle_string(lbText)
    my action_function(lbText)
    open location "x-launchbar:hide"
end handle_string

-- Call the function in case the script was run directly
-- (Don't worry; this line won't execute if called from LB or QS)
my action_function("")</pre>
<p></code></p>
<p>If you&#8217;re familiar with Applescript, the code should be pretty self-explanatory.  You wrap all of the scripts actions into a function (called <span class="code">action_function</span> in the example), and then call that function using the specific access routines for Quicksilver or LaunchBar (with a normal call to the function included just in case the user directly accesses the script).  The code within <span class="code">action_function</span> is merely a fall-back in case it receives a blank string (you&#8217;ll likely only need the fallback if they are calling the script directly).  I leave any more specific error checking to you.</p>
<p>This template specifically accepts text; if your script needs to process a list of files, for example, you&#8217;ll need to change the code for the various programs appropriately (how specifically to do that I leave up to you, but the general template should still serve you well).  One caveat is that if you&#8217;re compiling the code, you&#8217;ll need Quicksilver installed (even if you only use LaunchBar).  However, as far as I can tell, if you&#8217;re just running the Applescript you don&#8217;t need to have either program installed (or you can have just one or the other).  The main downside of needing both to compile is that if you rely on your users to adjust config variables in your script, then they will need to install Quicksilver (unless you include instructions to remove Quicksilver&#8217;s code if they aren&#8217;t using it).</p>
<p>Let me know if you run into any trouble using this code!  I haven&#8217;t run into any errors with it in my testing, but that certainly doesn&#8217;t mean that they don&#8217;t exist.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/ccZ3iNFMiKc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2008/11/accept_text_applescript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2008/11/accept_text_applescript/</feedburner:origLink></item>
		<item>
		<title>TextSoap 6 and my XHTML Suite of custom cleaners</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/uqGLOMhscXE/</link>
		<comments>https://ianbeck.webfactional.com/2008/11/textsoap_6/#comments</comments>
		<pubDate>Sat, 22 Nov 2008 18:48:58 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Flow]]></category>
		<category><![CDATA[custom solution]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=260</guid>
		<description>In case you hadn&amp;#8217;t heard, TextSoap was updated to version 6.0 a few weeks ago.  I&amp;#8217;ve waited on posting about it because I wanted to share some of my custom cleaners (you can jump straight to the download if you&amp;#8217;re so inclined), and now I&amp;#8217;ve finally found the time.
For those who know about TextSoap, [...]</description>
			<content:encoded><![CDATA[<p>In case you hadn&#8217;t heard, <a href="http://www.unmarked.com/textsoap/index.html">TextSoap</a> was updated to version 6.0 a few weeks ago.  I&#8217;ve waited on posting about it because I wanted to share some of my custom cleaners (you can <a href="#ts-download">jump straight to the download</a> if you&#8217;re so inclined), and now I&#8217;ve finally found the time.</p>
<p>For those who know about TextSoap, version 6.0&#8217;s main benefit (at least from my point of view) is a vastly redesigned custom cleaner editor.  Cleaners can now run text through sub-routines, there&#8217;s a quick regex reference right in the window, and you can attach notes to cleaner actions to remind yourself what the heck that complicated regex pattern is supposed to be doing.  There are other improvements, as well, but the custom cleaners interface is where it&#8217;s at for me.  If you&#8217;re curious, check out the <a href="http://www.unmarked.com/textsoap/history.html">release notes</a> for the full scoop.</p>
<p>For those not in the know, TextSoap is a fantastic piece of software that allows you to make changes to plain and rich text both using built-in cleaners or custom cleaners that you define yourself by combining regular expressions and any of the built-in cleaners with familiar Automator-style rules.</p>
<p>Yeah, I know, it doesn&#8217;t sound too impressive, does it?  But that&#8217;s only because you&#8217;re used to wasting a lot of your time on mindless repetitive tasks involving text.  TextSoap not only provides an easy way to save sets of common text-based find and replace actions, but it allows you access to them from pretty much anywhere on your computer by integrating with popular programs via plugins, offering a system-wide contextual menu, or hanging out in the Services menu.</p>
<p>When I first bought TextSoap, I regretted it because I barely ever used it (this was back in version 4.0, I think).  Then one day I was doing something incredibly repetitive with text (I don&#8217;t even remember what), and I got fed up, launched TextSoap, and took a look at the custom cleaners.  I&#8217;ve never looked back.  Although the most powerful custom cleaners require knowledge of regular expressions, there are still hundreds of things you can do without ever worrying about regex simply by combining TextSoap&#8217;s provided cleaners with the building blocks available in custom cleaners.  TextSoap provides an approach to text manipulation that has saved me hundreds of hours of drudgery.</p>
<p>Over time, I&#8217;ve found that the custom cleaners I create tend to fall into two categories:</p>
<ol>
<li><strong>Cleaners that address specific problems</strong> that either recur or only happen once but require the same actions repeated a bunch in that sitting.  For instance, for one client I have to convert a Word document into a newsletter every two weeks, observing their byzantine rules for HTML formatting.  The first time I did it, it took a mind-numbing four hours.  The second time, I created a custom cleaner while I worked and it took me two.  The third time all I had to do was use the custom cleaner, and it took me one.  With practice, I&#8217;m now down to about forty minutes.</li>
<li><strong>Cleaners that address generic recurring actions</strong>.  These are cleaners that I&#8217;ve slowly tweaked over time, and now use primarily as building blocks for my task-specific cleaners.</li>
</ol>
<p>It&#8217;s this last type of cleaner that I would like to share with you.</p>
<h4 id="ts-download">My XHTML suite of custom cleaners</h4>
<p>My main use for TextSoap is manipulating HTML, and because I know a lot of other people out there have to do this on a regular basis I&#8217;ve decided to share the basic cleaners that serve as the foundation for my workflow.  TextSoap has revolutionized how I perform certain tasks (particularly converting styled text to HTML and converting really hideous HTML into tasty XHTML), and I strongly recommend it to any web junkie who has cursed out a previous developer for their table-filled monstrosity of a website.  Before I get into the nitty-gritty details of what&#8217;s included, here&#8217;s the download:</p>
<p class="center"><a class="standout" href="http://onecrayon.com/downloads/TextSoap_XHTML_Suite.zip">Download TextSoap XHTML Suite</a></p>
<p>Included are eight custom cleaners (if you&#8217;re only interested in one or two, see the ReadMe for details on which cleaners require one of their brethren):</p>
<ul>
<li><strong>Encode Ampersands</strong>. This encodes every ampersand that isn&#8217;t already part of an HTML entity.</li>
<li><strong>Escape Single Quotes</strong>. Primarily useful for Javascript, PHP, etc., this escapes all single quotes with a backslash.</li>
<li><strong>HTML Curly Quotes</strong>. For those clients who must have curly quotes, this is your solution.  It converts every quote outside of HTML tags into a curly. (Please note: only works for English curly quotes.)</li>
<li><strong>HTML Paragraphs</strong>. This converts text blocks separated by double line breaks into paragraphs, and converts single line breaks to <span class="code">&lt;br /&gt;</span> tags.</li>
<li><strong>Style to HTML</strong>. One of my workhorses, this cleaner takes richly formatted text and turns it into simple, paragraph-delineated HTML with appropriately placed <span class="code">strong</span> and <span class="code">em</span> tags.</li>
<li><strong>URLs to HTML Links</strong>. This cleaner finds all of the easily recognizable URLs in a document (starting with http, https, or www) and converts them into HTML anchor links.</li>
<li><strong>WebHappy</strong>.  This happy little cleaner simply converts richly styled italics and bold into <span class="code">strong</span> and <span class="code">em</span> tags, straightens all quotes, and converts any problematic characters into HTML entities.</li>
<li><strong>XHTML Cleaner</strong>.  This is a pretty hefty cleaner, and I run it by default on any HTML that needs serious love to turn into XHTML.  The cleaner performs a laundry list of common tasks (properly escaping self-closing tags, <span class="code">b</span> to <span class="code">strong</span>, lowercased tag and attribute names, etc.) and also attempts to add and remove linebreaks so that you can easily indent the code in your favorite editor (like <a href="http://macromates.com/">Textmate</a>).  I rarely use XHTML Cleaner directly, but it offers a great starting point for any custom cleaner that needs to deal with poorly written HTML.</li>
</ul>
<p>Although some of these cleaners are great on their own (I have a special place in my workflow for WebHappy, for instance, even if I never did think of a good descriptive name for it), a lot of them work best as the starting place for your own task-specific custom cleaners.  I&#8217;ve tried to add notes to all of the regex rules, as well, so they may help you figure out how best to perform your own tasks (keep in mind that some of these cleaners were developed while I was still figuring regex out, so some of those regular expressions are <em>narsty</em>).  If you improve or otherwise modify any of the core suite of cleaners, <a href="https://ianbeck.webfactional.com/about/">drop me a line</a> because I&#8217;d love to see what you&#8217;ve done.</p>
<p>Enjoy!</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/uqGLOMhscXE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2008/11/textsoap_6/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2008/11/textsoap_6/</feedburner:origLink></item>
		<item>
		<title>Coda 1.6 released, minor TEA for Coda update</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/N7a49lkRy_0/</link>
		<comments>https://ianbeck.webfactional.com/2008/11/coda_16/#comments</comments>
		<pubDate>Wed, 12 Nov 2008 01:27:57 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Adversaria]]></category>
		<category><![CDATA[custom solution]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=257</guid>
		<description>Coda 1.6 has been released, and boy howdy is it exciting!  Coda now includes a plugin architecture, including Cocoa plugins for people who need to be able to manipulate the interface and an easy-to-use plugin creator that will allow you to run plugins using command-line languages (similar to Textmate).  This is a fantastic [...]</description>
			<content:encoded><![CDATA[<p><a href="http://panic.com/coda/">Coda 1.6</a> has been released, and boy howdy is it exciting!  Coda now includes a plugin architecture, including Cocoa plugins for people who need to be able to manipulate the interface and an easy-to-use plugin creator that will allow you to run plugins using command-line languages (similar to Textmate).  This is a fantastic update, and as we start to see plugins being produced I don&#8217;t doubt that Coda will become more and more appealing for Textmate users who have been holding out.  It&#8217;s certainly not as powerful and flexible (no tab stops, for instance), but the addition of user-generated plugins will certainly allow people to do great things.</p>
<p>Along with the update to Coda, I&#8217;ve updated the TEA for Coda bundle (find the most recent version on the <a href="https://ianbeck.webfactional.com/tea_for_coda/">dedicated TEA for Coda page</a>); all of the scripts will now perform their actions in the active document even if multiple windows are open.  Additionally Indent New Line should be significantly improved performance-wise.  The scripts do now require Coda 1.6, though; if you&#8217;re running an old version of Coda expect buggy behavior.</p>
<p>I am unlikely to improve the TEA for Coda scripts anymore; my new goal will be to get the Textmate bundle items that I know and love into Coda using the plugin interface.  This will necessitate learning some Cocoa, though (since some of the key actions require user input), so it may be a little bit of time before I&#8217;m able to get a working plugin up and running.  In the interim (or until someone else does it), TEA for Coda is still the best way that I know to get Coda to behave like a full-blooded HTML editor.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/N7a49lkRy_0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2008/11/coda_16/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2008/11/coda_16/</feedburner:origLink></item>
		<item>
		<title>TEA for Coda now Universal Binary</title>
		<link>http://feedproxy.google.com/~r/beckism/~3/f2nu723APmI/</link>
		<comments>https://ianbeck.webfactional.com/2008/11/tea_universal_binary/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 16:22:43 +0000</pubDate>
		<dc:creator>Ian Beck</dc:creator>
				<category><![CDATA[Adversaria]]></category>
		<category><![CDATA[custom solution]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://beckism.com/?p=250</guid>
		<description>I&amp;#8217;ve posted a minor update to my TEA for Coda bundle.  This update includes two changes:

The HTML Tidy script is now a universal binary!  At long last, our PPC friends can run it just as easily as those with newer hardware.
The Format with Em and Format with Strong scripts now keep your text [...]</description>
			<content:encoded><![CDATA[<p>I&#8217;ve posted a minor update to my <a href="https://ianbeck.webfactional.com/tea_for_coda/">TEA for Coda</a> bundle.  This update includes two changes:</p>
<ul>
<li>The HTML Tidy script is now a universal binary!  At long last, our PPC friends can run it just as easily as those with newer hardware.</li>
<li>The Format with Em and Format with Strong scripts now keep your text highlighted rather than moving the cursor to the end.  This is not only more congruent with Textmate&#8217;s behavior, but I think it makes better sense, particularly if you ever need to wrap the text in more than one tag (or wish to add a class name, or&#8230;).</li>
</ul>
<p>You can get the update from the <a href="https://ianbeck.webfactional.com/tea_for_coda/">dedicated TEA for Coda page</a>.  Unless you use PathFinder or have some other way of viewing invisible files, you&#8217;ll need to replace the entire HTML directory (if you&#8217;ve made changes to the scripts, you should copy them into the new directory before replacing the old one).  If you are comfortable with invisible files, then you&#8217;ll just need to replace the <span class="code">.lib</span> directory and the <span class="code">Format</span> directory.</p>
<img src="http://feeds.feedburner.com/~r/beckism/~4/f2nu723APmI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>https://ianbeck.webfactional.com/2008/11/tea_universal_binary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>https://ianbeck.webfactional.com/2008/11/tea_universal_binary/</feedburner:origLink></item>
	</channel>
</rss>
