<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title>Chris Adams' Weblog</title>
  <link href="http://improbable.org/chris/" />
  
  <updated>2009-10-16T23:06:52Z</updated>
  <author>
    <name>Chris Adams</name>
  </author>
  <id>urn:uuid:87118F23-FA47-47A2-AF0D-FAC8CBCDBF99</id>

		    <geo:lat>41.317197</geo:lat><geo:long>-72.927986</geo:long><link rel="self" href="http://feeds.feedburner.com/ChrisAdamsWeblog" type="application/atom+xml" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/ChrisAdamsWeblog" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsalloy.com/?rss=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.newsalloy.com/subrss3.gif">Subscribe with NewsAlloy</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.yourminis.com/subscribe.aspx?u=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.yourminis.com/images/addtoyourminisbadge.gif">Subscribe with Yourminis.com</feedburner:feedFlare><feedburner:feedFlare href="http://download.attensa.com/app/get_attensa.html?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.attensa.com/blogs/attensa/WindowsLiveWriter/BadgeredintoBadges_10C02/attensa_feed_button5.gif">Subscribe with Attensa for Outlook</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://hub.netomat.net/account/account.autoSubscribe.jspa?urls=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.netomat.net/blogger/images/icon_netomat_feedbutton.gif">Subscribe with netomat Hub</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.flurry.com/pushRssFeed.do?r=fb&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.flurry.com/images/flurry_rss_logo2.gif">Subscribe with Flurry</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2FChrisAdamsWeblog" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
  			<title type="text">Cross-Post experiment: Deploying Django Sites using RPM</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/ZMQcj7acMbQ/index.php" />
  			<id>http://improbable.org/chris/229</id>
  			<published>2009-10-16T23:06:52Z</published>
  			<updated>2009-10-16T23:06:52Z</updated>
  			<content type="html">&lt;p&gt;I'm experimenting with Tumblr and used it for my latest entry: &lt;a href="http://acdha.tumblr.com/post/214894889/deploying-django-sites-using-rpm"&gt;Deploying Django Sites using RPM&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=ZMQcj7acMbQ:_8E9V0-D6l8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=ZMQcj7acMbQ:_8E9V0-D6l8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=ZMQcj7acMbQ:_8E9V0-D6l8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=ZMQcj7acMbQ:_8E9V0-D6l8:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=ZMQcj7acMbQ:_8E9V0-D6l8:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/ZMQcj7acMbQ" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=229</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Site testing using RED Spider</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/THmDvAUZeDU/index.php" />
  			<id>http://improbable.org/chris/228</id>
  			<published>2009-07-25T15:20:45Z</published>
  			<updated>2009-07-25T15:22:08Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&lt;a href="http://mnot.net/"&gt;Mark Nottingham&lt;/a&gt; recently released &lt;a href="http://www.redbot.org/"&gt;redbot&lt;/a&gt;, a modern replacement for the classic &lt;a href="http://www.mnot.net/cacheability/"&gt;cacheability&lt;/a&gt; tester. I've been using it at work to audit website performance before releases since proper HTTP caching makes an enormous difference in perceived site performance.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
redbot is a focused tool and provides a great deal of detail about at most one page and, optionally, its resources. I wanted to expand the scope to testing an entire site and performing content validation and with a little work came up with &lt;a href="http://github.com/acdha/redbot/blob/master/src/red_spider.py"&gt;red_spider.py&lt;/a&gt;, which produces &lt;a href="http://acdha.github.com/redbot/red_spider_example.html "&gt;a consolidated report like this&lt;/a&gt;.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
I have a few ideas for the future, which should involve splitting the code into a separate project rather than a fork of &lt;a href="http://github.com/mnot/redbot"&gt;redbot&lt;/a&gt; as it acquires more validation capabilities such as borrowing from something like &lt;a href="http://pypi.python.org/pypi/collective.validator.css"&gt;collective.validator.css&lt;/a&gt; to validate CSS, RSS/Atom, etc., using PIL to verify that images don't have things like wasteful embedded thumbnails, and borrowing from my &lt;a href="http://gist.github.com/128284"&gt;wk-bench&lt;/a&gt; experiment to load pages using WebKit and report JavaScript errors.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=THmDvAUZeDU:upzSVXQgUL0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=THmDvAUZeDU:upzSVXQgUL0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=THmDvAUZeDU:upzSVXQgUL0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=THmDvAUZeDU:upzSVXQgUL0:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=THmDvAUZeDU:upzSVXQgUL0:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/THmDvAUZeDU" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=228</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Even friendlier shell prompts for version control</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/-aVWw1JSEm4/index.php" />
  			<id>http://improbable.org/chris/227</id>
  			<published>2009-04-03T22:51:26Z</published>
  			<updated>2009-04-03T22:51:26Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;I've extended the earlier &lt;a href="http://improbable.org/chris/index.php?ID=223"&gt;VCS-friendly shell prompt&lt;/a&gt; to add support for &lt;a href="http://www.selenic.com/mercurial/"&gt;Mercurial&lt;/a&gt; and you can now get &lt;a href="http://github.com/acdha/unix_tools/blob/master/etc/bash_profile"&gt;my current .bash_profile from GitHub&lt;/a&gt;:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_shell"&gt;&lt;span class="meta meta_function meta_function_shell"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_shell"&gt;__has_parent_dir&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_shell"&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_scope meta_scope_group meta_scope_group_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_shell"&gt;{&lt;/span&gt;&#xD;
    &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_shell"&gt;#&lt;/span&gt; Utility function so we can test for things like .git/.hg without firing&#xD;
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_shell"&gt;#&lt;/span&gt; up a separate process&#xD;
&lt;/span&gt;    test -d &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;&lt;span class="variable variable_other variable_other_positional variable_other_positional_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_shell"&gt;$&lt;/span&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;&amp;amp;&amp;amp;&lt;/span&gt; return 0&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;&#xD;
&#xD;
    current=&lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;.&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&#xD;
    &lt;span class="keyword keyword_control keyword_control_shell"&gt;while&lt;/span&gt; [ &lt;span class="keyword keyword_operator keyword_operator_pipe keyword_operator_pipe_shell"&gt;!&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;&lt;span class="variable variable_other variable_other_normal variable_other_normal_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_shell"&gt;$&lt;/span&gt;current&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt; -ef &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;&lt;span class="variable variable_other variable_other_normal variable_other_normal_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_shell"&gt;$&lt;/span&gt;current&lt;/span&gt;/..&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt; ]&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_shell"&gt;do&lt;/span&gt; &#xD;
        &lt;span class="keyword keyword_control keyword_control_shell"&gt;if&lt;/span&gt; [ -d &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;&lt;span class="variable variable_other variable_other_normal variable_other_normal_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_shell"&gt;$&lt;/span&gt;current&lt;/span&gt;/&lt;span class="variable variable_other variable_other_positional variable_other_positional_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_shell"&gt;$&lt;/span&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt; ]&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_shell"&gt;then&lt;/span&gt;&#xD;
            return 0&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;&#xD;
        &lt;span class="keyword keyword_control keyword_control_shell"&gt;fi&lt;/span&gt;&#xD;
        current=&lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;&lt;span class="variable variable_other variable_other_normal variable_other_normal_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_shell"&gt;$&lt;/span&gt;current&lt;/span&gt;/..&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;&#xD;
    &lt;span class="keyword keyword_control keyword_control_shell"&gt;done&lt;/span&gt;&#xD;
&#xD;
    return 1&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;&#xD;
