<?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>lyncd</title>
	<atom:link href="http://lyncd.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://lyncd.com</link>
	<description></description>
	<lastBuildDate>Thu, 26 Aug 2010 06:42:58 +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>Get it while it&#8217;s hot: User Spam Remover for WordPress</title>
		<link>http://lyncd.com/2010/08/user-spam-remover/</link>
		<comments>http://lyncd.com/2010/08/user-spam-remover/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 06:42:58 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[systems]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=244</guid>
		<description><![CDATA[I&#8217;m releasing a WordPress plugin that I wrote to tackle the scourge of user registration spam &#8212; those annoying bots that linkspam the WordPress registration form. If you need a way to silently and automatically delete these spam accounts, and block the new user notification e-mail that WordPress normally sends, check out User Spam Remover. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m releasing a WordPress plugin that I wrote to tackle the scourge of user registration spam &#8212; those annoying bots that linkspam the WordPress registration form.</p>
<p>If you need a way to silently and automatically delete these spam accounts, and block the new user notification e-mail that WordPress normally sends, check out <a href="/user-spam-remover/">User Spam Remover</a>.<span id="more-244"></span></p>
<p>If you&#8217;re thinking, <em>&#8220;But, I already know about [Plugin X] that uses Captchas, RBLs and double opt-in activation e-mail to keep spammers away!&#8221;</em> then well, that&#8217;s great. But I wrote User Spam Remover with a different goal in mind: It doesn&#8217;t interfere with the user registration process at all. It just deletes spam and other unused user accounts <em>after</em> it&#8217;s clear they&#8217;re abandoned.</p>
<p>I could <a href="/user-spam-remover/faq/#faq-why">totally go off on this topic</a>, but my logic is that Captchas, RBLs and activation are (a) easily and routinely exploited and (b) annoying to configure and deal with, both from an admin and user perspective. They&#8217;re a pain in the butt, and they don&#8217;t work 100% &#8212; you&#8217;ve still got spam getting through, and now you&#8217;ve got false positives as well, impacting your &#8220;real&#8221; users.</p>
<p>The problem is that, unlike comment spam, which can be reliably (thanks, <a href="http://akismet.com/">Akismet</a>) detected using pattern matching, there&#8217;s simply too little data in a user account to accurately identify spam based on just a username, password, URL and IP address. (The same goes for, say, a human attacker.)</p>
<p>So, User Spam Remover is designed based on the assumption that these users can and will register, but won&#8217;t be allowed to do anything other than comment. Then, if they do comment (99% of the time they won&#8217;t &#8212; they&#8217;re just linkspamming the registration URL), their comments will be caught by Akismet or otherwise modded into oblivion.</p>
<p>So, in the end, these accounts can be identified and deleted based on the fact that they&#8217;re totally unused (have added no posts, links or comments).</p>
<p><a href="/user-spam-remover/">User Spam Remover</a> takes care of identifying and removing these user accounts in the background. It&#8217;s fully configurable, and includes full logging and backup of every database record it deletes, for seamless restoration if need be (it <em>is</em> deleting from your users table, after all).</p>
<p>I&#8217;ve tested the released version on data dumps from several live blogs including thousands of users, and have been running it for several weeks without incident. That doesn&#8217;t mean it&#8217;s bug-free &#8212; this is an initial public release &#8212; but it&#8217;s ready for wider use.</p>
<p>I suggest testing it on a development copy of your site first: For instance, use it to delete some user spam, and then reload them from the SQL backup file:</p>
<pre><code>mysql your_wp_database < userspamremover.restore.sql</code></pre>
<p>Once you're confident that the plugin works, and that you know how to restore user accounts if something goes wrong, then you can feel a lot more secure about trying it out on your blog.</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2010/08/user-spam-remover/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML Minify for WordPress and WP Super Cache: Now a plugin!</title>
		<link>http://lyncd.com/2010/08/minify-wordpress-super-cache-plugin/</link>
		<comments>http://lyncd.com/2010/08/minify-wordpress-super-cache-plugin/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 07:18:34 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[minify]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[systems]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp-super-cache]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=206</guid>
		<description><![CDATA[It&#8217;s been a while, but I&#8217;ve updated my code that adds Minify to WP Super Cache, making everyone&#8217;s favorite WordPress caching plugin that much better. What&#8217;s better is that my code now operates as a fully fledged plugin to Super Cache, so it&#8217;s now a drop-in install (no more patches!). Go to WPSCMin&#8217;s project page [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been a while, but I&#8217;ve updated my code that adds <a href="http://code.google.com/p/minify/">Minify</a> to <a href="http://ocaoimh.ie/wp-super-cache/">WP Super Cache</a>, making everyone&#8217;s favorite WordPress caching plugin that much better.</p>
<p>What&#8217;s better is that my code now operates as a fully fledged plugin to Super Cache, so it&#8217;s now a drop-in install <em>(no more patches!)</em>. Go to WPSCMin&#8217;s <a href="/wpscmin/" title="WPSCMin, an HTML Minify plugin for WordPress and WP Super Cache">project page</a> for all the info.<span id="more-206"></span></p>
<h4>On an almost completely unrelated note</h4>
<p>Quite a while ago, I wrote about <a href="/2008/11/gzip-compression-levels-for-static-cached-html/">experimenting with gzip compression levels</a> for static HTML and concluded that zlib&#8217;s default (level 6) probably makes the most sense for an application like WP Super Cache.</p>
<p>At the time, Super Cache was using level 1 (compared to which, level 6 is an improvement of 5.9% file reduction at a cost of just 1/5 of a millisecond &#8212; and that on what was a <em>slow</em> test machine). Super Cache has since moved up to level 3.</p>
<p>If you&#8217;re like me, and still prefer to use zlib&#8217;s default, there&#8217;s now just one line of code in Super Cache&#8217;s <code>wp-cache-phase2.php</code> that you have to change. Here&#8217;s the edit for WP Super Cache version 0.9.9.3:</p>
<pre><code class="prettyprint">=== modified file 'htdocs/wp-content/plugins/wp-super-cache/wp-cache-phase2.php'
--- htdocs/wp-content/plugins/wp-super-cache/wp-cache-phase2.php	2010-08-08 04:07:50 +0000
+++ htdocs/wp-content/plugins/wp-super-cache/wp-cache-phase2.php	2010-08-08 04:08:14 +0000
@@ -444,6 +444,6 @@
 		$buffer = apply_filters( 'wpsupercache_buffer', $buffer );
 		if( $gz || $wp_cache_gzip_encoding ) {
 			if ( isset( $GLOBALS[ 'wp_super_cache_debug' ] ) &#038;&#038; $GLOBALS[ 'wp_super_cache_debug' ] ) wp_cache_debug( "Gzipping buffer.", 5 );
-			$gzdata = gzencode( $buffer . "<!-- Compression = gzip -->", 3, FORCE_GZIP );
+			$gzdata = gzencode( $buffer . "<!-- Compression = gzip -->");
 			$gzsize = strlen($gzdata);
 		}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2010/08/minify-wordpress-super-cache-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Replacing MacBook&#8217;s AirPort card with an Atheros AR5BXB6 from an IBM Thinkpad</title>
		<link>http://lyncd.com/2010/07/macbook-airport-ar5bxb6/</link>
		<comments>http://lyncd.com/2010/07/macbook-airport-ar5bxb6/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 00:08:15 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[systems]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=183</guid>
		<description><![CDATA[Four years of 85&#176;C CPU temperatures took their toll on my friend&#8217;s MacBook. Her AirPort wireless card still functioned, but suddenly her wifi signal had become unusably weak. I checked her system configuration, opened up her first-gen MacBook, and everything looked fine. But with plenty of others reporting similar issues, it was most likely the [...]]]></description>
			<content:encoded><![CDATA[<p>Four years of 85&deg;C CPU temperatures took their toll on my friend&#8217;s MacBook. Her AirPort wireless card still functioned, but suddenly her wifi signal had become unusably weak.</p>
<p>I checked her system configuration, opened up her first-gen MacBook, and everything looked fine. But with plenty of others reporting similar issues, it was most likely the card had succumbed to heat. It could sometimes maintain normal wireless range for several minutes &#8212; when started totally cold &#8212; but after the system temps warmed up, would go back to only a few feet of range.</p>
<p>The model number printed on the AirPort card is an Atheros AR5BXB6. A Google Products search for &#8220;<a href="http://www.google.com/products?hl=en&#038;q=AR5BXB6&#038;um=1&#038;ie=UTF-8&#038;ei=5mNXTLuUFIOC8gaA6q2GAw&#038;sa=X&#038;oi=product_result_group&#038;ct=title&#038;resnum=1&#038;ved=0CC0QrQQwAA">AR5BXB6</a>&#8221; turned up these $13 <a href="http://www.primelec.com/IBM-Mini-PCI-Express/Networking/Wireless-Networking/Wireless-Adapters-p8181130.html">Thinkpad pulls</a> among others available online, and for $13 we figured it was easily worth a shot as a drop-in replacement, compared to the cost of a new Apple card. It turned out be only a little tricksier than that.<span id="more-183"></span></p>
<p>With the new card <a href="http://www.ehow.com/how_4850079_upgrade-airport-wireless-card-macbook.html">installed</a>, her Mac started up fine, but it didn&#8217;t see the card at all, and <code>dmesg</code> and the kernel log were no help. But, after a few more minutes of head-scratching and googling than I&#8217;d care to admit, I found the answer, mostly thanks to the <a href="http://forum.thinkpads.com/viewtopic.php?f=32&#038;t=52240&#038;start=0&#038;sid=8862694bc93c59c33389b2b730b97eb1">hackintosh community</a>. Even though this was a genuine Atheros AR5BXB6, it wasn&#8217;t an Apple part, so I needed to edit the AirPort kernel extension property list to add the new card&#8217;s device ID to the list of recognized Atheros IDs.</p>
<p>The quick-and-dirty way to do this (if <code>vi</code> and the Terminal are your best friends) is:</p>
<pre><code class="prettyprint"># edit original plist in place
sudo vi /System/Library/Extensions/IO80211Family.kext/Contents/PlugIns/AirPortAtheros.kext/Contents/Info.plist
# and add this one line after the others like it:
#                                &lt;string&gt;pci168c,1014&lt;/string&gt;
# then clear and rebuild the kext caches:
sudo rm -fr /System/Library/Extensions.mkext
sudo kextcache -k /System/Library/Extensions</code></pre>
<p>And reboot!</p>
<p>(If that scared you, you&#8217;ll need to use the Finder and go to <code>/System/Library/Extensions</code>, then control-click on <code>IO80211Family.kext</code> and do &#8220;Show Package Contents.&#8221; Continuing inside the <code>Contents/PlugIns</code> folders, control-click again on <code>AirPortAtheros.kext</code> to show package contents. Then, inside <code>Contents</code>, double-click on <code>Info.plist</code> to open it with Property List Editor (or else TextEdit). Finally, add the vendor/device ID pair &#8220;pci168c,1014&#8243; after the other &#8220;pci168c&#8221; devices. Save, quit and reboot.)</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2010/07/macbook-airport-ar5bxb6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Better Google Analytics JavaScript that doesn&#8217;t block page downloading</title>
		<link>http://lyncd.com/2009/03/better-google-analytics-javascript/</link>
		<comments>http://lyncd.com/2009/03/better-google-analytics-javascript/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 06:57:42 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[google-analytics]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[systems]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=153</guid>
		<description><![CDATA[If you saw Steve Souders&#8217; March 5 talk at Google and have ever used Google Analytics, then you were probably amused when he used GA&#8217;s JavaScript insertion code as his &#8220;wrong&#8221; counterexample. Well, at least I was, and somebody else mentioned it in the Q&#038;A so I figure I&#8217;m not the only one. The GA [...]]]></description>
			<content:encoded><![CDATA[<p>If you saw Steve Souders&#8217; <a href="http://google-code-updates.blogspot.com/2009/03/steve-souders-lifes-too-short-write.html">March 5 talk</a> at Google and have ever used Google Analytics, then you were probably amused when he used GA&#8217;s JavaScript insertion code as his &#8220;wrong&#8221; counterexample. Well, at least <em>I</em> was, and somebody else mentioned it in the Q&#038;A so I figure I&#8217;m not the only one.</p>
<p>The GA insertion code that Google gives you to put on your site does a couple of bad things: First, it uses <code>document.write</code>, and second, it loads <code>ga.js</code> directly, which blocks browsers from doing any page rendering or downloading of other page components (images, scripts, stylesheets) during the whole time it takes <code>ga.js</code> to download and execute. In other words, Google Analytics makes your pages load slower!</p>
<p>Using Steve&#8217;s best practices, I&#8217;ve coded up a <a href="/2009/03/better-google-analytics-javascript/#thecode">better version</a> that does DOM insertion of the script tag and uses the &#8220;script onload&#8221; technique to initialize the tracker, so that it doesn&#8217;t block I/O, and you can inline it anywhere on the page or even load it from an external file. You can choose to lazy-load GA whenever you want &#8212; for instance, even after <code>window.onload</code> fires &#8212; so that it&#8217;s totally asynchronous and doesn&#8217;t interfere with page rendering at all.<span id="more-153"></span></p>
<p>If you&#8217;ve got no idea who Steve Souders is (former front-end optimization guru at Yahoo, and now at Google) or what I&#8217;m talking about, I strongly recommend you check out Steve&#8217;s book, <a href="http://www.amazon.com/gp/product/0596529309?ie=UTF8&#038;tag=amaz0-20&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=0596529309">High Performance Web Sites</a>, and its 14 rules for high-performance sites, which are also summarized on <a href="http://stevesouders.com/hpws/rules.php">Steve&#8217;s site</a> and Yahoo&#8217;s <a href="http://developer.yahoo.com/performance/rules.html">Exceptional Performance blog</a>. Steve is currently working on a follow-up book with 10 (so far) new rules, which you can get a sneak peak at by watching <a href="http://sites.google.com/site/io/even-faster-web-sites">this talk</a> on the first three and <a href="http://google-code-updates.blogspot.com/2009/03/steve-souders-lifes-too-short-write.html">the March 5 talk</a> on the next three (skip to 39:00 to see him bring up GA). Steve also gave a talk at SXSW (<a href="http://stevesouders.com/docs/sxsw-20090314.ppt">slides</a>) yesterday.</p>
<h4 id="thecode">The code</h4>
<p>Here&#8217;s the Google Analytics insertion code that I put together from Steve&#8217;s examples &#8212; it&#8217;s pretty simple, really. Instead of the code Google tells you to use, you can just copy-paste this instead. You can use it inline, or load it from an external .js file:</p>
<p><em>(Updated 3/27 per <a href="#comment-214">thread</a>)</em></p>
<pre class="prettyprint lang-js"><code>/*
Inserts GA using DOM insertion of &lt;script&gt; tag and "script onload" method to
initialize the pageTracker object. Prevents GA insertion from blocking I/O!

As suggested in Steve Souder's talk. See:

http://google-code-updates.blogspot.com/2009/03/steve-souders-lifes-too-short-write.html

*/

/* acct is GA account number, i.e. "UA-5555555-1" */
function gaSSDSLoad (acct) {
  var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."),
      pageTracker,
      s;
  s = document.createElement('script');
  s.src = gaJsHost + 'google-analytics.com/ga.js';
  s.type = 'text/javascript';
  s.onloadDone = false;
  function init () {
    pageTracker = _gat._getTracker(acct);
    pageTracker._trackPageview();
  }
  s.onload = function () {
    s.onloadDone = true;
    init();
  };
  s.onreadystatechange = function() {
    if (('loaded' === s.readyState || 'complete' === s.readyState) &#038;&#038; !s.onloadDone) {
      s.onloadDone = true;
      init();
    }
  };
  document.getElementsByTagName('head')[0].appendChild(s);
}

/* and run it */
gaSSDSLoad("UA-5555555-1");
</code></pre>
<p>Be sure to <strong>use your own tracking code</strong> in place of &#8220;UA-5555555-1.&#8221;</p>
<h4>Other things to consider</h4>
<p>Using code like this means you could choose to load the GA tracker higher up in your pages, with less of a penalty versus Google&#8217;s insertion code, which causes serious blocking if it isn&#8217;t at the very bottom just before <code>&lt;/body&gt;</code>. It&#8217;s still best to load GA last unless you <em>really</em> want to count every pageview possible.</p>
<p>You could also modify the last line of my example so that <code>gaSSDSLoad()</code> isn&#8217;t triggered until after <code>window.onload</code> (I didn&#8217;t do this in my example, because I wanted it to be a drop-in replacement for Google&#8217;s code). That way, GA doesn&#8217;t even <em>start</em> downloading or executing until after your page is displayed. For instance:</p>
<pre class="prettyprint lang-js"><code>window.onload = function () { gaSSDSLoad("UA-5555555-1"); };</code></pre>
<p>If you&#8217;re using Dojo, you might want to take a look at this <a href="http://trac.dojotoolkit.org/browser/dojox/trunk/analytics/Urchin.js?rev=15843">Dojo module</a> (mentioned by Steve in his talk), which also lazy-loads GA. My version is different in that (1) it&#8217;s standalone and doesn&#8217;t require Dojo and (2) it uses the &#8220;script onload&#8221; method to detect when <code>ga.js</code> has finished downloading (as Steve suggested), instead of polling with a timer. That means it does a slightly better job of firing <code>_gat._getTracker()</code> as soon as <code>ga.js</code> is loaded, compared to the Dojo version.</p>
<p>In his talk, Steve said he hoped the Dojo folks would incorporate his suggestions and improve their version. That&#8217;s all well and good, but considering where Steve works, let&#8217;s hope <em>Google</em> takes his suggestions! (Otherwise, the irony of &#8220;Google is the new Yahoo&#8221; will be just too much.)</p>
<p>I&#8217;ve been running my version for a few days and haven&#8217;t noticed any problems (no traffic drop-offs from any browsers/user agents), but no guarantees of course. Please let me know if you notice any bugs or have suggestions! (First person to tell me they already wrote this exact thing 6 months ago gets a special prize. :) )</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2009/03/better-google-analytics-javascript/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Optimize all your PNG and JPEG images with one command using imgopt</title>
		<link>http://lyncd.com/2009/03/imgopt-lossless-optimize-png-jpeg/</link>
		<comments>http://lyncd.com/2009/03/imgopt-lossless-optimize-png-jpeg/#comments</comments>
		<pubDate>Sun, 01 Mar 2009 15:53:08 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[image files]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[systems]]></category>
		<category><![CDATA[web graphics]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=103</guid>
		<description><![CDATA[Here&#8217;s something useful for the web developers out there. It&#8217;s a script I&#8217;ve been using for a while that makes it super-easy to losslessly compress entire folders of PNG and JPEG files for the web. If you&#8217;re familiar with PNG optimization, then you know about programs like advpng, optipng and pngout that optimize and recompress [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s something useful for the web developers out there. It&#8217;s a script I&#8217;ve been using for a while that makes it super-easy to losslessly compress entire folders of PNG and JPEG files for the web.</p>
<p>If you&#8217;re familiar with <a href="http://optipng.sourceforge.net/pngtech/optipng.html">PNG optimization</a>, then you know about programs like <a href="http://advancemame.sourceforge.net/">advpng</a>, <a href="http://optipng.sourceforge.net/">optipng</a> and <a href="http://www.advsys.net/ken/utils.htm">pngout</a> that optimize and recompress PNG files, making them much smaller than the likes of Photoshop can. My shell script combines all three of these utilities to achieve minimum file size, while hiding their command-line syntax and adding the ability to recursively process entire directory trees.</p>
<p>And, it works with JPEGs, too! It uses <code>jpegtran</code> (included with libjpeg) and another small utility I&#8217;ve included to optimize and strip all metadata from JPEG files. Since my script searches directories recursively, all you need to do is type, say, <code>imgopt myproj/htdocs</code> and it&#8217;ll take care of your entire website.</p>
<p>All compression is lossless, which means no pixels are changed and no information is lost, the files just get smaller &#8212; chances are your layout can shrink by as much as 50%, which is like getting free bandwidth, and it means your site will snap into place that much faster for users.<span id="more-103"></span></p>
<p>Read on for:</p>
<ul>
<li><a href="#how">How to use</a></li>
<li><a href="#whatwhy">What it does exactly, and why you should care</a></li>
<li><a href="#example">In action: How much can we optimize Reddit?</a></li>
</ul>
<h4 id="how">How to use: the quick and dirty</h4>
<p><code>imgopt</code> is a command-line bash shell script, so it&#8217;ll run on *nix systems like Mac OS X, Linux, BSD, and Windows running cygwin. I&#8217;ve been running it on OS X and Linux (both running <a href="http://www.gnu.org/software/bash/">bash</a> 2.05), but please let me know if you run into any problems on your platform.</p>
<p>The current version is <strong>0.1.2</strong>, released on 2009-04-02 (see <a href="/files/imgopt/changelog.txt"> changelog</a> for details). This post has been updated to reflect the current version, but some comments (especially those regarding bugs) are about prior releases. New bug reports and feature requests in the comments are welcome!</p>
<p>Download <a href="http://lyncd.com/files/imgopt-0.1.2.tar.gz">imgopt-0.1.2.tar.gz</a> and check out the included <a href="/files/imgopt/README.txt">README</a>. Basically, you just copy the <code>imgopt</code> script into your path and download and install all the helper programs if you don&#8217;t have them already.</p>
<p>Then you can use <code>imgopt</code> to optimize any combination of files, directories and wildcards in one fell swoop. Examples:</p>
<pre><code class="prettyprint lang-sh">$ imgopt A30.jpg
A30.jpg reduced 40 bytes to 1327 bytes

$ imgopt under60.jpg files/*png
under60.jpg reduced 36559 bytes to 49510 bytes
files/A11.png reduced 130 bytes to 669 bytes
files/A256.png reduced 55 bytes to 2106 bytes

# It is totally fine to run imgopt on the same file more than once, since it checks
# and only overwrites files when they have been reduced in size.
$ imgopt *
A30.jpg unchanged at 1327 bytes
A60.jpg reduced 36 bytes to 2119 bytes
files/A11.png unchanged at 669 bytes
files/A256.png unchanged at 2106 bytes
under50.jpg reduced 48 bytes to 18499 bytes
under60.jpg unchanged at 49510 bytes
</code></pre>
<p>Really, that&#8217;s all you need to know. Keep reading only if you&#8217;re curious or have time to kill.</p>
<h4 id="whatwhy">What it does and why you should care</h4>
<p>If you&#8217;re a website builder, hopefully you already understand the value of keeping website graphics as small as possible &#8212; even though it&#8217;s 2009 and most of us have megabit connections at home, each byte saved multiplied by every website visitor adds up to a huge reduction in bandwidth and server load, and a faster experience for users. (See: <a href="http://developer.yahoo.com/performance/rules.html">rules for exceptional performance</a>)</p>
<p>Hopefully, your image workflow looks like this. First, you know to <a href="http://mezzoblue.com/archives/2009/01/27/sprite_optim/">sprite your images</a>, especially those with shared color palettes, to minimize total file size and reduce HTTP request overhead. And you are a total expert at Photoshop or Illustrator&#8217;s &#8220;Save for Web&#8221; feature &#8212; you know when to save graphics as JPEG (continuous-tone images like photos) and when to use indexed-color PNG (line art, so probably most of the images in your website&#8217;s theme). You know a few of the manual color palette reduction tricks (like deleting colors with R/G/B values all &gt; 250, which reduces palette size <em>and</em> increases edge sharpness of type), so your PNGs only have 13 colors when that&#8217;s all they need, and not 256 just because that&#8217;s the default setting of some wizard thingy used by children and former print designers.</p>
<p>My <code>imgopt</code> script steps in at this point and further optimizes all the files that Photoshop (or whatever your graphics program is) spits out. Unfortunately, typical web graphics production software doesn&#8217;t really compress image data as much as it could &#8212; it doesn&#8217;t take the CPU time to really optimize the way the image data is ordered (because that would take too long), it inserts gamma and empty metadata structure that&#8217;s wasted on web layout graphics (yes, even in &#8220;Save for Web&#8221; mode), and, last but probably most important, uses an inferior zip compression algorithm.</p>
<p>One warning: My script strips <em>all</em> metadata (i.e. EXIF and JFIF) and gamma channels (which you should be removing for web use anyway; otherwise people running IE or Safari will complain about the color in your PNGs being &#8220;off&#8221;), so if you have image files with metadata, color profiles, masks or channels you want to keep, definitely make backup copies before optimizing!</p>
<p>I&#8217;ve commented the script and made it easy for you to go in and customize the helper programs I&#8217;m using and the parameters they&#8217;re passed. I&#8217;ve chosen options that minimize file size, so you could, for instance, make things run faster by choosing less compression, or you could opt to preserve some metadata, like photo credit information.</p>
<p>Here&#8217;s what it&#8217;s doing, to PNG and JPEG files, respectively &#8230;</p>
<h5>PNG</h5>
<p>My script piggybacks on the excellent work done by <a href="http://optipng.sourceforge.net/">optipng</a>, <a href="http://advancemame.sourceforge.net/">advpng</a>  and <a href="http://www.advsys.net/ken/utils.htm">pngout</a>. Now, I could go into a long explanation about how one of these (<code>pngout</code>) is good because it has a proprietary deflate algorithm that&#8217;s superior to zlib, while another is great at optimizing IDAT order (<code>optipng</code>), but the bottom line is that running all three of these utilities on your PNG files will produce smaller files than any one of them separately.</p>
<p>Very occasionally, you&#8217;ll be able to get a few more bytes of compression on PNGs just by running files through <code>imgopt</code> twice. So, feel free to try this and make it part of your routine if you like. Since it&#8217;s 2x the execution time to run the program twice, and the savings are very small, I elected not to just have <code>imgopt</code> do this on its own (and it&#8217;s so easy to just hit up arrow to run the command again). The reason a second pass occasionally works is related to the order the utilities are run in &#8212; sometimes a file, once deflated by <code>pngout</code>, can then be further optimized on a second pass thru <code>optipng</code> &#8212; and just doing a second run of the whole script is the easiest way to take care of any and all interaction cases like these. (FYI, in no instance have I ever found a third pass to do any good.)</p>
<h5>JPEG</h5>
<p>Here, the story is simpler: <code>imgopt</code> uses <code>jpegtran</code> (probably already on your system, since it&#8217;s part of <a href="http://www.ijg.org/">libjpeg</a>) to optimize the Huffman table and strip color profiles, EXIF data and other metadata. Second, it uses a small utility called <code>jfifremove</code> to remove JFIF metadata (<code>jpegtran</code> leaves at least a minimal 18-byte JFIF segment in place).</p>
<p>Results will depend mostly on how much metadata there is to strip from your images. If you&#8217;re running <code>imgopt</code> on files produced by Photoshop&#8217;s &#8220;Save for Web,&#8221; the savings may only be a few dozen bytes. Whereas, running it on random photos uploaded by users, files produced by Photoshop&#8217;s regular &#8220;Save&#8221; command or files straight from your digital camera will easily save 10-30K or more.</p>
<p>A word again about lossy compression vs. lossless. JPEG is a lossy format &#8212; most of the benefit of JPEG compression comes when you choose a compression level (of course it is <a href="http://www.ams.org/featurecolumn/archive/image-compression.html">more complicated than that</a> and there are some techniques you can use to get better control than what Photoshop provides, but I digress), and ultimately that&#8217;s what&#8217;s going to make the biggest difference to the final sizes of your JPEG files. My script and <code>jpegtran</code> are lossless and do not decode/recompress the JPEG image, they just optimize the existing JPEG data. Of course, if you want <code>imgopt</code> to automatically recompress JPEGs at a different quality setting, you could easily add that feature to the script by inserting a line before <code>jpegtran</code> that calls something like ImageMagick&#8217;s <a href="http://www.imagemagick.org/www/convert.html">convert</a>, but I&#8217;ll leave that to you.</p>
<p>About <code>jfifremove</code> &#8212; this is a <em>very</em> simple <a href="/files/imgopt/jfifremove.c">utility written in C</a> that I found <a href="http://archives.devshed.com/forums/compression-130/question-about-using-jpegtran-for-lossless-compression-of-jpegs-2013044.html">here</a>, debugged and compared against the JFIF standard. So, while I don&#8217;t claim authorship, I am the maintainer of the version included with my script. I&#8217;ve tested it thoroughly only as it is used in <code>imgopt</code> &#8212; i.e., for deleting the JFIF segment from files that already have had all other optional headers stripped by <code>jpegtran</code>. I have <em>not</em> tested it for standalone use (i.e. on files containing color profiles, thumbnails, EXIF data etc.), so I don&#8217;t recommend you use it outside my script unless you know what you&#8217;re doing. (I suspect it might fail to strip the JFIF segment from a file where the EXIF APP1 precedes the JFIF APP0, but at least do nothing destructive &#8230; but I&#8217;m only speculating.)</p>
<h4 id="example">In action: How much can we optimize Reddit?</h4>
<p>OK, let&#8217;s have some fun and optimize the graphics from a real website. I picked <a href="http://www.reddit.com/">Reddit</a> because it uses very few images, so this won&#8217;t take long. :)</p>
<p>Reddit is doing a pretty good job at performance optimization already, because they&#8217;re not overusing images, and the images they do use are small with few colors. But, they aren&#8217;t spriting their images or reducing colors effectively. Now, I&#8217;m not going to rebuild their website for them, but let&#8217;s see what happened when I ran <code>imgopt</code> on their homepage&#8217;s images, and also when I took another 5 minutes to do basic indexed color reductions on their PNGs. For the autogenerated thumbnail images, it would be unfair to do any manual reductions &#8212; but, it turns out they&#8217;re making another big mistake by using PNG instead of JPEG for these files. So, for these images, the third column is just a batch convert to JPEG with quality=60 (actually a pretty high setting for small thumbnails) to show what would happen if they fixed this.</p>
<table style="width: 90%;">
<caption>Reddit images optimized</caption>
<thead>
<tr>
<th abbr="filename" scope="col" style="width: 42%;">Filename</th>
<th abbr="original bytes" scope="col" style="width: 12%;" class="int">Bytes</th>
<th abbr="bytes after imgopt" scope="col" style="width: 23%;" class="int">imgopt only</th>
<th abbr="bytes after color reduction and imgopt" scope="col" style="width: 23%;" class="int">Colors reduced plus imgopt</th>
</tr>
</thead>
<tbody>
<tr>
<td>reddit.com.header.png</td>
<td class="int">2493</td>
<td class="int">1112</td>
<td class="int">871</td>
</tr>
<tr>
<td>static/adowngray.gif</td>
<td class="int">214</td>
<td class="int">214</td>
<td class="int">214</td>
</tr>
<tr>
<td>static/adownmod.gif</td>
<td class="int">145</td>
<td class="int">145</td>
<td class="int">145</td>
</tr>
<tr>
<td>static/aupgray.gif</td>
<td class="int">213</td>
<td class="int">213</td>
<td class="int">213</td>
</tr>
<tr>
<td>static/aupmod.gif</td>
<td class="int">148</td>
<td class="int">148</td>
<td class="int">148</td>
</tr>
<tr>
<td>static/create-a-reddit.png</td>
<td class="int">1187</td>
<td class="int">765</td>
<td class="int">579</td>
</tr>
<tr>
<td>static/droparrowgray.gif</td>
<td class="int">67</td>
<td class="int">67</td>
<td class="int">67</td>
</tr>
<tr>
<td>static/mailgray.png</td>
<td class="int">223</td>
<td class="int">127</td>
<td class="int">127</td>
</tr>
<tr>
<td>static/next_organic.png</td>
<td class="int">847</td>
<td class="int">208</td>
<td class="int">168</td>
</tr>
<tr>
<td>static/noimage.png</td>
<td class="int">1997</td>
<td class="int">1158</td>
<td class="int">668</td>
</tr>
<tr>
<td>static/prev_organic.png</td>
<td class="int">832</td>
<td class="int">225</td>
<td class="int">167</td>
</tr>
<tr>
<td>static/submit-alien.png</td>
<td class="int">2065</td>
<td class="int">1054</td>
<td class="int">607</td>
</tr>
<tr>
<td>static/wired_w.png</td>
<td class="int">650</td>
<td class="int">95</td>
<td class="int">95</td>
</tr>
<tr>
<th>Total</th>
<th class="int">11081</th>
<th class="int">5531</th>
<th class="int">4069</th>
</tr>
</tbody>
<thead>
<tr>
<th abbr="filename" scope="col">Filename</th>
<th abbr="original bytes" scope="col" class="int">Bytes</th>
<th abbr="bytes after imgopt" scope="col" class="int">imgopt only</th>
<th abbr="bytes after jpeg convert and imgopt" scope="col" class="int">JPEG convert plus imgopt</th>
</tr>
</thead>
<tbody>
<tr>
<td>thumbs/t3_80p41.png</td>
<td class="int">8472</td>
<td class="int">7037</td>
<td class="int">1762</td>
</tr>
<tr>
<td>thumbs/t3_80rcr.png</td>
<td class="int">9784</td>
<td class="int">7944</td>
<td class="int">1643</td>
</tr>
<tr>
<td>thumbs/t3_80sd0.png</td>
<td class="int">10383</td>
<td class="int">8391</td>
<td class="int">2089</td>
</tr>
<tr>
<td>thumbs/t3_80sfe.png</td>
<td class="int">2611</td>
<td class="int">1759</td>
<td class="int">1460</td>
</tr>
<tr>
<td>thumbs/t3_80ten.png</td>
<td class="int">2072</td>
<td class="int">1098</td>
<td class="int">1835</td>
</tr>
<tr>
<td>thumbs/t3_80tge.png</td>
<td class="int">4732</td>
<td class="int">3779</td>
<td class="int">1173</td>
</tr>
<tr>
<td>thumbs/t3_80ujf.png</td>
<td class="int">8660</td>
<td class="int">7064</td>
<td class="int">1840</td>
</tr>
<tr>
<td>thumbs/t3_80vt1.png</td>
<td class="int">2072</td>
<td class="int">1098</td>
<td class="int">1835</td>
</tr>
<tr>
<td>thumbs/t3_80xg6.png</td>
<td class="int">2136</td>
<td class="int">594</td>
<td class="int">816</td>
</tr>
<tr>
<th>Total</th>
<th class="int">50922</th>
<th class="int">38764</th>
<th class="int">14453</th>
</tr>
</tbody>
</table>
<p>So, the site&#8217;s main theme graphics shrunk by 50% just using <code>imgopt</code> alone, and another 25% on top of that with just a few minutes&#8217; common-sense color reduction. The autogenerated PNG thumbnails shrunk 20% &#8212; or, make them JPEGs and they&#8217;re down 70%. Reddit is a pretty graphics-sparse site, so saving 42K per page visitor isn&#8217;t too shabby. (Here&#8217;s a <a href="/files/2009/03/reddit-optimized.tar.gz">tarball of the end results</a>, in case anyone from Condé is reading.)</p>
<p>What about a site with a graphics-rich design? I gave the same experiment a whirl on a <a href="http://thinkprogress.org/">former top-20 blog</a> that I used to be tech lead for. Naturally, when I was there, the theme images were sprited and optimized and added to a total of maybe a dozen files and 20K &#8212; since then, there&#8217;s been a redesign and it&#8217;s now about 60 files and 150K (including some bad reminders of the dark ages, like sliced images and &#8220;blank.gif&#8221;). Result of a quick optimization on those files: I got them down to 50K, 1/3 the original size &#8212; so you know that with spriting and some sense you could get them down to 10-20 files and 30-40K pretty easily. I sent the result to a buddy, so hopefully the optimized versions will be making an appearance soon.</p>
<p>Still reading? Well, thanks for hanging in there. Now it&#8217;s time to go and make your own website go fast!</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2009/03/imgopt-lossless-optimize-png-jpeg/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Update to HTML Minify for WordPress and WP Super Cache</title>
		<link>http://lyncd.com/2009/02/update-minify-wordpress-wp-super-cache/</link>
		<comments>http://lyncd.com/2009/02/update-minify-wordpress-wp-super-cache/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 13:52:47 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[minify]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[systems]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp-super-cache]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=97</guid>
		<description><![CDATA[No big news here, but I&#8217;ve got an updated patch if you want to use my mod to add Minify to WordPress and WP Super Cache. For more information, check out my original explanation and instructions post, which I&#8217;ve updated with links to the new files. What&#8217;s changed? Well, nothing important. There have been some [...]]]></description>
			<content:encoded><![CDATA[<p>No big news here, but I&#8217;ve got an updated patch if you want to use my mod to add <a href="http://code.google.com/p/minify/">Minify</a> to WordPress and <a href="http://ocaoimh.ie/wp-super-cache/">WP Super Cache</a>. For more information, check out my original <a href="/2008/11/minify-for-wordpress/">explanation and instructions</a> post, which I&#8217;ve updated with links to the new files.<span id="more-97"></span></p>
<p>What&#8217;s changed? Well, nothing important. There have been some changes to WP Super Cache that caused parts of my patch not to apply automatically, so the patch is updated and tested against WP Super Cache 0.9. There&#8217;s also a tiny cosmetic change to the submit button on the WordPress configuration panel, so that it matches the WordPress 2.7+ backend.</p>
<p>Direct links to the new files:</p>
<ul>
<li><a href="/files/WPSCMin-0.2.tar.gz">WPSCMinify 0.2</a>, my standalone class and patch, which you can <a href="/2008/11/minify-for-wordpress/#install">install</a> into your existing Super Cache plugin</li>
<li><a href="/files/wp-super-cache-with-WPSCMin-0.2.tar.gz">wp-super-cache-with-WPSCMin-0.2.tar.gz</a>, which is a complete modded WP Super Cache 0.9 plugin that you can use if you don&#8217;t want to fiddle with patches</li>
</ul>
<h4>And FYI</h4>
<p>Be aware that recent versions of WP Super Cache fiddle with the <code>advanced-cache.php</code> file in <code>wp-content</code>, which previously you could just symlink to <code>plugins/wp-super-cache/wp-cache-phase1.php</code> (or you could copy the file if you don&#8217;t know what a symlink is). Now, instead of a symlink to <code>wp-cache-phase1.php</code>, it&#8217;s a PHP script that does a <code>require_once</code> of <code>wp-cache-phase1.php</code>. Whoop-de-do! I&#8217;m pretty sure the symlink is more efficient than doing a require in PHP, and it&#8217;s definitely annoying to have to copy and edit a file into a place outside the plugin directory, instead of a symlink that you could make once and leave alone forever, but whatever, it&#8217;s spaghetti code.</p>
<p>This doesn&#8217;t actually have anything to do with my mod, I just thought I&#8217;d mention it in case you&#8217;re upgrading WP Super Cache like I was &#8212; if so, be aware you&#8217;re going to have to manually shuffle this file around and edit it to look like this:</p>
<pre><code class="prettyprint">&lt;?php
# WP SUPER CACHE 0.8.9.1
require_once( dirname(__FILE__).'/plugins/wp-super-cache/wp-cache-phase1.php' );
?&gt;</code></pre>
<p>Don&#8217;t ask me why the <code>dirname(__FILE__).'/plugins/wp-super-cache/</code> isn&#8217;t already in there by default instead of a random placeholder string that you have to fix yourself (or else the plugin dies). Hey, it&#8217;s more fun this way!</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2009/02/update-minify-wordpress-wp-super-cache/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Review/first impressions of Poker Copilot software for Mac OS X</title>
		<link>http://lyncd.com/2009/02/poker-copilot-review/</link>
		<comments>http://lyncd.com/2009/02/poker-copilot-review/#comments</comments>
		<pubDate>Mon, 16 Feb 2009 04:31:22 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[poker]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=81</guid>
		<description><![CDATA[I&#8217;m not an expert poker player, haven&#8217;t used a lot of other poker tracking software, and have only been using Poker Copilot for a week, so I&#8217;m not going to do an exhaustive review, just share some first thoughts. (If you are an expert, please chime in!) Poker Copilot is currently the only actively developed [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m not an expert poker player, haven&#8217;t used a lot of other poker tracking software, and have only been using <a href="http://pokercopilot.com/">Poker Copilot</a> for a week, so I&#8217;m not going to do an exhaustive review, just share some first thoughts. (If you are an expert, please chime in!)</p>
<p>Poker Copilot is currently the only actively developed poker software for Mac OS X folks like me, since <a href="http://www.openendsoftware.com/macpokerpro/">Mac Poker Pro</a> is apparent abandonware and <a href="http://www.pokertracker.com/products/PT3/faq.php#misc_mac">Poker Tracker&#8217;s Mac port</a> has been repeatedly postponed. Given that, I can say first of all, without hesitation, that Copilot is absolutely worth a look if you&#8217;re on a Mac and not using any analysis software at all (it&#8217;s a snap to download and install, and you can use it for 30 days without registering). It works with both <a href="http://www.pokerstars.com/?source=10144129">PokerStars</a> and <a href="http://www.fulltiltpoker.com/">Full Tilt Poker</a> (the only two online poker rooms with native Mac software).<span id="more-81"></span></p>
<p>Poker Copilot can be used on its own, purely as an analysis tool for your past games. It maintains a database of all the hands you&#8217;ve played and calculates a bunch of standard summary statistics (% flops seen, % aggression) that you can use to study your own play and your opponents&#8217;, and analyze using both sortable tables and pretty line graphs. But Copilot also offers a HUD (or heads-up display) that overlays your opponents&#8217; stats right on the poker table while you&#8217;re playing, which is the main reason I wanted it and the feature I use most. Here&#8217;s what the HUD looks like (click to enlarge):</p>
<p><a href="http://lyncd.com/files/2009/02/hudscreenshot.jpg"><img src="http://lyncd.com/files/2009/02/hudscreenshot-small.jpg" alt="Poker Copilot HUD screenshot" width="446" height="318" class="aligncenter size-full wp-image-83" /></a></p>
<p>There&#8217;s also a <a href="http://blog.pokercopilot.com/2009/01/poker-copilot-video-demo.html">short video of the HUD</a> on the <a href="http://blog.pokercopilot.com/">Poker Copilot blog</a>. One thing you&#8217;ll notice about my screenshot is that the hole cards of the upper-right player are obscured by the HUD, which I found to be super annoying because the hole cards only flash for a second or so. I was about to file a bug/feature report about it, but then I found that Steve&#8217;s already <a href="http://blog.pokercopilot.com/2009/02/simplify-repeat-new-poker-copilot.html">fixed it in version 1.62</a> &#8212; and now you can drag and drop the HUD boxes anywhere you want. Awesome!</p>
<p>The HUD works perfectly well for my needs. I&#8217;d love it if I could input custom functions for analysis (I&#8217;ll say more on this later), and I suppose it would be cool if it integrated note-taking and did some other things Poker Tracker does, although those aren&#8217;t a priority for me (I just make notes directly in PokerStars).</p>
<p>One drawback is that when you click on an opponent (either in the HUD or main program), you don&#8217;t get nearly the same depth of information you can about yourself, or that programs like Poker Tracker provide. For instance, I&#8217;d like to see an opponents&#8217; hand history along with things like position and hole cards, to try to figure out, say, how/why they&#8217;re varying their preflop raises. Ideally, from the HUD I&#8217;d be able to click an opponent and get a sortable hand-history window with columns like hole cards (if known), preflop action (raise/limp/call/RR/fold/raise+fold to RR etc.), total preflop bet, position, flop action and outcome (folded on turn, lost at showdown to QQ etc.). Minimally, it would be nice to just be able to use the main program&#8217;s Hands, Recent Hands and Position views for opponents as well as yourself.</p>
<p>As far as the main program goes, its summary statistics and line charts are pretty slick, as you can see <a href="http://pokercopilot.com/">from the video walkthrough on the Poker Copilot homepage</a>. Here&#8217;s where I have to be honest and say that I haven&#8217;t used the program enough to give a useful critique &#8212; part of that is the statistician in me, wary of drawing conclusions from too little data (~1000 hands) or of projecting my own biases or conclusions onto data that could be interpreted in many ways (see the voodoo science of &#8220;technical analysis&#8221; stock traders, for example). So, I&#8217;ll wait until I have something more substantive to offer before critiquing the main program in depth.</p>
<p>In general, though, I will say that I&#8217;m initially a bit underwhelmed by the relatively simple aggregate statistics that most poker software (this isn&#8217;t unique to Poker Copilot) reports. These stats (VPiP, agression etc.) are fine for making overall judgments about your game (too tight, playing too many hands from the SB, not continuation betting enough), judgments mostly relating to hand selection. But poker is about so much more than picking what hands to throw away &#8212; it&#8217;s about playing your opponents, not your cards &#8212; and often these kinds of aggregate stats can be very similar for both a winning and losing (say, somebody like me who holds on to his KK too long) player. For instance, cbetting to loose players is basically throwing money away (unless you get lucky and draw out), but it&#8217;s usually a winning strategy against tight players who see you betting with a K on the board and assume that, if you&#8217;re betting, you&#8217;ve got a hand with at least another K in it.</p>
<p>Software can&#8217;t play the game for you, but it can do a better job of highlighting the <em>most relevant</em> information for you in a given game situation than just aggregate stats, which also have room for improvement (for instance, a statistic to identify a player&#8217;s slowplay tendency).</p>
<p>I&#8217;m something of a stats nerd, so personally I&#8217;d love to be able to plug in my own custom functions (for both analysis in the main program and for use in the HUD). Of course this is probably not a common feature request (and as a programmer I know it&#8217;s a lot harder than saying &#8220;make it work like Excel&#8221; &#8230; I&#8217;d be fine just using Java but there&#8217;s the obvious security/stability issue with letting people execute arbitrary code, and the &#8220;right&#8221; way of adding a language parser is far from trivial), but I would really love it!</p>
<p>As a programmer, one of the things I really love about Poker Copilot is that it&#8217;s a one-man startup project (good on you Steve!). I mean, the author even wrote something about the Listener or Producer/Consumer design pattern on his blog (nerdgasm!). But as such, along with the benefit of very rapid development (new features and improvements all the time), you get drawbacks such as sparse documentation that&#8217;s little more than a command reference. Happily, Copilot is <a href="http://blog.pokercopilot.com/2009/02/technical-writer-sought.html">looking for a technical writer</a>, so hopefully the documentation will improve. Personally, I&#8217;d love to see more use cases and practical examples that explain how to use the stats to change your play and improve your game.</p>
<h4>Conclusion</h4>
<p>The underpinnings are all there in Poker Copilot for a very solid product, even if it doesn&#8217;t yet measure up to Poker Tracker 3&#8242;s feature set &#8212; if PT3 is Photoshop, then Copilot is iPhoto. It&#8217;s well-designed, very easy to install and get rolling with, and at least worth my $49. So, it&#8217;s already a viable niche product for us second-class Mac users. Only time will tell if it matures into a competitor to the serious pro software out there.</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2009/02/poker-copilot-review/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to losslessly concatenate / merge MP3 files</title>
		<link>http://lyncd.com/2009/02/how-to-merge-mp3-files/</link>
		<comments>http://lyncd.com/2009/02/how-to-merge-mp3-files/#comments</comments>
		<pubDate>Sat, 07 Feb 2009 04:22:09 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[mp3]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=92</guid>
		<description><![CDATA[You&#8217;d think it would be very easy to combine multiple MP3 files into one, while preserving all the ID3 tag metadata and without re-encoding the audio (which is lossy). Well, it actually isn&#8217;t that hard at all, but since Google couldn&#8217;t find the answer for me, I thought I&#8217;d write it up. I did this [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;d think it would be very easy to combine multiple MP3 files into one, while preserving all the ID3 tag metadata and without re-encoding the audio (which is lossy). Well, it actually <em>isn&#8217;t</em> that hard at all, but since Google couldn&#8217;t find the answer for me, I thought I&#8217;d write it up.<span id="more-92"></span></p>
<p>I did this on my Powerbook, so these directions should work fine on any Mac/Linux/BSD/Unix system.</p>
<p>There is a handy command-line utility for combining MP3 files, <a href="http://mp3wrap.sourceforge.net/">mp3wrap</a>. Unfortunately, it doesn&#8217;t correct the audio duration tags/headers (so iTunes/iPod will only see the first part of the file), and it clobbers your ID3 tags with its own (so that the file can later be unmerged with <a href="http://mp3splt.sourceforge.net/">mp3split</a> &#8212; this is a &#8220;feature&#8221;). There&#8217;s also the easy cat solution (<code>cat 1.mp3 2.mp3 > all.mp3</code>), but it doesn&#8217;t correct the duration, either. Maybe <em>you</em> don&#8217;t care about ID3 tags, and your playback software doesn&#8217;t care about a wrong duration header (some ignore it) &#8212; in that case, go away! But if you want to get your MP3 files right or you&#8217;re using something like iTunes, which does care, read on.</p>
<h4>Instructions</h4>
<p>Install <a href="http://mp3wrap.sourceforge.net/">mp3wrap</a>, <a href="http://ffmpeg.org/">ffmpeg</a> and <a href="http://id3lib.sourceforge.net/">id3lib</a> if you don&#8217;t have them already. On Linux, you&#8217;ll likely just use your distro&#8217;s package manager to do this in a few seconds. On my Mac, I just installed mp3wrap and id3lib from source (easy &#8220;./configure &#038;&#038; make &#038;&#038; make install&#8221;) and used the <a href="http://www.macosxhints.com/article.php?story=20061220082125312">ffmpeg binary from ffmpegX</a> (since Fink mangled dependencies).</p>
<p>Do this (combines 1.mp3, 2.mp3 and 3.mp3 into all.mp3, and copies ID3 tags from 1.mp3):</p>
<pre><code class="prettyprint lang-sh">mp3wrap tmp.mp3 1.mp3 2.mp3 3.mp3
ffmpeg -i tmp_MP3WRAP.mp3 -acodec copy all.mp3 &#038;&#038; rm tmp_MP3WRAP.mp3
id3cp 1.mp3 all.mp3
</code></pre>
<p>Here&#8217;s what&#8217;s happening:</p>
<ol>
<li>mp3wrap merges the files. Unfortunately, it also leaves wrong file duration headers and clobbers any original ID3 tags.</li>
<li>ffmpeg fixes the file duration. You could also use something else, like mplayer/mencoder (<code>-oac copy</code> option) here.</li>
<li>id3cp copies the ID3 tags from 1.mp3 to all.mp3</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2009/02/how-to-merge-mp3-files/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>How to transfer domains away from GoDaddy</title>
		<link>http://lyncd.com/2009/02/transfer-domains-godadd/</link>
		<comments>http://lyncd.com/2009/02/transfer-domains-godadd/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 01:57:08 +0000</pubDate>
		<dc:creator>sticks</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[domain names]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=65</guid>
		<description><![CDATA[It&#8217;s Super Bowl Sunday, a day I particularly enjoy transferring domain names out of GoDaddy, the registrar that once tempted me with low prices but now mostly just annoys me. Here&#8217;s how to move your domains to a new registrar quickly, easily and without fouling anything up (you don&#8217;t want your website to disappear!) in [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s Super Bowl Sunday, a day I particularly enjoy transferring domain names out of GoDaddy, the registrar that once tempted me with low prices but now mostly just annoys me. Here&#8217;s how to move your domains to a new registrar quickly, easily and without fouling anything up (you don&#8217;t want your website to disappear!) in the process.<span id="more-65"></span></p>
<p>Aside: I happen to be transferring domains to <a href="http://www.dreamhost.com/r.cgi?25735">Dreamhost</a>, a web hosting company I&#8217;ve been using for many years that offers great pro features at good value. If you&#8217;re looking to park a bazillion domains, that&#8217;s not what they&#8217;re really for, but for hosting small- to mid-traffic sites, I totally recommend them. One thing that&#8217;s nice is that they anonymize your domain record for free, so your name and address aren&#8217;t crawled by a million spiders (many registrars like the aforementioned GoDaddy charge extra for &#8220;privacy&#8221;). If you&#8217;re transferring to a new registrar that&#8217;s not Dreamhost, don&#8217;t worry, these are generic directions and all about how to transfer <em>away</em> from GoDaddy.</p>
<h4>1. Make sure your domain is at least 90 days old</h4>
<p>GoDaddy fabulously won&#8217;t let you transfer a domain name you just registered. (OK, there are some ICANN regulations at work, too.) Of course, if you&#8217;re about saving money, you&#8217;ll probably wait until your domain is close to expiring before you transfer it &#8212; you&#8217;ve already paid your year&#8217;s rent.</p>
<h4>2. Change your GoDaddy settings and get your auth code</h4>
<p>In the GoDaddy Domain Manager, find the domain you want to transfer and click it&#8217;s lock icon to unlock it (if it&#8217;s already unlocked, you can just click on the domain name to manage the domain). Here&#8217;s what I&#8217;m talking about (click the screenshot to see it full size):</p>
<p><a href="http://lyncd.com/files/2009/02/domaintrans1.png"><img class="aligncenter" src="http://lyncd.com/files/2009/02/domaintrans1-small.png" alt="GoDaddy manage domains screen" width="500" height="335" class="size-full wp-image-66" /></a></p>
<p>Now you should be in the domain&#8217;s detail screen:</p>
<p><a href="http://lyncd.com/files/2009/02/domaintrans2.png"><img class="aligncenter" src="http://lyncd.com/files/2009/02/domaintrans2-small.png" alt="GoDaddy domain detail screen" width="500" height="335" class="size-full wp-image-67" /></a></p>
<ol>
<li>Make sure that &#8220;Privacy&#8221; and &#8220;Domain Ownership Protection&#8221; are Off and that the domain is unlocked (if you just did this, it will still show up as &#8220;Locked&#8221; as in the screenshot, but don&#8217;t worry, if you just unlocked it, then it&#8217;s unlocked).</li>
<li>Make sure your email address is correct in the administrative contact, because GoDaddy will be emailing your transfer authorization code (Email!?!?! What is this, 1995? @%&#038;*$#@ GoDaddy!)</li>
<li>
DNS settings: Chances are, you&#8217;re using GoDaddy&#8217;s free DNS service, as shown in the screenshot (<code>ns23.domaincontrol.com</code> means GoDaddy). If you&#8217;re already using your own or some other 3rd party DNS servers, you don&#8217;t need to do anything and can skip to step 4.</p>
<p>The important thing to know here is that this setting is part of your domain record, and will transfer over to the new registrar (i.e, it <em>won&#8217;t</em> automagically switch to your new registrar&#8217;s DNS servers, because there&#8217;s nothing about being a domain host that says you also provide DNS), so if you are using GoDaddy&#8217;s servers you need to change these now, <strong>before you transfer the domain!</strong> If you&#8217;re using GoDaddy&#8217;s DNS and you transfer the domain with the record still pointing to <code>ns.domaincontrol.com</code>, then your site will go dark because <code>ns.domaincontrol.com</code> will start telling folks it&#8217;s never heard of your domain.</p>
<p>So, if you&#8217;re using GoDaddy&#8217;s free DNS service, here&#8217;s what you need to do:</p>
<ul>
<li>Easy: If you&#8217;ve just got a parked domain or you&#8217;re only using the domain name for a website &#8212; you only care about <code>example.com</code> and <code>www.example.com</code> (and you&#8217;re not using subdomains like <code>mail.example.com</code> for your email) &#8212; just change these to your new registrar or DNS host&#8217;s nameservers. For Dreamhost, these are <code>ns1.dreamhost.com</code> and <code>ns2.dreamhost.com</code>.</li>
<li>Hard: If you do have special DNS records (like <code>mail.example.com</code> or ones you&#8217;ve manually created), you need to load these into your new registrar/DNS host <strong>before</strong> you change the nameservers. Unfortunately, some big registrars like Network Solutions have crappy systems and won&#8217;t let you start setting DNS records on a domain until after you&#8217;ve transferred the domain &#8212; so if you&#8217;re in a situation like this you can either half-ass it and just live with a few hours of downtime while you scurry to reinput your DNS records, or you can use a &#8220;real&#8221; DNS host like UltraDNS or run your own DNS (which you could just do temporarily &#8212; just for a few days and then change nameservers to your new registrar&#8217;s free DNS once you&#8217;re registered with them). Anyway, once you&#8217;ve got your special DNS records set up with your new nameservers (or have decided to half-ass it), follow the directions above in &#8220;Easy&#8221; to update your domain record with the new nameservers.</li>
</ul>
</li>
<li>Click &#8220;Send by Email&#8221; and GoDaddy will email you the transfer authorization code you need to give to your new registrar</li>
</ol>
<h4>3. Transfer the name into your new registrar</h4>
<p>Your new domain name registrar&#8217;s website will walk you through this. You&#8217;ll need to give them the auth code that GoDaddy just sent you.</p>
<p>Once your new registrar has verified the auth code with GoDaddy, it may ask you to confirm the transfer. Dreamhost usually does the verification in a few seconds, then sends you an email with a link you have to click to confirm.</p>
<h4>4. Wait (Or, go back to GoDaddy Domain Manager and confirm)</h4>
<p>You&#8217;re done! After you complete the previous step, GoDaddy will send you an email written by someone barely proficient in English to say that the domain transfer is approved and the domain will automatically transfer over in 5 days.</p>
<p>So, you <em>really</em> don&#8217;t have to do anything more at this point, I promise. But if you&#8217;re totally OCD, you can go back to GoDaddy&#8217;s Domain Manager, select Pending Transfers, check the checkbox next to your name(s) and use the Accept/Decline button to Accept the transfer. Naturally, GoDaddy has intentionally worded this to confuse you, so on the confirmation screen I think you actually have to select &#8220;Cancel&#8221; as in &#8220;Cancel this domain from my GoDaddy account&#8221; to &#8220;Accept&#8221; the transfer. So, just don&#8217;t get caught by their trap and accidentally cancel the transfer, or you&#8217;ll really feel like an idiot.</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2009/02/transfer-domains-godadd/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Ornament Creme Eggs are here</title>
		<link>http://lyncd.com/2008/11/ornament-creme-eggs-are-here/</link>
		<comments>http://lyncd.com/2008/11/ornament-creme-eggs-are-here/#comments</comments>
		<pubDate>Thu, 20 Nov 2008 23:20:54 +0000</pubDate>
		<dc:creator>pica</dc:creator>
				<category><![CDATA[Food]]></category>
		<category><![CDATA[cadbury]]></category>
		<category><![CDATA[creme eggs]]></category>

		<guid isPermaLink="false">http://lyncd.com/?p=58</guid>
		<description><![CDATA[It&#8217;s true, the fabulous ornament creme egg of last year is back, and I just picked up a bundle of them for only 39 cents an egg at Walgreens (they were marked at 2/$1), so now my head is floating and my muscles are twitching from all the cremey goodness. If you only know about [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_59" class="wp-caption alignright" style="width: 330px"><a href="http://lyncd.com/files/2008/11/oeggs.jpg"><img class="size-full wp-image-59" title="Cadbury ornament creme eggs" src="http://lyncd.com/files/2008/11/oeggs.jpg" alt="Cadbury Ornament Creme Eggs on the shelf at Walgreens" width="330" height="208" /></a><p class="wp-caption-text">Cadbury Ornament Creme Eggs on the shelf at Walgreens</p></div>
<p>It&#8217;s true, the fabulous <a href="http://www.typetive.com/candyblog/item/cadbury_ornament_creme_egg/">ornament creme egg</a> of last year is back, and I just picked up a bundle of them for <strong>only 39 cents an egg</strong> at Walgreens (they were marked at 2/$1), so now my head is floating and my muscles are twitching from all the cremey goodness.</p>
<p>If you only know about the regular, easter-time <a href="http://www.cadbury.com/ourbrands/featurebrands/cadburycremeegg1/Pages/cadburycremeegg.aspx">Cadbury creme egg</a>, never fear, these are 100% the same as the easter eggs &#8212; still laid by a bunny in the 1.2-oz. size that Cadbury moved to a couple of years ago, only with a red wrapper instead of the regular one. They aren&#8217;t supposed to hang on your tree or any nonsense like that.<span id="more-58"></span></p>
<p>I do miss the old, slightly larger size, but you have to figure that the smaller ones are easier on that bunny. And there are plenty of places like <a href="http://www.powellssweetshoppe.com/">Powell&#8217;s</a> that import the original-size eggs from the UK and stock them year-round, a valuable service for aspiring diabetics like me, because no matter how many cases of eggs I have stashed in the freezer at easter, I will <em>nom</em> them all by summer.</p>
<p>You know it is only a matter of time before Santa realizes the jig is up, and his lousy presents have been bested by a superior product, the creme egg. He will hand over the sleigh&#8217;s reins to the Cadbury xmas bunny, and then Cadbury can turn its attention to taking over some other secondary holiday, like Halloween or Bastille Day.</p>
]]></content:encoded>
			<wfw:commentRss>http://lyncd.com/2008/11/ornament-creme-eggs-are-here/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
