<?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>Keith Bentrup&#8217;s Portforlio</title>
	<atom:link href="http://portfolio.keithbentrup.com/feed" rel="self" type="application/rss+xml" />
	<link>http://portfolio.keithbentrup.com</link>
	<description>A brief sampling of my work</description>
	<lastBuildDate>Wed, 28 Jul 2010 18:09:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Cron jobs with mail notification on a Windows box in 5 minutes</title>
		<link>http://portfolio.keithbentrup.com/archives/282</link>
		<comments>http://portfolio.keithbentrup.com/archives/282#comments</comments>
		<pubDate>Wed, 28 Jul 2010 14:48:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://portfolio.keithbentrup.com/?p=282</guid>
		<description><![CDATA[So cygwin allows you to port all the great *nix utilities to a Windows environment, and that&#8217;s useful because 1) there are some many handy tools and 2) you can write scripts or tasks once and use them everywhere (Unix, Linux, OS X, Windows).
Today, let&#8217;s discover how you can get two of the most useful [...]]]></description>
			<content:encoded><![CDATA[<p>So cygwin allows you to port all the great *nix utilities to a Windows environment, and that&#8217;s useful because 1) there are some many handy tools and 2) you can write scripts or tasks <strong>once</strong> and use them everywhere (Unix, Linux, OS X, Windows).</p>
<p>Today, let&#8217;s discover <strong>how you can get two of the most useful tools (automated tasks and mail notification) installed in less than 5 min.</strong></p>
<p>Since the typical Windows box was not designed as a server, scheduled services/tasks and mail transfer agents are not commonly implemented/installed, but we can quickly fix that.</p>
<p>First, install the <code>exim</code> and <code>cron</code> cygwin package and then run <code>exim-config</code>. You can accept most of the defaults. The only change that you might want to make is to set up a primary hostname. I use &#8220;mail.local&#8221;. Be sure to add that to your hosts file (%WINDIR%\system32\drivers\etc\hosts), too:</p>
<pre class="brush: plain;">127.0.0.1 mail.local</pre>
<p>Next since you want mail to be deliverable for users without accounts, we need to disable the <code>check_local_user</code> option under the <code>localuser</code> router in <code>/etc/exim.conf</code>.</p>
<p>Verify the setup with </p>
<pre class="brush: plain;">$ exim -bt test@mail.local</pre>
<p>You should see something like &#8230;</p>
<pre class="brush: plain;">test@mail.local
   router = localuser, transport = local_delivery</pre>
<p>Now any output from the cron jobs will appear in the mail logs located in <code>/var/spool/mail</code>.</p>
<p>Also note that you can quickly send mail from the command line now without any other tools. Try this:</p>
<pre class="brush: plain;">$ exim -v -odf test@mail.local
This is a test message.</pre>
<p>Just end the message with a newline and then type Ctrl+D. Now check <code>/var/spool/mail/test</code>.</p>
<p><strong>Now for cron.</strong> Run <code>cron-config</code> accepting the defaults as needed. You can quickly test the setup afterward by editing your crontab.</p>
<pre class="brush: plain;">echo '* * * * * echo hi' | crontab -</pre>
<p>In less than a minute (<em>and every minute thereafter until you change it</em>), you should see the output in your mail spool. </p>
<p>And we&#8217;re done. Now just set up <strong>whatever cron jobs you want</strong> <em>on whatever schedule you want</em>. That wasn&#8217;t so bad, was it?</p>
]]></content:encoded>
			<wfw:commentRss>http://portfolio.keithbentrup.com/archives/282/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cleaning house (hardware edition)</title>
		<link>http://portfolio.keithbentrup.com/archives/277</link>
		<comments>http://portfolio.keithbentrup.com/archives/277#comments</comments>
		<pubDate>Mon, 05 Jul 2010 13:06:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://portfolio.keithbentrup.com/?p=277</guid>
		<description><![CDATA[I&#8217;m on a simplification kick, and I&#8217;ve been dramatically reducing the clutter in my life and enjoying the results.
I recently noticed a good deal on a drive at Microcenter and thought &#8220;Why keep 5 external drives (1.3 TB total, 5 usb cables, 5 power cords) when a single drive (1.5 TB, 1 usb cable, 1 [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m on a simplification kick, and I&#8217;ve been dramatically reducing the clutter in my life and enjoying the results.</p>
<p>I recently noticed a good deal on a drive at Microcenter and thought &#8220;Why keep 5 external drives (1.3 TB total, 5 usb cables, 5 power cords) when a single drive (1.5 TB, 1 usb cable, 1 power cord) will do?&#8221;</p>
<p>So began the long process of consolidating, organizing, and erasing years worth of files, and if you&#8217;re doing the same, I have a few tips to share.</p>
<p>After consolidating everything to one disk, I wanted to find duplicate files that may have proliferated over the years. Fortunately, there&#8217;s a little utility called <strong>fdupes</strong> that does the trick nicely. On a Windows system, you can use it through cygwin.</p>
<pre class="brush: plain;">
fdupes -r /cygdrive/VOLUME_HERE
</pre>
<p>The first pass was preliminary to see how bad it was. I found 100s of GBs worth of data that I had forgotten about. There were also several .svn directories cluttering up the results. To remove that useless (for a backup) metadata, I removed it with</p>
<pre class="brush: plain;">
IFS=$(echo -en &quot;\n\b&quot;)
for i in $(find -regex &quot;.*\.svn$&quot;); do rm -rf $i; done
</pre>
<p>The first line sets the input file separator to a newline character (as opposed to the space) so the results of the <strong>find</strong> in the next statement works as expected. Now it will treat filenames with spaces as a proper path.</p>
<p>Now I could recursively, forcibly delete all the duplicates:</p>
<pre class="brush: plain;">
fdupes -rFd /cygdrive/VOLUME_HERE
</pre>
<p>I also wanted to remove all those <strong>Thumbs.db</strong> files that Windows loves to create as well as all the empty files and (now) empty directories</p>
<pre class="brush: plain;">
find -regex &quot;.*Thumbs.db&quot; -delete
find -size 0 -type f -delete
find -type d -empty -delete
</pre>
<p><em>Note: You may want to run these commands without the delete option first as a sanity check.</em></p>
<p>Now prep the old drives for donation &hellip;</p>
<p>Considering that you may have very sensitive data (e.g. passwords, bank/credit card statements, etc.) on your old drives, be sure to clean the drives before you donate them.</p>
<p>I simply formatted each and then used the windows built in <strong>cipher</strong> utility to clean each drive after copying over the contents.</p>
<pre class="brush: plain;">
cipher /w:VOLUME_HERE:
</pre>
<p>This wipes all the empty space on a disk with a 3 pass system &#8211; writing all 0&#8217;s, writing all 1&#8217;s, and then writing random data. In all that&#8217;s 4 passes (including the original format).</p>
<p>I could go on to discuss encryption of your data on your new drive and offsite backup, but that&#8217;ll have to wait for another day &#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://portfolio.keithbentrup.com/archives/277/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimal Caching Strategies Gotcha</title>
		<link>http://portfolio.keithbentrup.com/archives/271</link>
		<comments>http://portfolio.keithbentrup.com/archives/271#comments</comments>
		<pubDate>Thu, 17 Jun 2010 17:31:29 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://portfolio.keithbentrup.com/?p=271</guid>
		<description><![CDATA[The fastest download is no download, so I was trying to prevent even the 304s (last modified requests &#038; responses) on a recent project. It had been a while since I had to configure Apache for this, but here was the start of a .htaccess file:

&#60;FilesMatch "\.(ico&#124;pdf&#124;flv&#124;jpg&#124;jpeg&#124;png&#124;gif&#124;js&#124;css&#124;swf)$"&#62;
 ExpiresActive On
 ExpiresDefault "access plus 10 years"
&#60;/FilesMatch&#62;
# compress [...]]]></description>
			<content:encoded><![CDATA[<p>The fastest download is no download, so I was trying to prevent even the 304s (last modified requests &#038; responses) on a recent project. It had been a while since I had to configure Apache for this, but here was the start of a .htaccess file:</p>
<p><code><br />
&lt;FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt;<br />
 ExpiresActive On<br />
 ExpiresDefault "access plus 10 years"<br />
&lt;/FilesMatch&gt;</p>
<p># compress text, html, javascript, css, xml:<br />
AddOutputFilterByType DEFLATE text/plain<br />
AddOutputFilterByType DEFLATE text/html<br />
AddOutputFilterByType DEFLATE text/xml<br />
AddOutputFilterByType DEFLATE text/css<br />
AddOutputFilterByType DEFLATE application/xml<br />
AddOutputFilterByType DEFLATE application/xhtml+xml<br />
AddOutputFilterByType DEFLATE application/rss+xml<br />
AddOutputFilterByType DEFLATE application/javascript<br />
AddOutputFilterByType DEFLATE application/x-javascript<br />
Header unset ETag<br />
FileETag None<br />
Header unset Last-Modified<br />
</code></p>
<p>I set up a versioning system on the backend so that whenever resources are updated new version numbers are automatically generated to create new request URLs. Thus, I could set far future expires tags. However, it didn&#8217;t seem to be working. I kept seeing the requests in fiddler even though the <strong>Expires</strong> header was set and the <strong>Last-Modified</strong> header removed. <strong>The problem? I was hitting refresh which was causing the clients (FF &#038; Chrome) to request the resources regardless of the headers.</strong> Navigating away and then back generated the expected behavior. :p</p>
]]></content:encoded>
			<wfw:commentRss>http://portfolio.keithbentrup.com/archives/271/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>wget and the web dev</title>
		<link>http://portfolio.keithbentrup.com/archives/266</link>
		<comments>http://portfolio.keithbentrup.com/archives/266#comments</comments>
		<pubDate>Sat, 27 Mar 2010 19:56:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://portfolio.keithbentrup.com/?p=266</guid>
		<description><![CDATA[wget can be a very handy tool during development. Combine wget with other *nix utilities (like time and cron), and you can write some very useful scripts/snippets. For example, 

wget -p -H -nv http://www.my-domain.com/cart/ 2&#62;&#38;1

uses -p/&#8211;page-requisites to download all the files necessary to render the page while -H causes it to span domains if necessary. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://linux.die.net/man/1/wget">wget</a> can be a very handy tool during development. Combine wget with other *nix utilities (like time and cron), and you can write some very useful scripts/snippets. For example, </p>
<pre class="brush: bash;">
wget -p -H -nv http://www.my-domain.com/cart/ 2&gt;&amp;1
</pre>
<p>uses -p/&#8211;page-requisites to download all the files necessary to render the page while -H causes it to span domains if necessary. If you pass this to grep (after redirecting the output (defaulted to STDERR) to STDOUT), you could look for 403/404&#8217;s or any other undesirable response code. The -nv/&#8211;no-verbose simply prevents the deluge of information that wget spits out by default.</p>
<p>Here&#8217;s part of a shell script run through my crontab that I have set up to time downloads during the development cycle. I can monitor a list of urls on my dev/test servers (passed in $1) and monitor the performance over time.</p>
<pre class="brush: bash;">
for i in $(
 # list of urls here
 echo '/product/index.jsp?productId=3633213'
 echo '/cart/index.jsp'
 # ....
); do
time -f &quot;`date` | %E | $1$i\n&quot; -a -o time.log wget -a wget.log -O /dev/null -p $1$i
done
</pre>
]]></content:encoded>
			<wfw:commentRss>http://portfolio.keithbentrup.com/archives/266/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>BOMs away!</title>
		<link>http://portfolio.keithbentrup.com/archives/263</link>
		<comments>http://portfolio.keithbentrup.com/archives/263#comments</comments>
		<pubDate>Fri, 12 Mar 2010 00:58:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://portfolio.keithbentrup.com/?p=263</guid>
		<description><![CDATA[So I was having problems backporting some changes to a fork of our platform today. WinMerge kept reporting files as different in the summary view, but displayed no differences in the file comparison view. I looked closer and noticed the character sets were &#8220;different&#8221;.
A developer on the team had started saving files in the repository [...]]]></description>
			<content:encoded><![CDATA[<p>So I was having problems backporting some changes to a fork of our platform today. <a href="http://winmerge.org/">WinMerge</a> kept reporting files as different in the summary view, but displayed no differences in the file comparison view. I looked closer and noticed the character sets were &#8220;different&#8221;.</p>
<p>A developer on the team had started saving files in the repository with <a href="http://en.wikipedia.org/wiki/Byte_order_mark">BOM (Byte Order Mark)</a> information. I don&#8217;t know if it was intentional or an effect of their IDE. Either way, it had to go, so &#8230; perl to the rescue.</p>
<pre class="brush: bash;">
for i in $(find -regex &quot;.*\.jsp$&quot;); do perl -pi.old -e 'BEGIN { $/ = undef; } s/^\xEF\xBB\xBF//' $i; done
</pre>
]]></content:encoded>
			<wfw:commentRss>http://portfolio.keithbentrup.com/archives/263/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