&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_shell"&gt;}&lt;/span&gt;&lt;/span&gt;&#xD;
&#xD;
&lt;span class="meta meta_function meta_function_shell"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_shell"&gt;__vcs_name&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_shell"&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_scope meta_scope_group meta_scope_group_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_shell"&gt;{&lt;/span&gt;&#xD;
  &lt;span class="keyword keyword_control keyword_control_shell"&gt;if&lt;/span&gt; [ -d .svn ]&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_shell"&gt;then&lt;/span&gt; &#xD;
    echo &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt; [svn]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt; &#xD;
  &lt;span class="keyword keyword_control keyword_control_shell"&gt;elif&lt;/span&gt; [ -d RCS ]&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;  &lt;span class="keyword keyword_control keyword_control_shell"&gt;then&lt;/span&gt; &#xD;
    echo &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt; [RCS]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;  &#xD;
    &lt;span class="keyword keyword_control keyword_control_shell"&gt;elif&lt;/span&gt; __has_parent_dir &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;.git&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_shell"&gt;then&lt;/span&gt;&#xD;
        echo &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;&lt;span class="string string_interpolated string_interpolated_dollar string_interpolated_dollar_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;$(&lt;/span&gt;__git_ps1 &lt;span class="string string_quoted string_quoted_single string_quoted_single_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;'&lt;/span&gt; [git %s]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt;&#xD;
    &lt;span class="keyword keyword_control keyword_control_shell"&gt;elif&lt;/span&gt; __has_parent_dir &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt;.hg&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_list keyword_operator_list_shell"&gt;;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_shell"&gt;then&lt;/span&gt;&#xD;
        echo &lt;span class="string string_quoted string_quoted_double string_quoted_double_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;"&lt;/span&gt; [hg &lt;span class="string string_interpolated string_interpolated_dollar string_interpolated_dollar_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;$(&lt;/span&gt;hg branch&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;)&lt;/span&gt;&lt;/span&gt;]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;"&lt;/span&gt;&lt;/span&gt;&#xD;
  &lt;span class="keyword keyword_control keyword_control_shell"&gt;fi&lt;/span&gt;&#xD;
&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_shell"&gt;}&lt;/span&gt;&lt;/span&gt;&#xD;
&#xD;
PS1=&lt;span class="string string_quoted string_quoted_single string_quoted_single_shell"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_shell"&gt;'&lt;/span&gt;\[\033]0;\u@\h:\w\007\]\u@\h:\w$(__vcs_name) $ &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_shell"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=-aVWw1JSEm4:nW9cCbX_bOM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=-aVWw1JSEm4:nW9cCbX_bOM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=-aVWw1JSEm4:nW9cCbX_bOM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=-aVWw1JSEm4:nW9cCbX_bOM:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=-aVWw1JSEm4:nW9cCbX_bOM:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/-aVWw1JSEm4" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=227</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Cleaning up the web with jQuery and a little help from Google</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/TWRsjbkTWu8/index.php" />
  			<id>http://improbable.org/chris/216</id>
  			<published>2008-09-06T01:44:41Z</published>
  			<updated>2009-04-03T07:00:00Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Recently the topic of enhancing web pages came up at work. It's a lot easier than it used to be thanks to two trends: the rise of modern JavaScript libraries and public &lt;a href="http://en.wikipedia.org/wiki/Content_delivery_network"&gt;CDNs&lt;/a&gt; hosting those libraries. This makes a lot easier to enhance content which you can't easily alter (e.g. the forms used by various big companies with marginal web competency) or in situations where you're worried about compatibility with existing code (some squirrelly vertical apps in our case). &#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;b&gt;Updated 2009-04-03:&lt;/b&gt; Moved the template and example scripts to &lt;a href="http://gist.github.com/"&gt;Gist&lt;/a&gt; for ease of copying/maintenance: &#xD;
&#xD;
&lt;a href="http://gist.github.com/89968"&gt;bookmarklet-template.js&lt;/a&gt;, &#xD;
&lt;a href="http://gist.github.com/89969"&gt;enable-autocomplete.js&lt;/a&gt; and&#xD;
&lt;a href="http://gist.github.com/89970"&gt;resize-textareas.js&lt;/a&gt;&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;b&gt;Updated 2008-10-14:&lt;/b&gt; there's a very similar jQuery-lovefest on &lt;a href="http://intertwingly.net/blog/2008/10/12/jQuery-and-Closures"&gt;Sam Ruby's weblog&lt;/a&gt; with plenty of useful tips.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;To illustrate just how little code this can require, here's an example which uses &lt;a href="http://www.jquery.com"&gt;jQuery&lt;/a&gt; to install a function which sanitizes input (we have a legacy app chokes on smart-quotes and people paste text in from Word), copies the submit buttons from the bottom of the form to the top and adds a graphical datepicker for every date field on the page:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_js"&gt;jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;:text,textarea&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;bind&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;change&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;sanitizer&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;form&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;bind&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;submit&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;,&lt;/span&gt;&#xD;
    &lt;span class="storage storage_type storage_type_js"&gt;function&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
        jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;:text,textarea&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;each&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;sanitizer&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
    &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&#xD;
&lt;span class="storage storage_type storage_type_js"&gt;var&lt;/span&gt; submit_buttons &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;input[type="submit"]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
submit_buttons&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;parent&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;clone&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="constant constant_language constant_language_boolean constant_language_boolean_true constant_language_boolean_true_js"&gt;true&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;prependTo&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&#xD;
    submit_buttons&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;parents&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;filter&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;form&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&#xD;
jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;input[id*="DATE"]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;datepicker&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;That's the complete, ready-to-go, “even works with crotchety old Internet Explorer” guts of the code (the take-home lesson is that jQuery is awesome for busy developers). The downside is that this requires a little but of work: you need to have jQuery (and possibly dependencies like the UI plugin I used above) available and you need to jump through some hoops to load jQuery into an existing page efficiently and without conflicts. &lt;/p&gt;&#xD;
&#xD;
&lt;h2&gt;Didn't we used to pay for hosting?&lt;/h2&gt;&#xD;
&lt;p&gt;One drawback to all of this is that you need somewhere to host your external libraries since you can't fit the core jQuery into a URL, much less UI components or the less svelte libraries. This meant setting up a server, getting an SSL certificate if you need to work on HTTPS sites, etc. Not that much work but it's now a lot easier and quite noticeably faster because &lt;a href="http://code.google.com/apis/ajaxlibs/"&gt;Google makes it trivial to get the popular AJAX libraries from their CDN&lt;/a&gt;.&lt;/p&gt;&#xD;
&#xD;
&lt;h2&gt;Developing with Bookmarklets&lt;/h2&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
The deployment scenario for the major projects where I've used these techniques is a situation where you have some limited access to the page source: perhaps inserting a single &lt;code&gt;script&lt;/code&gt; tag into a template or using something like &lt;a href="http://monkeygrease.org/"&gt;MonkeyGrease&lt;/a&gt; or an &lt;a href="http://httpd.apache.org/docs/2.2/mod/mod_substitute.html"&gt;Apache proxy with mod_substitute&lt;/a&gt; to rewrite the generated HTML as it passes through. This is great for making minimal changes but a bit cumbersome to develop and test with, particularly if you need to work on a production site or your instructions begin something like “Go change your browser's proxy settings…”&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;If I was only working in Firefox I could use &lt;a href="http://www.greasespot.net/"&gt;GreaseMonkey&lt;/a&gt; but I need to test in Safari and Internet Explorer, too. The portable solution is a simple&#xD;
&lt;a href="http://en.wikipedia.org/wiki/Bookmarklet"&gt;bookmarklet&lt;/a&gt;. &#xD;
I use a simple template (&lt;a href="http://gist.github.com/89968"&gt;bookmarklet-template.js&lt;/a&gt;) which loads jQuery from the Google CDN and, after everything is ready to go, runs either a simple function or the external script of my choosing. This makes it easy to prepare an injector bookmarklet which can be used to pull my code into the current page, after which I can run and debug it using &lt;a href="http://getfirebug.com"&gt;Firebug&lt;/a&gt;.&lt;/p&gt;&#xD;
&#xD;
&lt;h2&gt;Useful Examples&lt;/h2&gt;&#xD;
&lt;p&gt;This is also a useful technique for fixing other people's pages. Here are two bookmarklets and the commented source for tools which I use often:&lt;/p&gt;&#xD;
&#xD;
&lt;ol&gt;&lt;li&gt;&#xD;
&lt;a href="javascript:(function(){(function(target,msg){var%20loader=function(){if(arguments.callee._executed)return;arguments.callee._executed=true;if(typeof%20target===%22function%22){target();}else{jQuery.getScript(target);}var%20el=document.createElement('div');el.style.position='absolute';el.style.height='30px';el.style.width='200px';el.style.margin='0%20auto%200%20auto';el.style.top='0';el.style.left='40%';el.style.padding='5px%2010px%205px%2010px';el.style.backgroundColor='#f99';el.innerHTML=msg;document.body.appendChild(el);window.setTimeout(function(){jQuery(el).fadeOut('slow',function(){jQuery(this).remove();});},2500);};if(typeof%20jQuery!=='undefined'){loader();}else{var%20s=document.createElement('script');s.type=%22text/javascript%22;s.setAttribute('src',document.location.protocol+'//ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js');if(s.addEventListener){s.addEventListener(%22load%22,loader,false);}else%20if(%22onreadystatechange%22%20in%20s){s.onreadystatechange=function(){if(this.readyState=='complete'||this.readyState=='loaded'){loader();}};}else{window.setTimeout(loader(),2500);}document.getElementsByTagName('head')[0].appendChild(s);}})(function(){jQuery('[autocomplete]').attr(%22autocomplete%22,%22on%22);},%22autocomplete%20enabled!%22);})();"&gt;Enable autocomplete&lt;/a&gt; - changes autocomplete="off" to on throughout the page (&lt;a href="http://gist.github.com/89969"&gt;Source: enable-autocomplete.js&lt;/a&gt;)&lt;/li&gt;&#xD;
&#xD;
&lt;li&gt;&lt;a href="javascript:(function(){(function(target,msg){var%20loader=function(){if(arguments.callee._executed)return;arguments.callee._executed=true;if(typeof%20target===%22function%22){target();}else{jQuery.getScript(target);}var%20el=document.createElement('div');el.style.position='absolute';el.style.height='30px';el.style.width='200px';el.style.margin='0%20auto%200%20auto';el.style.top='0';el.style.left='40%';el.style.padding='5px%2010px%205px%2010px';el.style.backgroundColor='#f99';el.innerHTML=msg;document.body.appendChild(el);window.setTimeout(function(){jQuery(el).fadeOut('slow',function(){jQuery(this).remove();});},2500);};if(typeof%20jQuery!=='undefined'){loader();}else{var%20s=document.createElement('script');s.type=%22text/javascript%22;s.setAttribute('src',document.location.protocol+'//ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js');if(s.addEventListener){s.addEventListener(%22load%22,loader,false);}else%20if(%22onreadystatechange%22%20in%20s){s.onreadystatechange=function(){if(this.readyState=='complete'||this.readyState=='loaded'){loader();}};}else{window.setTimeout(loader(),2500);}document.getElementsByTagName('head')[0].appendChild(s);}})(function(){jQuery.getScript(document.location.protocol+%22//ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.js%22,function(){jQuery(%22textarea%22).resizable();});},%22Textareas%20are%20now%20resizable%22);})();"&gt;Resizable Textareas&lt;/a&gt; - makes all textareas resizable (alá Safari 3) using &lt;a href="http://docs.jquery.com/UI/Resizables"&gt;jQuery UI Resizable (&lt;/a&gt;&lt;a href="http://gist.github.com/89970"&gt;Source: resize-textareas.js&lt;/a&gt;)&lt;/li&gt;&#xD;
&lt;/ol&gt;&lt;p&gt;I keep both of these in my Firefox &amp;amp; IE bookmark toolbar since they come in handy throughout the day and I've created more any time I find myself regularly needing to deal with a cranky legacy site. The process is simple: copy &lt;a href="http://gist.github.com/89968"&gt;bookmarklet-template.js&lt;/a&gt;, add the code which does whatever fixups the target page needs, run the entire thing through &lt;a href="http://jslint.com/"&gt;JSLint&lt;/a&gt; and, finally paste it into Ted Mielczarek's very handy &lt;a href="http://ted.mielczarek.org/code/mozilla/bookmarklet.html"&gt;Bookmarklet Crunchinator&lt;/a&gt;.&lt;/p&gt;&#xD;
&#xD;
&lt;h1&gt;Good Code Injection Practices&lt;/h1&gt;&#xD;
&#xD;
&lt;h2&gt;Use Anonymous functions&lt;/h2&gt;&#xD;
&#xD;
&lt;p&gt;What's the difference between this bit of code and the first example above?&lt;/p&gt;&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_js"&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_js"&gt;function&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
    jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;:text,textarea&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;bind&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;change&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;sanitizer&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
    jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;form&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;bind&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;submit&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;,&lt;/span&gt;&#xD;
        &lt;span class="storage storage_type storage_type_js"&gt;function&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
            jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;:text,textarea&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;each&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;sanitizer&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
        &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&#xD;
    &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&#xD;
    &lt;span class="storage storage_type storage_type_js"&gt;var&lt;/span&gt; submit_buttons &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;input[type="submit"]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
    submit_buttons&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;parent&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;clone&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="constant constant_language constant_language_boolean constant_language_boolean_true constant_language_boolean_true_js"&gt;true&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;prependTo&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&#xD;
        submit_buttons&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;parents&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;filter&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;form&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&#xD;
    &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&#xD;
    jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;input[id*="DATE"]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;datepicker&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)()&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;It looks almost identical but there's a key difference: this code is inside an anonymous function and that means that all of my variables are local to the function itself, which means that they won't be visible to other JavaScript on the page and I don't have to worry about conflicting variable or function names. Note that &lt;a href="http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/var"&gt;this is only true for variables declared using "var"&lt;/a&gt; - if you leave that out or do something like &lt;code&gt;window.foo&lt;/code&gt; you can still touch the rest of the page if you need to - for example, replacing the broken validation logic on Comcast's forms.&lt;/p&gt;&#xD;
