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

<channel>
	<title>patspam.com</title>
	<atom:link href="http://blog.patspam.com/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.patspam.com</link>
	<description>patspampatspampatspampatspam</description>
	<pubDate>Wed, 09 Jul 2008 01:36:09 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
	<language>en</language>
			<item>
		<title>My Road Bike</title>
		<link>http://blog.patspam.com/2008/my-road-bike</link>
		<comments>http://blog.patspam.com/2008/my-road-bike#comments</comments>
		<pubDate>Mon, 07 Jul 2008 08:11:07 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Cycling]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/?p=1041</guid>
		<description><![CDATA[With the Tour De France in full swing I thought I'd post some details about my current road bike.
The original bike that I bought in July 2007 in Osaka, Japan was a 2008 model Specialized Roubaix Elite Compact. The image I grabbed from the Specialized website is the exact same colour of my bike (I [...]]]></description>
			<content:encoded><![CDATA[<p>With the Tour De France in full swing I thought I'd post some details about my current road bike.</p>
<p>The original bike that I bought in July 2007 in Osaka, Japan was a <a href="http://www.specialized.com/bc/SBCBkModel.jsp?spid=33106">2008 model Specialized Roubaix Elite Compact</a>. The image I grabbed from the Specialized website is the exact same colour of my bike (I would have gone for something more interesting looking but it was hard enough finding a frame in my size in Japan, let alone being picky about colour).</p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/07/roubaix.jpg"><img class="alignnone size-medium wp-image-1042" title="2008 Specialized Roubaix Elite Compact" src="http://blog.patspam.com/wp-content/uploads/2008/07/roubaix-300x186.jpg" alt="2008 Specialized Roubaix Elite Compact" width="300" height="186" /></a></p>
<p>I bought her from Yoshito Yamamoto at <a href="http://www.cs-speed.com/">Cycle Station Speed</a> for about AU$2,000, roughly $1k less than the equivalent price here in Australia at the time (and subsequently got hit with $350-odd in duty by Australian Customs on the way home.. damnit!).</p>
<p>5000kms on Melbourne roads later my drive train was pretty worn out and the spokes on both wheels were becoming quite a pain (either frequently loosening or siezing up completely so that I couldn't adjust them to re-true the wheels).</p>
<p>I recently upgraded the wheels to <a href="http://www.eastonbike.com/PRODUCTS/WHEELS/08/wheel_ea90_sl_%2708.html">Easton EA90 SL</a> for approx AU$500 (big ups to ebay). At 1532 grams they're a lot lighter than my old Specialized wheels. They're similar to Easton's flagship <a href="http://www.eastonbike.com/PRODUCTS/WHEELS/08/wheel_ea90_slx_%2708.html">EA90 SLX</a> wheelset except that they have some extra steel spokes, which is great for someone looking for light but durable wheels. I'm not sure if it's just psychological, but they feel really responsive when accelerating.</p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/07/easton.jpg"><img class="alignnone size-medium wp-image-1043" title="Easton EA90 SL Wheelset" src="http://blog.patspam.com/wp-content/uploads/2008/07/easton-300x203.jpg" alt="Easton EA90 SL Wheelset" width="300" height="203" /></a><a href="http://blog.patspam.com/wp-content/uploads/2008/07/ea90sl_set.jpg"><img class="alignnone size-medium wp-image-1050" title="ea90sl_set" src="http://blog.patspam.com/wp-content/uploads/2008/07/ea90sl_set-300x286.jpg" alt="" width="300" height="286" /></a></p>
<p>I've also started upgrading my groupset from Shimano 105 to Dura-Ace. So far I've done the crankset, bottom bracket, rear cassette, chain-rings, and chain. The bottom bracket has had a ceramic bearing upgrade. Not sure if I can feel the difference with the ceramic bearnings, but overall it's definitely smoother than with my worn out old 105 components.<br />
<a href="http://blog.patspam.com/wp-content/uploads/2008/07/cs7800.jpg"><img class="alignnone size-medium wp-image-1047" title="cs7800" src="http://blog.patspam.com/wp-content/uploads/2008/07/cs7800-300x268.jpg" alt="" width="300" height="268" /></a></p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/07/fc-7800.jpeg"><img class="alignnone size-medium wp-image-1048" title="fc-7800" src="http://blog.patspam.com/wp-content/uploads/2008/07/fc-7800-300x225.jpg" alt="" width="300" height="225" /></a></p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/07/cn-7801.jpeg"><img class="alignnone size-medium wp-image-1049" title="cn-7801" src="http://blog.patspam.com/wp-content/uploads/2008/07/cn-7801-300x225.jpg" alt="" width="300" height="225" /></a></p>
<p>Here's a couple of recent pictures post-upgrade:</p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/07/duraeastonspecial.jpg"><img class="alignnone size-medium wp-image-1044" title="Dura-Ace Easton Roubaix" src="http://blog.patspam.com/wp-content/uploads/2008/07/duraeastonspecial-300x201.jpg" alt="Dura-Ace Easton Roubaix" width="300" height="201" /></a></p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/07/duraeastonspecial_closeup.jpg"><img class="alignnone size-medium wp-image-1045" title="Dura-Ace Easton Roubaix Closeup" src="http://blog.patspam.com/wp-content/uploads/2008/07/duraeastonspecial_closeup-300x225.jpg" alt="Dura-Ace Easton Roubaix Closeup" width="300" height="225" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2008/my-road-bike/feed</wfw:commentRss>
		</item>
		<item>
		<title>The Fold - A Kind Of Lightening Album Launch</title>
		<link>http://blog.patspam.com/2008/the-fold-a-kind-of-lightening-album-launch</link>
		<comments>http://blog.patspam.com/2008/the-fold-a-kind-of-lightening-album-launch#comments</comments>
		<pubDate>Mon, 07 Jul 2008 07:44:52 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/?p=1040</guid>
		<description><![CDATA[The Fold recently finished their debut album "A Kind of Lightening", and they're launching it Saturday 19th July at Noise Bar in Brunswick. I play trumpet on track 5 of the album ("six in the morning"), and I'll be playing with them on a bunch of tracks at the launch. You can listen to streaming [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://thefold.com.au/" target="_blank">The Fold</a> recently finished their debut album "A Kind of Lightening", and they're launching it Saturday 19th July at Noise Bar in Brunswick. I play trumpet on track 5 of the album ("six in the morning"), and I'll be playing with them on a bunch of tracks at the launch. You can listen to streaming snippets of the album (including the section of track 5 that I'm on) <a href="http://cdbaby.com/cd/thefold" target="_blank">here</a>.<br />
<a href="http://blog.patspam.com/wp-content/uploads/2008/07/the-fold-album-launch.jpg"></a></p>
<p style="text-align: center;"><img title="Launch Poster A3.ai" src="http://blog.patspam.com/wp-content/uploads/2008/07/the-fold-album-launch-217x300.jpg" alt="" width="217" height="300" /></p>
<p>The Fold are also going to be interviewed about the album on RRR's <a href="http://www.myspace.com/localandorgeneral">Local and/or General</a> radio program on Monday 14 July, 2008 @ 8pm.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2008/the-fold-a-kind-of-lightening-album-launch/feed</wfw:commentRss>
		</item>
		<item>
		<title>Flux: Rule-based Authorisation for WebGUI</title>
		<link>http://blog.patspam.com/2008/flux-rule-based-authorisation-for-webgui</link>
		<comments>http://blog.patspam.com/2008/flux-rule-based-authorisation-for-webgui#comments</comments>
		<pubDate>Mon, 07 Jul 2008 07:09:28 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/?p=1037</guid>
		<description><![CDATA[Recently I've been plugging away at an experimental "WebGUI_flux" branch of the awesome Perl based content management system / web application framework WebGUI that wG founder JT created for me a month or so ago. I'm happy to say that the code has progressed to the point where I'm ready to announce Flux to the [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I've been plugging away at an experimental "<a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/" target="_blank">WebGUI_flux</a>" branch of the awesome Perl based content management system / web application framework <a href="http://webgui.org">WebGUI</a> that wG founder JT created for me a month or so ago. I'm happy to say that the code has progressed to the point where I'm ready to announce Flux to the world and invite anyone who is interested to have a play with the demo server, explore the API, give me feedback and if you like the look of it, contribute some plugins of your own.</p>
<p>Here's the original impetus for building Flux:</p>
<blockquote><p>As per most content management systems, WebGUI's built-in authorization mechanism is based on User Group membership. This is perfectly adequate for a large class of websites: content managers define one or more User Groups and then set the "Who Can View" and "Who Can Edit" Security Tab options on their Wobjects to the appropriate group. However in one important aspect such sites are static in nature: the set of pages that a user can access is fixed according to what groups they belong to. Authorization can be made dynamic by manipulating group membership (manually, which isn't really dynamic, or via custom code) or by writing custom Wobject authorization logic. Both of these approaches work, however, custom code leaves content managers out of the loop.</p></blockquote>
<p>You can find the latest version of the design doc in SVN in <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/fluxdesigndocs/flux.pdf" target="_blank">pdf</a> and <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/fluxdesigndocs/flux.odt" target="_blank">odt</a> formats. Flux is quite large in scope and hard to condense into a single post, so please refer to the design doc if you want more details, but I'll try to give a quick summary here.</p>
<p>For content managers:</p>
<ul>
<li>Flux is a rule-based authorization layer for WebGUI content managers. What that means is that you can define Rules (using a GUI) that define the conditions that must be met for a user to be given access to an Asset. Each time a user tries to access an Asset, Flux evaluates the Rule(s) you have defined to see if the user should be granted access.</li>
<li>By default Flux is disabled, meaning zero performance hit and no change to the UI.</li>
<li>You can enable/disable Flux at the site-wide level (via the Flux Admin Console), and also on individual Assets (via the asset's Security Tab).</li>
<li>With Flux turned on for an Asset, the Security Tab shows a combo box containing all Flux Rules that you have defined. These combo boxes appear for each action your Asset supports (e.g. "Who Can View", "Who Can Edit", etc..). If you pick a Rule for an action, authorization logic for that action is delegated to that particular Flux Rule.</li>
<li>Rules are powerful, flexible, and pluggable.</li>
<li>You define Rules via a simple, intuitive step-by-step wizard in the Flux Admin Console.</li>
<li>Rules can depend on static information, user-specific information, time-dependent information, asset-specific information, and anything else we plug into the framework.</li>
<li>Rules can also depend on other Rules, meaning that you can construct an arbitrarily complex graph of connected Rules. Flux makes sure that infinite loops don't occur, and can even dynamically generate a visualisation of your Flux Graph showing all interrelationship between Rules</li>
</ul>
<div style="text-align: center;"><a href="http://blog.patspam.com/wp-content/uploads/2008/07/fluxgraph.png"><img class="alignnone size-medium wp-image-1038" title="fluxgraph" src="http://blog.patspam.com/wp-content/uploads/2008/07/fluxgraph-264x300.png" alt="" width="264" height="300" /></a></div>
<div>That's all content managers need to know to drive Flux. The interface is designed to be a minimal knowledge "monkey-see, monkey do" type affair.</p>
<p>For developers:</p>
</div>
<ul>
<li>Rules are made up of one or more Expressions</li>
<li>Each Expression is comprised of an Operator and two Operands.</li>
<li>The UI guides content managers through the process of picking these, displaying helpful messages and prompting for any additional information required along the way</li>
<li>The following Operators are built:
<ul>
<li>IsEqualTo, IsNotEqualTo</li>
<li>LessThan, LessThenOrEqualTo, GreaterThan, GreaterThanOrEqualTo</li>
<li>MatchesPartialText, DoesNotMatchPartialText</li>
</ul>
</li>
<li>The following Operands have been built:
<ul>
<li>TextValue - allows the content manager to enter a simple text value</li>
<li>NumericValue - allows the content manager to enter a numeric value</li>
<li>TruthValue - allows the content manager to enter yes/no</li>
<li>DateTime - allows the content manager to enter a date from a date-picker</li>
<li>Group - allows the content manager to choose a group from the wG Group combo box. The Operand evaluates to true/false depending on whether the user being tested against belongs to that group</li>
<li>UserProfileField - allows the content manager to specify the name of a User Profile field. The Operand evaluates to the value of that user profile field for the user being tested against.</li>
<li>FluxRule - allows the content manager to choose another Flux Rule from a combo box. The Operand evaluates to true/false depending on the result of testing that Flux Rule against the user.</li>
</ul>
</li>
<li>Operands can prompt the user for an arbitrary number of extra arguments as part of the step-by-step wizard. These arguments are stored as a JSON-encoded string.</li>
<li>Modifiers can be registered against Operand return types, causing the UI to prompt the content manager for extra information when an Operand is chosen during Expression building. For example, the following two Modifiers have been built and registered against the DateTime type:
<ul>
<li>DateTimeFormat - prompts the content manager for date format patterns (as per <a href="http://search.cpan.org/%7Edrolsky/DateTime-0.4302/lib/DateTime.pm#strftime_Patterns" target="_blank">strftime</a>()) so that the DateTime object can be formatted as a string. Also prompts the content manager for a timezone to use (any valid timezone can be specified, or 'user' which indicates that the timezone of the user being tested against should be used). This is useful so that you can e.g. compare a DateTime object to a string such as "Monday".</li>
<li>DateTimeCompareToNow - prompts the content manager for a timezone and a Duration unit to use (e.g. 'hours', 'days', etc..). This allows you to construct Rules that evaluate to true a certain number of days since a particular date etc..</li>
</ul>
</li>
<li>By default, multiple Expressions are ANDed together. But if you like you can specify an arbitrarily complex boolean logical expression instead (using AND, OR, NOT and parenthesis).</li>
</ul>
<p>I've included a contrived example, which might makes things clearer. It might also make things more confusing since you don't have the nice UI to guide you through the process of building the Expressions, but see how you go..</p>
<p>Imagine you have a WebGUI site with some content that you want to show to your French users only.</p>
<ul>
<li>You create a Rule called "French Only" and then add an Expression to it that has:
<ul>
<li>operand1: <strong>UserProfileField</strong></li>
<li>operand1Args:<strong> {field: homeCountry}</strong> # note that this is JSON-encoded</li>
<li>operator: <strong>IsEqualTo</strong></li>
<li>operand2: <strong>TextValue</strong></li>
<li>operand2Args:<strong> {value: "France"}</strong></li>
</ul>
</li>
<li>You then enable Flux on the Security Tab for that content and choose the "French Only" Rule from the drop-down list for "Who Can View"&#8230; voila!</li>
</ul>
<p>Now say you've been using good old-fashioned Group membership on your site. Let's assume you have a "Premium Members" Group. On a whim, you decide your content should be restricted to French Premium Members:</p>
<ul>
<li>You add a second Expression to the "French Only" Rule to require the Premium Members group:
<ul>
<li>operand1: <strong>Group</strong></li>
<li>operand1Args: <strong>{groupId: &lt;id of Premium Members group as chosen from group combo box&gt;}</strong></li>
<li>operator: <strong>IsEqualTo</strong></li>
<li>operand2: <strong>TruthValue</strong></li>
<li>operand2Args: <strong>{value: 1}</strong></li>
</ul>
</li>
</ul>
<p>A few weeks later, you decide to add an extra page that French Premium Members can see on their birthday.</p>
<ul>
<li>You create a new Rule called "Bon Anniversaire" and add an Expression linking to your earlier "French Only" Rule:
<ul>
<li>operand1: <strong>FluxRule</strong></li>
<li>operand1Args: <strong>{fluxRuleId: &lt;id of the "French Only" Flux Rule as chosen from a combo box&gt;}</strong></li>
<li>operator: <strong>IsEqualTo</strong></li>
<li>operand2: <strong>TruthValue</strong></li>
<li>operand2Args:<strong> {value: 1}</strong></li>
</ul>
</li>
<li>..and a second Expression requiring that today be the user's birthday (in their time zone of course):
<ul>
<li>operand1: <strong>UserProfileField</strong></li>
<li>operand1Args: <strong>{field: birthdate}</strong></li>
<li>operand1Modifier: <strong>DateTimeCompareToNow</strong></li>
<li>operand1ModifierArgs: <strong>{units: "days", time_zone: "user"}</strong> # Modifier args are JSON-encoded too</li>
<li>operator: <strong>IsEqualTo</strong></li>
<li> operand2: <strong>NumericValue</strong></li>
<li>operand2Args:<strong> {value: 0}</strong></li>
</ul>
</li>
</ul>
<p>Cool huh?</p>
<p>Hopefully that gives you a feel for the power of the framework. Be sure to check out the design docs for more details (did I mention it also supports Workflow triggers?). The test suite (in t/Flux) is pretty comprehensive (currently at &gt;85% coverage) - the Operand-specific tests in particular should get you up to speed pretty quickly on how to drive Flux.</p>
<p>Test Coverage Report:</p>
<pre>---------------------------- ------ ------ ------ ------ ------ ------ ------

File                           stmt   bran   cond    sub    pod   time  total

---------------------------- ------ ------ ------ ------ ------ ------ ------

lib/WebGUI/Flux.pm             88.1   71.9   50.0  100.0   75.0    2.4   82.3

...WebGUI/Flux/Expression.pm   93.3   85.7   60.0   89.5  100.0   17.2   89.1

...lux/Expression/Builder.pm  100.0    n/a    n/a  100.0    n/a    0.1  100.0

lib/WebGUI/Flux/Modifier.pm    84.9   61.9   44.4  100.0  100.0    2.9   77.0

...r/DateTimeCompareToNow.pm  100.0  100.0    n/a  100.0    0.0    0.2   92.6

...odifier/DateTimeFormat.pm  100.0   50.0    n/a  100.0    0.0    0.3   87.5

lib/WebGUI/Flux/Operand.pm     85.9   66.7   44.4  100.0  100.0   14.7   78.9

.../Flux/Operand/DateTime.pm  100.0    n/a    n/a  100.0    0.0    0.2   91.3

.../Flux/Operand/FluxRule.pm   97.1   83.3    n/a  100.0    0.0    1.3   90.0

...GUI/Flux/Operand/Group.pm  100.0    n/a    n/a  100.0    0.0    0.1   90.5

...x/Operand/NumericValue.pm  100.0    n/a    n/a  100.0    0.0    0.1   89.5

...Flux/Operand/TextValue.pm  100.0    n/a    n/a  100.0    0.0    0.6   89.5

...lux/Operand/TruthValue.pm  100.0    n/a    n/a  100.0    0.0    0.1   89.5

...erand/UserProfileField.pm  100.0    n/a    n/a  100.0    0.0    0.1   90.5

lib/WebGUI/Flux/Operator.pm    84.5   53.1   33.3  100.0  100.0   14.5   75.0

...oesNotMatchPartialText.pm  100.0    n/a    n/a  100.0    0.0    0.1   95.5

...lux/Operator/IsEqualTo.pm  100.0  100.0  100.0  100.0    0.0    1.8   96.6

...Operator/IsGreaterThan.pm  100.0  100.0  100.0  100.0    0.0    0.2   96.6

...IsGreaterThanOrEqualTo.pm  100.0  100.0  100.0  100.0    0.0    0.2   96.6

...ux/Operator/IsLessThan.pm  100.0  100.0   66.7  100.0    0.0    0.2   93.1

...or/IsLessThanOrEqualTo.pm  100.0  100.0  100.0  100.0    0.0    0.2   96.6

.../Operator/IsNotEqualTo.pm  100.0  100.0  100.0  100.0    0.0    0.2   96.6

...tor/MatchesPartialText.pm  100.0    n/a    n/a  100.0    0.0    0.1   95.5

lib/WebGUI/Flux/Rule.pm        94.9   88.9   84.4   93.3   93.8   42.4   92.3

Total                          93.1   75.7   70.2   97.8   53.2  100.0   87.4

---------------------------- ------ ------ ------ ------ ------ ------ ------</pre>
<p>Implementation status:</p>
<ul>
<li>You can do just about everything through the API (check out the test suite for more info)</li>
<li>You can write your own Operands and Operators as plugins. To give you an idea of how easy it is to add your own plugins, <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operand/DateTime.pm" target="_blank">most</a> <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operand/Group.pm" target="_blank">of</a> <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operand/NumericValue.pm" target="_blank">the</a> <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operand/TextValue.pm" target="_blank">current</a> <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operand/TruthValue.pm" target="_blank">Operands</a> <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operand/UserProfileField.pm" target="_blank">require</a> 1-3 lines of unique code. Operators are <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operator/IsEqualTo.pm" target="_blank">simple</a> <a href="https://svn.webgui.org/plainblack/branch/WebGUI_flux/lib/WebGUI/Flux/Operator/IsLessThan.pm" target="_blank">too</a>.</li>
<li>The Flux Admin Console is working, although not ajaxified yet</li>
<li>Per-asset Flux authorization UI options are available on some Assets, although only tested on Article and PageLayout thus far and not pretty.</li>
<li>I've only implemented a simple CRUD interface for manipulating Rules and Expressions through the Admin console. The current interface is really just a simple slap-dash job put together so that people can play with the underlying framework without needing to write code. The Expression builder in particular is quite clunky to use - you need to pass in fully-formed JSON Operand arguments. The UI has inline documentation to help you do this. The design doc has mock-ups of what the finished UI will look like.</li>
<li>I haven't implemented Wobject-bound Rules, although I will soon - this is where Flux teams up with next generation WebGUI Wobjects such as Thingy and Survey 2.0 to do some really cool things (check the design doc).</li>
</ul>
<p>I've set up a <a href="http://flux.sdhconsulting.com.au/" target="_blank">demo server</a> where you can play with Flux. The demo sites come pre-bundled with some Rules to get you started: go the the Flux item in the Admin Console and click on Flux Graph to generate your version of the image attached to this email. As mentioned, you'll probably find the Expression builder pretty awkward since it nice step-by-step wizard isn't built yet.</p>
<p>You can also download the latest version of the code from SVN and run it yourself - be aware that visualisation of the Flux Graph is currently done using <a href="http://search.cpan.org/%7Elbrocard/GraphViz-2.03/lib/GraphViz.pm" target="_blank">GraphViz</a> so you will need to install it on your system using something similar to "apt-get install graphviz gsfonts" and "cpan GraphViz".</p>
<p>The big caveat for getting Flux included in a future version of WebGUI is performance. Obviously checking Flux Rules is more expensive than doing a single call to $user-&gt;isInGroup(). I've done quite a bit of work on benchmarking, profiling and optimisation, and so far things look good but there's still work to be done. I'll save that discussion for a later post.</p>
<div>I'm looking forward to your feedback. Anyone who wants to get involved please don't hesitate to drop me a line or ping me on #webgui on freenode. I'll also be at the 2008 WebGUI User Conference if you want to talk to me about Flux in person.</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2008/flux-rule-based-authorisation-for-webgui/feed</wfw:commentRss>
		</item>
		<item>
		<title>REST has won the war?</title>
		<link>http://blog.patspam.com/2008/rest-has-won-the-war</link>
		<comments>http://blog.patspam.com/2008/rest-has-won-the-war#comments</comments>
		<pubDate>Tue, 15 Apr 2008 03:19:59 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/?p=1034</guid>
		<description><![CDATA[Something interesting..
I was chatting to Mike Culver, Amazon Web Services "Evangelist", after his talk on AWS here in Melbourne the other day. I'd gone up to tell him how great it was that Amazon had implemented their web services with such a well-designed REST interface (I'm quite obsessed with REST at the moment). He made [...]]]></description>
			<content:encoded><![CDATA[<p>Something interesting..</p>
<p>I was chatting to <a href="http://www.amazon.com/gp/pdp/profile/A2D5YJLCHYWN9Q">Mike Culver</a>, <a href="http://aws.amazon.com/">Amazon Web Services</a> "Evangelist", after his talk on <a href="http://aws.amazon.com/">AWS</a> here in Melbourne the other day. I'd gone up to tell him how great it was that Amazon had implemented their web services with such a well-designed <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> interface (I'm quite <a href="http://extjs.com/learn/Manual:RESTful_Web_Services">obsessed</a> with REST at the moment). He made the comment that as far as he was concerned, REST had "won the war" against other architectures such as <a href="http://en.wikipedia.org/wiki/SOAP">SOAP</a>, REST-RPC, etc..</p>
<p>I don't think the battle is over yet but it's great to hear that coming from the mouth of someone at one of the biggest players in the Web Service field. REST ftw!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2008/rest-has-won-the-war/feed</wfw:commentRss>
		</item>
		<item>
		<title>Tarpo</title>
		<link>http://blog.patspam.com/2008/tarpo</link>
		<comments>http://blog.patspam.com/2008/tarpo#comments</comments>
		<pubDate>Tue, 15 Apr 2008 02:53:15 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[AIR]]></category>

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

		<guid isPermaLink="false">http://blog.patspam.com/?p=1030</guid>
		<description><![CDATA[A huge class of applications are nothing more than a bunch of relational database tables with a simple Create Read Update Delete (CRUD) user interface. More and more these applications are being built as web-apps, eg. the user interface is HTML/CSS/Javascript running inside a users' browser, and the backend is a simple server-side layer (Perl/PHP/Ruby/J2EE/..) [...]]]></description>
			<content:encoded><![CDATA[<p>A huge class of applications are nothing more than a bunch of relational database tables with a simple <strong>C</strong>reate <strong>R</strong>ead <strong>U</strong>pdate <strong>D</strong>elete (CRUD) user interface. More and more these applications are being built as web-apps, eg. the user interface is HTML/CSS/Javascript running inside a users' browser, and the backend is a simple server-side layer (Perl/PHP/Ruby/J2EE/..) controlling access to an online database. This architecture is becoming increasingly easy to implement with the advent of server-side web/application frameworks (Catalyst/Rails/Spring) and database <strong>O</strong>bject <strong>R</strong>elational <strong>M</strong>appers (DBIx::Class/ActiveRecord/Hibernate,..) that remove most of the tedium, along with awesome Javascript libraries in the front-end (ExtJS/jQuery/Dojo/..) that let you make the user interface much more engaging and adaptable.</p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/04/maningrida_surgery.jpg"><img class="alignleft size-thumbnail wp-image-1035" style="float: left; margin: 5px;" title="maningrida_surgery" src="http://blog.patspam.com/wp-content/uploads/2008/04/maningrida_surgery-150x150.jpg" alt="" width="150" height="150" /></a><a href="http://blog.patspam.com/wp-content/uploads/2008/04/maningrida_tech.jpg"><img class="alignright size-thumbnail wp-image-1036" style="float: right; margin: 5px;" title="maningrida_tech" src="http://blog.patspam.com/wp-content/uploads/2008/04/maningrida_tech-150x150.jpg" alt="" width="150" height="150" /></a>What happens, however, when your intended users have no internet access? I was recently faced with that exact problem: My Dad (Dr Ted Donelan) runs a pro bono dog health program in Maningrida, a self-governing aboriginal community in Arnhem Land (500km east of Darwin) where, unless you want to pay through the teeth for that Telstra NextG internet rubbish, there's no easy access to the internet. And certainly no way of logging into a website while you're riding around from house to house in a ute or carrying out surgery on an outdoor trestle table  underneath the local grog-shelter. Dr Ted wanted a way to record the statistical information that he collects (dog body conditions, mange scores, fleas, ticks, etc..) along with his formal veterinary records of surgical cases, medical cases, etc.. All of which can be neatly captured in a handful of relational tables (attested by the fact that previously he had been recording his data in hand-written tables, later to be transferred to Excel). I suppose I could have stepped back into the C#/Java world and implemented a stand-alone app to solve the problem, but I'm not familiar enough with any frameworks in those languages to whip up something quickly. And that was the point, I only had a small amount of time to come up with a solution. And what I really wanted was a way to build him a stand-alone app using my existing HTML/Javascript/CSS-fu..</p>
<p>Cue <a href="http://www.adobe.com/products/air/">Adobe AIR</a>.. a desktop framework that lets you build traditional dektop apps using web technologies. Now I'm not the biggest fan of proprietary technology (Adobe Flash being a prime example) since it goes against the grain of the Open Web, but there's really no open-source alternatives at the moment.</p>
<p>The first really awesome AIR app I saw was ExtJS creator Jack Slockum's "<a href="http://extjs.com/blog/2008/02/24/tasks2/">Simple Tasks</a>". Check out the screen-shots and you'll see why I was excited: here was a desktop application with an embedded (SQLite) database running pure HTML/CSS/Javascript. And not just any Javascript either. ExtJS shines most when used to create windows application-style interfaces, and as such it's the perfect library to use in an AIR app when you really are building a desktop application.</p>
<p>Simple Tasks is released under GPL v3, so I decided to base my code on Jack's. It was the right decision. With no prior experience with AIR it took less than a day to have a working prototype, and by working I mean a full database implementation, an editable data grid and an Add/Edit form for individual rows, all with the trademark ExtJS polish. That's ridiculously fast.</p>
<p>After about 4 days with lots of feedback from Dr. Ted we had a finished app, named <strong><a href="http://patspam.com/tarpo">Tarpo</a></strong>, complete with polished input forms, reporting, backup, CSV/XML export, &#8230;</p>
<p><a href="http://blog.patspam.com/wp-content/uploads/2008/04/tarpo.jpg"><img class="alignnone size-thumbnail wp-image-1032" title="tarpo" src="http://blog.patspam.com/wp-content/uploads/2008/04/tarpo-150x150.jpg" alt="" width="150" height="150" /></a><br />
<a href="http://blog.patspam.com/wp-content/uploads/2008/04/tarpo-2.jpg"><img class="alignnone size-thumbnail wp-image-1033" title="tarpo-2" src="http://blog.patspam.com/wp-content/uploads/2008/04/tarpo-2-150x150.jpg" alt="" width="150" height="150" /></a></p>
<p>I'll be releasing <a href="http://patspam.com/tarpo">Tarpo</a> under GPL v3. Until then I've got a little <a href="http://patspam.com/tarpo">page</a> where you can install it straight off the web and have a play. Dr. Ted is heading up to Maningrida next week so I'm excited to see how <a href="http://patspam.com/tarpo">Tarpo</a> goes on her first test-run. If everything works well we'll make her available to other Vets running similar programs in other indigenous communities. One cool follow-on from this will be that vets running <a href="http://amrric.org">AMRRIC</a>-endorsed programs could use <a href="http://patspam.com/tarpo">Tarpo</a> to submit their activity reports direct to the <a href="http://amrric.org">AMRRIC</a> website (which I recently developed).</p>
<p>Andy (also of <a href="http://sdhconsulting.com.au">SDH</a>) is whipping up a <a href="http://patspam.com/tarpo">Tarpo</a> logo for me, which I'll post up here as soon as he's finished inking it!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2008/tarpo/feed</wfw:commentRss>
		</item>
		<item>
		<title>cPanel Automated Backups</title>
		<link>http://blog.patspam.com/2008/cpanel-automated-backups</link>
		<comments>http://blog.patspam.com/2008/cpanel-automated-backups#comments</comments>
		<pubDate>Tue, 18 Mar 2008 09:24:02 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Bookmarklets]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/2008/03/18/cpanel-automated-backups/</guid>
		<description><![CDATA[I just scratched an itch I've had for a long time - a proper way to backup cPanel accounts from a reseller account. Up until now I've been scripting w get to grab the daily-generated backup of specific accounts every week (imitating what you can do manually by logging into cPanel and navigating to the [...]]]></description>
			<content:encoded><![CDATA[<p>I just scratched an itch I've had for a long time - a proper way to backup cPanel accounts from a reseller account. Up until now I've been scripting w get to grab the daily-generated backup of specific accounts every week (imitating what you can do manually by logging into cPanel and navigating to the Backup tab). It was annoying because I had to manually put in the username and password of each account I wanted to backup. What I really wanted was a solution to <strong>backup all accounts </strong>with minimal fuss.</p>
<p>The solution is a cron job that runs from my reseller account (you don't need SSH access to do this as cPanel gives you access to your crontab). The solution looks like this:</p>
<div class="codesnip-container" >nice -n 19 tar czhf - ~/backups | ssh user@server.com "cat > /cPanel_backups/$(date +\%A).tgz"</div>
<p>My reseller server puts the daily-generated backups into ~/backups. So, all we have to do is tar this up and copy it over to a backup server. </p>
<p>Notes:</p>
<ul>
<li>We give tar the <strong>h</strong> option so that it stores the contents of symlinked directories in the archive, not real symlinks (the /backups directory in the primary reseller account contains symlinks inside sub-account subdirectories to the real location of eg. mysql snapshots etc..)</li>
<li>We compress the entire directory and pipe it across the wire via ssh</li>
<li>The backup is stored with the current day of the week in the name, effectively giving us 7-day rotation</li>
<li>You should set up password-less SSH access using public/private keys so that the command isn't prompted for a password</li>
<li>The above command should be run from cron</li>
<li>The backslash escaping of the percentage sign in the date command is necessary when the command is run from cron </li>
<li>UPDATE: <strong>nice</strong>'d the command so that it doesn't consume too many resources and get killed by my provider <img src='http://blog.patspam.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </li>
</ul>
<p>As usual, I've documented this for future reference in <a href="http://paddypedia.patspam.com/index.php?title=CPanel">Paddypedia</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2008/cpanel-automated-backups/feed</wfw:commentRss>
		</item>
		<item>
		<title>Why do we bother with IE?</title>
		<link>http://blog.patspam.com/2007/why-do-we-bother-with-ie</link>
		<comments>http://blog.patspam.com/2007/why-do-we-bother-with-ie#comments</comments>
		<pubDate>Thu, 18 Oct 2007 11:02:45 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[On My Mind]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/2007/10/18/why-do-we-bother-with-ie/</guid>
		<description><![CDATA[Why do we web developers spend so many hours making web pages work for broken browsers like Internet Explorer? Aside from the technical challenge it's a complete waste of our collective energy, and every time you implement a work-around you're giving people one less reason to ditch the non-standards-compliant browser. Ok, if you're building a [...]]]></description>
			<content:encoded><![CDATA[<p>Why do we web developers spend so many hours making web pages work for broken browsers like <a href="http://en.wikipedia.org/wiki/Criticism_of_Internet_Explorer">Internet Explorer</a>? Aside from the technical challenge it's a complete waste of our collective energy, and every time you implement a work-around you're giving people one less reason to ditch the non-standards-compliant browser. Ok, if you're building a site for someone else they'll probably stipulate that you need to make the site as accessible as possible, so go ahead and apply the hacks for them. But if it's your own site, what's your excuse? </p>
<p><a href="http://getfirefox.com">Firefox</a> is obviously my browser of choice but there's also plenty of other alternatives to Internet Explorer. As of today, anyone viewing this site in Internet Explorer will be presented with a message across the top of the site encouraging them to ditch IE for a browser that supports the Open Web.</p>
<p><a href='http://blog.patspam.com/wp-content/uploads/2007/10/getfirefox2.png' title=''><img src='http://blog.patspam.com/wp-content/uploads/2007/10/getfirefox2.png' alt='' /></a></p>
<p>For those interested in implementing a similar scheme on their wordpress blogs, the code I have used is shown below (a modified version of Markus Opolka's <a href="http://www.martialblog.de">Anti IE Bar </a>wordpress plugin)</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">&lt;?php</span></p>
<p><span class="kw2">function</span> wp_anti_ie_bar<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$ua</span> = <a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">&#40;</span><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">'HTTP_USER_AGENT'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$isOpera</span> = !<span class="br0">&#40;</span><a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$ua</span>, <span class="st0">"opera"</span><span class="br0">&#41;</span> === <span class="kw2">false</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$isIE</span> = !<span class="re0">$isOpera</span> &amp;&amp; !<span class="br0">&#40;</span><a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$ua</span>, <span class="st0">"msie"</span><span class="br0">&#41;</span> === <span class="kw2">false</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$isIE</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">"&lt;div class='meta'&gt;"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">"It looks like you're using &lt;strong&gt;&lt;a href='http://en.wikipedia.org/wiki/Criticism_of_Internet_Explorer' target='_blank'&gt;Microsoft Internet Explorer&lt;/a&gt;&lt;/strong&gt; to browse the web. For the sake of &lt;a href='http://www.alternativebrowseralliance.com/why.html' target='_blank'&gt;the open web and the future of the internet&lt;/a&gt;, not to mention your own &lt;a href='http://www.mozilla-europe.org/en/products/firefox/features/#experience' target='_blank'&gt;web browsing experience&lt;/a&gt; and &lt;a href='http://www.mozilla-europe.org/en/products/firefox/features/#secure' target='_blank'&gt;security&lt;/a&gt;, please do yourself a favour and switch to &lt;a href='http://getfirefox.com' target='_blank'&gt;Firefox&lt;/a&gt; (follow the link for instructions on how to download and install Firefox)."</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">"&lt; /div&gt;"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>&nbsp; &nbsp; &nbsp; &nbsp;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">function</span> wp_anti_ie_bar_header<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/function_exists"><span class="kw3">function_exists</span></a> <span class="br0">&#40;</span><span class="st0">'wp_anti_ie_bar'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wp_anti_ie_bar<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p>add_action<span class="br0">&#40;</span><span class="st0">'wp_head'</span>, <span class="st0">'wp_anti_ie_bar_header'</span><span class="br0">&#41;</span>;<br />
<span class="kw2">?&gt;</span></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2007/why-do-we-bother-with-ie/feed</wfw:commentRss>
		</item>
		<item>
		<title>Multiple Columns Bookmarklet</title>
		<link>http://blog.patspam.com/2007/multiple-columns-bookmarklet</link>
		<comments>http://blog.patspam.com/2007/multiple-columns-bookmarklet#comments</comments>
		<pubDate>Fri, 05 Oct 2007 10:23:40 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Bookmarklets]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/2007/10/05/multiple-columns-bookmarklet/</guid>
		<description><![CDATA[Reading large chunks of text on a widescreen monitor can be a real pain if your eyes have to read across long horizontal lines. That's why newspapers print articles in columns! Ideally, websites should too, at least when you're trying to view them on a large monitor. Obviously you can't expect webpage designers to predict [...]]]></description>
			<content:encoded><![CDATA[<p>Reading large chunks of text on a widescreen monitor can be a real pain if your eyes have to read across long horizontal lines. That's why newspapers print articles in columns! Ideally, websites should too, at least when you're trying to view them on a large monitor. Obviously you can't expect webpage designers to predict the size of your screen, but if you're using Firefox you can use this simple <a href="http://en.wikipedia.org/wiki/Bookmarklet">bookmarklet</a> I wrote to reformat a selection of text (or the whole page) into multiple columns yourself.</p>
<p><strong>How to use it the Multiple Columns Bookmarklet:</strong><br />
This is the link to my <a href="javascript:(function(){var a = getSelection();if (a.isCollapsed) {	a=document.body;} else {	a = a.getRangeAt(0).commonAncestorContainer;	if (a.nodeType == 3) {	    a = a.parentNode;	}}if ('%s' == 'max') {a.style.height = window.innerHeight - 40;}a.style.MozColumnWidth = '200px';a.style.MozColumnGap = '20px';})();">Multiple Columns Bookmarklet</a>.</p>
<p>For starters, try it out yourself on this page! Select a few words in the first paragraph of this page and click the bookmarklet link. You should see it magically reformat into multiple columns 200px wide.</p>
<p>Now select two continuous paragraphs and click the bookmarklet link. You should see the entire article reformatted into easy to read columns. Cool huh?</p>
<p>If you want to use the bookmarklet on other pages, bookmark it now. When you're on a page that you want to reformat select the chunk of text and click on the bookmarklet. voila!</p>
<p>If you select text a single paragraph, only that paragraph will be turned into columns. If you select multiple paragraphs, the containing DOM element will be reformated (this isn't perfect but it usually does what you want). If no text is selected when you launch the bookmarklet, the entire page will be turned into multiple columns (that won't look great on my blog, but it's handy on pages with <a href="http://www.prescod.net/rest/encoding/">minimal styling</a>)</p>
<p>If you add a keyword such as <strong>col</strong> to your bookmarklet link (Right Click > Properties), then you can launch the bookmarklet from the location bar by typing <strong>col</strong> rather than clicking on the link. </p>
<p>Finally, if you provide an argument of <strong>max</strong>, eg. <strong>col max</strong> then the maximum height of the columns will be set to the size of your web browser window. This is really handy if you're viewing a long document and you don't want the columns to scroll vertically for miles and miles (by setting the column height the columns will instead continue horizonally, just like a large-format newspaper).</p>
<p>In case you're wondering, the bookmarklet is only intended for Firefox because none of the other browsers have implemented any column-related CSS features.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2007/multiple-columns-bookmarklet/feed</wfw:commentRss>
		</item>
		<item>
		<title>Getting lazy in Perl</title>
		<link>http://blog.patspam.com/2007/getting-lazy-in-perl</link>
		<comments>http://blog.patspam.com/2007/getting-lazy-in-perl#comments</comments>
		<pubDate>Mon, 01 Oct 2007 11:26:36 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/2007/10/01/getting-lazy-in-perl/</guid>
		<description><![CDATA[Maybe it's a sign I've been spending too much time playing with javascript lately, but when I revisited some code I'd written in Perl recently I suddenly realised that the tangled web of private object initialisers I was staring at would be so much simpler if I used lazy initialisation instead. Javascript makes lazy initialisation [...]]]></description>
			<content:encoded><![CDATA[<p>Maybe it's a sign I've been spending too much time playing with javascript lately, but when I revisited some code I'd written in Perl recently I suddenly realised that the tangled web of private object initialisers I was staring at would be so much simpler if I used <a href="http://en.wikipedia.org/wiki/Lazy_initialisation">lazy initialisation</a> instead. Javascript makes lazy initialisation easy because its a <a href="http://en.wikipedia.org/wiki/Functional_programming">functional programming language</a>:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">function</span> lazy<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> lazyVar = <span class="st0">"initialValue"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; lazy = <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="kw1">return</span> lazyVar;<span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> lazyVar;<br />
<span class="br0">&#125;</span><br />
console.<span class="me1">log</span><span class="br0">&#40;</span><span class="st0">"Before first call: "</span> + lazy.<span class="me1">toString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
console.<span class="me1">log</span><span class="br0">&#40;</span><span class="st0">"First call returns: "</span> + lazy<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
console.<span class="me1">log</span><span class="br0">&#40;</span><span class="st0">"After first call: "</span> + lazy.<span class="me1">toString</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
console.<span class="me1">log</span><span class="br0">&#40;</span><span class="st0">"Second call returns: "</span> + lazy<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</div>
<p>If you run the above in a javascript console such as Firebug, you'll see that after the first call which initialises <strong>lazyVar</strong>, the function is redefined to be the closure which eliminates the initialisation step on all subsequent calls.</p>
<p>So anyway, I started wondering how I'd achieve the same thing in Perl. It's easy enough to see how you'd cause the initialisation to be lazy (without actually redefining the subroutine to speed up subsequent calls):</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">sub</span> lazySub <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$self</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$priv</span> = <span class="st0">"_lazy"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> <span class="kw1">if</span> <a href="http://www.perldoc.com/perl5.6/pod/func/exists.html"><span class="kw3">exists</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> = <span class="st0">'initialValue'</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>The above is a handy template, but things would be a lot easier to use if we encapulated the above into a subroutine of its own:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">sub</span> lazyInit<span class="br0">&#40;</span>\&amp;<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$self</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$priv</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$f</span>&nbsp; &nbsp; = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> <span class="kw1">if</span> <a href="http://www.perldoc.com/perl5.6/pod/func/exists.html"><span class="kw3">exists</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> = &amp;<span class="re0">$f</span>;<br />
<span class="br0">&#125;</span><br />
<span class="kw2">sub</span> lazy <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$self</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="me1">lazyInit</span><span class="br0">&#40;</span><span class="st0">"_lazy"</span>, <span class="kw2">sub</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="st0">'initialValue'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Now that's looking better, we're passing in a string to use as the private identifier and an anonymous subroutine to use as the initialiser.</p>
<p>Now when I actually started using this, I realised that the private identifier that I was using was always the name of the subroutine (with an underscore prefix to indicate that it's private). So I eliminated the first argument altogether by using <strong>caller()</strong>;</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">sub</span> lazyInit<span class="br0">&#40;</span>\&amp;<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$self</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$f</span>&nbsp; &nbsp; = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$priv</span> = <span class="st0">"_"</span> . <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">"::"</span>, <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/caller.html"><span class="kw3">caller</span></a><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> <span class="kw1">if</span> <a href="http://www.perldoc.com/perl5.6/pod/func/exists.html"><span class="kw3">exists</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> = &amp;<span class="re0">$f</span>;<br />
<span class="br0">&#125;</span><br />
<span class="kw2">sub</span> lazy <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$self</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="me1">lazyInit</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">sub</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="st0">"initalValue"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>That's all well and good, but what if we want to be able to overwrite the value? Or force the initialising function to be called again?</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">sub</span> lazyInit<span class="br0">&#40;</span>\&amp;<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="br0">&#40;</span><span class="re0">$self</span>, <span class="re0">$initialiser</span>, <span class="re0">%args</span><span class="br0">&#41;</span> = <span class="re0">@_</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$priv</span> = <span class="st0">"_"</span> . <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">"::"</span>, <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/caller.html"><span class="kw3">caller</span></a><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/exists.html"><span class="kw3">exists</span></a> <span class="re0">$args</span><span class="br0">&#123;</span>overwrite<span class="br0">&#125;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> = <span class="re0">$args</span><span class="br0">&#123;</span>overwrite<span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">elsif</span> <span class="br0">&#40;</span><span class="kw1">not</span> <a href="http://www.perldoc.com/perl5.6/pod/func/exists.html"><span class="kw3">exists</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> <span class="kw1">or</span> <a href="http://www.perldoc.com/perl5.6/pod/func/defined.html"><span class="kw3">defined</span></a> <span class="re0">$args</span><span class="br0">&#123;</span>forceReload<span class="br0">&#125;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> = &amp;<span class="re0">$initialiser</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<span class="kw2">sub</span> lazy <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="br0">&#40;</span><span class="re0">$self</span>, <span class="re0">%args</span><span class="br0">&#41;</span> = <span class="re0">@_</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="me1">lazyInit</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">sub</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="st0">"lazyValue"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>, <span class="re0">%args</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
<span class="re0">$self</span>-&gt;<span class="me1">lazy</span>; <span class="co1"># get value</span><br />
<span class="re0">$self</span>-&gt;<span class="me1">lazy</span><span class="br0">&#40;</span>overwrite =&gt; <span class="st0">'newLazyValue'</span><span class="br0">&#41;</span>; <span class="co1"># overwrite value</span><br />
<span class="re0">$self</span>-&gt;<span class="me1">lazy</span><span class="br0">&#40;</span>reload =&gt; <span class="nu0">1</span><span class="br0">&#41;</span>; <span class="co1"># cause initialisation subroutine to be called again, returning value to 'lazyValue' </span><br />
&nbsp;</div>
</div>
<p>And you're free to use other paramaters of your own chosing in the anonymous closure (just don't use 'overwrite' or 'forceReload' to avoid conflicts!)</p>
<p>Finally, if the value only needs to be read-only, we can redine the subroutine after its first use (yes you can do this in Perl!) so that subsequent calls don't require the unnecessary (i<strong>f defined</strong>) test:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">sub</span> lazyInit<span class="br0">&#40;</span>\&amp;<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$self</span>&nbsp; &nbsp;= <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$f</span>&nbsp; &nbsp; &nbsp; = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$overrideName</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/shift.html"><span class="kw3">shift</span></a>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$priv</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">my</span> <span class="re0">$method</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/defined.html"><span class="kw3">defined</span></a> <span class="re0">$overrideName</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$priv</span> = <span class="st0">"_"</span> . <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">"::"</span>, <span class="re0">$overrideName</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$method</span> = <span class="re0">$overrideName</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$priv</span> = <span class="st0">"_"</span> . <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">"::"</span>, <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/caller.html"><span class="kw3">caller</span></a><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$method</span> = <span class="br0">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/caller.html"><span class="kw3">caller</span></a><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">#&nbsp; &nbsp; &nbsp; &nbsp;$self-&gt;debug(&quot;slow - $method&quot;);</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span> = &amp;<span class="re0">$f</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/no.html"><span class="kw3">no</span></a> warnings <span class="st0">'redefine'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/no.html"><span class="kw3">no</span></a> strict <span class="st0">'refs'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *<span class="br0">&#123;</span> <span class="re0">$method</span> <span class="br0">&#125;</span> = <span class="kw2">sub</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1"># $self-&gt;debug(&quot;fast - $method&quot;);</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/return.html"><span class="kw3">return</span></a> <span class="re0">$self</span>-&gt;<span class="br0">&#123;</span><span class="re0">$priv</span><span class="br0">&#125;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>If you uncomment the comments and run this, you will see that the first time it is run "<strong>slow - $method</strong>" is printed, but on all subsequent calls "<strong>fast - $method</strong>" is called. I've also added the ability to override the method name used, which actually lets you achieve read-write if you call lazyInit() from a different function and have it redifine a suboutine of your chosing.</p>
<p>Cool huh?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2007/getting-lazy-in-perl/feed</wfw:commentRss>
		</item>
		<item>
		<title>Perl, the first postmodern computer language</title>
		<link>http://blog.patspam.com/2007/perl-the-first-postmodern-computer-language</link>
		<comments>http://blog.patspam.com/2007/perl-the-first-postmodern-computer-language#comments</comments>
		<pubDate>Wed, 26 Sep 2007 03:28:36 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
		
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://blog.patspam.com/2007/09/26/perl-the-first-postmodern-computer-language/</guid>
		<description><![CDATA["In Perl, AND has higher precedence than OR does. There you have it. That proves Perl is a postmodern language."  (link)
]]></description>
			<content:encoded><![CDATA[<p>"In Perl, AND has higher precedence than OR does. There you have it. That proves Perl is a postmodern language."  (<a href="http://www.perl.com/pub/a/1999/03/pm.html">link</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.patspam.com/2007/perl-the-first-postmodern-computer-language/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
