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

<channel>
	<title>Wheel 2.0: Jason Huck's Devblog &#187; Lasso</title>
	<atom:link href="http://devblog.jasonhuck.com/category/lasso/feed/" rel="self" type="application/rss+xml" />
	<link>http://devblog.jasonhuck.com</link>
	<description>Rounder. Smoother. Rollier?</description>
	<lastBuildDate>Wed, 25 Mar 2009 14:17:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Installing Lasso on CentOS 5</title>
		<link>http://devblog.jasonhuck.com/2009/01/08/installing-lasso-on-centos-5/</link>
		<comments>http://devblog.jasonhuck.com/2009/01/08/installing-lasso-on-centos-5/#comments</comments>
		<pubDate>Thu, 08 Jan 2009 13:31:53 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>

		<guid isPermaLink="false">http://devblog.jasonhuck.com/?p=37</guid>
		<description><![CDATA[Officially, Lasso Professional is only supported on one flavor and version of linux: Red Hat Enterprise Linux 4. However, many Lasso users have opted to forego RHEL4, which requires a commercial support subscription, for its community supported twin, CentOS 4, despite the fact that it isn&#8217;t officially supported by LassoSoft. Because CentOS 4 is based [...]]]></description>
			<content:encoded><![CDATA[<p>Officially, Lasso Professional is only supported on one flavor and version of linux: Red Hat Enterprise Linux 4. However, many Lasso users have opted to forego RHEL4, which requires a commercial support subscription, for its community supported twin, CentOS 4, despite the fact that it isn&#8217;t officially supported by LassoSoft. Because CentOS 4 is based on the same core code and designed to be 100% binary compatible with RHEL4, installing Lasso on either distribution is essentially an identical process. Marc Pope has provided an excellent set of <a href="http://www.lassotech.com/centoslinuxfaststart">quick start instructions for installing Lasso on CentOS 4</a> at LassoTech.</p>
<p>Unfortunately, Lasso is not supported on newer versions of either distribution, even though RHEL5 was released in March of 2007, and CentOS 5 followed in the next month. Given the length of time the 5 series has been available, along with the significant number of bug fixes and enhancements it contains over the previous releases, many users would like to run Lasso on CentOS 5. This article describes the steps I took to get Lasso Professional 8.5.5 running on a clean install of CentOS 5.2, both the most current releases, respectively, at the time of this writing.</p>
<p>Please note that I am far from a linux guru. To the extent that I have tested this setup so far, I have not seen any errors and performance has been on par with what I would expect for the given hardware and conditions, but it has, by no means, been exhaustively tested. Use this unsupported setup in a production environment at your own risk. I welcome any feedback which can improve, correct, or add to the instructions below. Good luck!</p>
<ol>
<li>
<h4>Install and update CentOS 5.2 as usual.</h4>
<p>The details of installing the base operating system are beyond the scope of this article. Suffice it to say, if you are not comfortable installing Linux on your own, you probably do not want to install Lasso on it either. These instructions were created against clean installs of version 5.2. If you have upgraded from an earlier version of CentOS, you may find that you do not need to install some of the compatibility packages that I needed.</p>
</li>
<li>
<h4>Become the Root User</h4>
<p>As usual, you&#8217;ll need root privileges for many of these operations, so it&#8217;s easiest to just become the root user for the duration, rather than prefixing every command with &#8220;sudo.&#8221;</p>
<pre><code>[prompt]# su root
</code></pre>
<p>(enter the root password when prompted)</p>
</li>
<li>
<h4>Install the latest JRE from Sun.</h4>
<p>Download the latest Java Runtime Edition, or JRE, from java.sun.com and create a symlink to the i386 directory from within the &#8220;latest&#8221; directory, where Lasso looks for it. At the time of this writing, the latest version was 1.6.0 Update 11. You may wish to check for a newer version rather than using the link shown below.</p>
<pre><code>[prompt]# wget http://javadl.sun.com/webapps/download/AutoDL?BundleId=26213 -O jre-6u11-linux-i586-rpm.bin
[prompt]# chmod +x jre-6u11-linux-i586-rpm.bin
[prompt]# ./jre-6u11-linux-i586-rpm.bin
</code></pre>
<p>(type &#8220;yes&#8221; to accept the license agreement)</p>
<pre><code>[prompt]# ln -s /usr/java/jre1.6.0_11/lib/i386/ /usr/java/latest/lib/i386
</code></pre>
</li>
<li>
<h4>Install Missing/Deprecated X11 Libraries</h4>
<p>Find and install xorg-x11-deprecated-libs-6.8.2-1.EL.33.i386.rpm. Afterwards, yum will show it as installed, but the Lasso RPM will still complain that a required package is missing. I used the deprecated package because the regular one overrides the mesa-based package that CentOS 5 uses by default, which causes problems with the windowing system and Gnome.</p>
<pre><code>[prompt]# wget ftp://mirror.switch.ch/pool/3/mirror/centos/4.7/os/x86_64/CentOS/RPMS/xorg-x11-deprecated-libs-6.8.2-1.EL.52.i386.rpm
[prompt]# rpm -ivh xorg-x11-deprecated-libs-6.8.2-1.EL.33.i386.rpm
</code></pre>
<p><strong>Note:</strong> On an otherwise identical system with the KDE desktop installed, we were able to install just libXp (via yum), which is the specific package from the deprecated X11 libs that is missing in CentOS 5&#8242;s X11 install, instead of using the deprecated libs. Apparently this has been a common problem with the new version of X11.</p>
</li>
<li>
<h4>Install Older Version of OpenSSL</h4>
<p>CentOS has OpenSSL 098a, but Lasso requires 097a. I did not have to uninstall the newer version to include the older one.</p>
<pre><code>[prompt]# yum install openssl097a
</code></pre>
</li>
<li>
<h4>Install OpenLDAP Compatibility Layer</h4>
<p>Lasso requires libldap-2.2.so.7, which is in an OpenLDAP Compatibility package:</p>
<pre><code>[prompt]# yum install compat-openldap.i386
</code></pre>
</li>
<li>
<h4>Symlink /etc/localtime To Your Time Zone</h4>
<p>Lasso expects /etc/localtime to be a symlink to /usr/share/zoneinfo/[your zone], but it wasn&#8217;t, by default, on the machines I set up.</p>
<pre><code>[prompt]# mv /etc/localtime /etc/localtime_bak
[prompt]# ln -s /usr/share/zoneinfo/EST /etc/localtime
</code></pre>
</li>
<li>
<h4>Install LassoService and Documentation</h4>
<p>Install the Lasso-Service and Lasso-Documentation RPM&#8217;s, but <em>skip</em> the Lasso Connector RPM since we need the 2.2 connector anyway. <strong>NOTE:</strong> Use &#8211;nodeps on the LassoService RPM to keep it from complaining about the xorg-x11-libs not being installed.</p>
<pre><code>[prompt]# wget http://download.lassosoft.com/pub/Lasso85/Lasso_Pro_8.5.5_Lin.tar.gz
[prompt]# tar -zxvf Lasso*
[prompt]# cd Lasso\ Pro\ 8.5.5\ for\ Red\ Hat\ Enterprise\ Linux\ 4/
[prompt]# rpm -ivh --nodeps Lasso-Service*.rpm
[prompt]# rpm -ivh Lasso-Documentation*.rpm
</code></pre>
</li>
<li>
<h4>Install Lasso Connector for Apache 2.2</h4>
<p>Copy the connector out of Lasso&#8217;s Extensions folder into Apache&#8217;s modules folder, copy the config file into Apache&#8217;s conf directory, modify the httpd.conf file to include it, and restart Apache.</p>
<pre><code>[prompt]# cd /usr/local/Lasso\ Professional\ 8/Extensions/Lasso\ Connector\ for\ Apache\ 2.2/
[prompt]# cp lasso8.conf /etc/httpd/conf/lasso8.conf
[prompt]# cp Lasso8ConnectorforApache2.2.so /etc/httpd/modules/Lasso8ConnectorforApache2.2.so
[prompt]# cd /etc/httpd/conf
[prompt]# vi httpd.conf
</code></pre>
<p>Press &#8220;i&#8221; to enter insert mode, then add the following lines:</p>
<pre><code>    # Include Lasso config.
    Include conf/lasso8.conf
</code></pre>
<p>Press [esc] to enter command mode, then &#8220;:w&#8221; to write (save) the file, and &#8220;:q&#8221; to quit the vi editor. Next, start or restart apache:</p>
<pre><code>[prompt]# /etc/init.d/httpd start
</code></pre>
<p>Or, if Apache is already running:</p>
<pre><code>[prompt]# /etc/init.d/httpd restart
</code></pre>
</li>
<li>
<h4>Add Unicode Properties Support to PCRE</h4>
<p>Lasso&#8217;s [string_findregexp] and [string_replaceregexp] rely on the PCRE regular expression library. However, the version included in CentOS is missing &#8220;Unicode properties support&#8221;, which prevents you from using regular expressions which include \L, \l, \N, \P, \p, \U, \u, or \X. In order to fix this, you must download the source RPM for the PCRE library, edit the compilation options in its SPEC file, and rebuild it so that when you (re)install the RPM, it will include the missing Unicode properties support. Once that&#8217;s done, you&#8217;ll need to create a set of symlinks from where Lasso expects to find these libraries to where they actually get installed on your system.</p>
<p><strong>Note:</strong> These instructions were written by Bil Corry as part of a discussion on Lasso Talk. To use them, you will need to have the &#8220;rpmbuild&#8221; tool and a compiler such as GCC installed on your system. If you did not choose to include these components when you installed CentOS, be sure to add them via yum before proceeding.</p>
<pre><code>[prompt]# mkdir /usr/src/redhat
[prompt]# cd /usr/src/redhat
[prompt]# wget http://mirrors.kernel.org/centos/5.2/os/SRPMS/pcre-6.6-2.el5_1.7.src.rpm
[prompt]# rpm -ivh pcre-6.6-2.el5_1.7.src.rpm
[prompt]# cd /usr/src/redhat/SPECS/
[prompt]# vi pcre.spec
</code></pre>
<p>Press &#8220;i&#8221; to enter insert mode, find the &#8220;%configure&#8221; line and add the option for Unicode property support, so it looks like this:</p>
<pre><code>%configure --enable-utf8 --enable-unicode-properties
</code></pre>
<p>Press [esc] to enter command mode, then &#8220;:w&#8221; to write (save) the file, and &#8220;:q&#8221; to quit the vi editor. Next, rebuild the RPM with the new configuration option in place and install it:</p>
<pre><code>[prompt]# rpmbuild -bb pcre.spec
[prompt]# cd /usr/src/redhat/RPMS/i386/
[prompt]# rpm -Uhv pcre*.rpm
</code></pre>
<p>Finally, replace the PCRE libraries in /usr/local/lib with symlinks to the versions in /usr/lib:</p>
<pre><code>[prompt]# mkdir /usr/local/lib/pcre-old
[prompt]# mv /usr/local/lib/libpcre*.* /usr/local/lib/pcre-old
[prompt]# ln -s /usr/lib/libpcre.a /usr/local/lib/libpcre.a
[prompt]# ln -s /usr/lib/libpcre.so /usr/local/lib/libpcre.so
[prompt]# ln -s /usr/lib/libpcre.so.0 /usr/local/lib/libpcre.so.0
[prompt]# ln -s /usr/lib/libpcrecpp.a /usr/local/lib/libpcrecpp.a
[prompt]# ln -s /usr/lib/libpcrecpp.so /usr/local/lib/libpcrecpp.so
[prompt]# ln -s /usr/lib/libpcrecpp.so.0 /usr/local/lib/libpcrecpp.so.0
[prompt]# ln -s /usr/lib/libpcreposix.a /usr/local/lib/libpcreposix.a
[prompt]# ln -s /usr/lib/libpcreposix.so /usr/local/lib/libpcreposix.so
[prompt]# ln -s /usr/lib/libpcreposix.so.0 /usr/local/lib/libpcreposix.so.0
</code></pre>
</li>
<li>
<h4>Start Lasso</h4>
<p>In our testing, Lasso ran fine when started using any of the provided startup scripts, but it did not have sufficient permissions when started from Gnome&#8217;s Services control panel, resulting in ISE&#8217;s.</p>
<pre><code>[prompt]# cd /usr/local/Lasso\ Professional\ 8/Tools/
[prompt]# sh ./startLassoService.sh
</code></pre>
<p><strong>Note:</strong> The problem starting from the Services control panel is apparently due to the fact that Lasso wants to run a process as root in order to spawn other processes under the lasso user. In CentOS 5.2, by default, only console users can do this (hence the need to use the startup scripts). A potential workaround is to comment out this line in /etc/sudoers, though there are likely security implications in doing so:</p>
<pre><code>Defaults requiretty
</code></pre>
</li>
</ol>
<h3>Other Notes</h3>
<ul>
<li>This should be run against a test suite to determine if there are any other dependencies that may still be causing problems.</li>
<li>In one test install, we saw a &#8220;file not found&#8221; error looking for &#8220;startup.LassoApp&#8221; vs. &#8220;Startup.LassoApp&#8221;, but doing a case-sensitive search on the source of the admin LassoApps didn&#8217;t produce any results, so I&#8217;m not sure where it&#8217;s coming from. On that machine, I made a copy of &#8220;Startup.LassoApp&#8221; with a lowercase &#8220;s.&#8221; I don&#8217;t know if having two otherwise identical startup scripts in place will cause any problems or not.</li>
<li>It was brought to my attention that the lasso user&#8217;s shell is set to /dev/null, but that the standard for service accounts on CentOS is /sbin/nologin. It shouldn&#8217;t make any difference, but the perfectionists among you may wish to make that change.</li>
<li>You may wish to add /usr/sbin to your user&#8217;s path, which gives you access to several handy shortcuts such as &#8220;apachectl&#8221; and &#8220;lasso8ctl&#8221;, among others, and also add your user to the /etc/sudoers file as an administrator. These two things will provide a more Mac-like experience without requiring you to log in as the root user.</li>
<li>Depending on what choices you made when installing CentOS, some packages required by Lasso that were present in my installs may be missing from yours. If you follow these instructions and Lasso does not start up properly, try starting it in console mode (cd to the Tools directory and sh ./consoleLassoService.sh) and watch for error messages about missing files. One person reported that they had to install libxslt (yum install libxslt) in order to get Lasso running, whereas our test machines already had this package installed.</li>
</ul>
<p>So, that&#8217;s it! Hopefully not too scary. If you try this, let me know how it goes. Once again, any suggestions for how to improve these instructions is welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2009/01/08/installing-lasso-on-centos-5/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>An Asset Management System for Lasso Powered Sites</title>
		<link>http://devblog.jasonhuck.com/2008/09/23/an-asset-management-system-for-lasso-powered-sites/</link>
		<comments>http://devblog.jasonhuck.com/2008/09/23/an-asset-management-system-for-lasso-powered-sites/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 01:45:42 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>
		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://devblog.jasonhuck.com/?p=18</guid>
		<description><![CDATA[At the 2008 Lasso Developer Conference in Chicago, I presented a paper entitled Server Side Techniques for Client Side Optimization, in which I reviewed the original 13 Rules For Making Web Sites Fast from Yahoo!&#8217;s Exceptional Performance Team. These rules quickly became the seminal document on the topic of client side optimization and have since [...]]]></description>
			<content:encoded><![CDATA[<p>At the <a href="http://www.lassosoft.com/Community/LDC/" target="_blank">2008 Lasso Developer Conference in Chicago</a>, I presented a paper entitled <em>Server Side Techniques for Client Side Optimization</em>, in which I reviewed the original <em>13 Rules For Making Web Sites Fast</em> from Yahoo!&#8217;s Exceptional Performance Team. These rules quickly became the seminal document on the topic of client side optimization and have since been expanded to include (at the time of this writing) <a href="http://developer.yahoo.com/performance/rules.html" target="_blank">37 rules across 7 categories</a>. They also became the basis for the performance tests used by the <a href="http://developer.yahoo.com/yslow/" target="_blank">YSlow add-on for Firebug</a>, which is a great tool for evaluating the performance of your site.</p>
<p>The second half of my presentation described an asset management system for Lasso which manages the JavaScript and CSS files used throughout the site, automating many of the aforementioned best practices by handling the concatenation, minification (via <a href="http://developer.yahoo.com/yui/compressor/" target="_blank">YUI Compressor</a>), compression, caching, and integration of JavaScript and CSS files. The system is designed to be adaptable to any Lasso framework or codebase without substantially impacting existing workflows, and can easily be partially or completely disabled for debugging purposes.</p>
<p>Even though some of the convenience features of the system are relatively fresh code, and suffer from at least one minor bug (discovered while helping Tami Williams integrate the system into the LassoFuseBox framework), the core components of this system have now been deployed several times over in production sites and work beautifully together. The following graph displays the average savings in response time, bytes transferred, and total number of requests from one of my code samples:</p>
<p><img src="/assets/assetmanagerresults.png" width="429" height="345" align="bottom" border="0" /></p>
<p>Video of my presentation (as well as the others) should be available in the near future. In the meantime, now that the conference is over, I am making my paper, code samples, and slides available for download:</p>
<ul>
<li><a href="/assets/LDC08_Paper.pdf">LDC 2008 Paper (220kb pdf)</a></li>
<li><a href="/assets/LDC08_CodeSamples.zip">LDC 2008 Code Samples (3.4mb zip)</a></li>
</ul>
<p><a href="http://tagswap.net/asset_manager">Documentation for the individual tags that make up the system is available at tagSwap.net.</a> Be sure to check there for any future updates and/or bug fixes.</p>
<p>The slides can be viewed (and downloaded) via SlideShare:</p>
<div style="width:425px;text-align:left" id="__ss_609182"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/jasonhuck/client-side-optimization-techniques-presentation?type=powerpoint" title="Client Side Optimization Techniques">Client Side Optimization Techniques</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=ldcpresentation-1221941101146448-9&#038;stripped_title=client-side-optimization-techniques-presentation" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=ldcpresentation-1221941101146448-9&#038;stripped_title=client-side-optimization-techniques-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View SlideShare <a style="text-decoration:underline;" href="http://www.slideshare.net/jasonhuck/client-side-optimization-techniques-presentation?type=powerpoint" title="View Client Side Optimization Techniques on SlideShare">presentation</a> or <a style="text-decoration:underline;" href="http://www.slideshare.net/upload?type=powerpoint">Upload</a> your own. (tags: <a style="text-decoration:underline;" href="http://slideshare.net/tag/ldc2008">ldc2008</a> <a style="text-decoration:underline;" href="http://slideshare.net/tag/ldc08">ldc08</a>)</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2008/09/23/an-asset-management-system-for-lasso-powered-sites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lasso Developer Conference 2008</title>
		<link>http://devblog.jasonhuck.com/2008/07/02/lasso-developer-conference-2008/</link>
		<comments>http://devblog.jasonhuck.com/2008/07/02/lasso-developer-conference-2008/#comments</comments>
		<pubDate>Wed, 02 Jul 2008 22:44:10 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>
		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://devblog.jasonhuck.com/2008/07/02/lasso-developer-conference-2008/</guid>
		<description><![CDATA[Over the past few weeks, I&#8217;ve been preparing for this year&#8217;s Lasso Developer Conference in Chicago. It&#8217;s my second time speaking at the event, and although it&#8217;s not until September, a written paper and demo materials which will accompany the presentation were due July 1st are due July 14th (thanks to LassoSoft for the gracious [...]]]></description>
			<content:encoded><![CDATA[<p>Over the past few weeks, I&#8217;ve been preparing for this year&#8217;s <a href="http://www.lassosoft.com/Community/LDC/">Lasso Developer Conference</a> in Chicago. It&#8217;s my second time speaking at the event, and although it&#8217;s not until September, a written paper and demo materials which will accompany the presentation <del>were due July 1st</del> are due July 14th (thanks to LassoSoft for the gracious extension). I&#8217;m really looking forward to the event. It&#8217;s truly a great chance to meet and interact with members of the Lasso community as well as the LassoSoft team.</p>
<p>The title of my talk is <a href="http://www.lassosoft.com/Community/LDC/Topics/index.lasso">&#8220;Server Side Techniques for Client Side Optimization&#8221;</a>, and it explores ways to streamline the delivery of modern web apps by reducing HTTP requests, combining, minifying, and compressing assets with tools such as the <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>, using asset subdomains, and more, all wrapped up in a self-contained system that won&#8217;t force you to change your existing workflow. And, although I agree somewhat with criticisms that it&#8217;s &#8220;teaching to the test&#8221;, it&#8217;ll also help you score an A(100) in <a href="http://developer.yahoo.com/yslow/">YSlow</a>. <img src='http://devblog.jasonhuck.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2008/07/02/lasso-developer-conference-2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery File Tree</title>
		<link>http://devblog.jasonhuck.com/2008/07/02/jquery-file-tree/</link>
		<comments>http://devblog.jasonhuck.com/2008/07/02/jquery-file-tree/#comments</comments>
		<pubDate>Wed, 02 Jul 2008 21:59:53 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://devblog.jasonhuck.com/2008/07/02/jquery-file-tree/</guid>
		<description><![CDATA[Cory S.N. LaViska over at A Beautiful Site has created a very nice jQuery plugin for displaying file trees called, naturally, jQuery File Tree. The great thing about it is its simplicity. It doesn&#8217;t have an overabundance of bells and whistles, but it&#8217;s super easy to integrate with a simple API (it even includes Lasso [...]]]></description>
			<content:encoded><![CDATA[<p>Cory S.N. LaViska over at <a href="http://abeautifulsite.net/">A Beautiful Site</a> has created a very nice <a href="http://jquery.com/">jQuery</a> plugin for displaying file trees called, naturally, <a href="http://abeautifulsite.net/notebook.php?article=58">jQuery File Tree</a>. The great thing about it is its simplicity. It doesn&#8217;t have an overabundance of bells and whistles, but it&#8217;s super easy to integrate with a simple API (it even includes <a href="http://www.lassosoft.com/">Lasso</a> support), has plenty of hooks to add your own custom functionality, and generates nice clean markup. <a href="http://abeautifulsite.net/notebook.php?article=58">Check it out!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2008/07/02/jquery-file-tree/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Namespaces To Load Lasso Tags Into Memory</title>
		<link>http://devblog.jasonhuck.com/2008/04/10/using-namespaces-to-load-lasso-tags-into-memory/</link>
		<comments>http://devblog.jasonhuck.com/2008/04/10/using-namespaces-to-load-lasso-tags-into-memory/#comments</comments>
		<pubDate>Thu, 10 Apr 2008 04:07:46 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>

		<guid isPermaLink="false">http://devblog.jasonhuck.com/2008/04/10/using-namespaces-to-load-lasso-tags-into-memory/</guid>
		<description><![CDATA[This article describes different ways to load custom tags into memory in Lasso, and presents an alternative method of managing tag libraries. LassoStartup and LassoLibraries Lasso provides a number of different ways to make custom tags (and types) available for use in your scripts. Tag definitions can be pasted directly into scripts, or included from [...]]]></description>
			<content:encoded><![CDATA[<p>This article describes different ways to load custom tags into memory in Lasso, and presents an alternative method of managing tag libraries.</p>
<h4>LassoStartup and LassoLibraries</h4>
<p><a href="http://www.lassosoft.com/Products/LassoPro/" target="_blank">Lasso</a> provides a number of different ways to make custom tags (and types) available for use in your scripts. Tag definitions can be pasted directly into scripts, or included from external files. Alternatively, tag files can be placed in one of two special folders within the Lasso application folder, <strong>LassoStartup</strong> and <strong>LassoLibraries</strong>, for automatic loading.</p>
<p>Placing tags within these special folders provides two distinct advantages. First, Lasso handles the loading of the tags for you, so it&#8217;s not necessary to manually include any extra files or code in your scripts; the tags are simply always available for use. If placed in LassoStartup, they&#8217;re loaded as part of the initialization process when the Lasso Service starts. If placed in LassoLibraries (and arranged in a certain way), they&#8217;re loaded on-demand, the first time they are used in a script.</p>
<p>Secondly, once loaded, tags placed in these special folders remain resident in memory until the Lasso Service is restarted. This eliminates the overhead of reading a file from disk, parsing the tag definition, constructing an internal prototype, and adding it to the tag registry, a process that must otherwise be repeated for each tag every time a script which uses that tag runs. For a single tag, all of those actions happen in a few milliseconds, but with larger libraries, those milliseconds can add up to noticeable delays.</p>
<p>Despite the advantages, it&#8217;s not always convenient or even possible to place tags in these special folders. For instance, if your project is hosted in a shared hosting environment, you may not have access to the Lasso application folder. If you use a <a href="http://subversion.tigris.org/" target="_blank">version control system such as Subversion</a>, you&#8217;d have to maintain separate working copies in order to keep two directories in different locations in sync. Although LassoLibraries provides a mechanism for unloading tags programmatically, reloading custom tags defined in LassoStartup requires a restart of the Lasso Site and/or the entire Lasso Service. Generally speaking, it&#8217;s just more convenient to be able to keep all the files related to a single project within a single folder.</p>
<h4>Pushing Tags Into The Global Namespace</h4>
<p>The ideal setup, then, is one where the developer can both specify the location of tag libraries, and have them loaded into memory. Fortunately, the same mechanism that allows files in LassoLibraries to be loaded into memory on-demand can be used on other paths as well.</p>
<p>You may have noticed that Lasso&#8217;s tag names use a categorization system to organize sets of tags into groups. For example, the tags which deal with string manipulation are all prefixed by <em>string_</em>. These groups are called <em>namespaces</em> (<a href="http://en.wikipedia.org/wiki/Namespace_(computer_science)" target="_blank">namespaces in general</a> | <a href="http://www.lassotech.com/TotW_20080321" target="_blank">namespaces in Lasso</a>) and they have a number of interesting uses. What&#8217;s important to understand in this context, however, is that Lasso&#8217;s namespaces are hierarchical, and all descend from a top-level namespace known as the <em>global</em> namespace. Tags defined within the global namespace remain resident in memory, and thanks to the <a href="http://reference.lassosoft.com/Reference.LassoApp?[Namespace_Using]" target="_blank">[namespace_using]</a> tag, we can push tag definitions into the global namespace programmatically.</p>
<p>For example, once the following code snippet runs, the [foo] tag will be available for use on any page until Lasso is restarted. Without the namespace tags, [foo] will only exist on the page in which it was defined.</p>
<pre><code class="lasso">[
	namespace_using(namespace_global);
		define_tag('foo');
			return('bar');
		/define_tag;
	/namespace_using;
]</code></pre>
<h4>A Flexible Loader For Managing Tag Libraries</h4>
<p>The <a href="http://tagSwap.net/tags_load/" target="_blank">[tags_load]</a> custom tag uses this technique to &#8220;watch&#8221; the given folder and make sure all the tags within it are loaded into memory. Basic usage is simply:</p>
<pre><code class="lasso">[tags_load('/path/to/mytags/')]</code></pre>
<p>Optionally, you can specify what type of files to load by extension (the default is .inc), and a condition for whether or not to refresh all tags:</p>
<pre><code class="lasso">[
	tags_load(
		'/path/to/mytags/',
		-ext='.lasso',
		-refresh=(var_defined('reloadmytags') &#038;&#038; $reloadmytags === true)
	);
]</code></pre>
<p>When the tag loader is called, it will list every file in the given path which matches the given extension. It does not currently recurse into subdirectories, and will ignore files that begin with a period.</p>
<p>It will then iterate through that list, checking to see if a tag by that name already exists. For instance, if the file is &#8220;foo_bar.inc&#8221;, it will check for a tag called [foo_bar]. If none is found (or the refresh condition has been met), it will include the file using the <a href="http://reference.lassosoft.com/Reference.LassoApp?[Library]" target="_blank">[library]</a> tag within a <a href="http://reference.lassosoft.com/Reference.LassoApp?[Protect]" target="_blank">[protect]</a> block. Any errors that occur when loading an individual file will be trapped and logged to Lasso&#8217;s built-in error database, and the tag loader will move on to the next file. Log entries made by the tag loader are prefixed with &#8220;[Tagloader]&#8221; like so:</p>
<blockquote><p>[Tagloader] Error loading [foo_bar]: No permission.</p></blockquote>
<p>The total number of successfully loaded tags for each path is stored in a global variable. On subsequent calls for that path, if the number of files to load matches the number of tags already loaded (and the refresh condition is not met), the rest of the routine is skipped. Thus, even if the tag loader is called on every page load, it&#8217;s usually only doing work if a new tag is added to the path, or a refresh is requested. When it&#8217;s finished, the results are logged to the error database:</p>
<blockquote><p>[Tagloader] 113 of 115 tags loaded successfully.</p></blockquote>
<p>In its current incarnation, it&#8217;s important that each file loaded with the tag loader contain a tag with the same name as the file. Otherwise, that file will be reloaded every time, regardless of whether it&#8217;s necessary. So, for instance, if you have all of the tags in the <em>foo_</em> namespace in a single file called <em>foo_library.inc</em>, you&#8217;ll want to include a placeholder tag to register the library with the tag loader. I typically just define a simple tag which returns &#8220;Loaded&#8221; and place it at the end of the file (so that it only loads if there are no other errors):</p>
<pre><code class="lasso">[
	define_tag('foo_bar');
		...
	/define_tag;

	...

	define_tag('foo_library');
		return('Loaded');
	/define_tag;
]</code></pre>
<p>The tag loader could be extended with more options for greater flexibility, but the current feature set has met my needs well for quite some time. Some ideas include:</p>
<ul>
<li>Optionally accepting an array instead of a string for the path, so that multiple locations can be loaded via a single tag call.</li>
<li>Recursing subdirectories so that tags can be broken down into nested folders.</li>
<li>Replacing the -ext param with -match and/or -deny params which would accept arrays of conditions to match against filenames.</li>
<li>An additional -usenamespace param which could override or append to the default global namespace.</li>
</ul>
<p>Hopefully a future version of Lasso will support custom paths to LassoLibraries and/or other methods of moving things in and out of memory. The namespace library which ships with Lasso is, itself, written in LassoScript, and could easily be modified to support custom paths. However, that would require maintaining a custom-compiled version of Startup.LassoApp everywhere you want to deploy your code &#8212; not a very portable solution. In the meantime, I think this is a satisfactory workaround.</p>
<p><a href="http://tagSwap.net/tags_load/" target="_blank">[tags_load] can be downloaded at tagSwap.net</a></p>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2008/04/10/using-namespaces-to-load-lasso-tags-into-memory/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Error Management Techniques for Lasso</title>
		<link>http://devblog.jasonhuck.com/2007/12/31/error-management-techniques-for-lasso/</link>
		<comments>http://devblog.jasonhuck.com/2007/12/31/error-management-techniques-for-lasso/#comments</comments>
		<pubDate>Mon, 31 Dec 2007 19:12:57 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>
		<category><![CDATA[User Experience]]></category>

		<guid isPermaLink="false">http://devblog.jasonhuck.com/2007/12/31/error-management-techniques-for-lasso/</guid>
		<description><![CDATA[An important aspect of web application design is error management. Many factors outside a developer&#8217;s control can cause problems, even if the deployed code is free of syntax errors, from changes in the underlying subsystems to edge cases in user input that haven&#8217;t been accounted for, to remote services that stop responding. It&#8217;s the responsibility [...]]]></description>
			<content:encoded><![CDATA[<p>An important aspect of web application design is error management. Many factors outside a developer&#8217;s control can cause problems, even if the deployed code is free of syntax errors, from changes in the underlying subsystems to edge cases in user input that haven&#8217;t been accounted for, to remote services that stop responding. It&#8217;s the responsibility of the developer to prepare for the unexpected and attempt to handle whatever errors may crop up over time. The following techniques take advantage of the error management capabilities built into Lasso Professional to trap and log errors, notify system administrators that a problem has occurred, and provide a friendly message to end users.</p>
<h4>Set the Error Reporting Level to Full</h4>
<p>There are three levels of error reporting available for Lasso: Full, Minimal, and None. The error reporting level can be set globally from the administration interface, and/or adjusted at the page level through the use of the <a href="http://reference.lassosoft.com/Reference.LassoApp?[Lasso_ErrorReporting]" title="[lasso_errorreporting]" target="_blank">[lasso_errorreporting]</a> tag.</p>
<p>Lasso developers are often advised to set the error reporting level to Minimal or None in production in order to reduce the amount of debugging information shown to site visitors when an error occurs, and for good reason. Legitimate users have no use for the debugging data, and the less information you divulge to would-be hackers about the architecture of your system, the better.</p>
<p>So why do I recommend setting the error reporting level to Full? Simple. We&#8217;re going to use a custom error page anyway (see below) and we&#8217;ll control the display of debugging information there. Also, since we want to log as much information as possible about the error, we&#8217;ll want the contents of <a href="http://reference.lassosoft.com/Reference.LassoApp?[Error_Msg]" target="_blank" title="[error_msg]">[error_msg]</a> to be as detailed as we can make it. The only way to get <a href="http://reference.lassosoft.com/Reference.LassoApp?[Error_Msg]" target="_blank" title="[error_msg]">[error_msg]</a> to return a full stack trace for an error is to set the error reporting level to Full.</p>
<p>If your application follows a &#8220;onefile&#8221; type of methodology where you have a master controller file and/or a global configuration file that&#8217;s loaded as part of any and all requests, I would recommend leaving the server-wide setting at Minimal or None, and overriding it to Full from within your application. That way you don&#8217;t have to worry about visitors seeing errors created by other apps on the same server, such as the built-in Admin apps, or some utility script you may have forgotten about.</p>
<h4>Merge File Errors with Regular Errors</h4>
<p>One of the more peculiar idiosyncracies of Lasso is the fact that errors thrown by file manipulation tags are handled separately from all other types of errors. File-specific errors won&#8217;t be reported by <a href="http://reference.lassosoft.com/Reference.LassoApp?[Error_Code]" title="[error_code]" target="_blank">[error_code]</a> or <a href="http://reference.lassosoft.com/Reference.LassoApp?[Error_Msg]" title="[error_msg]" target="_blank">[error_msg]</a> tags (or any of their brethren in the error_ namespace), nor will they trigger <a href="http://reference.lassosoft.com/Reference.LassoApp?[Handle_Error]" title="[handle_error]" target="_blank">[handle_error]</a> blocks. Thus, file errors won&#8217;t cause an error page to be displayed. Instead, you must check <a href="http://reference.lassosoft.com/Reference.LassoApp?[File_CurrentError]" title="[file_currenterror]" target="_blank">[file_currenterror]</a> when working with the file tags. It&#8217;s easy to overlook this separate error tag, which can lead to confusion when debugging.</p>
<p>Fortunately, we can alter this behavior so that file errors are reported as regular errors. In the following code snippet, a <a href="http://reference.lassosoft.com/Reference.LassoApp?[Handle]" title="[handle]" target="_blank">[handle]</a> block is defined that checks for the existence of a file error. If a file error is detected*, a <a href="http://reference.lassosoft.com/Reference.LassoApp?[Fail]" title="[fail]" target="_blank">[fail]</a> tag is used to trigger a normal error, and the normal error code and error message are set to match the code and message that <a href="http://reference.lassosoft.com/Reference.LassoApp?[File_CurrentError]" title="[file_currenterror]" target="_blank">[file_currenterror]</a> reports.</p>
<pre><code class="lasso">handle(file_currenterror( -errorcode));
    fail(
        file_currenterror( -errorcode),
        file_currenterror
    );
/handle;</code></pre>
<p><em>* Here&#8217;s how this works: [file_currenterror( -errorcode)] will return just the current error number. If there&#8217;s no error, that number will be zero. Zero evaluates to false. All other numbers evaluate to true. Thus, the handle block will only be triggered if there is an actual file error.</em></p>
<h4>Provide a Custom Error Page</h4>
<p>Lasso makes implementing a custom error page so easy there&#8217;s no excuse for not having one. By simply placing a file named &#8220;error.lasso&#8221; at the root level of your web site, you can replace the default &#8220;blue screen&#8221; error page with anything you like. It&#8217;s a good idea to match the look and feel of the rest of your application, but otherwise keep the page as simple as possible. Attempting to use a lot of complex logic within a custom error page can quickly lead to problems, since errors in your error management code can create a recursive failure (even though Lasso will bail out of the loop when the recursion limit is reached). Nonetheless, there are a few simple things worth doing, which are outlined below.</p>
<h4>Capture the Error Code and Message Right Away</h4>
<p>Since we are going to be doing a bit of code within our custom error.lasso page, let&#8217;s make sure that we don&#8217;t accidentally reset the error code or message that we&#8217;ll be working against:</p>
<pre><code class="lasso">var(
    'code' = error_code,
    'msg' = error_msg
);</code></pre>
<h4>Inline Errors vs. Full Page Errors</h4>
<p>If an error occurs within an <a href="http://reference.lassosoft.com/Reference.LassoApp?[Include]" title="[include]" target="_blank">[include]</a>, Lasso will display the contents of error.lasso inline with the rest of the calling page, whereas otherwise the entire calling page will be replaced with the contents of error.lasso. This can be problematic if your custom error.lasso page uses the same template as the rest of your site, since inline errors will display the entire template twice: once for the calling page and once for the area where an <a href="http://reference.lassosoft.com/Reference.LassoApp?[Include]" title="[include]" target="_blank">[include]</a> threw an error.</p>
<p>Ideally, we want to detect whether a given error came from within an include or from the calling page itself, so that we can alter the presentation of the error message accordingly. We do this by inspecting the error stack (which, again, requires that the error reporting level be set to Full):</p>
<pre><code class="lasso">var('errorInline') = ($msg &gt;&gt; 'at: include with params:');</code></pre>
<p>If the error stack references <a href="http://reference.lassosoft.com/Reference.LassoApp?[Include]" title="[include]" target="_blank">[include]</a>, we know that the error occurred within an included file and that our error.lasso page will be displayed within the context of the calling page. Now we can easily enclose portions of our error management code in conditional statements for more precise control:</p>
<pre><code class="lasso">if($errorInline);
    // only do this for inline errors
/if;

if(!$errorInline);
    // only do this for full-page errors
/if;</code></pre>
<h4>Display a Friendly Message to Users</h4>
<p>Visitors should be presented with a simple message explaining that the operators of the site have been notified of a potential problem. There&#8217;s no need for them to see any technical details about the error itself. An example message might look something like this:</p>
<blockquote><p><em>An error has occurred. The error has been logged and the system administrator has been notified. You may go back and try again now, or, if the error persists, try again later. We apologize for the inconvenience.</em></p></blockquote>
<h4>Return An Appropriate HTTP Status Code</h4>
<p>In addition to the message you provide for the human user, you should also deliver the correct message to the user agent (usually a web browser, but also search engine spiders and other programs) in the form of an HTTP status code. By default, Lasso will return status code 500 for most errors, and status code 401 for some permission-based errors. These are perfectly reasonable defaults, but you may wish to be more specific. A few potential matches are listed below:</p>
<blockquote><p><strong>Lasso Errors:</strong><br />
-9963 Invalid password. The password supplied is not valid.<br />
-9964 Invalid user name. The user name supplied is not valid.</p>
<p><strong>HTTP Status Code:</strong><br />
401 Unauthorized<br />
The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in &#8220;HTTP Authentication: Basic and Digest Access Authentication&#8221;.<br />
<strong>Lasso Error:</strong><br />
-9961 No permission. The current user is not allowed to perform the specified action. This could mean that a file suffix is not allowed by Lasso security. Edit user security permissions as configured within Lasso security.</p>
<p><strong>HTTP Status Code:</strong><br />
403 Forbidden<br />
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.<br />
<strong>Lasso Errors:</strong><br />
-9967 Resource not found.<br />
-9984 Unauthorized file suffix or file not found. The error -9984 can be seen if you specify a Lasso page with a file suffix which is not included in the Lasso Security settings. Also returned by file management tags.</p>
<p><strong>HTTP Status Code:</strong><br />
404 Not Found<br />
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.</p></blockquote>
<p>A full list of HTTP 1.1 status codes and their definitions can be found here:<br />
<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html" title="HTTP 1.1 Status Codes" target="_blank"> http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html</a></p>
<p>To set the HTTP status code according to the list above, you could use code like this within your custom error.lasso page:</p>
<pre><code class="lasso">if(!$errorInline);¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† // only for full-page
    var('statuses') = map(
              0¬†¬†¬† =¬†¬†¬† '200 Okay',¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† ¬†¬†¬† // just in case
        -9963¬†¬†¬† =¬†¬†¬† '401 Unauthorized',
        -9964¬†¬†¬† =¬†¬†¬† '401 Unauthorized',
        -9961¬†¬†¬† =¬†¬†¬† '403 Forbidden',
        -9967¬†¬†¬† =¬†¬†¬† '404 Not Found',
        -9984¬†¬†¬† =¬†¬†¬† '404 Not Found'
    );

    var('status') = $statuses-&gt;find($code);
    !$status ? $status = '500 Internal Server Error';¬†¬†¬† // default to 500

    $__http_header__ = string_replaceregexp(
        $__http_header__,
        -find='(^HTTP\\S+)\\s+.*?\r\n',
        -replace='\\1 ' + $status + '\r\n'
    );
/if;</code></pre>
<h4>Log As Much Information About The Error As Possible</h4>
<p>Once an error has been identified, the application should log as much detail as possible about the event to aid in subsequent debugging efforts. The simplest way to accomplish this is via the <a href="http://reference.lassosoft.com/Reference.LassoApp?[Log_Critical]" title="[log_critical]" target="_blank">[log_critical]</a> tag, which will insert whatever message you provide into Lasso&#8217;s built-in error database, timestamped and flagged as critical. (BTW, the default error.lasso page will log the error code and message to the error database at the &#8220;detail&#8221; level if the error reporting level is less than Full.)</p>
<p>While extremely convenient, there are some downsides to relying on the built-in error database. For one, longer error messages will be truncated due to the column size used in the errors table, although I assume it&#8217;s possible to alter the column size using the database browser utility from within SiteAdmin. Also, the UI for viewing logged messages doesn&#8217;t provide any way to sort or filter entries beyond the static list of error levels: critical, warning, detail, and deprecated. As a result, finding a particular series of errors, especially when more than one virtual host is handled by the same Lasso Site, can be a very tedious process.</p>
<p>Nevertheless, we get this functionality &#8220;for free&#8221;, and it&#8217;s a good idea to make use of it. I prefer to prefix my log entries with the complete URL the user submitted when the error occurred. This is a succinct way of separating errors between different virtual hosts, and often pinpoints the exact conditions required (i.e., a particular set of GET arguments in the query string) to reproduce the error. So, my log entry looks like this:</p>
<pre><code class="lasso">// log error to error database
var('desc') = ('[' + client_url + '] ' + error_code + ': ' + error_msg);
log_critical($desc);</code></pre>
<p>However, for the reasons outlined above, I also log additional information to my own custom audit tables, where I can include much more information that I can search and filter as needed. Whether you log to a database or a file, some of the things you should consider logging include:</p>
<blockquote><p><strong>Information about the user.</strong><br />
If your application requires a login, and the user is authenticated, log the user&#8217;s ID. You may also want to log another unique identifier that is easier to use when filtering messages, such as a username or email address. If you use Lasso&#8217;s built-in session manager, you may also want to log the user&#8217;s session ID (using the <a href="http://reference.lassosoft.com/Reference.LassoApp?[Session_ID]" title="[session_id]" target="_blank">[session_id]</a> tag), in case there&#8217;s a clue in the sessions table.</p>
<p><strong>Information about the request.</strong><br />
Log the complete request header sent by the user agent using <a href="http://reference.lassosoft.com/Reference.LassoApp?[Client_Headers]" title="[client_headers]" target="_blank">[client_headers]</a>. I also prefer to break out the client&#8217;s IP using <a href="http://reference.lassosoft.com/Reference.LassoApp?[Client_Address]" title="[client_address]" target="_blank">[client_address]</a>, and, as mentioned above, the complete URL requested using <a href="http://reference.lassosoft.com/Reference.LassoApp?[Client_URL]" title="[client_url]" target="_blank">[client_url]</a>. You could also log the user agent separately (Bil Corry&#8217;s <a href="http://tagswap.net/lp_client_browser/" title="[lp_client_browser]" target="_blank">[lp_client_browser]</a> tag is especially useful for this), but the raw form of that information is already included in <a href="http://reference.lassosoft.com/Reference.LassoApp?[Client_Headers]" title="[client_headers]" target="_blank">[client_headers]</a>, and since we&#8217;re logging server-side errors, it&#8217;s usually of little value in debugging.</p></blockquote>
<h4>Send A Notification</h4>
<p>In addition to logging, the application should immediately notify the developer when a problem occurs. The simplest solution is to use <a href="http://reference.lassosoft.com/Reference.LassoApp?[Email_Send]" title="[email_send]" target="_blank">[email_send]</a> to fire off an email containing the same information you chose to log. Other possibilities include gateways to other realtime messaging systems like SMS, IM, or even <a href="http://twitter.com/" title="Twitter.com" target="_blank">Twitter</a> &#8212; anything you tend to check on a regular basis. It may seem like a nuisance if a given site starts to generate a lot of errors, but remember that it&#8217;s also a nuisance to your clients, customers, and end users. Of course, you&#8217;ll want to disable notifications when in a development environment.</p>
<h4>Further Reading</h4>
<p><a href="http://www.lassosoft.com/" title="LassoSoft" target="_blank">LassoSoft</a> has published several <a href="http://www.lassosoft.com/Documentation/TotW/" title="Tip of the Week" target="_blank">Tip of the Week</a> articles on the subject of error management:</p>
<ul>
<li><strong>Finishing Touches &#8211; Professional Error Pages</strong><br />
<a href="http://www.lassosoft.com/Documentation/TotW/index.lasso?9217" title="Finishing Touches - Professional Error Pages" target="_blank"> http://www.lassosoft.com/Documentation/TotW/index.lasso?9217</a></li>
<li><strong>Error Handling</strong><br />
<a href="http://www.lassosoft.com/Documentation/TotW/index.lasso?7622" title="Error Handling" target="_blank"> http://www.lassosoft.com/Documentation/TotW/index.lasso?7622</a></li>
<li><strong>Custom Error Pages</strong><br />
<a href="http://www.lassosoft.com/Documentation/TotW/index.lasso?7621" title="Custom Error Pages" target="_blank"> http://www.lassosoft.com/Documentation/TotW/index.lasso?7621</a></li>
</ul>
<p>The <a href="http://pageblocks.org/" title="pageblocks.org" target="_blank">pageblocks</a> framework includes integrated error management:</p>
<ul>
<li><strong>pageblocks Error Handling and Debugging Overview</strong><br />
<a href="http://www.pageblocks.org/ftrs/api_err" title="pageblocks Error Handling and Debugging Overview" target="_blank"> http://www.pageblocks.org/ftrs/api_err</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2007/12/31/error-management-techniques-for-lasso/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Smart String Truncation in Lasso</title>
		<link>http://devblog.jasonhuck.com/2007/10/02/smart-string-truncation-in-lasso/</link>
		<comments>http://devblog.jasonhuck.com/2007/10/02/smart-string-truncation-in-lasso/#comments</comments>
		<pubDate>Tue, 02 Oct 2007 22:56:15 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Lasso]]></category>

		<guid isPermaLink="false">http://www.jasonhuck.com/2007/10/02/testing-syntax-highlighter/</guid>
		<description><![CDATA[I needed to generate some short intros/teasers from longer body text today, and not having anything readily at hand, decided to see what was available at <a href="http://tagSwap.net/" title="Lasso Code Sharing" target="_blank">tagSwap</a>. Searching for "truncate" brought up two tags, one based on the other.

The first is <a href="http://tagSwap.net/string_truncate" title="[string_truncate]" target="_blank">[string_truncate]</a> by John Burwell. It's pretty straightforward. Pass in a string and the desired length, and it will return the string truncated to exactly the specified length, plus an optional string to indicate the continuation (for instance, an ellipsis). It checks to see if the source string is shorter than the given length, in which case it returns the string unaltered.

This looked like it would do the trick, but I decided to check out the other tag anyway. It was <a href="http://tagSwap.net/gf_lowtext" title="[gf_lowtext]" target="_blank">[gf_lowtext]</a> by Gaetano Frascolla. Gaetano's tag is based on John's, but adds an additional check to see if the truncated string ends with a space. If not, it assumes a word is being split, and truncates an additional character until it reaches a space before returning the result.

It's a nice enhancement, but only checking for a space presents some potential limitations. First of all, there are plenty of other whitespace characters that may break up words, and secondly, it doesn't take punctuation and other special characters into consideration. I'd rather not see the result end with a comma or apostrophe, especially when followed by an ellipsis.

It seemed as if a little regex and some elbow grease might provide me with a few additional enhancements, so I grabbed Gaetano's tag and got to work.]]></description>
			<content:encoded><![CDATA[<p>I needed to generate some short intros/teasers from longer body text today, and not having anything readily at hand, decided to see what was available at <a href="http://tagSwap.net/" title="Lasso Code Sharing" target="_blank">tagSwap</a>. Searching for &#8220;truncate&#8221; brought up two tags, one based on the other.</p>
<p>The first is <a href="http://tagSwap.net/string_truncate" title="[string_truncate]" target="_blank">[string_truncate]</a> by John Burwell. It&#8217;s pretty straightforward. Pass in a string and the desired length, and it will return the string truncated to exactly the specified length, plus an optional string to indicate the continuation (for instance, an ellipsis). It checks to see if the source string is shorter than the given length, in which case it returns the string unaltered.</p>
<p>This looked like it would do the trick, but I decided to check out the other tag anyway. It was <a href="http://tagSwap.net/gf_lowtext" title="[gf_lowtext]" target="_blank">[gf_lowtext]</a> by Gaetano Frascolla. Gaetano&#8217;s tag is based on John&#8217;s, but adds an additional check to see if the truncated string ends with a space. If not, it assumes a word is being split, and truncates an additional character until it reaches a space before returning the result.</p>
<p>It&#8217;s a nice enhancement, but only checking for a space presents some potential limitations. First of all, there are plenty of other whitespace characters that may break up words, and secondly, it doesn&#8217;t take punctuation and other special characters into consideration. I&#8217;d rather not see the result end with a comma or apostrophe, especially when followed by an ellipsis.</p>
<p>It seemed as if a little regex and some elbow grease might provide me with a few additional enhancements, so I grabbed Gaetano&#8217;s tag and got to work. The result is below:</p>
<pre><code class="lasso">define_tag(
	'truncate',
	-namespace='string_',
	-req='text',
	-req='length', -type='integer', -copy,
	-priority='replace',
	-encodenone,
	-description='Truncates the given string to the given number of characters.'
);
	// if the original string is shorter than or equal to the desired length,
	// just return it unaltered.
	#text-&gt;size &lt;= #length ? return(#text);

	local('out') = string;

	// while #out is empty, #length is still greater than zero,
	// and the last character of the new string is not whitespace...
	while(!#out-&gt;size || !#out-&gt;iswhitespace(#out-&gt;size) &amp;&amp; #length);
		// store a new substring in #out
		#out = #text-&gt;substring(1, #length);
		// decrement #length by 1
		#length -= 1;
	/while;

	// if we reached zero, return nothing
	!#length ? return;

	// remove any trailing non-alphanumeric characters and whitespace
	#out = string_replaceregexp(
		#out,
		-find='[^A-Za-z0-9]*\\s*$',
		-replace=''
	);

	// return the final result with an ellipsis character appended
	return(#out + '‚Ä¶');
/define_tag;
</code></pre>
<p>The changes I made include:</p>
<ul>
<li>Using <a href="http://reference.lassosoft.com/Reference.LassoApp?[String-%3EIsWhiteSpace]" title="[string-&gt;iswhitespace]" target="_blank">[string-&gt;iswhitespace]</a> to check for any whitespace character (tabs, newlines, etc.) instead of just spaces.</li>
<li>Returning null if there is no reasonable place to truncate the string within the desired length. This may be an unlikely edge case in normal usage, but without the additional check for #length in the [while], there is the potential to create an endless loop. (For instance, in my test code below.)</li>
<li>Trimming not only the whitespace from the result, but also any non-alphanumeric characters. This took care of the &#8220;hanging punctuation&#8221; issue and seemed reasonable for English strings. Additional exceptions could be added for accented characters.</li>
<li>Appending an HTML-encoded ellipsis character to the result automatically instead of a user supplied value and/or three periods. This is the only way I&#8217;ve ever wanted to show the continuation, so I didn&#8217;t bother making it optional.</li>
</ul>
<p>To test the tag, I looped the length of a test string to see where it would break given every possible position:</p>
<pre><code class="lasso">var('str') = 'The quick, brown-fox jumps over the "lazy" dog.';

loop($str-&gt;size);
    loop_count + ' - ' + string_truncate($str, loop_count) + '\n';
/loop;
</code></pre>
<p>&#8230;resulting in the following output:</p>
<p>1 -<br />
2 -<br />
3 -<br />
4 &#8211; The‚Ä¶<br />
5 &#8211; The‚Ä¶<br />
6 &#8211; The‚Ä¶<br />
7 &#8211; The‚Ä¶<br />
8 &#8211; The‚Ä¶<br />
9 &#8211; The‚Ä¶<br />
10 &#8211; The‚Ä¶<br />
11 &#8211; The quick‚Ä¶<br />
12 &#8211; The quick‚Ä¶<br />
13 &#8211; The quick‚Ä¶<br />
14 &#8211; The quick‚Ä¶<br />
15 &#8211; The quick‚Ä¶<br />
16 &#8211; The quick‚Ä¶<br />
17 &#8211; The quick‚Ä¶<br />
18 &#8211; The quick‚Ä¶<br />
19 &#8211; The quick‚Ä¶<br />
20 &#8211; The quick‚Ä¶<br />
21 &#8211; The quick, brown-fox‚Ä¶<br />
22 &#8211; The quick, brown-fox‚Ä¶<br />
23 &#8211; The quick, brown-fox‚Ä¶<br />
24 &#8211; The quick, brown-fox‚Ä¶<br />
25 &#8211; The quick, brown-fox‚Ä¶<br />
26 &#8211; The quick, brown-fox‚Ä¶<br />
27 &#8211; The quick, brown-fox jumps‚Ä¶<br />
28 &#8211; The quick, brown-fox jumps‚Ä¶<br />
29 &#8211; The quick, brown-fox jumps‚Ä¶<br />
30 &#8211; The quick, brown-fox jumps‚Ä¶<br />
31 &#8211; The quick, brown-fox jumps‚Ä¶<br />
32 &#8211; The quick, brown-fox jumps over‚Ä¶<br />
33 &#8211; The quick, brown-fox jumps over‚Ä¶<br />
34 &#8211; The quick, brown-fox jumps over‚Ä¶<br />
35 &#8211; The quick, brown-fox jumps over‚Ä¶<br />
36 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
37 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
38 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
39 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
40 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
41 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
42 &#8211; The quick, brown-fox jumps over the‚Ä¶<br />
43 &#8211; The quick, brown-fox jumps over the &#8220;lazy‚Ä¶<br />
44 &#8211; The quick, brown-fox jumps over the &#8220;lazy‚Ä¶<br />
45 &#8211; The quick, brown-fox jumps over the &#8220;lazy‚Ä¶<br />
46 &#8211; The quick, brown-fox jumps over the &#8220;lazy‚Ä¶<br />
47 &#8211; The quick, brown-fox jumps over the &#8220;lazy&#8221; dog.</p>
<p>I&#8217;m satisfied with the results so far, but of course suggestions are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://devblog.jasonhuck.com/2007/10/02/smart-string-truncation-in-lasso/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