&#xD;
&lt;h2&gt;Reliably detecting when external code has loaded&lt;/h2&gt;&#xD;
&#xD;
&lt;p&gt;When jQuery has loaded, it's easy to say "Load this .js file and run this function when it's ready" - here's how the text-area resizer works:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_js source_js_yui"&gt;jQuery&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;getScript&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_js"&gt;document&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;location&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;protocol&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;//ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.js&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;,&lt;/span&gt;&#xD;
    &lt;span class="storage storage_type storage_type_js"&gt;function&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
        jQuery&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;textarea&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;resizable&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
    &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt; &lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
	Loading jQuery itself requires you to do this the hard way: generate a script tag on the fly, insert it into the document and listen for the load events to tell when it's safe to run code which depends on the library you're loading. This is easy for Safari, Firefox, etc. which support the &lt;a href="http://developer.mozilla.org/En/DOM/Element.addEventListener"&gt;standard W3C DOM addEventListener&lt;/a&gt;: simply run your code after the script tag fires a "load" event. Unfortunately, it's not that simple for Internet Explorer: in theory &lt;code&gt;attachEvent("onload")&lt;/code&gt; would be equivalent but unfortunately load events are quite unreliable for script tags with IE and so we need to use an &lt;code&gt;onReadyStateChange&lt;/code&gt; handler as seen below and check for either of two events which may be fired:&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_js"&gt;&lt;span class="storage storage_type storage_type_js"&gt;var&lt;/span&gt; s &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_js"&gt;document&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_dom support_function_dom_js"&gt;createElement&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;script&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
s&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_dom support_constant_dom_js"&gt;type&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;text/javascript&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
s&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_dom support_function_dom_js"&gt;setAttribute&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;src&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;&lt;span class="support support_class support_class_js"&gt;document&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;location&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;protocol&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;//ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&#xD;
&lt;span class="keyword keyword_control keyword_control_js"&gt;if&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;s&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;addEventListener&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
    s&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;addEventListener&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;load&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;loader&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;&lt;span class="constant constant_language constant_language_boolean constant_language_boolean_false constant_language_boolean_false_js"&gt;false&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_js"&gt;else&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_js"&gt;if&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;"&lt;/span&gt;onreadystatechange&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;in&lt;/span&gt; s&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
    &lt;span class="meta meta_function meta_function_js"&gt;&lt;span class="support support_class support_class_js"&gt;s&lt;/span&gt;.&lt;span class="entity entity_name entity_name_function entity_name_function_js"&gt;onreadystatechange&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; &lt;span class="storage storage_type storage_type_function storage_type_function_js"&gt;function&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_begin punctuation_definition_parameters_begin_js"&gt;(&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_end punctuation_definition_parameters_end_js"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
        &lt;span class="keyword keyword_control keyword_control_js"&gt;if&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="variable variable_language variable_language_js"&gt;this&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;readyState&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;==&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;complete&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;||&lt;/span&gt; &lt;span class="variable variable_language variable_language_js"&gt;this&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;readyState&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;==&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;loaded&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
            loader&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
        &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&#xD;
    &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_js"&gt;else&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;{&lt;/span&gt;&#xD;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_js"&gt;//&lt;/span&gt; Chances are if your browser is this old jQuery won't even work but just in case:&#xD;
&lt;/span&gt;    &lt;span class="support support_class support_class_js"&gt;window&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_js"&gt;setTimeout&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;loader&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;()&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js"&gt;, &lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_js"&gt;2500&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&lt;span class="meta meta_brace meta_brace_curly meta_brace_curly_js"&gt;}&lt;/span&gt;&#xD;
&#xD;
&lt;span class="support support_class support_class_js"&gt;document&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_dom support_function_dom_js"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;head&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_square meta_brace_square_js"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_js"&gt;0&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_square meta_brace_square_js"&gt;]&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_dom support_function_dom_js"&gt;appendChild&lt;/span&gt;&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;s&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
It's conceivable that a buggy browser could fire the same event twice in an unusual scenario and if you have any sort of user-driven or timer-based code, you'll want to prevent your payload from being run multiple times using a guard like this which allows the function to check whether it has executed before without using the more common approach of relying on a global variable. Besides cleanliness, this also makes it easy if you might inject multiple things onto a page and don't want to have to rely only on a global variable naming convention to prevent chaos:&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="lazy textmate-source"&gt;&lt;span class="source source_js source_js_yui"&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_js"&gt;//&lt;/span&gt; Avoid executing this function twice:&#xD;
&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_js"&gt;if&lt;/span&gt; &lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;(&lt;/span&gt;arguments&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;callee&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;_executed&lt;span class="meta meta_brace meta_brace_round meta_brace_round_js"&gt;)&lt;/span&gt;  &lt;span class="keyword keyword_control keyword_control_js"&gt;return&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&#xD;
arguments&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;callee&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;_executed &lt;span class="keyword keyword_operator keyword_operator_js"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_boolean constant_language_boolean_true constant_language_boolean_true_js"&gt;true&lt;/span&gt;&lt;span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;h2&gt;Avoid HTTP/HTTPS conflicts&lt;/h2&gt;&#xD;
&#xD;
&lt;p&gt;If you're injecting code into pages which may or may not use SSL, you have a problem: if you hard-code a URL in your code and the protocol doesn't match you'll either incur the extra overhead of starting an SSL session (which isn't a major problem) by using &lt;code&gt;https&lt;/code&gt; even when you don't need to or encounter Internet Explorer's popular mixed-mode security warning. This is easy to avoid by using the current page's protocol for your scripts as long as you're using a server which can handle either protocol (Google's CDN does; Yahoo's does not):&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="lazy textmate-source"&gt;&lt;span class="source source_js source_js_yui"&gt;&lt;span class="support support_class support_class_js"&gt;document&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;location&lt;/span&gt;&lt;span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js"&gt;.&lt;/span&gt;&lt;span class="support support_constant support_constant_js"&gt;protocol&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_js"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_js"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js"&gt;'&lt;/span&gt;//path.to.example.com/something.js&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=TWRsjbkTWu8:aKJlEuQcG6E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=TWRsjbkTWu8:aKJlEuQcG6E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=TWRsjbkTWu8:aKJlEuQcG6E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=TWRsjbkTWu8:aKJlEuQcG6E:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=TWRsjbkTWu8:aKJlEuQcG6E:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/TWRsjbkTWu8" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=216</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Tracking down mod_auth_cas segfaults</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/0-gmmzYP2Pk/index.php" />
  			<id>http://improbable.org/chris/226</id>
  			<published>2009-03-27T22:47:04Z</published>
  			<updated>2009-03-27T22:47:04Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Just a quick note to boost Google rank: if you use &lt;a href="https://www.ja-sig.org/svn/cas-clients/mod_auth_cas/"&gt;the mod_auth_cas Apache module&lt;/a&gt; for &lt;a href="http://www.jasig.org/cas"&gt;CAS single-signon&lt;/a&gt; and have noticed sporadic Apache segfaults (typically a blank page which reloads correctly), &lt;a href="https://www.ja-sig.org/svn/cas-clients/mod_auth_cas/trunk/"&gt;mod_auth_cas 1.0.9&lt;/a&gt; includes my patch which traps crashes caused by corrupted XML ticket files. Please &lt;a href="mailto:chris@improbable.org"&gt;let me know&lt;/a&gt; if this fixes your problem as we're still trying to isolate the underlying failure.&#xD;
&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=0-gmmzYP2Pk:g80Y_6957-E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=0-gmmzYP2Pk:g80Y_6957-E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=0-gmmzYP2Pk:g80Y_6957-E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=0-gmmzYP2Pk:g80Y_6957-E:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=0-gmmzYP2Pk:g80Y_6957-E:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/0-gmmzYP2Pk" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=226</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Inching towards a Pythonic Keychain wrapper</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/u0AJdj7G-gE/index.php" />
  			<id>http://improbable.org/chris/225</id>
  			<published>2009-03-21T21:18:42Z</published>
  			<updated>2009-03-21T21:19:42Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;I've started adding some more advanced &lt;a href="http://docs.python.org/library/ctypes.html"&gt;ctypes&lt;/a&gt; wrappers for the OS X Keychain to &lt;a href="http://pymacadmin.googlecode.com/"&gt;PyMacAdmin&lt;/a&gt;. There's still a bunch of work to do but the upshot is that you can write code like this and expect it to work:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_python"&gt;&lt;span class="keyword keyword_control keyword_control_flow keyword_control_flow_python"&gt;try&lt;/span&gt;:&#xD;
    keychain &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_python"&gt;=&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_python"&gt;Keychain&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;options.keychain&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
    item &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_python"&gt;=&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_python"&gt;keychain.find_generic_password&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;&#xD;
        &lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_python"&gt;service_name&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_python"&gt;=&lt;/span&gt;options.service&lt;span class="punctuation punctuation_separator punctuation_separator_parameters punctuation_separator_parameters_python"&gt;,&lt;/span&gt;&#xD;
        &lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_python"&gt;account_name&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_python"&gt;=&lt;/span&gt;options.account&#xD;
    &lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
&#xD;
    &lt;span class="keyword keyword_other keyword_other_python"&gt;print&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_single-line string_quoted_double_single-line_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_python"&gt;"&lt;/span&gt;Removing &lt;span class="constant constant_other constant_other_placeholder constant_other_placeholder_python"&gt;%s&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_python"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_python"&gt;%&lt;/span&gt; item&#xD;
    &lt;span class="meta meta_function-call meta_function-call_python"&gt;keychain.remove&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;item&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
&lt;span class="keyword keyword_control keyword_control_flow keyword_control_flow_python"&gt;except&lt;/span&gt; &lt;span class="support support_type support_type_exception support_type_exception_python"&gt;KeyError&lt;/span&gt;, exc:&#xD;
    &lt;span class="keyword keyword_other keyword_other_python"&gt;print&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_python"&gt;&amp;gt;&amp;gt;&lt;/span&gt;sys.stderr, exc.message&#xD;
&lt;span class="keyword keyword_control keyword_control_flow keyword_control_flow_python"&gt;except&lt;/span&gt; &lt;span class="support support_type support_type_exception support_type_exception_python"&gt;RuntimeError&lt;/span&gt;, exc:&#xD;
    &lt;span class="keyword keyword_other keyword_other_python"&gt;print&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_python"&gt;&amp;gt;&amp;gt;&lt;/span&gt;sys.stderr, &lt;span class="string string_quoted string_quoted_double string_quoted_double_single-line string_quoted_double_single-line_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_python"&gt;"&lt;/span&gt;Unable to delete keychain item: &lt;span class="constant constant_other constant_other_placeholder constant_other_placeholder_python"&gt;%s&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_python"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_python"&gt;%&lt;/span&gt; exc&#xD;
&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt; and get output like this: &lt;/p&gt;&#xD;
&lt;pre&gt;chris@Enceladus:~/Development/pymacadmin [git master] $ ./bin/keychain-delete.py -a "acdha"&#xD;
Removing GenericPassword(service_name='', account_name='acdha', label='Audioscrobbler: acdha')&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&#xD;
There's a bunch of stuff going on behind the scenes now to make things easier than the sadly-unimproved state &lt;a href="http://www.wilshipley.com/blog/2006/10/pimp-my-code-part-12-frozen-in.html"&gt;discussed at length by Wil Shipley back in 2006&lt;/a&gt;:&#xD;
&lt;/p&gt;&#xD;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://github.com/acdha/pymacadmin/blob/649dae5c16e380d8ac36c8430e4dcca81ab57fe7/lib/PyMacAdmin/Security/__init__.py"&gt;PyMacAdmin.Security&lt;/a&gt; now defines many of the &lt;code&gt;kSec*&lt;/code&gt; defines from &lt;code&gt;SecKeychainItem.h&lt;/code&gt;, simplifying many calls which either required magic numbers or complicated &lt;a href="http://docs.python.org/library/struct.html#struct.unpack"&gt;&lt;code&gt;struct.unpack()&lt;/code&gt;&lt;/a&gt; calls.&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://github.com/acdha/pymacadmin/blob/649dae5c16e380d8ac36c8430e4dcca81ab57fe7/lib/PyMacAdmin/Security/Keychain.py"&gt;PyMacAdmin.Security.Keychain&lt;/a&gt;	now defines a few classes which represent some of the native typedefs: &lt;code&gt;SecKeychainAttribute&lt;/code&gt;, &lt;code&gt;SecKeychainAttributeList&lt;/code&gt; and &lt;code&gt;SecKeychainAttributeInfo&lt;/code&gt;.&#xD;
&lt;/li&gt;&#xD;
	&lt;li&gt;Core &lt;a href="http://github.com/acdha/pymacadmin/blob/649dae5c16e380d8ac36c8430e4dcca81ab57fe7/lib/PyMacAdmin/__init__.py"&gt;PyMacAdmin&lt;/a&gt; improvements to make it a little easier to work with Carbon-style APIs:&#xD;
		&lt;ul&gt;&lt;li&gt;&lt;code&gt;mac_strerror()&lt;/code&gt; provides a way to lookup the error message for Carbon&#xD;
return codes&lt;/li&gt;&#xD;
&lt;li&gt;&lt;code&gt;carbon_call()&lt;/code&gt; simplifies the process of calling a Carbon function by automatically checking its return code and throwing an exception any time the return code is negative.&lt;/li&gt;&#xD;
&lt;li&gt;&lt;code&gt;carbon_errcheck()&lt;/code&gt; can be used as a &lt;a href="http://docs.python.org/library/ctypes.html#ctypes._FuncPtr.errcheck"&gt;ctypes errcheck function&lt;/a&gt; using the same logic as &lt;code&gt;carbon_call()&lt;/code&gt;&lt;/li&gt;&#xD;
&lt;li&gt;&lt;code&gt;load_carbon_framework()&lt;/code&gt; wraps &lt;a href="http://docs.python.org/library/ctypes.html#ctypes.LibraryLoader.LoadLibrary"&gt;the ctypes LoadLibrary() method&lt;/a&gt; to automatically use &lt;code&gt;carbon_errcheck()&lt;/code&gt; for every function in the loaded library - this won't work for functions which use negative return codes for non-error results but the Carbon APIs are pretty consistent in that regard.&lt;/li&gt;&#xD;
&lt;/ul&gt;&lt;/li&gt;&#xD;
&lt;li&gt;All of the above combines to allow &lt;a href="http://github.com/acdha/pymacadmin/blob/649dae5c16e380d8ac36c8430e4dcca81ab57fe7/lib/PyMacAdmin/Security/Keychain.py"&gt;PyMacAdmin.Security.Keychain&lt;/a&gt;'s &lt;code&gt;find_generic_password()&lt;/code&gt; to call &lt;code&gt;SecKeychainItemCopyAttributesAndData&lt;/code&gt; behind the scenes to collect the item's label and will allow arbitrary other attributes in the future.&lt;/li&gt;&#xD;
&lt;/ul&gt;&lt;p&gt;If you have any interest in wrapping native Mac APIs with Python please join the discussion over on the &lt;a href="http://groups.google.com/group/pymacadmin"&gt;PyMacAdmin group&lt;/a&gt; - any sort of Python-OS X integration discussion is welcome.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=u0AJdj7G-gE:wxmTM6xgEFQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=u0AJdj7G-gE:wxmTM6xgEFQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=u0AJdj7G-gE:wxmTM6xgEFQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=u0AJdj7G-gE:wxmTM6xgEFQ:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=u0AJdj7G-gE:wxmTM6xgEFQ:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/u0AJdj7G-gE" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=225</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Using SystemConfiguration events within Python</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/PSByFEgbRCs/index.php" />
  			<id>http://improbable.org/chris/200</id>
  			<published>2008-02-28T17:45:24Z</published>
  			<updated>2009-03-13T22:08:17Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p class="note"&gt;&#xD;
	Since this post was originally written, I've been working on the &lt;a href="http://pymacadmin.googlecode.com/"&gt;PyMacAdmin&lt;/a&gt; project with &lt;a href="http://explanatorygap.net/"&gt;Nigel Kersten&lt;/a&gt;. The information below is still correct but the kicker-replacement script has gained the ability to handle filesystem events and workspace notifications and been renamed to &lt;a href="http://code.google.com/p/pymacadmin/source/browse/trunk/bin/crankd.py"&gt;crankd&lt;/a&gt;.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;In a perfect world software would gracefully network transitions. Unfortunately my users have encountered a fair number of things which don't always handle things like a laptop moving from ethernet to WiFi, a DHCP server taking awhile to respond, etc. While many programs have at least reached the point of eventually timing out and retrying it would be nice to automatically restart something as soon as the system network configuration changes. This is unfortunately system-specific and frequently required some hackish approach involving &lt;code&gt;tail -f&lt;/code&gt; or equivalent to watch a log file, which is slow and tends to break on upgrades.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;OS X has a nice way to query the current system configuration and receive event notifications when things change: the &lt;a href="http://developer.apple.com/documentation/Networking/Reference/SysConfig/index.html#//apple_ref/doc/framework/sysconfig_fw"&gt;SystemConfiguration Framework&lt;/a&gt; (&lt;a href="http://developer.apple.com/technotes/tn/tn1145.html"&gt;Technical Note TN1145: Living in a Dynamic TCP/IP Environment&lt;/a&gt; is also of interest). You can explore this using the &lt;a&gt;scutil&lt;/a&gt; command-line tool - in the example below, I've looked at the list of available events and chosen to watch for power-state changes, receiving a notice when I unplugged the power cable from my laptop:&lt;/p&gt; &#xD;
&#xD;
&lt;pre&gt;&#xD;
chris@Enceladus:~ $ scutil&#xD;
&amp;gt; list&#xD;
  subKey [0] = Plugin:IPConfiguration&#xD;
  subKey [1] = Plugin:InterfaceNamer&#xD;
  subKey [2] = Setup:&#xD;
  subKey [3] = Setup:/&#xD;
  subKey [4] = Setup:/Network/Global/IPv4&#xD;
  subKey [5] = Setup:/Network/HostNames&#xD;
…&#xD;
  subKey [21] = State:/IOKit/PowerManagement/CurrentSettings&#xD;
  subKey [22] = State:/IOKit/PowerSources/InternalBattery-0&#xD;
…&#xD;
&amp;gt; n.add State:/IOKit/PowerSources/InternalBattery-0&#xD;
&amp;gt; n.watch&#xD;
&amp;gt; notification callback (store address = 0x1036c0).&#xD;
  changed key [0] = State:/IOKit/PowerSources/InternalBattery-0&#xD;
notification callback (store address = 0x1036c0).&#xD;
  changed key [0] = State:/IOKit/PowerSources/InternalBattery-0&#xD;
&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;This is pretty cool stuff but I'd like to do something smarter than scripting a copy of scutil. I could write an Objective-C application but OS X 10.5 included the very handy &lt;a href="http://pyobjc.sourceforge.net/"&gt;PyObjC 2.0&lt;/a&gt; which allows access to most of the native APIs directly from within Python. James Reynolds &lt;a href="http://lists.psu.edu/cgi-bin/wa?A2=ind0802&amp;amp;L=macenterprise&amp;amp;T=0&amp;amp;F=&amp;amp;S=&amp;amp;P=343876"&gt;posted a message to the MacEnterprise mailing list&lt;/a&gt; which prompted me to stop procrastinating and actually write some code. A little poking around later and I have a Python script which is ready for me to add whatever custom actions I want to take when the network state changes - the version below is abbreviated so you'll want to download the full &lt;a href="http://improbable.org/chris/Software/watch-network-config"&gt;watch-network-config.py&lt;/a&gt; for your own use:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_python"&gt;&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_from keyword_control_import_from_python"&gt;from&lt;/span&gt; Cocoa &lt;span class="keyword keyword_control keyword_control_import keyword_control_import_python"&gt;import&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_python"&gt;*&lt;/span&gt;&#xD;
&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_from keyword_control_import_from_python"&gt;from&lt;/span&gt; SystemConfiguration &lt;span class="keyword keyword_control keyword_control_import keyword_control_import_python"&gt;import&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_python"&gt;*&lt;/span&gt;&#xD;
&#xD;
&lt;span class="meta meta_function meta_function_python"&gt;&lt;span class="storage storage_type storage_type_function storage_type_function_python"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_python"&gt;handleNetworkConfigChange&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_begin punctuation_definition_parameters_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function meta_function_parameters meta_function_parameters_python"&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_python"&gt;store&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_parameters punctuation_separator_parameters_python"&gt;,&lt;/span&gt; &lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_python"&gt;changedKeys&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_parameters punctuation_separator_parameters_python"&gt;,&lt;/span&gt; &lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_python"&gt;info&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_end punctuation_definition_parameters_end_python"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_begin punctuation_section_function_begin_python"&gt;:&lt;/span&gt;&lt;/span&gt;&#xD;
	&lt;span class="keyword keyword_other keyword_other_python"&gt;print&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_single-line string_quoted_double_single-line_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_python"&gt;"&lt;/span&gt;Global network configuration changed: &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_python"&gt;"&lt;/span&gt;&lt;/span&gt;, changedKeys&#xD;
	&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_python"&gt;#&lt;/span&gt; Kick a change-intolerant service in the head here&#xD;
&lt;/span&gt;&#xD;
store &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_python"&gt;=&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_python"&gt;SCDynamicStoreCreate&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;&lt;span class="constant constant_language constant_language_python"&gt;None&lt;/span&gt;, &lt;span class="string string_quoted string_quoted_double string_quoted_double_single-line string_quoted_double_single-line_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_python"&gt;"&lt;/span&gt;global-network-watcher&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_python"&gt;"&lt;/span&gt;&lt;/span&gt;, handleNetworkConfigChange, &lt;span class="constant constant_language constant_language_python"&gt;None&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
&#xD;
&lt;span class="meta meta_function-call meta_function-call_python"&gt;SCDynamicStoreSetNotificationKeys&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;store, &lt;span class="constant constant_language constant_language_python"&gt;None&lt;/span&gt;, &lt;span class="meta meta_structure meta_structure_list meta_structure_list_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_list punctuation_definition_list_begin punctuation_definition_list_begin_python"&gt;[&lt;/span&gt; &lt;span class="meta meta_structure meta_structure_list meta_structure_list_item meta_structure_list_item_python"&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_single-line string_quoted_single_single-line_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_python"&gt;'&lt;/span&gt;State:/Network/Global/IPv4&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_python"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_list punctuation_separator_list_python"&gt;,&lt;/span&gt; &lt;span class="meta meta_structure meta_structure_list meta_structure_list_item meta_structure_list_item_python"&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_single-line string_quoted_single_single-line_python"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_python"&gt;'&lt;/span&gt;State:/Network/Global/IPv6&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_python"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_list punctuation_definition_list_end punctuation_definition_list_end_python"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
&#xD;
&lt;span class="meta meta_function-call meta_function-call_python"&gt;CFRunLoopAddSource&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;&lt;span class="meta meta_function-call meta_function-call_python"&gt;CFRunLoopGetCurrent&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;, &lt;span class="meta meta_function-call meta_function-call_python"&gt;SCDynamicStoreCreateRunLoopSource&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_arguments meta_function-call_arguments_python"&gt;&lt;span class="constant constant_language constant_language_python"&gt;None&lt;/span&gt;, store, &lt;span class="constant constant_numeric constant_numeric_integer constant_numeric_integer_decimal constant_numeric_integer_decimal_python"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;, kCFRunLoopCommonModes&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
&lt;span class="meta meta_function-call meta_function-call_python"&gt;CFRunLoopRun&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_begin punctuation_definition_arguments_begin_python"&gt;(&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_arguments punctuation_definition_arguments_end punctuation_definition_arguments_end_python"&gt;)&lt;/span&gt;&lt;/span&gt;&#xD;
&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;Geoff Franks took the time to have the event handler use a dictionary so you can listen for multiple events and run a specific command for each one; I added a little syslog support and am releasing this version as a replacement for the widely-used Kicker which was removed in 10.5: &lt;a href="http://improbable.org/chris/Software/kicker-replacement"&gt;Download kicker-replacement&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p class="aside"&gt;&#xD;
Fun lessons from the trenches: in versions of OS X prior to 10.5 there were several &lt;strong&gt;nasty&lt;/strong&gt; bugs due to lookupd and DirectoryService not having real timeouts: we have some rigs which use DHCP on our public network and static IPs on a private experiment network. When the system booted the private interface didn't need to wait for a DHCP lease and thus came up slightly faster than the public interface — this should have been harmless except that DirectoryService immediately attempted to connect to our LDAP server which isn't reachable on the private network and network timeout values aren't actually used in any version prior to 10.5, causing network accounts and NFS mounts to be unavailable until someone manually killed DirectoryService!&#xD;
&lt;/p&gt;&#xD;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=PSByFEgbRCs:cavRZsexwaE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=PSByFEgbRCs:cavRZsexwaE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=PSByFEgbRCs:cavRZsexwaE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=PSByFEgbRCs:cavRZsexwaE:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=PSByFEgbRCs:cavRZsexwaE:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/PSByFEgbRCs" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=200</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">LDAP progress</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/PxGevMB23-4/index.php" />
  			<id>http://improbable.org/chris/224</id>
  			<published>2009-03-10T12:54:01Z</published>
  			<updated>2009-03-10T12:54:01Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;One of the fixes for &lt;a href="http://improbable.org/chris/index.php?ID=201"&gt;the LDAP problems I wrote about last year&lt;/a&gt; was just&#xD;
&lt;a href="http://bugzilla.padl.com/show_bug.cgi?id=366"&gt;integrated into pam_ldap&lt;/a&gt;. This would have taken a very brief amount of time except that an updated patch vanished at some point between my mail server and  the upstream bugzilla — ah, software!&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=PxGevMB23-4:qsPQT9sHo0g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=PxGevMB23-4:qsPQT9sHo0g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=PxGevMB23-4:qsPQT9sHo0g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=PxGevMB23-4:qsPQT9sHo0g:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=PxGevMB23-4:qsPQT9sHo0g:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/PxGevMB23-4" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=224</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Friendlier shell prompts for version control systems</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/5qkphytDKno/index.php" />
  			<id>http://improbable.org/chris/223</id>
  			<published>2009-02-03T14:49:00Z</published>
  			<updated>2009-02-03T14:49:32Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&#xD;
Like many developers, I'm using multiple version control systems these days - lots of Subversion, increasingly git and even some old RCS we haven't migrated away from yet. Here's handy little shell addition which includes info in the prompt, &lt;a href="http://www.simplicidade.org/notes/archives/2008/02/git_bash_comple.html"&gt;combining this git-specific tip&lt;/a&gt; with my older checks:&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;pre&gt;&#xD;
__vcs_name() {&#xD;
  if [ -d .svn ]; then&#xD;
    echo " [svn]";&#xD;
  elif [ -d RCS ];  then&#xD;
    echo " [RCS]";&#xD;
  else&#xD;
    echo "$(__git_ps1 ' [git %s]')"&#xD;
  fi&#xD;
}&#xD;
&#xD;
PS1='\[\033]0;\u@\h:\w\007\]\u@\h:\w$(__vcs_name) $ '&#xD;
&#xD;
if [ -d ~/.bash_completion.d ]; then&#xD;
  for c in ~/.bash_completion.d/*; do&#xD;
    . "$c"&#xD;
  done&#xD;
fi&#xD;
&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;Note that the last bit is needed to make the git part work - depending on your bash distribution you may not need to have the for loop to process &lt;code&gt;~/.bash_completion.d&lt;/code&gt;. In my case, using the Mac git distribution I simply created that directory and added a symlink to &lt;code&gt;/usr/local/git/contrib/completion/git-completion.bash&lt;/code&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;The final result will look something like this:&lt;/p&gt;&#xD;
&lt;pre&gt;&#xD;
chris@Enceladus:~ $ cd Development/pymacadmin.googlecode/&#xD;
chris@Enceladus:~/Development/pymacadmin.googlecode [svn] $ cd ../pymacadmin&#xD;
chris@Enceladus:~/Development/pymacadmin [git master] $ &#xD;
&lt;/pre&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=5qkphytDKno:AaQHYSmv6H0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=5qkphytDKno:AaQHYSmv6H0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=5qkphytDKno:AaQHYSmv6H0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=5qkphytDKno:AaQHYSmv6H0:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=5qkphytDKno:AaQHYSmv6H0:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/5qkphytDKno" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=223</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">In which the GOP surrenders any pretense of economic expertise</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/uUSmA1F_2io/index.php" />
  			<id>http://improbable.org/chris/222</id>
  			<published>2009-02-02T23:32:30Z</published>
  			<updated>2009-02-03T01:10:29Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&#xD;
From the "We need a credible opposition party" file: Mitch McConnell wasn't laughed out of the GOP for claiming that the stimulus bill is flawed because &#xD;
&lt;a href="http://www.foxnews.com/politics/2009/02/02/republicans-stimulus-address-housing-crisis/"&gt;it needs  more cheap mortgages&lt;/a&gt;.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;blockquote cite="http://www.foxnews.com/politics/2009/02/02/republicans-stimulus-address-housing-crisis/"&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Senate Republican leader Mitch McConnell on Monday demanded an amendment to the mammoth economic stimulus package to give government-backed, low-interest loans to homeowners -- a revision that he says will both increase the demand for houses and boost the average household income.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;"We believe that a stimulus bill must fix the main problem first and that's housing," McConnell told reporters Monday in introducing a plan to offer fixed mortgages of 4 percent to "any credit-worthy borrower."&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
What is it about housing that causes this to be treated any more reasonably than, say, the idea that the US government should have offered cheap loans back in 2000 to protect the people who bought Pets.com at its peak? That's effectively the situation in many parts of the country and the housing market isn't going to settle on reasonable valuations any time soon if the federal government gets into the business of encouraging mortgages which no sane bank would otherwise offer. I can offer some recent experience: last week none of our local banks was anywhere near 4% even with excellent credit, a solid job, 50% down and a special employer-negotiated discount — and that's entirely what you would expect &lt;a href="http://www.phoenixrealestateguy.com/historical-mortgage-rate-trend-charts-updated-through-august-2008/1256"&gt;if you looked at the historical record&lt;/a&gt;.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;McConnell is shamelessly pandering to people who don't want to accept reality - and it seems increasingly unlikely that the remaining fiscal conservatives are going to be able to put adults in charge of GOP policy any time soon. It's also likely that &lt;a href="http://www.opensecrets.org/politicians/summary.php?cid=N00003389"&gt;the buckets of cash McConnell gets from real estate&lt;/a&gt; might have something to do with his zealous bubble-conservation efforts…&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=uUSmA1F_2io:ME65-mmSooA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=uUSmA1F_2io:ME65-mmSooA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=uUSmA1F_2io:ME65-mmSooA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=uUSmA1F_2io:ME65-mmSooA:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=uUSmA1F_2io:ME65-mmSooA:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/uUSmA1F_2io" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=222</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">PyMacAdmin update</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/iXhxH1wKQrI/index.php" />
  			<id>http://improbable.org/chris/221</id>
  			<published>2009-01-08T23:55:49Z</published>
  			<updated>2009-01-08T23:55:49Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&#xD;
	Macworld has inspired some &lt;a href="http://pymacadmin.googlecode.com/"&gt;PyMacAdmin&lt;/a&gt; activity lately:&#xD;
there's now a &lt;a href="http://code.google.com/p/pymacadmin/source/browse/trunk/lib/PyMacAdmin/Security/Keychain.py"&gt;Keychain wrapper&lt;/a&gt; and &lt;a href="http://code.google.com/p/pymacadmin/source/browse/trunk/bin/airport-update.py"&gt;a simple tool for updating Airport network passwords&lt;/a&gt;.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;If you're interested in managing your Macs using Python, check out &lt;a href="http://docs.google.com/Presentation?id=dg382zb7_24hmmztnf5"&gt;the presentation slides&lt;/a&gt; and join &lt;a href="http://groups.google.com/group/pymacadmin"&gt;our mailing list&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=iXhxH1wKQrI:JXww_bdjLdU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=iXhxH1wKQrI:JXww_bdjLdU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=iXhxH1wKQrI:JXww_bdjLdU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=iXhxH1wKQrI:JXww_bdjLdU:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=iXhxH1wKQrI:JXww_bdjLdU:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/iXhxH1wKQrI" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=221</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">No volatility in VW TDI mileage</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/ud3CLse1clk/index.php" />
  			<id>http://improbable.org/chris/220</id>
  			<published>2008-11-25T03:13:58Z</published>
  			<updated>2008-11-25T03:15:06Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;I found &lt;a href="http://www.nytimes.com/2008/11/23/automobiles/autoreviews/23-vw-jetta.html"&gt;this review of the latest VW Jetta TDI&lt;/a&gt; curious:&lt;/p&gt;&#xD;
&lt;blockquote cite="http://www.nytimes.com/2008/11/23/automobiles/autoreviews/23-vw-jetta.html"&gt;&lt;p&gt;&#xD;
But like many new clean diesels, which meet even California’s tough emissions rules, the Jetta scoffs at its sticker. Hoarding fuel like a mobile Scrooge, I averaged a remarkable 48 m.p.g. over more than 150 miles of freeway driving. That’s the best mileage of any American-market car I’ve tested — gas, diesel or hybrid. I never knew that driving a steady 60 m.p.h. could be so gratifying, and I vowed to try it more often.&#xD;
&lt;/p&gt;&lt;/blockquote&gt;&#xD;
&#xD;
&lt;p&gt;Back when I bought my TDI in 1999 48 MPG would have seemed like a bigger deal but it's actually lower than the 52 MPG I averaged on the ~270 mile round-trip from San Diego to Pasadena and back, with an average speed over 70MPH (other trips weren't as precisely measured . I'm curious whether this is simply due to the extra power or the tighter emissions standards - intriguingly, the 42 MPG average for mixed driving matches the more or less constant value I measured for the last couple of years of mixed highway / city commuting. I know Volkswagen tweaked things to favor power-hungry American drivers for years - I'm curious whether we'll see that switch back now that everyone has rediscovered budgeting.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=ud3CLse1clk:mUUv1vmEvEQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=ud3CLse1clk:mUUv1vmEvEQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=ud3CLse1clk:mUUv1vmEvEQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=ud3CLse1clk:mUUv1vmEvEQ:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=ud3CLse1clk:mUUv1vmEvEQ:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/ud3CLse1clk" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=220</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">The sky is falling … always</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/0ot5e37g6jU/index.php" />
  			<id>http://improbable.org/chris/218</id>
  			<published>2008-10-15T02:28:47Z</published>
  			<updated>2008-11-11T23:01:33Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;A great &lt;a href="http://erratasec.blogspot.com/2008/10/wpa-is-not-obsolete.html"&gt;take-down for the recent “Elcomsoft made WPA obsolete”&lt;/a&gt; freak–out by people who should know better, pointing out that adding a single character to the password will cancel out the attacker's new-found boost. The part which I find scary and my reason for blogging is the frequent recommendation that you use a VPN instead: this is Ronco Spray-On Security and it's downright hazardous because it puts the focus on the network rather than on the insecure systems and applications which have caused almost every security problems you've ever heard about.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;I first &lt;a href="http://improbable.org/chris/Presentations/RWNS/"&gt;talked about this back in 2003&lt;/a&gt; and it wasn't a new idea (or original to me) back then that trusting the network is a really bad idea. Unless used with more discipline than most places manage, a VPN simply enables people to continue ignoring their insecure applications. The underlying problem is that a VPN is convenient but very broad: your salespeople will start using one because you told them they couldn't access the fileserver otherwise — and pretty soon your internal network is getting scanned by the malware installed on their home PC and your network admin is getting DMCA notices because of their kids P2P habit. Worse yet, that one user with a habit of opening malware now has the ability of attacking everyone else in the organization over your mistakenly-trusted network.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
There's an easier way to configure your wireless network: treat it like the internet and provide protocol-level security for the resources your users need to access, enforced by firewall rules blocking insecure protocols. This enormously reduces the support cost of VPNs, avoids the significant performance and reliability hits and gets you out of the business of trusting the network at all — which is good, because that trust was almost certainly misplaced.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=0ot5e37g6jU:oLbiHmWQOBE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=0ot5e37g6jU:oLbiHmWQOBE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=0ot5e37g6jU:oLbiHmWQOBE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=0ot5e37g6jU:oLbiHmWQOBE:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=0ot5e37g6jU:oLbiHmWQOBE:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/0ot5e37g6jU" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=218</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Harness the power of your wingnut relatives</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/egywbGCzycM/index.php" />
  			<id>http://improbable.org/chris/219</id>
  			<published>2008-10-18T02:24:26Z</published>
  			<updated>2008-10-30T22:31:34Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;&#xD;
Like many people, I have a few relatives who have persistent honesty problems when it comes to politics. I'm not talking about things like disagreeing over the best way to deal with poverty or trade but people who consider things like “Liberals are driven by Satan and lie constantly” to constitute a  legitimate description of the opposition party. This election, I've been receiving these entirely in the form of multiply-forwarded smears directed at Hillary Clinton and now Barack Obama and it's been getting a bit repetitive listening to the same “Cryto-Muslim-terrorist-eats-babies-hates-America” tirade over and over again. Unfortunately, these are also the people who consider forwarding urban legends their best way to combat the dread menace facing our country and they tend not to listen to either fact-checking or requests not to forward unsourced rumours.&#xD;
&lt;/p&gt;&#xD;
&lt;p&gt;&#xD;
It turns out, however, that there's a way to both lower the volume of crap received and do some good: take a page from the people at Planned Parenthood who started the &lt;a href="http://freakonomics.blogs.nytimes.com/2005/09/17/planned-parenthood-gets-freaky/"&gt;Pledge-a-Picket&lt;/a&gt; program and set a bounty for vicious slander: I picked $50 donated to the target (Obama, the ACLU, etc.) — $500 later and my inbox has remained clear for the first time in recent memory.&#xD;
&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&#xD;
Update: the flood has gone down but not dried up. At the conservative inability to stick to facts and logic has raised ~$750 for something better…&#xD;
&lt;/p&gt;&#xD;
&#xD;
&#xD;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=egywbGCzycM:uFFv2lfvUNI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=egywbGCzycM:uFFv2lfvUNI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=egywbGCzycM:uFFv2lfvUNI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=egywbGCzycM:uFFv2lfvUNI:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=egywbGCzycM:uFFv2lfvUNI:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/egywbGCzycM" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=219</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Not that this is a huge surprise…</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/pQbf4wwkVE4/index.php" />
  			<id>http://improbable.org/chris/217</id>
  			<published>2008-09-13T13:19:15Z</published>
  			<updated>2008-09-13T13:50:57Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Let's be honest: I had already ruled out voting for McCain over his &lt;a href="http://q.queso.com/archives/002317"&gt;integrity deficit&lt;/a&gt; but I was amused by the rather in-character faces of the two major campaign websites this morning:&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://www.johnmccain.com/"&gt;&lt;img src="http://improbable.org/chris/photos/Ike-McCain.png" alt="John McCain's campaign homepage on Sept 13"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://www.barackobama.com/"&gt;&lt;img src="http://improbable.org/chris/photos/Ike-Obama.png" alt="Barack Obama's campaign homepage on Sept 13"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Unsurprisingly, both Obama and the Red Cross got my dollar, along with &lt;a href="http://www.aclu.org"&gt;the ACLU&lt;/a&gt; in honor of their new &lt;a href="http://aclu.org/constitutionvoter/"&gt;Constitution Voter&lt;/a&gt; campaign.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=pQbf4wwkVE4:nbWTI3bcqSA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=pQbf4wwkVE4:nbWTI3bcqSA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=pQbf4wwkVE4:nbWTI3bcqSA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=pQbf4wwkVE4:nbWTI3bcqSA:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=pQbf4wwkVE4:nbWTI3bcqSA:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/pQbf4wwkVE4" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=217</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">An Olympic protestor speaks out</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/o2vIZpWnf3o/index.php" />
  			<id>http://improbable.org/chris/215</id>
  			<published>2008-09-02T00:03:05Z</published>
  			<updated>2008-09-02T00:03:05Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Two &lt;a href="http://gothamist.com/2008/08/29/james_powderly.php"&gt;interesting&lt;/a&gt; &lt;a href="http://www.brooklynpaper.com/stories/31/34/31_34_bm_powderly.html"&gt;interviews&lt;/a&gt; with an American protester who was held for a week by the Chinese government's in case some Western reporters were feeling particularly motivated to do their job and detract from &lt;a href="http://www.timesonline.co.uk/tol/comment/columnists/martin_samuel/article4615162.ece"&gt;the Olympics' warm totalitarian glow&lt;/a&gt;:&lt;/p&gt;&#xD;
&#xD;
&lt;blockquote&gt;&lt;p&gt;Powderly said that prison guards believed — correctly — that he was the man who assembled the laser but not the protest’s organizer. They accused him of trying to “murder China,” he said.&#xD;
“We know that you didn’t murder China, but you made the knife and you’re going to take credit for it — unless you show us the hand,’ they said,” in an apparent bid to learn the leader’s identity, Powderly said.&#xD;
&#xD;
Safely back in his Grand Street apartment, Powderly told The Brooklyn Paper how he was deprived of sleep, water, food and medicine, cuffed into painful positions, and had $2,000 stolen from his bank account — “non-lethal methods of waging war on people” that he considers “just as insidious as waterboarding.”&#xD;
&#xD;
After hours without sleep and threats against their lives and the lives of their loved ones, Powderly and the other Americans began to crack.&#xD;
“That’s when I started to realize that I’m really good at being a douche-baggy art star, but I’m really bad at this secret agent business,” he said.&#xD;
&lt;/p&gt;&lt;/blockquote&gt;&#xD;
&#xD;
&lt;p&gt;A few years ago we'd have raised a huge fuss over stifling dissent, abuse of an American citizen (remember the Singapore caning?), etc. Now we're quiet, in no small part because the Chinese tactics described are less than those which our government considers standard operating procedure. This isn't to equate the two governments or deny that China has engaged in worse but … they also think they're protecting their country from outside threats. Once we've allowed torture and murder under that guise, who are we to say that their threats are less real than the &lt;a href="http://en.wikipedia.org/wiki/Maher_Arar"&gt;minimally supported “threats” our government has claimed were deadly serious&lt;/a&gt;  in the past?&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;I'm somewhat curious how many conservatives are conflicted between their desire to raise a fuss in service of the long-standing goal of promoting China as the new Evil Empire and the deep, abiding belief that liberal performance artists could do with a little waterboarding.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Of particular interest in this regard is McCain's latest reversal: now that he's secured the GOP nomination he's less enthusiastic about ordaining torture than he was earlier this year and, quite unusually for a key player, &lt;a href="http://voices.washingtonpost.com/the-talk/2008/08/mccain_suggests_bush_has_endor.html"&gt;he isn't lying or resorting to euphemism to describe what we've been doing&lt;/a&gt;:&lt;/p&gt;&#xD;
&#xD;
&lt;blockquote cite="http://voices.washingtonpost.com/the-talk/2008/08/mccain_suggests_bush_has_endor.html"&gt;&lt;p&gt;&#xD;
During an assessment of the Bush presidency on "Fox News Sunday," McCain discussed the administration's use over "waterboarding," a technique that has been used to interrogate terrorist detainees.&#xD;
&#xD;
"Waterboarding to me is torture, okay? And waterboarding was advocated by the administration, and according to a published report, was used," McCain said. "I obviously don't want to torture any prisoners."&#xD;
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=o2vIZpWnf3o:NzOXRqSXlsI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=o2vIZpWnf3o:NzOXRqSXlsI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=o2vIZpWnf3o:NzOXRqSXlsI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=o2vIZpWnf3o:NzOXRqSXlsI:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=o2vIZpWnf3o:NzOXRqSXlsI:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/o2vIZpWnf3o" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=215</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">So much for profiling</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/EUrbEUVga7I/index.php" />
  			<id>http://improbable.org/chris/214</id>
  			<published>2008-09-01T23:40:44Z</published>
  			<updated>2008-09-01T23:40:44Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Looks like &lt;a href="http://www.guardian.co.uk/uk/2008/aug/20/uksecurity.terrorism1"&gt;MI5 is reluctantly giving up on profiling&lt;/a&gt;:&lt;/p&gt;&#xD;
&lt;blockquote&gt;&lt;p&gt;MI5 has concluded that there is no easy way to identify those who become involved in terrorism in Britain, according to a classified internal research document on radicalisation seen by the Guardian.&#xD;
&#xD;
The sophisticated analysis, based on hundreds of case studies by the security service, says there is no single pathway to violent extremism.&#xD;
&#xD;
It concludes that it is not possible to draw up a typical profile of the "British terrorist" as most are "demographically unremarkable" and simply reflect the communities in which they live.&#xD;
&#xD;
The "restricted" MI5 report takes apart many of the common stereotypes about those involved in British terrorism.&#xD;
&#xD;
They are mostly British nationals, not illegal immigrants and, far from being Islamist fundamentalists, most are religious novices. Nor, the analysis says, are they "mad and bad".&#xD;
&#xD;
Those over 30 are just as likely to have a wife and children as to be loners with no ties, the research shows.&#xD;
&lt;/p&gt;&lt;/blockquote&gt;&#xD;
&#xD;
&lt;p&gt;One key point which doesn't get enough attention  is that why profiles don't work they also cause problems by making easier for people who don't fit the profile to avoid the attention of the police who are over-worked investigating profile victims&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=EUrbEUVga7I:Bnq8gE8xqlo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=EUrbEUVga7I:Bnq8gE8xqlo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=EUrbEUVga7I:Bnq8gE8xqlo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=EUrbEUVga7I:Bnq8gE8xqlo:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=EUrbEUVga7I:Bnq8gE8xqlo:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/EUrbEUVga7I" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=214</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Introducing crankd</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/W_juG9hS6Mk/index.php" />
  			<id>http://improbable.org/chris/213</id>
  			<published>2008-07-22T01:32:18Z</published>
  			<updated>2008-07-22T01:32:18Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Awhile back I &lt;a href="http://improbable.org/chris/index.php?ID=200"&gt;posted a kicker replacement&lt;/a&gt; which was also a &lt;a href="http://pyobjc.sf.net"&gt;PyObjC&lt;/a&gt; promo. Since then, kicker-replacement has advanced and gained the ability to handle &lt;a href="http://www.cocoadev.com/index.pl?FSEvents"&gt;filesystem events&lt;/a&gt; and &lt;a href="http://www.cocoadev.com/index.pl?NSWorkspace"&gt;workspace notifications&lt;/a&gt; and is now available on Google Code:&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://pymacadmin.googlecode.com"&gt;http://pymacadmin.googlecode.com&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://www.realityartisans.com/"&gt;Kok-Yong Tan&lt;/a&gt; was kind enough &lt;a href="http://www.afp548.com/comment.php?mode=view&amp;amp;cid=10010"&gt;to suggest a new name&lt;/a&gt;: crankd. I've updated the repository and even engaged in (gasp) random acts of documentation by adding a wiki page describing &lt;a href="http://code.google.com/p/pymacadmin/wiki/SOCKSProxyExample"&gt;how to use crankd for policy-based proxy settings&lt;/a&gt;, in this case by enabling an OpenSSH SOCKS proxy when on a remote network as demoed at WWDC.&lt;/p&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=W_juG9hS6Mk:CqaPiRMiFJ4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=W_juG9hS6Mk:CqaPiRMiFJ4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=W_juG9hS6Mk:CqaPiRMiFJ4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=W_juG9hS6Mk:CqaPiRMiFJ4:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=W_juG9hS6Mk:CqaPiRMiFJ4:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/W_juG9hS6Mk" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=213</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">iPhone OS 2.0: The Good, Bad and very Ugly</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/yityYHYXtPc/index.php" />
  			<id>http://improbable.org/chris/212</id>
  			<published>2008-07-12T00:05:54Z</published>
  			<updated>2008-07-12T00:05:54Z</updated>
  			<content type="html">&lt;p&gt;The iPhone's new Exchange support works really well: bidirectional pushes take only a second or two as promised, the contact app has seamless searching of our corporate directory and so on, exactly as demoed. Unfortunately, there's a major drawback: once you enable Exchange, the iPhone inexplicably &lt;em&gt;disables&lt;/em&gt; the local calendar and address book support. Initially I had assumed that this was an unfortunate compromise to get it out the door by July 11th, along with other notable omissions like tasks and attendee information but it's actually inexcusable: the mobile iCal &lt;strong&gt;has&lt;/strong&gt; full support for multiple calendars if you pay Apple $100/year for Mobile Me. ActiveSync isn't the only trick Apple learned from Microsoft…&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=yityYHYXtPc:S7TUW0uvvhg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=yityYHYXtPc:S7TUW0uvvhg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=yityYHYXtPc:S7TUW0uvvhg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=yityYHYXtPc:S7TUW0uvvhg:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=yityYHYXtPc:S7TUW0uvvhg:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/yityYHYXtPc" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=212</feedburner:origLink></entry>
    	    <entry>
  			<title type="text">Unix Quickie: redirecting to a pipe within a script</title>
  			<link href="http://feedproxy.google.com/~r/ChrisAdamsWeblog/~3/NYSLHzGmOlI/index.php" />
  			<id>http://improbable.org/chris/211</id>
  			<published>2008-07-01T13:23:29Z</published>
  			<updated>2008-07-01T13:23:29Z</updated>
  			<content type="html">&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;The &lt;a href="http://tldp.org/LDP/abs/html/x16659.html"&gt;bash exec function&lt;/a&gt; has an underutilized feature allowing you to redirect stdin or stderr for the entire script, avoiding the need to&#xD;
make sure that the user always runs &lt;code&gt;myscript.sh &amp;gt; output.log&lt;/code&gt;:&lt;/p&gt;&#xD;
&#xD;
&lt;code&gt;exec &amp;gt; example.`date +%Y-%m-%d`.log&lt;/code&gt;&#xD;
&#xD;
&lt;p&gt;Unfortunately, when the documentation says "If FILE is not specified,&#xD;
the redirections take effect in this shell" there's a key omission:&#xD;
you can't simply use a normal pipe to have your output go to mail,&#xD;
logger, etc. or in non-interactive environments like grid / batch&#xD;
schedulers which don't allow you to specify a pipe for job output.&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;Googling won't turn up much useful other than some hacks which&#xD;
redirect to a temporary file/pipe or re-exec the script and I wanted&#xD;
something cleaner. The solution is to use the &lt;a href="http://tldp.org/LDP/abs/html/process-sub.html"&gt;bash process substitution feature&lt;/a&gt;&#xD;
which allows you to create a file handle for a given command and use&#xD;
that where you might normally use a filename. This is normally demoed&#xD;
for &lt;a href="http://consttype.blogspot.com/2008/05/process-substitution-in-bash.html"&gt;cool input hacks such as diff-ing the output of two commands&lt;/a&gt; but it's also useful for our purposes:&lt;/p&gt;&#xD;
&#xD;
&lt;pre class="code bash"&gt;&#xD;
#!/bin/bash&#xD;
exec &amp;gt; &amp;gt;(mail -s "$0: normal job output" user@example.edu)&#xD;
exec 2&amp;gt; &amp;gt;(mail -s "$0: error job output" syadmin@example.edu)&#xD;
&#xD;
&lt;i&gt;... commands which will be executed normally ...&lt;/i&gt;&#xD;
&lt;/pre&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=NYSLHzGmOlI:FOLY2IK_sDo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=NYSLHzGmOlI:FOLY2IK_sDo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=NYSLHzGmOlI:FOLY2IK_sDo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?a=NYSLHzGmOlI:FOLY2IK_sDo:xV-nOlbwiiM"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ChrisAdamsWeblog?i=NYSLHzGmOlI:FOLY2IK_sDo:xV-nOlbwiiM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisAdamsWeblog/~4/NYSLHzGmOlI" height="1" width="1"/&gt;</content>
	    <feedburner:origLink>http://improbable.org/chris/index.php?ID=211</feedburner:origLink></entry>
    </feed>
