<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>The Bloggroll</title>
    <link>http://www.bloggroll.com/</link>
    <description>The webshite of Jonathan Groll</description>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Bloggroll" /><feedburner:info uri="bloggroll" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
      <title>Add subtitles to a DVD</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/lWnM4kf-Fq0/28</link>
      <description>&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/je_reve.png" class="l" alt="" /&gt;&lt;br /&gt;
Many people want to add subtitles to a &lt;span class="caps"&gt;DVD&lt;/span&gt; in their own language, and often &lt;span class="caps"&gt;DVD&lt;/span&gt; disks don&amp;#8217;t come with subtitles in a language you want. For instance, if you&amp;#8217;re staying in a foreign country and want English subtitles added to your rental movie. Or in my case, the library at the local Alliance Française has a lot of interesting movies completely in French, without English subtitles, and my french isn&amp;#8217;t yet good enough to fully understand everything that is being said.&lt;/p&gt;
&lt;p&gt;What is interesting is that there are sites on the internet that offer downloadable subtitle files for many movies. Simply type the name of your movie, plus the word &amp;#8220;subtitle&amp;#8221; into google and provided the movie is popular or well known enough you should be able to find a site offering the subtitle file for download. Mostly it seems that these subtitles were extracted from a &lt;span class="caps"&gt;DVD&lt;/span&gt; owned by someone else with the right languages. In other cases, it is purely fans of the movie who loved it so much and wanted to translate the words of the movie into a language that they know so that others can also enjoy the movie. I&amp;#8217;m not so sure about the legality of the subtitles obtained in the first case, but certainly an argument may be made that since you own or have legally rented a copy of the movie it does seem to fall within &amp;#8220;fair usage&amp;#8221; to watch this movie with subtitles in a language you require.&lt;/p&gt;
&lt;p&gt;So, you may be lucky. You may find the (fan-written) subtitle file that exactly matched your movie. By this I mean that the person who created your file had exactly the same version of the &lt;span class="caps"&gt;DVD&lt;/span&gt;, so that the lead in at the beginning of the movie is exactly the same length and in this case the subtitles remain perfectly in synch with the video.&lt;/p&gt;
&lt;p&gt;However, don&amp;#8217;t expect to watch the movie in your living room just yet. Most stand-alone &lt;span class="caps"&gt;DVD&lt;/span&gt; players that I&amp;#8217;ve used do not have a facility to specify an external subtitles file, but almost all of the software based players on your computer do have this facility. So provided you got lucky, and got the correct subtitles file that matched your &lt;span class="caps"&gt;DVD&lt;/span&gt;, and are also content to watch movies in front of your computer that will be sufficient and you don&amp;#8217;t need to read further.&lt;/p&gt;
&lt;p&gt;Mostly though, the subtitles file doesn&amp;#8217;t have the right timings for your &lt;span class="caps"&gt;DVD&lt;/span&gt;, or you might really really want to watch it on your TV in the lounge rather than with bowls of popcorn balanced on your lap in front of the computer. The guide that follows is for people who are running Linux, are comfortable with the command line, and who wish to hardcode &lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; subtitles into a &lt;span class="caps"&gt;XVID&lt;/span&gt; file for watching on a (living-room) player that can play &lt;span class="caps"&gt;DIVX&lt;/span&gt; movies. If this is not exactly what you want there still may be something for you in this blog post. I&amp;#8217;ll outline my six-step method:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Rip (extract) contents of the &lt;span class="caps"&gt;DVD&lt;/span&gt; disk.&lt;/li&gt;
	&lt;li&gt;Attempt to play &lt;span class="caps"&gt;DVD&lt;/span&gt; file with subtitle files on desktop.&lt;/li&gt;
	&lt;li&gt;Create a &lt;span class="caps"&gt;XVID&lt;/span&gt; file without subtitles.&lt;/li&gt;
	&lt;li&gt;Transform the subtitle file so that subtitles are synchronized with the video.&lt;/li&gt;
	&lt;li&gt;Create a &lt;span class="caps"&gt;XVID&lt;/span&gt; file with subtitles hardcoded in.&lt;/li&gt;
	&lt;li&gt;Break up this file into smaller segments for players that cannot handle large files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I myself don&amp;#8217;t follow the above recipe every time &amp;#8211; depending on the circumstances some of these steps may not be needed. And you may very well want a different outcome &amp;#8211; it may be enough for you just to align the subtitles with the video, or you may want more such as recreating a &lt;span class="caps"&gt;DVD&lt;/span&gt; with subtitles. You may even despise &lt;span class="caps"&gt;XVID&lt;/span&gt; files with harcoded subtitles in them!&lt;/p&gt;&lt;p&gt;If you are running Debian/Ubuntu you&amp;#8217;ll need a lot of packages to be installed &amp;#8211; at least: mplayer mencoder ogmtools libdvdcss dvdbackup gaupol ffmpeg gstreamer0.10-x plus dependancies and probably gnome-codec-install.&lt;/p&gt;
&lt;p&gt;The principal tools involved are the wonderful &lt;a href="http://www.mplayerhq.hu/"&gt;mplayer/mencoder command line tools&lt;/a&gt; :- they give fine control, are scriptable, and are compatible with each other in terms of command line flags.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;step 1&lt;/strong&gt;, extract the &lt;span class="caps"&gt;DVD&lt;/span&gt; to your hard disk:&lt;/p&gt;
&lt;pre&gt;
dvdbackup -i /dev/dvd -M -o name_of_movie
&lt;/pre&gt;
&lt;p&gt;This will create a folder called name_of_movie in the current directory. If your &lt;span class="caps"&gt;DVD&lt;/span&gt;-device is not /dev/dvd put the correct device name there.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;step 2&lt;/strong&gt;, you&amp;#8217;ll need to work out which of the titles on the &lt;span class="caps"&gt;DVD&lt;/span&gt; disk contains the movie, start by typing:&lt;/p&gt;
&lt;pre&gt;
mplayer -v -dvd-device name_of_movie/VIDEO_TS/ dvd://1
&lt;/pre&gt;
&lt;p&gt;Keep on increasing the number at the end &amp;#8211; from 1 to 2 to 3 etc until you find the actual movie and not just the adverts and bonus features. In the examples that follow I refer to title 1, you will need to replace that with your correct title number.&lt;/p&gt;
&lt;p&gt;The next thing to do is test the downloaded subtitle file:&lt;/p&gt;
&lt;pre&gt;
mplayer -v -dvd-device name_of_movie/VIDEO_TS/ dvd://1 -sub downloaded_sub.srt
&lt;/pre&gt;
&lt;p&gt;The subtitle file doesn&amp;#8217;t have to end in .srt &amp;#8211; mplayer supports multiple formats. Make a careful note if the subtitles are in synch, namely do the spoken words match the subtitles. Press the right arrow key on your keyboard to advance the video. Ensure that subtitles remain in synch until the end of the movie.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;step 3&lt;/strong&gt;, create an initial &lt;span class="caps"&gt;XVID&lt;/span&gt; file without subtitles. Yes, I know this can be lossy. And it really is not a required step if your subtitles are already in synch, if they are you can move straight on to step 5. However, if you do need to adjust the subtitle file to match the video, then in order to do so it may be necessary to work with the entire movie as a single file, instead of multiple individual &lt;span class="caps"&gt;VOB&lt;/span&gt; files.&lt;/p&gt;
&lt;p&gt;So, here is a simple two-pass recipe for encoding a movie to &lt;span class="caps"&gt;XVID&lt;/span&gt; without subtitles:&lt;/p&gt;
&lt;pre&gt;mencoder -idx -dvd-device name_of_movie/VIDEO_TS/ dvd://1 -ovc xvid -oac pcm -xvidencopts pass=1:bitrate=1200:aspect=16/9 -o /dev/null&lt;/pre&gt;
&lt;pre&gt;mencoder -idx -dvd-device name_of_movie/VIDEO_TS/ dvd://1 -ovc xvid -oac pcm -xvidencopts pass=2:bitrate=1200:aspect=16/9 -o movie.avi&lt;/pre&gt;
&lt;p&gt;Note the bitrate in the above call (1200) can be adjusted as required (higher numbers mean higher quality but also larger files). You will obviously need to make sure this call has the correct path for your VIDEO_TS folder, and also for the title track from the &lt;span class="caps"&gt;DVD&lt;/span&gt; (replace the dvd://1 with the appropriate title). Experienced mencoder users will possibly also want to add extra mencoder flags. Transcoding to &lt;span class="caps"&gt;XVID&lt;/span&gt; can take some time, depending on the speed of your computer.&lt;/p&gt;
&lt;p&gt;Next up is &lt;strong&gt;step 4&lt;/strong&gt; &amp;#8211; adjusting the subtitle file if that is needed. To do this, I prefer using the &lt;a href="http://home.gna.org/gaupol/"&gt;gaupol&lt;/a&gt; application under Linux. So, open gaupol and within gaupol select your subtitle file, and at the bottom of the gaupol screen select your .avi video file that you produced in the previous step. The trick to adjusting is to note exactly the time at which the first useful spoken words occur for which you have a matching subtitle, and the same for the last spoken words (unfortunately, knowing the last spoken words may spoil the end of the movie for you!). So, if you click the green play icon in gaupol it will play the video file with a clock at the top of the screen which you can use for noting when the spoken words occur. Based on the above, in an example I worked out that someone said subtitle #2 (you should be able to recognise the words based on context, even if you don&amp;#8217;t speak the language) at 00:02:54.000 and that the one of the last spoken texts occurred for subtitle #613 at 01:29:17.000. The important thing is to get the timing of the first subtitle as accurate as possible, for the last subtitle it doesn&amp;#8217;t matter if you&amp;#8217;re a second or two out. To do the actual synchronization choose the &amp;#8220;Transform Positions&amp;#8221; tool from the subtitle menu (see screenshot below), specify the times you observed and the positions of the other subtitles will be adjusted proportionally.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/gaupol_transform.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;To test the subtitle file is now correct, play the middle of the movie and see if the subtitles are fully in sync there as well. Repeat, if necessary with other time points, and if necessary adjusting only part of the file (&amp;#8220;Transform selected subtitles&amp;#8221;) rather than the entire file (&amp;#8220;Transform current project&amp;#8221;).&lt;/p&gt;
&lt;p&gt;Now, for &lt;strong&gt;step 5&lt;/strong&gt; we are going to hardcode the subtitles into a new &lt;span class="caps"&gt;XVID&lt;/span&gt; file which we produce. We can choose to either start with the source coming from the original &lt;span class="caps"&gt;DVD&lt;/span&gt;-rip folder produced by step one, or we can choose to work with the &lt;span class="caps"&gt;XVID&lt;/span&gt; file produced in step three as the source. Obviously, working with the &lt;span class="caps"&gt;XVID&lt;/span&gt; file will be lossy, as one can expect some picture degradation using the &lt;span class="caps"&gt;XVID&lt;/span&gt; file as a source file. However, if this file were to be used, you would know for sure that your subtitles will sync up with the file. Think back to the &lt;span class="caps"&gt;DVD&lt;/span&gt; extract step with dvdbackup &amp;#8211; did it report any errors at all during the extract from the &lt;span class="caps"&gt;DVD&lt;/span&gt;? For instance, if there was a scratch on the &lt;span class="caps"&gt;DVD&lt;/span&gt; disk dvdbackup would still be able to work around it by block filling in the file produced, but I have observed such a &amp;#8220;repaired error&amp;#8221;  might cause problems with the timing and sync of subtitles in the step to follow if the original &lt;span class="caps"&gt;DVD&lt;/span&gt; extract is used as the source. Generally, because of this I prefer to work with the &lt;span class="caps"&gt;XVID&lt;/span&gt; file as the source, even though it may be lossy.&lt;/p&gt;
&lt;p&gt;Before starting, remove any file in the current folder called &amp;#8220;divx2pass.log&amp;#8221;, this file will have been produced if you did a two-pass encoding as above and will interfere with the two-pass encode we are about to do.&lt;/p&gt;
&lt;p&gt;To hardcode in the subtitles, using the divx file produced in step three as the source, here are the commands that will perform the two-pass encode for you:&lt;/p&gt;
&lt;pre&gt;mencoder -idx movie.avi -ovc xvid -sub subtitles_adjusted.srt -subpos 96 -oac pcm -xvidencopts pass=1:bitrate=1200:aspect=16/9 -o /dev/null&lt;/pre&gt;
&lt;pre&gt;mencoder -idx movie.avi -ovc xvid -sub subtitles_adjusted.srt -subpos 96 -oac pcm -xvidencopts pass=2:bitrate=1200:aspect=16/9 -o hardcoded.avi
&lt;/pre&gt;
&lt;p&gt;Now, if you wanted to work with the original &lt;span class="caps"&gt;DVD&lt;/span&gt;-rip folder as the source, rather than perform the lossy re-encoding of the &lt;span class="caps"&gt;DIVX&lt;/span&gt; file, then replace &amp;#8220;movie.avi&amp;#8221; in the above with &amp;#8220;-dvd-device name_of_movie/VIDEO_TS/ dvd://1&amp;#8221; adjusted where appropriate.&lt;/p&gt;
&lt;p&gt;Also, note in the above that &amp;#8220;subtitles_adjusted.srt&amp;#8221; refers to your subtitle file that you produced with gaupol, and also note that I prefer specifying that my subtitles appear at position 96 (you can leave this out if it doesn&amp;#8217;t bother you).&lt;/p&gt;
&lt;p&gt;And also note that there is &lt;a href="http://wiki.showmedo.com/index.php/Video_editing_Ubuntu#Merge_video_with_subtitles"&gt;another way to hardcode in subtitles&lt;/a&gt; but this way can result in enormous files.&lt;/p&gt;
&lt;p&gt;Finally, in &lt;strong&gt;step 6&lt;/strong&gt; I break up the resultant &lt;span class="caps"&gt;DIVX&lt;/span&gt; file (which would be called &amp;#8220;harcoded.avi&amp;#8221; if you followed step 5 exactly). Why do I do this? For two possible reasons:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;If you are playing off a &lt;span class="caps"&gt;VFAT&lt;/span&gt; formatted memory stick files cannot be larger than 2GB in size.&lt;/li&gt;
	&lt;li&gt;My player can play &lt;span class="caps"&gt;DIVX&lt;/span&gt; files, but once the file exceeds 1GB in size the playback simply stops.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, there are two possible workarounds. You could have simply lowered the bitrate so that the final &lt;span class="caps"&gt;XVID&lt;/span&gt; file was less than 1GB in size. Or you could chop up a big file as I do below. Of course, if your player can play big &lt;span class="caps"&gt;DIVX&lt;/span&gt; files and you&amp;#8217;re not working with a &lt;span class="caps"&gt;VFAT&lt;/span&gt; memory stick then there is no need to perform this step.&lt;/p&gt;
&lt;p&gt;In this example I am working with a 3.1G file. Firstly, to determine how long the video is, I issue:&lt;/p&gt;
&lt;pre&gt;
ffmpeg -i hardcoded.avi
&lt;/pre&gt;
&lt;p&gt;In my case, it tells me that my video has&lt;/p&gt;
&lt;pre&gt;
Duration: 02:05:16.88.
&lt;/pre&gt;
&lt;p&gt;So, I&amp;#8217;d like to split that into four parts, so that each part will come to less than 1GB in size (roughly) &amp;#8211; so after some quick mental arithmetic I think I&amp;#8217;d like each piece to be 32 minutes long.&lt;/p&gt;
&lt;p&gt;Based on the above example, these are the four mencoder commands to splice the video into four 32 minute chunks (the last chunk will be less than 32 minutes):&lt;/p&gt;
&lt;pre&gt;
mencoder -ovc copy -oac copy -endpos 0:32:00 -o hardcoded1.avi hardcoded.avi
mencoder -ovc copy -oac copy -ss 0:32:00 -endpos 0:32:00 -o hardcoded2.avi hardcoded.avi
mencoder -ovc copy -oac copy -ss 1:04:00 -endpos 0:32:00 -o hardcoded3.avi hardcoded.avi
mencoder -ovc copy -oac copy -ss 1:36:00  -o hardcoded4.avi hardcoded.avi
&lt;/pre&gt;
&lt;p&gt;Granted, this is an extreme example (normally you don&amp;#8217;t let the &lt;span class="caps"&gt;XVID&lt;/span&gt; file get so big!) but it does show how to splice up a video using the -ss and -endpos flags. Unlike the transcoding to &lt;span class="caps"&gt;XVID&lt;/span&gt; steps, this step executes very quickly as all it does is copy the video and audio streams.&lt;/p&gt;
&lt;p&gt;And voilà, copy the split files to your memory stick, and take it to the lounge to enjoy with your popcorn, knowing that you&amp;#8217;ve managed to render a previously unwatchable video into something you&amp;#8217;ll enjoy, and somehow all this extra work makes the video more enjoyable too.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Hardcoding means the actual video file is altered so that the subtitle is in the video stream. It&amp;#8217;s a little nasty, and I agree softcoding (keeping the subtitles separate from the video stream) is better. The only problem is that my player refuses to accept files where the subtitles have been muxed in. If you&amp;#8217;re curious about softcoding, I can recommend &lt;a href="http://www.alexander-noe.com/video/amg/"&gt;&lt;span class="caps"&gt;AVI&lt;/span&gt;-Mux &lt;span class="caps"&gt;GUI&lt;/span&gt;&lt;/a&gt; which does run under wine.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/lWnM4kf-Fq0" height="1" width="1"/&gt;</description>
      <pubDate>Sun, 05 Dec 2010 17:29:46 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/28</guid>
      <dc:date>2010-12-05T17:29:46.0068+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/28</feedburner:origLink></item>
    <item>
      <title>Tunnel through ISA proxy</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/b4yKNyu6Qyk/27</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/tunnel.png" class="r" title="Image of tunnel attributed to Richard Freeman" alt="Image of tunnel attributed to Richard Freeman" /&gt; Geeks often need to access their *nix computers from work. Doesn&amp;#8217;t everyone want to do that? True geeks control their computers strictly using the command-line, of course, and the tool that is used to control a remote command-line session is &lt;a href="http://openssh.org/"&gt;ssh&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What one usually does is use a tool like &lt;a href="http://www.agroman.net/corkscrew/"&gt;corkscrew&lt;/a&gt; to send ssh traffic through an &lt;span class="caps"&gt;HTTP&lt;/span&gt; proxy.&lt;/p&gt;
&lt;p&gt;At one place of employment, a known trick of using corkscrew to tunnel out using the work proxy failed, with this message:&lt;/p&gt;
&lt;p&gt;Proxy Authentication Required ( The &lt;span class="caps"&gt;ISA&lt;/span&gt; Server requires authorization to fulfill the request. Access to the Web Proxy service is denied.  )&lt;/p&gt;
&lt;p&gt;I tried all combinations of &lt;i&gt;&lt;span class="caps"&gt;DOMAIN&lt;/span&gt;&lt;/i&gt;\&lt;i&gt;&lt;span class="caps"&gt;USERNAME&lt;/span&gt;&lt;/i&gt;:&lt;i&gt;&lt;span class="caps"&gt;PASSWORD&lt;/span&gt;&lt;/i&gt; in my corkscrew auth file but nothing worked.&lt;/p&gt;
&lt;p&gt;If you see this message have no fear! What you need is a utility that can negotiate &lt;a href="http://en.wikipedia.org/wiki/NTLM"&gt;&lt;span class="caps"&gt;NTLM&lt;/span&gt;&lt;/a&gt; authorization with the proxy.&lt;/p&gt;&lt;p&gt;There are several open source tools that can do &lt;span class="caps"&gt;NTLM&lt;/span&gt;, of these I chose &lt;a href="http://iitmlug.a.wiki-site.com/index.php/Cntlm"&gt;cntlm&lt;/a&gt;. Often &lt;a href="http://ntlmaps.sourceforge.net/"&gt;ntlmaps&lt;/a&gt; is recommended as a utility to negotiate the authorization. The cntlm man page indicates that cntlm is far more efficient than ntlmaps, both in terms of memory and &lt;span class="caps"&gt;CPU&lt;/span&gt; usage.&lt;/p&gt;
&lt;p&gt;One oddity about cntlm relative to other software that you may have worked with is that configuration is a two-step procedure: firstly you configure the software with a default config file, like the following (the settings that need to be configured for now in the first-step are in the first paragraph: username, domain, password, proxy, proxy-port):&lt;/p&gt;
&lt;pre&gt;
#
# Cntlm Authentication Proxy Configuration
#
# NOTE: all values are parsed literally, do NOT escape spaces,
# do not quote. Use 0600 perms if you use plaintext password.
#
&lt;br&gt;
Username	__username__
Domain		__domain__
Password	__password__		# Use hashes instead (-H)
#Workstation	netbios_hostname	# Should be auto-guessed
&lt;br&gt;
Proxy		__PROXY__:__PROXY_PORT__
&lt;br&gt;
#
# This is the port number where Cntlm will listen
#
Listen		3128
&lt;br&gt;
#
# If you wish to use the SOCKS5 proxy feature as well, uncomment
# the following option, SOCKS5. It can be used several times
# to have SOCKS5 on more than one port or on different network
# interfaces (specify explicit source address for that).
#
# WARNING: The service accepts all requests, unless you use
# SOCKS5User and make authentication mandatory. SOCKS5User
# can be used repeatedly for a whole bunch of individual accounts.
#
#SOCKS5Proxy	8010
#SOCKS5User	dave:password
&lt;br&gt;
#
# Use -M first to detect the best NTLM settings for your proxy.
# Default is to use the only secure hash, NTLMv2, but it is not
# as available as the older stuff.
#
# This example is the most universal setup known to man, but it
# uses the weakest hash ever. I won't have it's usage on my
# conscience. :) Really, try -M first.
#
#
&lt;br&gt;Auth		LM
#Flags		0x06820000
#
# Enable to allow access from other computers
#
#Gateway	yes
&lt;br&gt;
#
# Useful in Gateway mode to allow/restrict certain IPs
#
#Allow		127.0.0.1
#Deny		0/0
&lt;br&gt;
#
# GFI WebMonitor-handling plugin parameters, disabled by default
#
#ISAScannerSize	1024
#ISAScannerAgent	Wget/
#ISAScannerAgent	APT-HTTP/
#ISAScannerAgent	Yum/
&lt;br&gt;
#
# Headers which should be replaced if present in the request
#
#Header		User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)
&lt;br&gt;
#
# Tunnels mapping local port to a machine behind the proxy
# 
Tunnel		11443:__OUTSIDE_HOST.COM__:443
&lt;/pre&gt;&lt;p&gt;Then, run &lt;br /&gt;
&lt;code&gt;
cntlm -v -M http://google.com      (or any other external site)
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Cntlm will use this to assess the type of auth your proxy can handle. In my case I got back something like the following output:&lt;/p&gt;
&lt;pre&gt;
Config profile  1/11... OK (HTTP code: 301)
----------------------------[ Profile  0 ]------
Auth            NTLMv2
PassNTLMv2      AE1234567890123234567890123456C4
------------------------------------------------
&lt;/pre&gt;&lt;p&gt;For the second configuration step, these two lines need to be pasted back into your configuration file replacing the line that said &amp;#8220;Auth LM&amp;#8221; (and you must do this for your own situation, you can&amp;#8217;t reuse my lines).&lt;/p&gt;
&lt;p&gt;Then, startup the cntlm daemon:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
cntlm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#8217;s test if it works. Note that in the above config file I have a tunnel defined (the last line of the config file). Now, in order to ssh to port 443 of host __outside_host.com__ which is outside the proxy, one can do so using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
ssh -p 11443 localhost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above assumes that outside_host.com has an sshd listening on port 443.&lt;/p&gt;
&lt;p&gt;Cntlm also works fine under windows. If you don&amp;#8217;t have &amp;#8220;administrator&amp;#8221; authorisation under windows, you can still run the cntlm executable, but need to specify which cntlm.ini file to use, in other words, something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
cntlm.exe -c cntlm.ini
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course, if you&amp;#8217;re running on windows you won&amp;#8217;t have an ssh command line client, but putty can be used nicely for this purpose. Bear in mind that putty needs to be configured (for the default cntlm configuration above) to use an &lt;span class="caps"&gt;HTTP&lt;/span&gt; proxy on host &amp;#8220;localhost&amp;#8221; listening on port 3128.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/b4yKNyu6Qyk" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 03 Nov 2010 16:30:33 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/27</guid>
      <dc:date>2010-11-03T16:30:33.473359+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/27</feedburner:origLink></item>
    <item>
      <title>Split and encrypt files for google docs</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/ssmZyYmEz1s/26</link>
      <description>&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/meat_grinder2.jpg" class="l" title="Creative commons image of meat grinder from http://www.flickr.com/photos/amayu/3629064681/" alt="Creative commons image of meat grinder from http://www.flickr.com/photos/amayu/3629064681/" /&gt;Since January 2010, &lt;a href="http://googlecode.blogspot.com/2010/01/documents-list-api-upload-any-file-type.html"&gt;Google docs has allowed you to store any type of file&lt;/a&gt;, even arbitrary binary files. However, there are a couple of gotchas: one cannot upload files greater than 1GB in size, and you may want to encrypt your files so that not just anyone can read them (for instance server backup files).&lt;/p&gt;
&lt;p&gt;The two bash scripts below provide a solution for the above. I call them the &amp;#8216;mince&amp;#8217; scripts &amp;#8216;cos they slice and dice your files and hopefully you&amp;#8217;ll get hamburgers back at the end of the day. These scripts depend on you having a fairly new version of bash on your unix-like system, the &amp;#8216;split&amp;#8217; utility and gnupg (&lt;span class="caps"&gt;GPG&lt;/span&gt;) which is used for the encryption/decryption. If you&amp;#8217;re unsure of &lt;span class="caps"&gt;GPG&lt;/span&gt;, a good getting started guide can be found &lt;a href="http://www.madboa.com/geek/gpg-quickstart/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It must be said that google docs is (in my opinion) currently not the best way to store your files in the cloud. In fact, I wrote another blog post describing the  &amp;#8220;google storage&amp;#8221; options in &lt;a href="http://www.bloggroll.com/view/25"&gt;greater depth&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The encrypt&amp;amp;split script is mince.sh and it takes two parameters, the first one a directory or archive, the second the email address for an already imported public key:&lt;br /&gt;

&lt;pre&gt;&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;!/bin/&lt;/span&gt;&lt;span class="keyword-face-0002"&gt;bash&lt;/span&gt;&lt;span class="comment-face-0001"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter-face-0000"&gt;# &lt;/span&gt;&lt;span class="comment-face-0001"&gt;gpg encrypt archive and split into chunks
&lt;/span&gt;&lt;span class="comment-delimiter-face-0000"&gt;# &lt;/span&gt;&lt;span class="comment-face-0001"&gt;$1 specifies base directory or compressed archive to encrypt.
&lt;/span&gt;&lt;span class="comment-delimiter-face-0000"&gt;# &lt;/span&gt;&lt;span class="comment-face-0001"&gt;$2 is the recipients public key, eg. 'myfriend@his.isp.net'
&lt;/span&gt;&lt;span class="builtin-face-0003"&gt;set&lt;/span&gt; -e
&lt;br&gt;
&lt;span class="variable-name-face-0004"&gt;CHUNK_SIZE&lt;/span&gt;=1000000000 &lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;1000000000==1GB (not 1GiB!&lt;/span&gt;&lt;span class="comment-face-0001"&gt;)&lt;/span&gt;&lt;span class="comment-face-0001"&gt;
&lt;/span&gt;&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;=~/scratch_space
&lt;span class="variable-name-face-0004"&gt;TAR_REGEX&lt;/span&gt;=&lt;span class="string-face-0005"&gt;'\.tar'&lt;/span&gt;
&lt;br&gt;
usage() {
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;ERROR: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; $*&amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;USAGE: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; mince.sh [DIRECTORY|ARCHIVE] PUBLIC_KEY_NAME&amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;EXAMPLE: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; ./mince.sh directory myfriend@her.isp.net&amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;FURTHER COMMENTS: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; if an ARCHIVE is supplied instead of a directory, it must have a name like file.tar or file.tar.gz or file.tar.bz2 &amp;quot;&lt;/span&gt;
}
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;check parameters entered are valid
&lt;/span&gt;[ $# -ne 2 ] &amp;amp;&amp;amp; usage &lt;span class="string-face-0005"&gt;&amp;quot;Two parameters are required.&amp;quot;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="keyword-face-0002"&gt;exit&lt;/span&gt; 1
&lt;span class="keyword-face-0002"&gt;if&lt;/span&gt; [ ! -d &lt;span class="string-face-0005"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; ] &amp;amp;&amp;amp; [[ ! $&lt;span class="variable-name-face-0004"&gt;1&lt;/span&gt; =~ $&lt;span class="variable-name-face-0004"&gt;TAR_REGEX&lt;/span&gt; ]]; &lt;span class="keyword-face-0002"&gt;then&lt;/span&gt;
    usage &lt;span class="string-face-0005"&gt;&amp;quot;$1 is not a directory or tar/tar.gz/tar.bz2 archive.&amp;quot;&lt;/span&gt;
    &lt;span class="keyword-face-0002"&gt;exit&lt;/span&gt; 1
&lt;span class="keyword-face-0002"&gt;fi&lt;/span&gt;
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;if 1st parameter is a directory, then tar it up in the scratch space
&lt;/span&gt;&lt;span class="keyword-face-0002"&gt;if&lt;/span&gt; [ -d &lt;span class="string-face-0005"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; ]; &lt;span class="keyword-face-0002"&gt;then&lt;/span&gt;
    &lt;span class="variable-name-face-0004"&gt;absolute&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;`cd $1; pwd` &amp;quot;&lt;/span&gt;
    mkdir -p $&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;cd&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;
    &lt;span class="variable-name-face-0004"&gt;nameonly&lt;/span&gt;=${&lt;span class="variable-name-face-0004"&gt;absolute&lt;/span&gt;##*/}
    &lt;span class="variable-name-face-0004"&gt;nameonly&lt;/span&gt;=${&lt;span class="variable-name-face-0004"&gt;nameonly&lt;/span&gt;/ /} &lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;remove trailing spaces
&lt;/span&gt;    tar -cf $&lt;span class="variable-name-face-0004"&gt;nameonly&lt;/span&gt;.tar $&lt;span class="variable-name-face-0004"&gt;absolute&lt;/span&gt;
    &lt;span class="variable-name-face-0004"&gt;arch&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;${SCRATCH_DIR}/${nameonly}.tar&amp;quot;&lt;/span&gt;
    &lt;span class="variable-name-face-0004"&gt;created&lt;/span&gt;=true
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;Created temporary archive $arch&amp;quot;&lt;/span&gt;
&lt;span class="keyword-face-0002"&gt;else&lt;/span&gt;
    &lt;span class="variable-name-face-0004"&gt;arch&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;`&lt;/span&gt;&lt;span class="string-face-0005"&gt;readlink -f $1`&amp;quot;&lt;/span&gt;
    &lt;span class="variable-name-face-0004"&gt;created&lt;/span&gt;=false
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;Working with existing archive $arch&amp;quot;&lt;/span&gt;
&lt;span class="keyword-face-0002"&gt;fi&lt;/span&gt;
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;call for GPG encryption and compression of the archive
&lt;/span&gt;&lt;span class="variable-name-face-0004"&gt;target&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;${arch&lt;/span&gt;&lt;span class="string-face-0005"&gt;##&lt;/span&gt;&lt;span class="string-face-0005"&gt;*/}.gpg&amp;quot;&lt;/span&gt;
&lt;span class="variable-name-face-0004"&gt;name&lt;/span&gt;=${&lt;span class="variable-name-face-0004"&gt;target&lt;/span&gt;%&lt;span class="string-face-0005"&gt;\.&lt;/span&gt;gpg}
mkdir -p $&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;
&lt;span class="builtin-face-0003"&gt;cd&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;
&lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;Commencing GPG encryption, please be patient&amp;quot;&lt;/span&gt;
gpg --bzip2-compress-level 6 --compress-algo bzip2 --output $&lt;span class="variable-name-face-0004"&gt;target&lt;/span&gt; --encrypt --recipient $&lt;span class="variable-name-face-0004"&gt;2&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;arch&lt;/span&gt;
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;split .gpg file into chunks of size CHUNK_SIZE
&lt;/span&gt;&lt;span class="variable-name-face-0004"&gt;outdir&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;${SCRATCH_DIR}/output&amp;quot;&lt;/span&gt;
mkdir -p &lt;span class="string-face-0005"&gt;&amp;quot;$outdir&amp;quot;&lt;/span&gt;
mkdir -p &lt;span class="string-face-0005"&gt;&amp;quot;$outdir/$name&amp;quot;&lt;/span&gt;
&lt;span class="builtin-face-0003"&gt;cd&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;outdir&lt;/span&gt;/$&lt;span class="variable-name-face-0004"&gt;name&lt;/span&gt; &amp;amp;&amp;amp; rm -f $&lt;span class="variable-name-face-0004"&gt;name&lt;/span&gt;*
&lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;Splitting files&amp;quot;&lt;/span&gt;
split -b $&lt;span class="variable-name-face-0004"&gt;CHUNK_SIZE&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;${SCRATCH_DIR}/$target&amp;quot;&lt;/span&gt;
&lt;span class="keyword-face-0002"&gt;for&lt;/span&gt; x&lt;span class="keyword-face-0002"&gt; in&lt;/span&gt; *
&lt;span class="keyword-face-0002"&gt;do&lt;/span&gt;
  mv $&lt;span class="variable-name-face-0004"&gt;x&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;../${name}__$x&amp;quot;&lt;/span&gt;
&lt;span class="keyword-face-0002"&gt;done&lt;/span&gt;
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;clean up - remove .gpg and temporary archive and temporary directory
&lt;/span&gt;&lt;span class="builtin-face-0003"&gt;cd&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;
rmdir &lt;span class="string-face-0005"&gt;&amp;quot;$outdir/$name&amp;quot;&lt;/span&gt;
rm $&lt;span class="variable-name-face-0004"&gt;target&lt;/span&gt;
&lt;span class="keyword-face-0002"&gt;if&lt;/span&gt; [ $&lt;span class="variable-name-face-0004"&gt;created&lt;/span&gt; == true ]; &lt;span class="keyword-face-0002"&gt;then&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;Removing temporary archive $arch&amp;quot;&lt;/span&gt;
    rm $&lt;span class="variable-name-face-0004"&gt;arch&lt;/span&gt;
&lt;span class="keyword-face-0002"&gt;fi&lt;/span&gt;
&lt;br&gt;&lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;All file splits produced placed in $outdir&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Download link for &lt;a href="http://www.bloggroll.com/stat/mince.sh"&gt;mince.sh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The bash script to reconstitute the file is called unmince.sh and takes one parameter &amp;#8211; the name of the first file downloaded from google docs:&lt;br /&gt;
&lt;pre&gt;&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;!/bin/&lt;/span&gt;&lt;span class="keyword-face-0002"&gt;bash&lt;/span&gt;&lt;span class="comment-face-0001"&gt;
&lt;/span&gt;&lt;span class="comment-delimiter-face-0000"&gt;# &lt;/span&gt;&lt;span class="comment-face-0001"&gt;reassemble an archive from chunks of a file that have been gpg-encrypted
&lt;/span&gt;&lt;span class="comment-delimiter-face-0000"&gt;# &lt;/span&gt;&lt;span class="comment-face-0001"&gt;$1 specifies the first file produced from the mincing process, eg, file__xaa
&lt;/span&gt;&lt;span class="builtin-face-0003"&gt;set&lt;/span&gt; -e
&lt;br&gt;
&lt;span class="variable-name-face-0004"&gt;SCRATCH_DIR&lt;/span&gt;=~/scratch_space
&lt;span class="variable-name-face-0004"&gt;REGEX&lt;/span&gt;=&lt;span class="string-face-0005"&gt;'__xaa'&lt;/span&gt;
&lt;br&gt;
usage() {
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;ERROR: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; $*&amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;USAGE: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; unmince.sh file$REGEX&amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;WHERE: &amp;quot;&lt;/span&gt;
    &lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot; file$REGEX is the first file produced by the mince script&amp;quot;&lt;/span&gt;
}
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;check parameters
&lt;/span&gt;[ $# -ne 1 ] &amp;amp;&amp;amp; usage &lt;span class="string-face-0005"&gt;&amp;quot;Only one parameter is required&amp;quot;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="keyword-face-0002"&gt;exit&lt;/span&gt; 1
&lt;span class="keyword-face-0002"&gt;if&lt;/span&gt; [ -d &lt;span class="string-face-0005"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; ] || [[ ! $&lt;span class="variable-name-face-0004"&gt;1&lt;/span&gt; =~ &lt;span class="string-face-0005"&gt;'_xaa'&lt;/span&gt; ]]; &lt;span class="keyword-face-0002"&gt;then&lt;/span&gt;
    usage &lt;span class="string-face-0005"&gt;&amp;quot;$1 cannot be a directory and must end in _xaa.&amp;quot;&lt;/span&gt;
    &lt;span class="keyword-face-0002"&gt;exit&lt;/span&gt; 1
&lt;span class="keyword-face-0002"&gt;fi&lt;/span&gt;
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;combine all chunks of the file
&lt;/span&gt;&lt;span class="variable-name-face-0004"&gt;sourcepath&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;`readlink -f $1`&amp;quot;&lt;/span&gt;
&lt;span class="variable-name-face-0004"&gt;pathonly&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;`&lt;/span&gt;&lt;span class="string-face-0005"&gt;dirname $sourcepath`&amp;quot;&lt;/span&gt;
&lt;br&gt;
&lt;span class="variable-name-face-0004"&gt;just&lt;/span&gt;=${&lt;span class="variable-name-face-0004"&gt;sourcepath&lt;/span&gt;##*/}
&lt;span class="variable-name-face-0004"&gt;basenam&lt;/span&gt;=${&lt;span class="variable-name-face-0004"&gt;just&lt;/span&gt;%$&lt;span class="variable-name-face-0004"&gt;REGEX&lt;/span&gt;}
&lt;span class="variable-name-face-0004"&gt;indir&lt;/span&gt;=&lt;span class="string-face-0005"&gt;&amp;quot;${SCRATCH_DIR}/reconstituted&amp;quot;&lt;/span&gt;
mkdir -p $&lt;span class="variable-name-face-0004"&gt;indir&lt;/span&gt;
&lt;span class="builtin-face-0003"&gt;cd&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;indir&lt;/span&gt;
[ -e $&lt;span class="variable-name-face-0004"&gt;indir&lt;/span&gt;/combined.gpg ] &amp;amp;&amp;amp; rm $&lt;span class="variable-name-face-0004"&gt;indir&lt;/span&gt;/combined.gpg
&lt;span class="keyword-face-0002"&gt;for&lt;/span&gt; x&lt;span class="keyword-face-0002"&gt; in&lt;/span&gt; $&lt;span class="variable-name-face-0004"&gt;pathonly&lt;/span&gt;/$&lt;span class="variable-name-face-0004"&gt;basenam&lt;/span&gt;*
&lt;span class="keyword-face-0002"&gt;do&lt;/span&gt;
    cat $&lt;span class="variable-name-face-0004"&gt;x&lt;/span&gt; &amp;gt;&amp;gt; combined.gpg
&lt;span class="keyword-face-0002"&gt;done&lt;/span&gt;
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;decrypt the .gpg file
&lt;/span&gt;&lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;Commencing GPG decryption, please be patient&amp;quot;&lt;/span&gt;
gpg --output $&lt;span class="variable-name-face-0004"&gt;basenam&lt;/span&gt; --decrypt combined.gpg
&lt;br&gt;
&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;tidy up - remove the gpg file
&lt;/span&gt;rm combined.gpg
&lt;br&gt;
&lt;span class="builtin-face-0003"&gt;echo&lt;/span&gt; &lt;span class="string-face-0005"&gt;&amp;quot;The reconstituted archive $indir/$basenam was created&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Download link for &lt;a href="http://www.bloggroll.com/stat/unmince.sh"&gt;unmince.sh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since I might still tinker and improved these scripts, to get the newest version of these files take a look at my github repo at &lt;a href="http://github.com/eyesonly/kenwood"&gt;http://github.com/eyesonly/kenwood&lt;/a&gt; (Named after the Kenwood Chef, a famous mincer!)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/ssmZyYmEz1s" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 29 Oct 2010 15:25:12 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/26</guid>
      <dc:date>2010-10-29T15:25:12.203799+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/26</feedburner:origLink></item>
    <item>
      <title>"Google paid storage" and "google storage" are different things (for now)</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/qy3jOaAwXHM/25</link>
      <description>&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/google_storage_80.png" class="c" alt="" /&gt;&lt;br /&gt;
So, at a friend&amp;#8217;s prompting (and that it struck me as a bargain) I paid $20 over to &amp;#8220;Google paid storage&amp;#8221; to give me 80GB storage for one year. This may be cheaper than Amazon S3 storage where the cost calculation is more complicated (see below &lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;) and is significantly cheaper than &lt;a href="https://www.dropbox.com/pricing"&gt;dropbox&lt;/a&gt; which charges $9.99 per month for 50GB. However, if you read further you&amp;#8217;ll see that this price is too good to be true.&lt;/p&gt;
&lt;p&gt;What I paid for was essentially this, an extension of the normal storage space that Google provides for free for gmail, gdocs, picasa and so forth: &amp;#8220;Google offers a way to purchase more storage space when you run out of free storage space in Gmail, Google Docs, Picasa Web Albums, Blogger (for photos), and Google Buzz (for photos).&amp;#8221;&lt;/p&gt;
&lt;p&gt;So, in my google docs account I can now see that I&amp;#8217;ve got 80GB available, but interestingly, if I want to access real &amp;#8220;Google Storage&amp;#8221; (ie. using an Amazon-S3-like &lt;span class="caps"&gt;API&lt;/span&gt;) it is &lt;a href="http://code.google.com/apis/storage/"&gt;something else, called Google storage for developers&lt;/a&gt;. Unfortunately, Google have named their products in a way that has confused me and is possibly confusing for others with these similar names.&lt;/p&gt;&lt;p&gt;Sadly, &amp;#8220;Google Storage for Developers&amp;#8221;, hereafter called by me &amp;#8220;Real Google Storage&amp;#8221;, is also only currently available to a limited number of U.S. developers only.&lt;/p&gt;
&lt;p&gt;It kind of sucks that I can&amp;#8217;t (currently) assign some of my 80GB over to Real Google Storage, although I assume Google will make some sort of plan for this in future.&lt;/p&gt;
&lt;p&gt;In the mean time, I must make use of google docs, but it has some limitations. The way I see it, there are two big hurdles with google docs: firstly, the need to chunk files into 1GiB or less, and secondly for non-premier accounts (even if you paid for google storage) access is only through a web interface.&lt;/p&gt;
&lt;p&gt;With respect to the first problem, I&amp;#8217;ve written a script that encrypts/decrypts and then chunks files for storage in google docs, this is described in another blog post of mine &lt;a href="http://www.bloggroll.com/view/26"&gt;here&lt;/a&gt;. With these scripts one is able to securely store your own private files on google docs and not worry about others reading the contents; also files greater than the 1GiB limit are split into multiple parts.&lt;/p&gt;
&lt;p&gt;Secondly, with respect to access being through the web front-end, I investigated alternative ways of accessing my gdocs, for example as one would have to do from a server without a graphical web browser (for my primary use case I have a strictly command line only server overseas that I&amp;#8217;d like to back up to my google storage).&lt;/p&gt;
&lt;p&gt;There are two &lt;span class="caps"&gt;FUSE&lt;/span&gt; filesystem mounters for Linux (that I know of) which allow one to attach your google docs as a regular filesystem, there is a python one &amp;#8211; &lt;a href="http://code.google.com/p/google-docs-fs/"&gt;google-docs-fs&lt;/a&gt; and a java one &amp;#8211; &lt;a href="http://code.google.com/p/gdocsfs/"&gt;gdocsfs&lt;/a&gt;. They work as advertised, except both do not appear to have support for content of an arbitrary file type, as the google-docs_fs manual &lt;a href="http://code.google.com/p/google-docs-fs/wiki/OnlineManual"&gt;states:&lt;/a&gt; &amp;#8220;Google-docs-fs does not support the new feature of Google Docs which allows any file type to be stored. I am looking to add this in future releases.&amp;#8221; The ability to upload files of any type is one of my primary needs with online files storage, I&amp;#8217;d like to be able to store my server backups and files for my own personal transfer on google docs, and not just spreadsheet and document type files.&lt;/p&gt;
&lt;p&gt;Well, since I&amp;#8217;m a programmer I thought I&amp;#8217;d write a simple utility to upload arbitrary files, and I discovered &lt;a href="http://cookingandcoding.com/2010/04/28/gdocs4ruby-access-google-docs-api-with-ruby/"&gt;gdocs4ruby&lt;/a&gt;, but alas this seemed to only support an older version &lt;sup class="footnote"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; of the &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html"&gt;&lt;span class="caps"&gt;API&lt;/span&gt; that google provides for google docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Luckily, and unsurprisingly, python has official &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_python.html"&gt;support for the gdocs V3 &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;.  So, I quickly wrote a python script using the linked-to guide, and also quickly found out that I could not simply upload an arbitray file.&lt;/p&gt;
&lt;p&gt;I obviously didn&amp;#8217;t read version 3 of the google docs &lt;span class="caps"&gt;API&lt;/span&gt; closely enough as it quite clearly states that &lt;a href="http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html"&gt;upload of files with an arbitrary content-type is only for Google Apps Premier domains&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not the only one that has a problem with this: there is a forum thread &lt;a href="http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=2070"&gt;here&lt;/a&gt; with many other frustrated folk who have paid for google storage and would like to use an &lt;span class="caps"&gt;API&lt;/span&gt; call to upload files of arbitrary types. On the one hand, perhaps I shouldn&amp;#8217;t expect something for the price I paid, and I can understand the google do not want to turn google docs into another Rapidshare filled with copyrighted materials. On the other hand, Google&amp;#8217;s vagueness about what one is buying at the time of buying it without spelling out the limitations, and not providing a contactable link or address for obtaining a refund for what they&amp;#8217;ve sold you is also unfair.&lt;/p&gt;
&lt;p&gt;So, I probably won&amp;#8217;t end up using my google storage for much and can&amp;#8217;t really recommend it to others who want to use it for the same things that I do, rather look at Dropbox or even Ubuntu One. Being forced to upload files through a web browser that supports javascript means I probably won&amp;#8217;t be able to use it for uploading my server backup files to google docs as my overseas server is strictly command-line only. And uploading files from home using the web frontend for google docs is still painful and &lt;a href="http://docs.google.com/support/bin/answer.py?hl=en&amp;amp;answer=106734"&gt;flaky&lt;/a&gt; &amp;#8211; the web frontend consistently gives me &amp;#8220;server error&amp;#8221; messages when I attempt to upload my files just like &lt;a href="http://www.google.com/support/forum/p/Google%20Docs/thread?tid=3dfc97dd7bdd82d3&amp;amp;hl=en"&gt;others have experienced&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Regarding S3 pricing, it is composed of both an in/out traffic charge and a &lt;a href="http://aws.amazon.com/s3/faqs/#How_much_does_Amazon_S3_cost"&gt;storage charge&lt;/a&gt;; based on the examples given on the page, assume in a given year that I store 50GB in my account for the whole year, and that I transfer in 200GB and out 200GB during that year, then the charge for this will come to:&lt;br /&gt;
$0.150 per GB (US standard, not California)! * 50GB = $7.50 per month&lt;br /&gt;
16.667GB transfer-in per month * $0.10 per GB = $1.66 per month&lt;br /&gt;
16.667GB transfer-out per month * $0.15 per GB = $2.50 per month&lt;br /&gt;
So, approximately $11.66 per month which works out to be lot more than the $20 that google currently charge for so-called &amp;#8220;storage&amp;#8221; of 80GB for one year.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; I may be wrong about gdocs4ruby supporting only an older &lt;span class="caps"&gt;API&lt;/span&gt; for google docs as I didn&amp;#8217;t tarry too long in Rubyland once I saw that I could not upload files of arbitrary type.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/qy3jOaAwXHM" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 15 Oct 2010 15:29:11 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/25</guid>
      <dc:date>2010-10-15T15:29:11.150681+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/25</feedburner:origLink></item>
    <item>
      <title>Emacs-like keybindings for the new ABAP frontend editor</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/QaiyQlOfJKE/24</link>
      <description>&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/emacs_logo.png" class="l" alt="" /&gt;In the new &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;ABAP&lt;/span&gt; &lt;a href="https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/2142"&gt;editor&lt;/a&gt;, it&amp;#8217;s sort-of possible to remap the keybindings you use. If you&amp;#8217;re a regular &lt;a href="http://www.gnu.org/software/emacs/emacs.html"&gt;Emacs&lt;/a&gt; user, you often find yourself pressing the wrong key combination accidentally &amp;#8211; for instance C-a to go to the beginning of a line, only to find that the new &lt;span class="caps"&gt;ABAP&lt;/span&gt; editor by default respects the regular &lt;a href="http://en.wikipedia.org/wiki/Common_User_Access"&gt;windows &lt;span class="caps"&gt;CUA&lt;/span&gt;&lt;/a&gt; keybindings &amp;#8211; so C-a does a &amp;#8220;Select All&amp;#8221; as it does in many windows programs.&lt;/p&gt;&lt;p&gt;I&amp;#8217;ve redefined many of the new editor keybindings that I use to be more Emacs-like. If you&amp;#8217;re interested, &lt;a href="http://www.bloggroll.com/stat/abap_emacs.pdf"&gt;here is a &lt;span class="caps"&gt;PDF&lt;/span&gt; document&lt;/a&gt; listing all of my defined keybindings for the &amp;#8220;emacs&amp;#8221; schema. This is a stylesheet transformation of the file &amp;#8220;keymap.xml&amp;#8221; that is stored in your &lt;span class="caps"&gt;SAP&lt;/span&gt; work directory (so, in my case this is C:\Documents and Settings\Jonathan User\SapWorkDir\ab4_data\keymap.xml). &lt;a href="http://www.bloggroll.com/stat/keymap.xml"&gt;Here is my keymap.xml file&lt;/a&gt;, I would say simply replace your own keymap.xml file with mine &lt;strong&gt;&lt;span class="caps"&gt;BUT&lt;/span&gt;&lt;/strong&gt; I&amp;#8217;ve had sufficient grief doing it even when upgrading my &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;GUI&lt;/span&gt; from one release to another, so doubt this will work for you. If you do want to try that, please backup your entire SapWorkDir first (as a point of reference, I&amp;#8217;ve had this blog post in draft form since December 2008 due to not being sure how to share my keybindings with others).&lt;/p&gt;
&lt;p&gt;What is probably more sensible if you want to try a similar Emacs keybinding scheme is to take a look at the &lt;span class="caps"&gt;PDF&lt;/span&gt; containing my keybindings and to manually create your own Emacs keybinding scheme. To do so, start by clicking on the little yellow icon on the far right bottom of your editor screen (indicated by the arrow):&lt;br /&gt;
&lt;img src="http://www.bloggroll.com/stat/abap_emacs.png" class="c" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Why do I say that its only &amp;#8220;sort-of&amp;#8221; possible to remap the keybindings? Well, there are limitations : (1) Our nice custom keybindings can&amp;#8217;t be used when in display only mode, like when we&amp;#8217;re on a non-development system (2) We can&amp;#8217;t do complicated key sequences, eg. C-x C-w can&amp;#8217;t be bound to &amp;#8220;File.Saveas&amp;#8221;. (3) Meta key bindings are difficult as pressing the &lt;span class="caps"&gt;ALT&lt;/span&gt; key on its own makes the menu bar at the top of the screen active, so the &lt;span class="caps"&gt;ALT&lt;/span&gt; key must always be combined with other modifiers like control (4) The windows key cannot be bound. In fact, we seem to be stuck with Shift, Control and Alt as modifiers. (5) Some things like kill-line (C-k) have no equivalent command in the front-end editor. (5) Block mode in the two editors is different in concept.&lt;/p&gt;
&lt;p&gt;There are some windows &lt;span class="caps"&gt;CUA&lt;/span&gt; keybindings that you may be particularly fond of that get lost if you rebind them &amp;#8211; for instance C-v does a &amp;#8220;Clipboard Paste&amp;#8221;. I&amp;#8217;ve also bound that to C-y in the keybindings file above to be more like Emacs, but you may not like that, so I guess whatever keybindings you end up using will become a matter of personal taste, which is as for all things Emacs. Still, some sensible substitutions for cut-copy-paste are also defined by default in the new editor &amp;#8211; for instance Shift-Insert performs a paste as it does on many terminal emulators.&lt;/p&gt;
&lt;p&gt;By the way, as far as I know the new editor mode only is available for the windows &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;GUI&lt;/span&gt;. &lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; The option to select the new editor does not appear in all the versions of the Java &lt;span class="caps"&gt;GUI&lt;/span&gt; that I&amp;#8217;ve tried. It would be a shame if the new editor was never ported to the Java &lt;span class="caps"&gt;GUI&lt;/span&gt;, and my Linux street cred has suffered enormously as a consequence.&lt;/p&gt;
&lt;p&gt;I have considered developing a proper &amp;#8220;abap-mode&amp;#8221; for the stand-alone Emacs editor as well, but it does seem it would have very little benefit for the effort involved &amp;#8211; the benefit would apply if you opened a saved file with &lt;span class="caps"&gt;ABAP&lt;/span&gt; code in it in Emacs, or if you pasted into an Emacs window outside of your &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;GUI&lt;/span&gt;. If it were feasible to embed Emacs into the &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;GUI&lt;/span&gt; as the default editor then an abap-mode would be a real consideration. However, I don&amp;#8217;t see how it&amp;#8217;ll be feasible due to the tight integration that the new editor enjoys. For instance, one would have to allow for drill-down into other sections of code, allow for integration with the SE80 code browser and so forth. So I personally see a truly embedded Emacs as a wonderful thing (that will never happen!).&lt;/p&gt;
&lt;p&gt;I also have a wish-list for commands that I&amp;#8217;d love the new &lt;span class="caps"&gt;ABAP&lt;/span&gt; editor to support. Top of this list would be an Emacs kill-ring. Luckily, there is something similar &amp;#8211; pressing &amp;#8220;Edit.PasteExtended&amp;#8221; (By default bound to Control-Shift-V) pops up a list of the clipboard history, so all is not lost however, and if you didn&amp;#8217;t know about this feature it&amp;#8217;s great.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; The new front-end editor is available for &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;GUI&lt;/span&gt; for Windows 6.40 Patch level 10 and onwards, also your server must be able to support it &amp;#8211; the first official server version that supports it is &lt;span class="caps"&gt;SAP&lt;/span&gt; NetWeaver2004s, although since then the editor has been &lt;a href="https://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/3914"&gt;backported&lt;/a&gt;, you can also run with it on older versions going back to 6.20 (but your system must be at one of the newer patch levels).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/QaiyQlOfJKE" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 12 Aug 2010 10:15:44 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/24</guid>
      <dc:date>2010-08-12T10:15:44.33544+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/24</feedburner:origLink></item>
    <item>
      <title>Kinesis Advantage Ergonomic Keyboard</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/QRJ7mN_R2r0/23</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/kinesis.jpg" class="c" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Never trust your hands to a generic, sticky old Dell keyboard that you just find on your desk at work. In my case, it took about a month of using that keyboard to develop a case of tendinitis. To be fair this is the second time I&amp;#8217;d experienced such a problem; the mouse was partially responsible, and Emacs chording was also contributing it&amp;#8217;s share.&lt;/p&gt;
&lt;p&gt;Since this was the second time I&amp;#8217;d experienced pains in my hands from typing I&amp;#8217;d already done my research and knew that I&amp;#8217;d want to look at buying a &amp;#8220;Kinesis&amp;#8221;: http://www.kinesis-ergo.com/ keyboard. The problem was primarily that Kinesis make two very different styles of keyboards &amp;#8211; the &lt;a href="http://www.kinesis-ergo.com/freestyle.htm"&gt;freestyle&lt;/a&gt; which is most similar to a conventional keyboard &amp;#8211; with a similar layout except that it is split into two independent halves and the more radical &lt;a href="http://www.kinesis-ergo.com/contoured.htm"&gt;Advantage&lt;/a&gt;. The Advantage has two recessed key &amp;#8216;wells&amp;#8217;, and radically has thumb keypads forcing you to make use of your more powerful digits. It was this latter feature that made me order the advantage even though this is an expensive keyboard. Personally I&amp;#8217;ve never seen any true ergonomic keyboards (other than Microsoft Natural boards and the like) in real life &amp;#8211; they just aren&amp;#8217;t sold in South Africa and it costs a lot to have them shipped over here. So I asked around on various forums and newsgroups before committing to the capital outlay. One of the things that I&amp;#8217;d never considered when making the choice was the type of keyswitches in the keyboard. In the past I owned an &lt;span class="caps"&gt;IBM&lt;/span&gt; buckling spring keyboard, so I do appreciate the feel of a good keyboard, although quite frankly I found the gentle softness and quietness of cheap membrane PC keyboards to be a relief after the &lt;span class="caps"&gt;IBM&lt;/span&gt;! It turns out that the kinds of keyswitch most highly prized on the &lt;a href="http://geekhack.org/"&gt;geekhack forums&lt;/a&gt; are the Cherry (Cherry &amp;#8220;Brown&amp;#8221; is liked the most by some) and Topre switches. So, reason number two to buy a Kinesis Advantage &amp;#8211; it has Cherry Browns. If you&amp;#8217;re interested in ordering the same from South Africa bear in mind that it&amp;#8217;ll cost you about twice the direct exchange rate once you&amp;#8217;ve factored in &lt;span class="caps"&gt;UPS&lt;/span&gt; shipping (obligatory) and customs duties. So anyone who lives in Cape Town and wants to try mine out before buying, I fully understand!&lt;/p&gt;&lt;p&gt;It has been an interesting journey and things I&amp;#8217;ve long considered to be true have had to be reviewed. One of these things is about learning to type correctly. My wife, Shira, took the time to learn to type correctly &amp;#8211; she bought a typing instructor (Deluxe!) CD-&lt;span class="caps"&gt;ROM&lt;/span&gt; and did all the exercises and games, and the first thing she does is position her fingers correctly on the home row. I&amp;#8217;ve been hacking computers for years and have been able to fully touch type without looking down at my fingers since around about the time I took up programming full time. And of course I&amp;#8217;ve picked up the same bad typing habits you have, and have never considered it a worthwhile use of time to learn typing &lt;em&gt;per se&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;My first experience of the Kinesis is that it felt like being taken straight back to being a complete keyboarding beginner &amp;#8211; I was only able to type at a few words per minute at first and the feeling of disorientation was strong. The keyboard ships with a little booklet with typing exercises in it to help you pick up the habit of blind typing again, and spending a couple of evenings following the exercises in the book is sufficient to develop some basic keyboarding confidence again. The main Kinesis manual is clear that during the adaption phase one shouldn&amp;#8217;t switch between the Kinesis and conventional keyboards, although after you have adapted you can switch back and forth easily (conventional keyboards do feel cramped after one has become accustomed to the Kinesis, and the staggered arrangement of keys on conventional keyboards mean that typing blind one starts to hit the &amp;#8216;B&amp;#8217; key accidentally quite a lot again, but this is not so much of a problem). The booklet of typing exercises that is shipped with the keyboard is worthwhile and useful &amp;#8211; I gained an appreciation of the logic behind key placement and design and also learned useful things about typing correctly, such as using the opposite hand to press shift when capitalizing  a letter.&lt;/p&gt;
&lt;p&gt;Some things I&amp;#8217;ve noticed:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Using your pinkies&lt;/strong&gt;. I never learned to use my &amp;#8216;pinkie&amp;#8217; fingers in typing (possibly because laptop keyboards are compressed and you don&amp;#8217;t need to), but I learned that in proper touch typing you will use your weakest digit quite a lot, especially for pressing &amp;#8216;shift&amp;#8217; and the letter &amp;#8216;P&amp;#8217; amongst others. Also, it is good typing practice to use the opposite hand for the modifier key, so you don&amp;#8217;t scrunch up a single hand and injure it in this way (think of the compression that your left hand experiences if you press &amp;#8216;Control&amp;#8217; and &amp;#8216;C&amp;#8217; with this hand on a conventional keyboard).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Split keyboards&lt;/strong&gt;. If you&amp;#8217;re forced to type correctly and use the correct hands and fingers then even a non-ergonomic keyboard is fine. So if you really and truly never cross over your hands when typing you no longer need this feature, but I&amp;#8217;m going to need to use a split keyboard with a gap between the left and right group of keys for some time to come. Even after using the Kinesis for a couple of weeks I find that I still try and type &amp;#8216;T&amp;#8217;, &amp;#8216;G&amp;#8217; and &amp;#8216;B&amp;#8217; with my right hand occasionally, swapping over is a difficult habit to drop. Here&amp;#8217;s a pic of the split keyboards in Webwit&amp;#8217;s collection:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://bloggroll.com/stat/webwit1.jpg" class="c" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;(Picture shown with &lt;a href="http://webwit.nl/"&gt;permission&lt;/a&gt;. Note that he has arranged the keyboards with his favourites in the front row &amp;#8211; and the Kinesis advantage is the black and blue keyboard in the center of the second row from the front, so it is not one of his top picks although little can compete with the &lt;a href="http://datahand.com/"&gt;datahand&lt;/a&gt; in the front center. This is an impressive collection &amp;#8211; about the only board that I&amp;#8217;ve noticed missing is the &lt;a href="http://www.datadesktech.com/desktop_sb.html"&gt;smartboard&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Posture and balance&lt;/strong&gt; &amp;#8211; I&amp;#8217;ve noticed that I walk up stairs differently after using the Kinesis for a few hours. This is partly because it has forced me to sit upright, although I think using all five fingers for typing is also a factor &amp;#8211; the experience of typing on the Kinesis is more like that of a pianist using the whole hand; a greater muscular sensitivity and suppleness is developed by typing on this keyboard &amp;#8211; it isn&amp;#8217;t necessary to have to bash the keys as the keys register before bottoming out) and this does have a muscular repercussion on a greater level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Non-staggered key arrangement.&lt;/strong&gt; Why none of the Kinesis reviews don&amp;#8217;t mention this is a mystery for me &amp;#8211; this is one of the best selling points of this keyboard. Keys are in vertical rows &amp;#8211; for example &amp;#8216;E&amp;#8217; is directly above &amp;#8216;D&amp;#8217; &amp;#8211; this really does make it easier to type since all you need to remember to do is to move your finger directly upward one key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Size&lt;/strong&gt;. Ever so slightly smaller keys on the Kinesis would be nice. Sometimes it does feel like it was designed for someone with slightly bigger hands than mine, and slightly smaller keys and keywells would improve my experience of this board considerably.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cannot raise the front of the keyboard&lt;/strong&gt;. Other ergonomic keyboards offer the ability to tilt the front or the back of the keyboard (and I have found that raising the &lt;strong&gt;front&lt;/strong&gt; of such keyboards does help me) but unfortunately the Kinesis does not offer this facility and it is difficult to maintain keyboard stability by propping it up from underneath due to the curved design of the underside.&lt;/p&gt;
&lt;p&gt;For alphanumeric entry the Kinesis has become quite comfortable for me and I can hit a decent &lt;span class="caps"&gt;WPM&lt;/span&gt;, but when it comes to hitting ctrl- and alt- and the arrow keys I&amp;#8217;ve been struggling. I also mispress &amp;#8216;enter&amp;#8217; and &amp;#8216;space&amp;#8217; quite frequently (they are on the same thumb with enter requiring a slighly greater stretch). A large part of the problem is the thumb keypads are elevated above where my hands are while typing. If you look at other ergonomic keyboard designs such as the Maltron (the similarity to the Kinesis is not accidental!) you will notice that the thumb keypads &lt;a href="http://www.maltron.com/maltron-kbd-dual.html"&gt;are recessed&lt;/a&gt;. Since the Kinesis is fully programmable in firmware you can remap keys however you desire. I have found that placing &amp;#8216;Alt&amp;#8217; on the bottom of the thumb pads (where &amp;#8216;end&amp;#8217; and page down&amp;#8217; are normally) has helped me to avoid doing weird contortions with my thumbs, and I&amp;#8217;ve also taken care to have an &amp;#8216;Alt&amp;#8217; key available for both my left and right hands so that I don&amp;#8217;t have to scrunch up a single hand.&lt;/p&gt;
&lt;p&gt;Certainly, I need to give myself more than a couple of months usage on this keyboard before I can say more about whether I like it or hate it &amp;#8211; it has become much easier to use after a couple of weeks, but I do wonder if I&amp;#8217;ll ever be able to use this keyboard completely on autopilot where there is not one part of my brain thinking where the alt key lies or how to find the arrow keys. On the other hand, the excellent keyswitches and the non-staggered split design are features that I will always look for on other keyboards in future.&lt;/p&gt;
&lt;p&gt;Keyboard buying could easily become an expensive and distracting hobby. Sites like &lt;a href="http://www.elitekeyboards.com/"&gt;Elite keyboards&lt;/a&gt; offer an interesting range of mechanical keyboards, and hardened collectors order custom made &lt;a href="http://keycapsdirect.com/"&gt;keycaps&lt;/a&gt;. I&amp;#8217;ll almost certainly be ordering a keyboard with Cherry blue keyswitches in the next while, but shipping to South Africa is a major cost and I&amp;#8217;m not even sure I&amp;#8217;ll like the feel of the keyboard without having access to other enthusiasts in Cape Town who have them on hand to try out. So, if you&amp;#8217;re in Cape Town (or Joburg) and have a keyboard with Cherry Blues then please add a comment below.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/QRJ7mN_R2r0" height="1" width="1"/&gt;</description>
      <pubDate>Mon, 14 Jun 2010 11:59:28 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/23</guid>
      <dc:date>2010-06-14T11:59:28.643544+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/23</feedburner:origLink></item>
    <item>
      <title>Powerball Odds</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/F_c87RVvSs0/18</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/pachinko.jpg" class="c" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This week&amp;#8217;s powerball currently has a rollover jackpot of &lt;a href="http://www.nationallottery.co.za/"&gt;90 million Rands&lt;/a&gt;. A highly attractive target. But before going off to &amp;#8220;tata your chance&amp;#8221;, let&amp;#8217;s look at the statistical probability that you&amp;#8217;ll win the South African powerball game.&lt;/p&gt;&lt;p&gt;To win the jackpot prize in powerball, you&amp;#8217;ll need to select 5 numbers between 1 and 45 and also the matching powerball number which is between 1 and 20. The powerball number can be the same as one of the group of 5 numbers selected previously.&lt;/p&gt;
&lt;p&gt;So, by my calculation, the number of ways 5 numbers can be randomly selected from a set of 45 is:&lt;br /&gt;
45! / ( 5! * (45-5)! ) = 1221759&lt;/p&gt;
&lt;p&gt;And since, for each of the 1221759 combinations there are 20 different ways to pick the powerball number, the overall chance of getting the jackpot is one in ( 1221759 * 20 ) =  24435180, so in English it is &lt;em&gt; roughly one in 24.4 million&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Out of curiosity, is it easier to win the regular South African lotto? Here the rules are simpler, you&amp;#8217;ll need to select 6 numbers between 1 and 49. So, using a similar calculation as before:&lt;br /&gt;
49! / ( 6! * (49-6)! ) = 13983816, or in English &lt;em&gt;nearly one in 14 million&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Tax on the stupid or not? Even knowing these odds though, I&amp;#8217;ll probably be buying a powerball ticket for the next draw and pretend I&amp;#8217;ve got a decent chance ☺&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/F_c87RVvSs0" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 10 Feb 2010 12:20:00 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/18</guid>
      <dc:date>2010-02-10T12:20:00.533989+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/18</feedburner:origLink></item>
    <item>
      <title>Crapple "release" the iPoo</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/7k-U2LwT8I0/17</link>
      <description>&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/tamagotyou.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;CUPOOTINO&lt;/span&gt;, California. Steven Jobless, &lt;span class="caps"&gt;CEO&lt;/span&gt; of Crapple Corp, announced his company&amp;#8217;s long awaited tablet form-factor machine last Wednesday. Whilst sequestered in the backwoods of Tennessee last year, Mr Jobless spent a lot of time waiting for medical test results and considering the meaning of life. Whereupon he had what he described as a &amp;#8220;number 1 experience&amp;#8221;. It hit him &amp;#8211; the perfect Captive Market. The new product, marketed as the iPoo is of the ideal form factor for use whilst positioned on the lavatory. Unlike the early tablet products produced by their competitors, the iPoo is not a fully fledged compooter, but follows the &lt;a href="http://www.asktog.com/papers/raskinintuit.html"&gt;Jeff Raskin school of thought&lt;/a&gt; on what constitutes a suitable &amp;#8220;Intuitive Interface&amp;#8221; for the average user.&lt;/p&gt;&lt;p&gt;Marketing of the new product is intended to involve heavy use of anti-social media &amp;#8211; each geek on the planet is forced into deciding whether they would buy the device or not. Since most of them think it&amp;#8217;ll be shit, it&amp;#8217;ll count as a ringing endorsement for the non-tech savvy public. It seems that the geek public is waiting for the next shitteration of the device.&lt;/p&gt;
&lt;p&gt;Taking full advantage of the &lt;span class="caps"&gt;DRM&lt;/span&gt; the product provides, it comes in two models. The slightly more expensive option, &amp;#8220;Comes with Porn&amp;#8221; (seemingly aimed at competitor Noklue) unlocks &lt;span class="caps"&gt;DRM&lt;/span&gt; for porn on the device, and also uses a new technology known only as &amp;#8220;3D-multitouch&amp;#8221; (details not yet provided at time of going to press).&lt;/p&gt;
&lt;p&gt;We spent some time after the media announcement assessing the mood amongst the company faithful, and by and large that mood was one of &amp;#8220;Relief&amp;#8221;. Reaction amongst the Linux community was less positive, with comments ranging from &amp;#8220;We invented Brown&amp;#8221; (Ubuntu&amp;#8217;s &lt;a href="http://www.markshuttleworth.com/"&gt;Mark Shuttleworth&lt;/a&gt;), &amp;#8220;We invented shit-casting&amp;#8221; (Communitization manager, &lt;a href="http://www.jonobacon.org/"&gt;Jono Bacon&lt;/a&gt;) to &amp;#8220;It&amp;#8217;s Crap&amp;#8221; (Fabian Scherschel, from the &lt;a href="http://linuxoutlaws.com/"&gt;Linuxoutlaws&lt;/a&gt;).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/7k-U2LwT8I0" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 03 Feb 2010 14:59:58 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/17</guid>
      <dc:date>2010-02-03T14:59:58.995943+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/17</feedburner:origLink></item>
    <item>
      <title>Dynamically hide elements with javascript - SAP CRM 2007</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/NHeE0Vksk-U/16</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/sap.png" class="r" alt="" /&gt; In a recent &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;CRM&lt;/span&gt; 2007 implementation, we had the requirement to hide a view &lt;em&gt;(&amp;#8220;partial&amp;#8221;)&lt;/em&gt; in response to a change in a dropdown value.&lt;/p&gt;
&lt;p&gt;This is easily done using javascript code on the client side, and what&amp;#8217;s more such a solution to the problem is easy to implement and is not really restricted to &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;CRM&lt;/span&gt; 2007 or even &lt;span class="caps"&gt;SAP&lt;/span&gt; web development in general.&lt;/p&gt;&lt;p&gt;This is what we wished to achieve &amp;#8211; hide block &amp;#8216;A&amp;#8217; on the following screen if the value in the category dropdown &amp;#8216;B&amp;#8217; is anything other than &amp;#8220;corporate brands&amp;#8221;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://bloggroll.com/stat/block_a_b_half.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This can be done using the &lt;span class="caps"&gt;ABAP&lt;/span&gt; &lt;span class="caps"&gt;CRM&lt;/span&gt; framework, but there are several potential concerns:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Components not previously enhanced may require enhancement&lt;/li&gt;
	&lt;li&gt;Components are designed to be independent, and making one component rely on another (which we want to do here) involves creating some sort of shared attribute&lt;/li&gt;
	&lt;li&gt;In order to suppress a view it will be necessary to re-render all views on the current frame and will involve an unnecessary round trip.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It was therefore decided to solve this problem using javascript code.&lt;/p&gt;
&lt;p&gt;As &lt;span class="caps"&gt;SAP&lt;/span&gt; &lt;span class="caps"&gt;CRM&lt;/span&gt; 2007 is supported by Firefox (version 2, although version 3 will work with rendering glitches), it is possible to use the Firefox &amp;#8216;Firebug&amp;#8217; extension to inspect a web page and determine the relationship between elements on screen and appropriate blocks of &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;From Firebug analysis (or if you have patience to do this manually) it was determined that this block of &lt;span class="caps"&gt;HTML&lt;/span&gt; code represents the Dropdown B:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td class="th-ip-td1" style="overflow: hidden; width: 100%;"&amp;gt;
&amp;lt;fieldset class="th-if-wrapper-onfocus" style="border: 0pt none ; margin-right: 3px;"&amp;gt;
&amp;lt;input id="C14_W59_V60_ClassificationDdlb1" class="th-if th-if-icon" readonly="readonly" 
value="Corporate Brands" onkeydown="thtmlb_ddlbInputKeyDown(this,event);"
style="width: 100%;" size="16" onblur="thtmlb_inputBlur(this);"
onfocus="thtmlb_inputFocus(this);thtmlbSaveKeyboardFocus('C14_W59_V60_ClassificationDdlb1');"
onclick="thtmlb_inputClick(this,7);"/&amp;gt;
&amp;lt;/fieldset&amp;gt;&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;The element we&amp;#8217;re interested in detecting a change of value for is the input tag with id &amp;#8220;C14_W59_V60_ClassificationDdlb1&amp;#8221;&lt;/p&gt;
&lt;p&gt;This block of &lt;span class="caps"&gt;HTML&lt;/span&gt; code represents the viewset area A that we will be hiding (ignoring a lot of the inner &lt;span class="caps"&gt;HTML&lt;/span&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td class="th-gr-td" valign="top" rowspan="1" colspan="1"&amp;gt;
&amp;lt;div id="C11_W43_V44_V48" excevt=""
intevt="c:C11_W43_V44_V48:C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do;" 
automode="true" tgt="" dhe="true" 
style="display: inline;"&amp;gt;
&amp;lt;!-- Begin C11_W43_V44_V48 --&amp;gt;
&amp;lt;div id="C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do" class="th-ajax-area"&amp;gt;
&amp;lt;!-- Begin C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do --&amp;gt;
&amp;lt;table ....&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;The element we&amp;#8217;re interested in hiding is the div with id=&amp;#8220;C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do&amp;#8221;&lt;/p&gt;
&lt;p&gt;In it&amp;#8217;s simplest case, the following javascript, if inserted into the view somewhere after the thtmlb:gridCell tag that declares dropdown element B, does what is required &amp;#8211; it will hide block A if the value of dropdown B changes to anything other than &amp;#8220;Corporate Brands&amp;#8221;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script for="ClassificationDdlb1" event=onchange type="text/javascript"&amp;gt;
var dd = document.getElementById("C14_W59_V60_ClassificationDdlb1");
var hidee = document.getElementById("C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do");
if(dd.value != "Corporate Brands"){
  hidee.style.display = 'none';
}
else {
  hidee.style.display = 'inline';
}
&amp;lt;/script&amp;gt;&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;Of course, we&amp;#8217;re going to require something a little more complicated! The problem is that the id for the elements under consideration is not fixed &amp;#8211; the C14_W59_V60 will be different for different roles and is affected by configuration changes. One way to solve this problem is to write a javascript function that will go through all elements and check for a regular expression match based on the contents of id. However the javascript function getElementById only accepts an exact match on id.&lt;/p&gt;
&lt;p&gt;A custom function fuzzyElementSearch was created to find the element of interest (this function is contained within the file jonathan.js which will be listed afterwards), this is what the call to this function looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script src="/sap/bc/bsp/sap/crmcmp_ic_frame/scripts/common/jonathan.js" type="text/javascript"&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script for="ClassificationDdlb1" event=onchange type="text/javascript"&amp;gt;&lt;/code&gt;

&lt;code&gt;var dd       = fuzzyElementSearch("th-ip-td1","td",null,"input","ClassificationDdlb1", 0)[0];
var dd2      = dd[0];
var hide     = fuzzyElementSearch("th-gr-td","td", null, "div","productdetailviewset", 1)[0];
if ((hide) &amp;amp;&amp;amp; (dd2) &amp;amp;&amp;amp; (hide.length &amp;gt; 0)) {
  var hide2    = hide[0];&lt;/code&gt;

&lt;code&gt;  if ((dd2.value) != "Corporate Brands") {
    hide2.style.display = 'none';
  }
  else {
    hide2.style.display = 'inline';
  }
}&lt;/code&gt;

&lt;code&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;The file jonathan.js contains the following javascript:-&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function fuzzyElementSearch(classname, tagname, root, tag2, subbie, level) {&lt;/code&gt;

&lt;code&gt;    // Call function from Rhino book that returns
    // an array of DOM elements that are members of the specified class,
    // have the specified tagname, and are descendants of the specified root.
    var elements = getElements(classname, tagname, root);&lt;/code&gt;

&lt;code&gt;    // Find children (of tag2) for each of these elements
    var subfound = [];&lt;/code&gt;

&lt;code&gt;    for(var i = 0; i &amp;lt; elements.length; i++) {
        var subchild  = elements[i];
        var grandkids = subchild.getElementsByTagName(tag2);
        if (grandkids) subfound.push(grandkids);
    }&lt;/code&gt;

&lt;code&gt;    // search "level" deep for each of the above matches
    // for an element where the id contains the substring
    var pattern = new RegExp(subbie, "g");
    var matches = [];
    for(var i = 0; i &amp;lt; subfound.length; i++) {
        var matchee  = subfound[i];
        if (matchee.length &amp;gt; level) {
          var matchin = matchee[level];
          var matchid = matchin.id;
          var reslt = pattern.test(matchid);
          if(reslt == true) {
             matches.push(matchee);
          }
        }
    }&lt;/code&gt;

&lt;code&gt;    // Note that we always return an array, even if it is empty
    return matches;&lt;/code&gt;


&lt;code&gt; // *** The following attribution applies to the rest of the code in this file
 // This code is from the book JavaScript: The Definitive Guide, 5th Edition,
 // by David Flanagan. Copyright 2006 O'Reilly Media, Inc. (ISBN #0596101996)
 // *** &lt;/code&gt;

&lt;code&gt; /* Rest of code == EXAMPLE 15-4 From David Flanagan, "Javascript"
 * getElements(classname, tagname, root):
 * Return an array of DOM elements that are members of the specified class,
 * have the specified tagname, and are descendants of the specified root.
 *
 * If no classname is specified, elements are returned regardless of class.
 * If no tagname is specified, elements are returned regardless of tagname.
 * If no root is specified, the document object is used.  If the specified
 * root is a string, it is an element id, and the root
 * element is looked up using getElementsById()
 */
    function getElements(classname, tagname, root) {
        // If no root was specified, use the entire document
        // If a string was specified, look it up
        if (!root) root = document;
        else if (typeof root == "string") root = document.getElementById(root);&lt;/code&gt;

&lt;code&gt;        // if no tagname was specified, use all tags
        if (!tagname) tagname = "*";&lt;/code&gt;

&lt;code&gt;        // Find all descendants of the specified root with the specified tagname
        var all = root.getElementsByTagName(tagname);&lt;/code&gt;

&lt;code&gt;        // If no classname was specified, we return all tags
        if (!classname) return all;&lt;/code&gt;

&lt;code&gt;        // Otherwise, we filter the element by classname
        var elements = [];  // Start with an emtpy array
        for(var i = 0; i &amp;lt; all.length; i++) {
            var element = all[i];
            if (isMember(element, classname)) // isMember() is defined below
                elements.push(element);       // Add class members to our array
        }&lt;/code&gt;

&lt;code&gt;        // Note that we always return an array, even if it is empty
        return elements;&lt;/code&gt;

&lt;code&gt;        // Determine whether the specified element is a member of the specified
        // class.  This function is optimized for the common case in which the
        // className property contains only a single classname.  But it also
        // handles the case in which it is a list of whitespace-separated classes.
        function isMember(element, classname) {
            var classes = element.className;  // Get the list of classes
            if (!classes) return false;             // No classes defined
            if (classes == classname) return true;  // Exact match&lt;/code&gt;

&lt;code&gt;            // We didn't match exactly, so if there is no whitespace, then
            // this element is not a member of the class
            var whitespace = /\s+/;
            if (!whitespace.test(classes)) return false;&lt;/code&gt;

&lt;code&gt;            // If we get here, the element is a member of more than one class and
            // we've got to check them individually.
            var c = classes.split(whitespace);  // Split with whitespace delimiter
            for(var i = 0; i &amp;lt; c.length; i++) { // Loop through classes
                if (c[i] == classname) return true;  // and check for matches
            }&lt;/code&gt;

&lt;code&gt;            return false;  // None of the classes matched
        }
    }
}&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;The function fuzzyElementSearch accepts five parameters, and is used to find the element based on it&amp;#8217;s relation to an an outer element. In other words, we find the element we&amp;#8217;re interested in based on the context of the surrounding &lt;span class="caps"&gt;HTML&lt;/span&gt; code.&lt;/p&gt;
&lt;p&gt;So, if we consider the case where we are looking for the element that represents viewset A that we want to hide:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;td class="th-gr-td" valign="top" rowspan="1" colspan="1"&amp;gt;
&amp;lt;div id="C11_W43_V44_V48" excevt=""
intevt="c:C11_W43_V44_V48:C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do;" 
automode="true" tgt="" dhe="true" style="display: inline;"&amp;gt;
&amp;lt;!-- Begin C11_W43_V44_V48 --&amp;gt;
&amp;lt;div id="C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do" class="th-ajax-area"&amp;gt;
&amp;lt;!-- Begin C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do --&amp;gt;
&amp;lt;table ....&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;The outer element in this case is &lt;code&gt;&amp;lt;td class="th-gr-td" valign="top" rowspan="1" colspan="1"&amp;gt;&lt;/code&gt;&lt;br /&gt;
The inner element (which is what we want in the end) will be &lt;code&gt;&amp;lt;div id="C1_W1_V2_C1_W1_V2_V3_C11_W43_V44_C11_W43_V44_V48_productdetailviewset.do" class="th-ajax-area"&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The following five parameters supplied to the fuzzyElementSearch are what the function uses to robustly identify the element we want:-&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;classname = the &lt;span class="caps"&gt;CSS&lt;/span&gt; class of the outer element, or th-gr-td in this case.&lt;/li&gt;
	&lt;li&gt;tagname = the tag type of the outer element, td in this case&lt;/li&gt;
	&lt;li&gt;root = the root element from which we start searching. We&amp;#8217;ll search the entire document so can leave this as null&lt;/li&gt;
	&lt;li&gt;tag2 = the tag type of the inner element, or div in this case&lt;/li&gt;
	&lt;li&gt;subbie = substring (actually a regular expression string) that will match the id of the inner element&lt;/li&gt;
	&lt;li&gt;level = number of levels down from outer tag to inner tag. In the above case, we are interested in the 2nd div tag nested inside the td tag. Since javascript counting starts at 0 the level we are interested in is level 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Putting it all together, the following call to the fuzzyElementSearch gives us the inner element we want every time (it will be the first item in the array returned):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var hide     = fuzzyElementSearch("th-gr-td","td", null, "div","productdetailviewset", 1)[0];&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;How does fuzzyElementSearch work? It makes use of a function getElements that is from David Flanagan&amp;#8217;s book &amp;#8220;Javascript&amp;#8221; (&lt;span class="caps"&gt;ISBN&lt;/span&gt;  0-596-10199-6, also known as the Rhino book) &amp;#8211; this function allows us to search for elements based on class and/or tag name. With the results of this function similar code is used to find all the children of these elements that have the correct tag and regular expression match. I heartily endorse David Flanagan&amp;#8217;s book, and if you are interested in learning javascript then consider visiting &lt;a href="http://www.davidflanagan.com/javascript5/"&gt;the book&amp;#8217;s web site&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/NHeE0Vksk-U" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 18 Dec 2009 16:58:06 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/16</guid>
      <dc:date>2009-12-18T16:58:06.245512+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/16</feedburner:origLink></item>
    <item>
      <title>Using mencoder to fix a broken video file index</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/FbtR9EOeV9I/15</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/mplayer.jpg" class="l" alt="" /&gt;An oldie, but a goodie, and there is always someone out there who doesn&amp;#8217;t know about this. Often, one encounters video files that do not have an index or have a broken index- this is almost certainly the case if your media player or &lt;span class="caps"&gt;PVR&lt;/span&gt; refuses to allow you to fast forward within the file. Easily fixed under Linux using the following mencoder incantation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mencoder -idx input.avi -ovc copy -oac copy -o output.avi&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;As a bonus, this apparently also repairs broken &lt;a href="http://forum.doom9.org/archive/index.php/t-93469.html"&gt;interleaving&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some more great mplayer/mencoder hints, including tricks such as appending multiple &lt;span class="caps"&gt;AVI&lt;/span&gt; &lt;a href="http://web.njit.edu/all_topics/Prog_Lang_Docs/html/mplayer/encoding.html"&gt;files are here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/FbtR9EOeV9I" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 24 Nov 2009 09:32:06 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/15</guid>
      <dc:date>2009-11-24T09:32:06.0010+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/15</feedburner:origLink></item>
    <item>
      <title>Linode and Panix VPS benchmark comparison</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/jxrki1AUxrM/14</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/comparison.jpg" class="r" alt="" /&gt;In May 2009 I moved my &lt;span class="caps"&gt;VPS&lt;/span&gt; (Virtual Private Server) from being hosted by &lt;a href="http://www.linode.com/"&gt;Linode&lt;/a&gt; in Dallas to &lt;a href="http://www.panix.com/"&gt;Panix&lt;/a&gt; in New York City. Price wise, the offerings are identical, $21 monthly consisted of a Xen virtual server with 360MB of &lt;span class="caps"&gt;RAM&lt;/span&gt;, 16GB storage and 200GB of transfer, plus one additional public IP address. However, not all virtual private servers are created equal, and as I discovered benchmark measurements showed performance differences between the two offerings. Please bear in mind that the benchmark results that follow are not up to a proper standard of testing (the one host was running a 32 bit operating system whilst the other was 64 bit), testing was done in May (things may have changed subsequently), and you may luck out and be assigned to an underutilized host and get better than expected performance. These benchmark tests are just an interesting read, and may not be as conclusive as I would like, but they allowed me to make up my mind to move over to Panix.&lt;/p&gt;&lt;p&gt;One of the greatest limitations on any virtual host is the reduced amount of &lt;span class="caps"&gt;RAM&lt;/span&gt; available. This affects things like the number of web application instances you can keep running on your web server at the same time. For instance, the &lt;a href="http://www.modrails.com/documentation/Users%20guide.html"&gt;Phusion Passenger Users Guide&lt;/a&gt; recommends that the parameter &amp;#8220;PassengerMaxPoolSize&amp;#8221; which is the maximum number of Ruby on Rails or Rack application instances that may be simultaneously active be set to a value of 2 for a &lt;span class="caps"&gt;VPS&lt;/span&gt; with only 256MB of &lt;span class="caps"&gt;RAM&lt;/span&gt;. Having more &lt;span class="caps"&gt;RAM&lt;/span&gt; makes a big difference &amp;#8211; the same guide recommends that if your system has 2GB of &lt;span class="caps"&gt;RAM&lt;/span&gt; the parameter be set to a value of 30.&lt;/p&gt;
&lt;p&gt;However, another consideration in the case of virtual private servers is the issue of contention for disk access. If your &lt;span class="caps"&gt;VPS&lt;/span&gt; is sharing the same host with &lt;a href="http://www.linode.com/forums/archive/o_t/t_4347/linodes_per_host.html"&gt;approximately 40&lt;/a&gt; others and you&amp;#8217;re all trying to read the same physical disk simultaneously it makes sense this will also be a bottleneck. In the case of a Panix &lt;span class="caps"&gt;VPS&lt;/span&gt; it is explicitly stated that storage is achieved using &lt;a href="http://www.panix.com/corp/v-colo/vfaq.html#hardware"&gt;&lt;span class="caps"&gt;SAN&lt;/span&gt; disk arrays over fibre channel&lt;/a&gt;. From what I can tell about Linode, disks are not &lt;span class="caps"&gt;SAN&lt;/span&gt; but are directly &lt;a href="http://blog.linode.com/2009/07/22/king-size-linodes-now-available/"&gt;attached &lt;span class="caps"&gt;RAID&lt;/span&gt; 10&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the benchmark results that follow, &amp;#8216;old&amp;#8217; is the Linode running 32-bit Debian stable (Lenny) vs 64-bit on &amp;#8216;mail&amp;#8217; &amp;#8211; the Panix host. &lt;a href="http://www.coker.com.au/bonnie++/"&gt;Bonnie++&lt;/a&gt; is a tool for disk and filesystem performance measurement, and showed superior benchmarks for Panix (at the cost of higher &lt;span class="caps"&gt;CPU&lt;/span&gt; utilization):&lt;/p&gt;
&lt;p&gt;Panix:&lt;br /&gt;
&lt;pre&gt;Version 1.03d       ------Sequential Output------ --Sequential Input- --Random-
                     -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
mail             1G 41869  75 47323  15 22774   4 51539  72 53464   3 410.8   0
                     ------Sequential Create------ --------Random Create--------
                     -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
               files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                  16 +++++ +++ +++++ +++ +++++ +++ 31720  72 +++++ +++ +++++ +++
mail,1G,41869,75,47323,15,22774,4,51539,72,53464,3,410.8,0,16,+++++,+++,+++++,+++,+++++,+++,31720,72,+++++,+++,+++++,+++
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Linode:&lt;br /&gt;
&lt;pre&gt;Version 1.03d       ------Sequential Output------ --Sequential Input- --Random-
                     -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
old              1G 25095  51 21076   4  8116   0 22256  41 36907   0  74.1   0
                     ------Sequential Create------ --------Random Create--------
                     -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
               files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                  16  3171  98 +++++ +++ +++++ +++  3285  98 +++++ +++ 12042  98
old,1G,25095,51,21076,4,8116,0,22256,41,36907,0,74.1,0,16,3171,98,+++++,+++,+++++,+++,3285,98,+++++,+++,12042,98
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;hdparm -t /dev/xvda doesn&amp;#8217;t show much difference between the two services, but is too unscientific to come to any conclusion. An odd hdparm conclusion is that &amp;#8216;secondary&amp;#8217; disks, eg. /xvdb are slower, but it could just be file composition.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.tux.org/~mayer/linux/bmark.html"&gt;Nbench&lt;/a&gt; test results showed that the offerings were largely equal in terms of &lt;span class="caps"&gt;CPU&lt;/span&gt; speed:&lt;/p&gt;
&lt;p&gt;Panix:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BYTEmark* Native Mode Benchmark ver. 2 (10/95)
Index-split by Andrew D. Balsa (11/97)
Linux/Unix* port by Uwe F. Mayer (12/96,11/97)&lt;/code&gt;

&lt;code&gt;TEST                : Iterations/sec.  : Old Index   : New Index
                    :                  : Pentium 90* : AMD K6/233*
--------------------:------------------:-------------:------------
NUMERIC SORT        :          872.48  :      22.38  :       7.35
STRING SORT         :          131.52  :      58.77  :       9.10
BITFIELD            :      4.0716e+08  :      69.84  :      14.59
FP EMULATION        :           137.8  :      66.12  :      15.26
FOURIER             :           26793  :      30.47  :      17.11
ASSIGNMENT          :          30.251  :     115.11  :      29.86
IDEA                :          6029.6  :      92.22  :      27.38
HUFFMAN             :          1976.1  :      54.80  :      17.50
NEURAL NET          :          39.809  :      63.95  :      26.90
LU DECOMPOSITION    :          1396.4  :      72.34  :      52.24
==========================ORIGINAL BYTEMARK RESULTS==========================
INTEGER INDEX       : 62.027
FLOATING-POINT INDEX: 52.042
Baseline (MSDOS*)   : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0
==============================LINUX DATA BELOW===============================
CPU                 : 4 CPU GenuineIntel Intel(R) Xeon(R) CPU           E5410  @ 2.33GHz 2333MHz
L2 Cache            : 6144 KB
OS                  : Linux 2.6.28-xen3-U-64
C compiler          : gcc version 4.3.2 (Debian 4.3.2-1.1)
libc                : libc-2.7.so
MEMORY INDEX        : 15.823
INTEGER INDEX       : 15.224
FLOATING-POINT INDEX: 28.865
Baseline (LINUX)    : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38
* Trademarks are property of their respective holder.&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;Linode:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BYTEmark* Native Mode Benchmark ver. 2 (10/95)
Index-split by Andrew D. Balsa (11/97)
Linux/Unix* port by Uwe F. Mayer (12/96,11/97)&lt;/code&gt;

&lt;code&gt;TEST                : Iterations/sec.  : Old Index   : New Index
                    :                  : Pentium 90* : AMD K6/233*
--------------------:------------------:-------------:------------
NUMERIC SORT        :          818.88  :      21.00  :       6.90
STRING SORT         :           117.4  :      52.46  :       8.12
BITFIELD            :      3.6408e+08  :      62.45  :      13.04
FP EMULATION        :          123.95  :      59.48  :      13.72
FOURIER             :           23156  :      26.33  :      14.79
ASSIGNMENT          :          29.876  :     113.68  :      29.49
IDEA                :          5413.8  :      82.80  :      24.58
HUFFMAN             :          1786.4  :      49.54  :      15.82
NEURAL NET          :          35.209  :      56.56  :      23.79
LU DECOMPOSITION    :          1297.9  :      67.24  :      48.55
==========================ORIGINAL BYTEMARK RESULTS==========================
INTEGER INDEX       : 56.803
FLOATING-POINT INDEX: 46.438
Baseline (MSDOS*)   : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0
==============================LINUX DATA BELOW===============================
CPU                 : 4 CPU GenuineIntel Intel(R) Xeon(R) CPU           L5335  @ 2.00GHz 2000MHz
L2 Cache            : 4096 KB
OS                  : Linux 2.6.18.8-linode16
C compiler          : gcc version 4.3.2 (Debian 4.3.2-1.1)
libc                : libc-2.7.so
MEMORY INDEX        : 14.617
INTEGER INDEX       : 13.852
FLOATING-POINT INDEX: 25.756
Baseline (LINUX)    : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38
* Trademarks are property of their respective holder.&lt;/code&gt;

&lt;/pre&gt;
&lt;p&gt;Performance differences for the Nbench benchmarks may be largely attributed to the difference in processor speed between 2.33 GhZ (Panix) and 2.00 GhZ (Linode). I do know that Linode do continuously and regularly upgrade their hardware, so bear in mind that the above was what I saw on a single instance in May and that things may have moved on since.&lt;/p&gt;
&lt;p&gt;There are some minor ping latency differences between Linode and Panix, but in the case of Linode you can choose which data center you want your &lt;span class="caps"&gt;VPS&lt;/span&gt; to be &lt;a href="http://www.linode.com/forums/viewtopic.php?t=2636"&gt;hosted in&lt;/a&gt;. Often ping differences are more an accident of geography and network topology; I have been led to believe though that it makes sense that if you&amp;#8217;re in South Africa, or Europe to try and use a data center on the upper East Coast to reduce the number of network hops. A friend in the UK had an average ping time to the Linode data center in Newark of 90 ms which seemed to be 40-50 ms faster than the Linode data center in Dallas that I used. Conversely, in my limited testing from Cape Town, I recorded an average ping time to Linode Dallas of 386-400 ms but to Panix in New York it was 432-433 ms (proving nothing really other than that South African &lt;span class="caps"&gt;ADSL&lt;/span&gt; is pretty awful!).&lt;/p&gt;
&lt;p&gt;If performance is not your sole reason for choosing a &lt;span class="caps"&gt;VPS&lt;/span&gt; provider then Linode has got a lot going for it with the Linode control panel which is by far the best way to control your &lt;span class="caps"&gt;VPS&lt;/span&gt;. With Linode, I was able to shrink disk images, expand disk images and clone disk images, all of which is useful for making backups. The Panix interface is a lot simpler, and only options to create or destroy images are provided. But, keeping to the topic of backups, Linode &lt;a href="http://www.linode.com/faq.cfm"&gt;do not backup your &lt;span class="caps"&gt;VPS&lt;/span&gt; for you&lt;/a&gt; (RAID10 aside) whereas Panix offers a &lt;a href="http://www.panix.com/corp/v-colo/vfaq.html#rsync"&gt;free rsync backup&lt;/a&gt;. The Linode backup service is currently in &lt;a href="http://www.linode.com/forums/viewtopic.php?t=4067"&gt;Beta&lt;/a&gt; &amp;#8211; it looks like it&amp;#8217;ll cost you about $5 per month for the Linode plan I was on, but it is &lt;a href="http://www.linode.com/forums/viewtopic.php?t=4433"&gt;worth&lt;/a&gt; &lt;a href="http://www.linode.com/forums/viewtopic.php?t=4316"&gt;it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you like &lt;span class="caps"&gt;BSD&lt;/span&gt; it is important to note that Panix provide disk images for FreeBSD and NetBSD guests, whereas Linode only offers Linux guests. BSDs are possible with Linode, but seem to be more &lt;a href="http://www.linode.com/wiki/index.php/BSD_Howto"&gt;experimental at this moment in time&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/jxrki1AUxrM" height="1" width="1"/&gt;</description>
      <pubDate>Mon, 23 Nov 2009 11:49:01 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/14</guid>
      <dc:date>2009-11-23T11:49:01.790695+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/14</feedburner:origLink></item>
    <item>
      <title>The Time Traveler's Wife</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/rEU3B1F1exY/13</link>
      <description>&lt;p&gt;&lt;img src="http://www.bloggroll.com/stat/time_travelers_wife.jpg" class="l" alt="" /&gt;I&amp;#8217;ve been quite taken by the Time Traveler&amp;#8217;s Wife (The novel by Audrey Niffenegger). Which is why I&amp;#8217;m writing this post &amp;#8211; the film adaptation of the book has left me with a hollowness inside that the book did not have, even though I so enjoyed the film. So herewith my first blog film review. &lt;strong&gt;&lt;em&gt;&lt;span class="caps"&gt;DISCLAIMER&lt;/span&gt;&lt;/em&gt;: &lt;span class="caps"&gt;PLOT&lt;/span&gt; &lt;span class="caps"&gt;AND&lt;/span&gt; &lt;span class="caps"&gt;FILM&lt;/span&gt; &lt;span class="caps"&gt;SPOILERS&lt;/span&gt; TO &lt;span class="caps"&gt;FOLLOW&lt;/span&gt;&lt;/strong&gt;, please do stop reading if you ever intend to read the book or see the film. My recommendation is to read the book first.&lt;/p&gt;&lt;p&gt;According to Wikipedia, Niffenegger wrote the book as a &amp;#8220;metaphor&amp;#8221; for her &lt;a href="http://en.wikipedia.org/wiki/The_Time_Traveler%27s_Wife"&gt;own failed relationships&lt;/a&gt;. Out of which came what aspires to be a heady love story mixed with science-fiction. Not since Marge Piercy&amp;#8217;s &lt;a href="http://en.wikipedia.org/wiki/He,_She_and_It"&gt;Body of Glass&lt;/a&gt; has such a blend of the realistic and fantastical appealed to me in the same way. When reading the book, I kept on thinking to myself &amp;#8220;I wish I could have thought of this story myself&amp;#8221; and &amp;#8220;I wish that I could write like this!&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Niffenegger&amp;#8217;s Henry suffers from an involuntary genetic condition which causes him to spontaneously time travel to places and people in his life. Although Henry has no control of destination (or much else in his existence), the destination is not completely random and is often as a result of Henry&amp;#8217;s unconscious yearnings.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s an ambitious theme to follow &amp;#8211; and such a romantic one at that &amp;#8211; when Clare meets Henry for the first time as an adult at the age of 22 she&amp;#8217;s known him on and off since she was 6 and has an unquestioning certainty of their love. Henry at the age of 28 however has never met her before. It should be completely unfair to Clare, who after all never did have an opportunity up until then to meet Henry as an equal but only as a mysterious adult. It is unfair to Henry too, but it will be an older Henry who later on will go back in time and who will eventually meet up with (and finally seduce) the younger Clare. The book downplays the seductive element of it &amp;#8211; Henry is given a free pass here as he lives in a deterministic universe where he is unable to change the flow of time or to alter outcomes. Or at least that would have to have been the defense in a court of law &amp;#8220;your honour, I couldn&amp;#8217;t help myself&amp;#8221;. I guess one should lift a little scepticism here and just believe that it is all for the good, financial and otherwise, which is what I did and I thoroughly enjoyed reading the book. In many ways it strives to be the ultimate love story &amp;#8211; in this universe it is as simple as the fact that Henry and Clare will love each other for who they are intrinsically, regardless of their lack of shared personal history or shared personal time line, and it is as if their love has been pre-written in the book of time.&lt;/p&gt;
&lt;p&gt;The film starts by covering the scene in the book where Henry&amp;#8217;s mother dies in a car crash. It&amp;#8217;s a good starting point for the story-translated-to-script. But other choices made to translate the book into the film, although essential, feel like an amputation of the book. Characters are eliminated &lt;em&gt;en mass&lt;/em&gt; (including all the black characters in the book, which I guess is not too much of a bad thing as they&amp;#8217;re all servants except for the token Lesbian &amp;#8211; hey we&amp;#8217;re all equal opportunity discriminatory). One of the things that I was looking forward to from reading the book is seeing what the real world &lt;a href="http://en.wikipedia.org/wiki/Newberry_Library"&gt;Newberry  Library&lt;/a&gt; looks like (Henry works there as a librarian, and it is lovingly described throughout the book). But although I got to see the inside of a library (and maybe the outside too, I may have missed it!) I&amp;#8217;m not sure if it was the actual library itself, and I never got to see &amp;#8220;the cage&amp;#8221; in the library &amp;#8211; a meshed-in stairwell where Henry gets trapped due to his time travelling. The cage is such a strong visual metaphor, and I couldn&amp;#8217;t help but feel that the writer of the screenplay thought it might be too strong an image for his audience. And therein lies the rub. The film has been cleansed and sanitized. It almost feels like the book was rushed too quickly into a movie, or perhaps, and this is my own bias showing, a director of the European school &lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;may have been sensitive to which cuts were kind to the story, and which were unnecessarily kind to an audience deemed too sensitive to see the amputation of Henry&amp;#8217;s feet.&lt;/p&gt;
&lt;p&gt;I loved Rachel McAdams in &amp;#8220;The Notebook&amp;#8221; but in this movie she fell short of my own expectations of Clare. She was great, in a beautiful almost Angelina Jolie like way, and her character carried loads of emotional depth and a sort of unforgettable &amp;#8220;shimmer&amp;#8221; on screen, similar to her portrayal of Allie in &lt;a href="http://en.wikipedia.org/wiki/The_Notebook_(film)"&gt;The Notebook&lt;/a&gt;. She just was different to what I was expecting of a Clare, perhaps due to my own misreading of the character. On the other hand, there are some scenes in the movie that for me personally had a far higher emotional impact when seen on celluloid than when read in the book. And I&amp;#8217;m thinking here of the scene where Henry meets his daughter for the first time and learns of his own death. What a tear jerker, I don&amp;#8217;t know if it&amp;#8217;s my own personal childhood losses that are being triggered here, or if I was being taken in by the universal chick flick. It could also be that the character of the 10 year old Alba so strongly reminds me, and I&amp;#8217;m sure many others, of our need to protect our children from the uncertainties of life.&lt;/p&gt;
&lt;p&gt;Perhaps the unkindest cut of all was the changing of the ending. In &lt;a href="http://en.wikipedia.org/wiki/Titanic_(1997_film)"&gt;The Titanic&lt;/a&gt; James Cameron fished together a mystical final scene where the protagonists are reunited after death. Hollywood is quite capable of appending its own version of a satisfying ending to a story of disaster and tragedy. Niffenegger&amp;#8217;s book too has its similar anchoring final chapter where an old Clare living alone is visited one last time by her &amp;#8220;late&amp;#8221; husband Henry as a much younger man. Inexplicably this too was removed from the movie, and replaced with a scene where Henry and Clare get to say good bye to each other at an earlier stage. Satisfying, sure, after all there is no long waiting suspenseful period, but it is somehow without the intensity and poignancy of the original.&lt;/p&gt;
&lt;p&gt;What are your thoughts on the transition from book to film? Anything that you need to process about this film or book? Please &lt;a href="http://www.bloggroll.com/view/13#comments"&gt;comment&lt;/a&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; The director Robert Schwentke is German, but is also Hollywood trained&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/rEU3B1F1exY" height="1" width="1"/&gt;</description>
      <pubDate>Sat, 12 Sep 2009 22:19:35 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/13</guid>
      <dc:date>2009-09-12T22:19:35.04396+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/13</feedburner:origLink></item>
    <item>
      <title>Why begone :-(</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/jNWPEWvxJNI/12</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/jelly.jpg" class="r" alt="" /&gt;I&amp;#8217;ve been quite shocked and saddened by the &lt;a href="http://ejohn.org/blog/eulogy-to-_why/"&gt;online disappearance&lt;/a&gt; of &lt;a href="http://en.wikipedia.org/wiki/Why_the_lucky_stiff"&gt;why the lucky stiff&lt;/a&gt; last week. Heck, the blogging engine for this site is written to make use of his micro web framework &amp;#8211; &lt;a href="http://github.com/judofyr/camping"&gt;camping&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;_why wrote (writes!! we await the second coming) some of the more interesting ruby code out there. And he also wasn&amp;#8217;t afraid to write things that were quite out there &amp;#8211; on the borderland between programming and art. One of his creations was called &lt;a href="/stat/blimlimb.rb"&gt;blimlimb&lt;/a&gt; (the code is still around, but I fear some of the blimlimb scripts and repository history is lost). Imagine this, you&amp;#8217;re sitting in a peaceful &lt;span class="caps"&gt;IRC&lt;/span&gt; channel and all of a sudden a whole troupe of bot actors appear in channel. They start performing a play for you, complete with actions and appropriate dramatic pauses. And the weird part is that the bot puppetmaster can also add a bit of improvisational scripting to spook those in channel further.&lt;/p&gt;&lt;p&gt;Unsurprisingly (knowing the delicate nature of &lt;span class="caps"&gt;IRC&lt;/span&gt; in-tractions) blimlimb was poorly received! I don&amp;#8217;t think it was a case of &amp;#8220;the implementation lacketh much&amp;#8221; but rather that the blimlimb works themselves were directed towards the wrong audience.&lt;/p&gt;
&lt;p&gt;I wrote a blimlimb script too, but have always been too scared to present it. It was destined to have been run in #clug (the Cape Town Linux Users group channel on the Atrum network) and featured pseudonymous appearances by some of the denizens of that darkened pit. The intention was to advertise the appearance of a new version of &lt;a href="http://www.github.com/eyesonly/irbie"&gt;irbie&lt;/a&gt;, my &lt;span class="caps"&gt;IRC&lt;/span&gt; bot, that was now able to do two new things &amp;#8211; it could now parse python code and had an intelligence engine added so that irbie could interact as if it were an &lt;span class="caps"&gt;ELISA&lt;/span&gt; robot. My apologies to Mary Shelley and all those mentioned (and not mentioned), herewith is presented the lost blimlimb script of #clug:&lt;/p&gt;
&lt;pre&gt;
[a] aizonli
(a) Cough. Announcement time. Will take about 5 mins.
[v] viatta
v: All names are changed to protect the *innocent*
[w] woozy
[m] MrKkkkkkkkkken
[y] MythRandy
[s] humblesteed
w: http://www.zimbabwesituation.com/
m: innocent? did someone mention my name?
a: Hmmm... everyone seems to be too much in character, lets go with the Frakenstein theme now
v=VictorFrankenstein
a=TheMonster
m: Oh all right, I'll be Igor...
m=Igor
m: Yess master
a: Well there once was a poor misunderstood bot, called...
m: Monster?
a: No, Irbie
[f] LordoftheFlies
(f) /kill irbie
a: too much in _character_ again :-(
(f) goes back to the bovines
-f
a: Who needed a makeover.
w: or a personality?
[i] influence
[c] cocochanel
[h] hodgepodge
[j] jermy
c: fp
j: Spinasie: choose Erlang or Ruby\ to go with my chunky bacon
(a) Cue lightning. Loud scary noises.
y: As a child, I thought I could live without pain,without sorrow
(w) straps Monster to the lab-bench
m: Looks like irbie, although noone really knows what he looks like
[p] pipecleaner
(p) threatens irbie with the leadpipe
p=irby
(p) starts speaking parseltongue
a: Or for the humans among you irbie now evals python
a: (Smoke and mirrors, of course)
a: and just like the python shell anything starting with &amp;gt;&amp;gt;&amp;gt; gets evaluated
v: Of course, the monster still can speak Japanese?
a: Yes, that's a double chevron &amp;gt;&amp;gt; , as before
w: What about personality?
a: Well, hopefully the lightning worked. How about addressing irbie directly?
v: Message delivered, can we go back to being ourselves?
a: kbye
-h
s: k...
-i
c: ...bye. Darn too late again.
-j
-a
-v
-w
-m
-y
-s
&lt;/pre&gt;
&lt;p&gt;Of course, _why&amp;#8217;s withdrawal from the world means that irbie is currently broken. It used to use _why&amp;#8217;s &amp;#8220;TryRuby&amp;#8221; website to parse ruby code, so you won&amp;#8217;t see it in channel at the moment.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/jNWPEWvxJNI" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 26 Aug 2009 15:10:20 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/12</guid>
      <dc:date>2009-08-26T15:10:20.125669+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/12</feedburner:origLink></item>
    <item>
      <title>Max DB log is full - SAP NW 2004S TestDrive for Linux</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/MQGZjQsNjys/11</link>
      <description>&lt;p&gt;&lt;img src="http://bloggroll.com/stat/sap.png" class="l" alt="" /&gt;A short while back I downloaded and installed the &lt;a href="https://www.sdn.sap.com/irj/scn/nw-downloads"&gt;&lt;span class="caps"&gt;SAP&lt;/span&gt; NetWeaver 2004S TestDrive&lt;/a&gt; &lt;span class="caps"&gt;SAP&lt;/span&gt; system (running on my Atom! machine at home). This provided me with my own (90-day licensed) basic &lt;span class="caps"&gt;SAP&lt;/span&gt; R/3 system which, according to the documentation, includes both &lt;span class="caps"&gt;ABAP&lt;/span&gt; and Java stacks running on SAP&amp;#8217;s own database Max DB.&lt;/p&gt;
&lt;p&gt;One of the issues that this system is prone to is that the Max DB log gets full (there is no default log cycling). It is quite a well known issue and is even described on the &lt;a href="http://www.sdn.sap.com/irj/sdn/linux?rid=/webcontent/uuid/60981e8e-1183-2a10-9d8a-956eb74f5492"&gt;&lt;span class="caps"&gt;SAP&lt;/span&gt; on Linux: Test Drives &amp;#8211; Tips and Tricks &lt;span class="caps"&gt;FAQ&lt;/span&gt;&lt;/a&gt; . In my case, I encountered this issue after running an &lt;span class="caps"&gt;SGEN&lt;/span&gt; job to generate all the basis components on the system. I could log into the &lt;span class="caps"&gt;SAP&lt;/span&gt; system, but the &lt;span class="caps"&gt;GUI&lt;/span&gt; froze before anything useful came up. Trying to run stopsap, it hung forever at the checking database step (where it runs R3trans d).&lt;/p&gt;
&lt;p&gt;Looking in knldiag, I knew I had a full log problem because of this message:&lt;/p&gt;
&lt;pre&gt;2009-07-17 10:38:54    21 WNG 20001 KernelDB  99 percent of log area occupied, 126717 pages used
&lt;/pre&gt;&lt;p&gt;What one should do in this case is use one of the database management tools (either dbmgui or dbmcli) to clear the log area. However, no matter which &amp;#8220;database owner&amp;#8221; username and password I tried, I could not gain access to administer the database, and others &lt;a href="https://forums.sdn.sap.com/thread.jspa?tstart=0&amp;amp;threadID=424386"&gt;have experienced the same problem too&lt;/a&gt; . In other words, I was trying something like this:&lt;/p&gt;
&lt;pre&gt;dbmcli -u some_username,some_password -d N4S util_execute set log auto overwrite on&lt;/pre&gt;
&lt;p&gt;but was receiving this error message:&lt;/p&gt;
&lt;pre&gt;Error! Connection failed to node (local) for database N4S: ERR_USRFAIL: User authorization failed&lt;/pre&gt;
&lt;p&gt;Luckily that &lt;a href="https://forums.sdn.sap.com/thread.jspa?tstart=0&amp;amp;threadID=424386"&gt;same &lt;span class="caps"&gt;SDN&lt;/span&gt; page&lt;/a&gt; described another means by which I could authenticate in order to perform database management.  Philip Kisloff mentioned that it is possible to connect using&lt;/p&gt;
&lt;pre&gt;dbmcli -U c&lt;/pre&gt;
&lt;p&gt;instead of&lt;/p&gt;
&lt;pre&gt;dbmcli -u some_username,some_password&lt;/pre&gt;
&lt;p&gt;(For the record, his method works for me when logged on as the n4sadm user, which did have a .&lt;span class="caps"&gt;XUSER&lt;/span&gt;.62 file in ~/&lt;br /&gt;
This .XUSER62 file was created by the TestDrive install script).&lt;/p&gt;
&lt;p&gt;The log was cleared by issuing the following as n4sadm (originally obtained from this &lt;a href="https://forums.sdn.sap.com/message.jspa?messageID=5654486"&gt;forum thread&lt;/a&gt; ):&lt;/p&gt;
&lt;pre&gt;dbmcli -U c -d N4S db_admin
dbmcli -U c -d N4S util_connect
dbmcli -U c -d N4S util_execute clear log
dbmcli -U c -d N4S db_online&lt;/pre&gt;
&lt;p&gt;These steps should be performed on a stopped &lt;span class="caps"&gt;SAP&lt;/span&gt; system. If you can&amp;#8217;t stop the &lt;span class="caps"&gt;SAP&lt;/span&gt; system since stopsap will stall with a full log &amp;#8211; then the first step of the above will take the database offline and will allow you to run stopsap to completion. &lt;strong&gt;BE &lt;span class="caps"&gt;AWARE&lt;/span&gt;&lt;/strong&gt; that you&amp;#8217;re deleting all log information &amp;#8211; in my case I wasn&amp;#8217;t too worried as I could just reinstall the testdrive system, but you must be warned that this could be risky.&lt;/p&gt;
&lt;p&gt;To prevent future overflow of the log the following can be used:&lt;/p&gt;
&lt;pre&gt;dbmcli -U c -d N4S util_execute set log auto overwrite on&lt;/pre&gt;
&lt;p&gt;This is also not without risk. As &lt;span class="caps"&gt;SAP&lt;/span&gt; put it on &lt;a href="http://www.sdn.sap.com/irj/sdn/linux?rid=/webcontent/uuid/60981e8e-1183-2a10-9d8a-956eb74f5492"&gt;this page&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Please note: With this setting, the database will overwrite its logs circularly, so the database will be unable to recover, if the &lt;span class="caps"&gt;DATA&lt;/span&gt; volume crashed. When developing a lot with the TestDrive, doing a backup or increasing the &lt;span class="caps"&gt;LOG&lt;/span&gt; volume would be a better solution.&lt;/p&gt;
&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/MQGZjQsNjys" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 17 Jul 2009 13:36:26 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/11</guid>
      <dc:date>2009-07-17T13:36:26.233184+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/11</feedburner:origLink></item>
    <item>
      <title>Evaluate python from ruby</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/o5I609X4T3A/5</link>
      <description>&lt;p&gt;The newest version of my &lt;span class="caps"&gt;IRC&lt;/span&gt; bot, &lt;a href="http://github.com/eyesonly/irbie/tree/master"&gt;irbie&lt;/a&gt; is able to evaluate python code in channel and respond with the output.&lt;/p&gt;
&lt;p&gt;It does this in only 33 lines of &lt;span class="caps"&gt;RUBY&lt;/span&gt; code.&lt;/p&gt;&lt;pre&gt;&lt;span class="comment-delimiter-face-0000"&gt;#&lt;/span&gt;&lt;span class="comment-face-0001"&gt;!/usr/bin/env ruby
&lt;/span&gt;require &lt;span class="string-face-0002"&gt;'rubygems'&lt;/span&gt;
require &lt;span class="string-face-0002"&gt;'mechanize'&lt;/span&gt;

&lt;span class="keyword-face-0003"&gt;class&lt;/span&gt; &lt;span class="type-face-0004"&gt;Sacrilege&lt;/span&gt;


  &lt;span class="keyword-face-0003"&gt;def&lt;/span&gt; &lt;span class="function-name-face-0005"&gt;initialize&lt;/span&gt;
    &lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt; = &lt;span class="type-face-0004"&gt;Array&lt;/span&gt;.new
    &lt;span class="variable-name-face-0006"&gt;@agent&lt;/span&gt; = &lt;span class="type-face-0004"&gt;WWW::Mechanize&lt;/span&gt;.new
    &lt;span class="variable-name-face-0006"&gt;@agent&lt;/span&gt;.user_agent_alias = &lt;span class="string-face-0002"&gt;'Linux Mozilla'&lt;/span&gt;

    page = &lt;span class="variable-name-face-0006"&gt;@agent&lt;/span&gt;.get(&lt;span class="string-face-0002"&gt;'http:&lt;/span&gt;&lt;span class="string-face-0002"&gt;/&lt;/span&gt;&lt;span class="string-face-0002"&gt;/&lt;/span&gt;&lt;span class="string-face-0002"&gt;shell.appspot.com/'&lt;/span&gt;)
    &lt;span class="variable-name-face-0006"&gt;@form&lt;/span&gt; = page.forms[0]
  &lt;span class="keyword-face-0003"&gt;end&lt;/span&gt;

  &lt;span class="keyword-face-0003"&gt;def&lt;/span&gt; &lt;span class="function-name-face-0005"&gt;eval&lt;/span&gt;(msg)
    &lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt;.push(msg) &lt;span class="keyword-face-0003"&gt;if&lt;/span&gt; ( msg =~ &lt;span class="string-face-0002"&gt;/&lt;/span&gt;&lt;span class="string-face-0002"&gt;:$&lt;/span&gt;&lt;span class="string-face-0002"&gt;/&lt;/span&gt; || !(&lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt;.empty?))
    &lt;span class="keyword-face-0003"&gt;if&lt;/span&gt; msg == &lt;span class="variable-name-face-0006"&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; !(&lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt;.empty?)
      set(&lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt;.join(&lt;span class="string-face-0002"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;) + &lt;span class="string-face-0002"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;)
      &lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt;.clear
      page = &lt;span class="variable-name-face-0006"&gt;@agent&lt;/span&gt;.submit(&lt;span class="variable-name-face-0006"&gt;@form&lt;/span&gt;)
    &lt;span class="keyword-face-0003"&gt;elsif&lt;/span&gt; &lt;span class="variable-name-face-0006"&gt;@code_stack&lt;/span&gt;.empty?
      set(msg)
      page = &lt;span class="variable-name-face-0006"&gt;@agent&lt;/span&gt;.submit(&lt;span class="variable-name-face-0006"&gt;@form&lt;/span&gt;)
    &lt;span class="keyword-face-0003"&gt;end&lt;/span&gt;

    &lt;span class="keyword-face-0003"&gt;return&lt;/span&gt; page.body.split(&lt;span class="string-face-0002"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;).slice(0, 15) &lt;span class="keyword-face-0003"&gt;if&lt;/span&gt; page
    []
  &lt;span class="keyword-face-0003"&gt;end&lt;/span&gt;

  &lt;span class="keyword-face-0003"&gt;def&lt;/span&gt; &lt;span class="function-name-face-0005"&gt;set&lt;/span&gt;(val)
    &lt;span class="variable-name-face-0006"&gt;@form&lt;/span&gt;.fields.find{|f| f.name == &lt;span class="string-face-0002"&gt;'statement'&lt;/span&gt; }.value = val
  &lt;span class="keyword-face-0003"&gt;end&lt;/span&gt;


&lt;span class="keyword-face-0003"&gt;end&lt;/span&gt;&lt;span class="keyword-face-0003"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Of course, as with everything irbie does it&amp;#8217;s smoke and mirrors. I just call it efficient use of webservices.&lt;/p&gt;
&lt;p&gt;If you haven&amp;#8217;t used mechanize before, it&amp;#8217;s also a good advert for mechanize, which, by the way, has been ported to many other languages. Python included.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/o5I609X4T3A" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 01 Jul 2009 15:02:34 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/5</guid>
      <dc:date>2009-07-01T15:02:34.581205+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/5</feedburner:origLink></item>
    <item>
      <title>Targeted AIDS advertising</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/PgmOVn1vJps/4</link>
      <description>&lt;p&gt;&lt;img src="/stat/cemetery.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;(Sign seen at the Bellville cemetery) No camping, no cars, no &lt;span class="caps"&gt;HIV&lt;/span&gt;&amp;#8230;&lt;/p&gt;
&lt;p&gt;This is the most directly targeted &lt;span class="caps"&gt;HIV&lt;/span&gt;/&lt;span class="caps"&gt;AIDS&lt;/span&gt; campaign that I have seen thus far, but I&amp;#8217;m afraid it may be a little too late.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/PgmOVn1vJps" height="1" width="1"/&gt;</description>
      <pubDate>Sat, 27 Jun 2009 13:58:18 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/4</guid>
      <dc:date>2009-06-27T13:58:18.300248+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/4</feedburner:origLink></item>
    <item>
      <title>Seek within long podcasts on your car stereo</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/qjDBbGSbzJ4/3</link>
      <description>&lt;p&gt;&lt;img src="/stat/mp3seeksmall.jpg" class="l" alt="" /&gt;Seek and ye shall find&amp;#8230;&lt;/p&gt;
&lt;p&gt;My car stereo (a &lt;span class="caps"&gt;JVC&lt;/span&gt; that accepts &lt;span class="caps"&gt;USB&lt;/span&gt; thumb drives) is really slow at seeking to a specific position in long audio files [To be fair regarding long seek times, the &lt;span class="caps"&gt;JVC&lt;/span&gt; does seek faster off a &lt;span class="caps"&gt;CDR&lt;/span&gt; disk. However, it&amp;#8217;s not much faster and then you&amp;#8217;re left with a pile of disks that have been played only once.]. So, if you loose your place in a long podcast (e.g. the kids want to listen to something) you can spend up to 15 minutes holding down the fast forward button just to find your place again. It also jumbles up the play sequence for all the audio files within a folder. Both problems can be easily solved on the computer or when you put the audio files onto the &lt;span class="caps"&gt;USB&lt;/span&gt; drive.&lt;/p&gt;&lt;p&gt;My solution to the first problem is to split the audio file into multiple files, each file being 5 minutes long. &lt;a href="http://mp3splt.sourceforge.net/mp3splt_page/home.php"&gt;mp3splt&lt;/a&gt; is a free utility that splits mp3 or ogg files &lt;strong&gt;without decoding&lt;/strong&gt; the file into another format first, so there is no lossy decryption and encryption step. It is also pretty neat in that mp3splt tries to split on silent areas of the file (in between words), and the newer versions can preserve the ID3 tags within the file.&lt;/p&gt;
&lt;p&gt;Here is the incantation that I&amp;#8217;ve worked out to call mp3splt:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mp3splt -g %[@o,@N=1] -t 5.00 -a -o @n_@t YOUR_AUDIO_FILENAME&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A brief explanation of the various command line switches:&lt;/p&gt;
&lt;table id="fancy"&gt;
	&lt;tr&gt;
		&lt;th&gt;switch&lt;/th&gt;
		&lt;th&gt;explanation&lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;-g      %[@o,@N=1]   &lt;/td&gt;
		&lt;td&gt;set custom tags on the split files where @o = set original tags; @N=1 auto increment track number&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;-t 5.00&lt;/td&gt;
		&lt;td&gt;split file into five minute chunks&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;-a&lt;/td&gt;
		&lt;td&gt;use auto-adjust silence detection&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;-o @n_@t&lt;/td&gt;
		&lt;td&gt;output filename format @n = track number; @t = title&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Note that the &amp;#8216;-g&amp;#8217; clause of the above was not available from the Debian Lenny repository version of mp3splt (that version is very old).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Optional extra: On &lt;span class="caps"&gt;BSD&lt;/span&gt;/Unix/Linux systems instead of remembering that whole string,  I would recommend putting the above incantation line into a file with executable permissions in the /bin folder called say /bin/mp3s. Replace the YOUR_AUDIO_FILE part with $1. So you could then easily split an audio file called SOME_FILE simply by typing: &lt;code&gt;mp3s SOME_FILE&lt;/code&gt; and it&amp;#8217;s not necessary to remember the complex switches as above.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The solution to the second problem (scrambled audio files within a folder) where files seem to be playing in some random order is really trivial. It seems that windows users have never encountered the problem because when they copy an entire folder to the &lt;span class="caps"&gt;USB&lt;/span&gt; drive, the file modification information is in the same sequence as the filenames. For instance, if a windows user were to copy a folder with three tracks in it&lt;/p&gt;
&lt;pre&gt;
track01.ogg
track02.ogg
track03.ogg
&lt;/pre&gt;
&lt;p&gt;to the &lt;span class="caps"&gt;USB&lt;/span&gt; disk the top file would be the oldest one and the bottom file would be the youngest one. If you did the same thing on a Linux workstation, say by copying a folder with&lt;/p&gt;
&lt;pre&gt;
cp -r somefolder /mnt/usb/
&lt;/pre&gt;
&lt;p&gt;The bottom file from the list might not necessarily be the youngest one (in other words the file modification time is not in the same sequence as the alphabetical sequence). The solution is really trivial, copy your files like this:&lt;/p&gt;
&lt;pre&gt;
cp somefolder/* /mnt/usb/somefolder/
&lt;/pre&gt;
&lt;p&gt;The asterisk (*) gets expanded by the shell to a file list in the same order as you see when you list your files sorted by filename.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/qjDBbGSbzJ4" height="1" width="1"/&gt;</description>
      <pubDate>Sat, 27 Jun 2009 13:44:06 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/3</guid>
      <dc:date>2009-06-27T13:44:06.823552+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/3</feedburner:origLink></item>
    <item>
      <title>Gitosis on Debian Lenny</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/fyQWuleaSJY/2</link>
      <description>&lt;p&gt;No, not &lt;a href="http://en.wikipedia.org/wiki/Halitosis"&gt;halitosis&lt;/a&gt; !&lt;br /&gt;
&lt;img src="/stat/giraffe.jpg" class="r" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;There are many wonderful public git repositories out there &amp;#8211; like &lt;a href="http://github.com/"&gt;github&lt;/a&gt;, of course, and &lt;a href="http://gitorious.org/"&gt;gitorious&lt;/a&gt; (pity they didn&amp;#8217;t seem to be able to find a sexual pun in that name!). But they don&amp;#8217;t offer you a free &lt;em&gt;private&lt;/em&gt; repository where you can store the code that you&amp;#8217;re not particularly proud of or don&amp;#8217;t wish to release into the public domain, etc. However, if you have a public facing internet host, or just about any ssh accessible box you can easily setup gitosis to create a private repository that is world accessible.&lt;/p&gt;&lt;p&gt;When I first looked at setting up my own private git repository, I looked at running git as a daemon, and in fact there is an Ubuntu/Debian package called git-daemon-run for that purpose. But it&amp;#8217;s overkill for a private repo only going to be used by yourself, or yourself and your development team. Also, it seems from my limited research that git-daemon is most useful for providing read-only access in much the same way that github provides public clone URLs. If you do decide you need git-daemon, this article looks like it may be helpful, especially when it comes to &lt;a href="http://escapegoat.org/2009/5/20/git-gitweb-gitosis-and-git-daemon-in-harmony-on-debian"&gt;integrating git-daemon with gitosis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Gitosis steps neatly around the need to have yet another permanently running daemon (so there is one less permanently available server process that may be compromised by an attacker). What it does is create its own gitosis user (also called &amp;#8216;gitosis&amp;#8217; on Debian) with access to the git repository being through ssh private/public key transfers as that user. It is not possible to ssh to a shell prompt as that user, it is all automatically controlled. And another neat gitosis feature is that configuration is all done through git itself. One clones the gitosis configuration repository from the server, alters the configuration files on one&amp;#8217;s own workstation, and then simply git pushes the configuration back to the server. Really neat!&lt;/p&gt;
&lt;p&gt;I found a really good tutorial covering gitosis at &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;scie.nti.st&lt;/a&gt;. However, it really isn&amp;#8217;t Debian Lenny specific so that&amp;#8217;s why I&amp;#8217;m going to add a few extra notes here. From my usage on Lenny, the Debian supplied gitosis package is stable. So, my recommendation is to rather use the Debian supplied version, and skip the git-clone/compiling/dependancy parts of the scie.nti.st tutorial. The next big difference by doing things the Debian-way is that the user created for gitosis is called &amp;#8216;gitosis&amp;#8217; and not &amp;#8216;git&amp;#8217;. So, after installing the gitosis package, the next thing you&amp;#8217;ll need to do is become root and then su to the gitosis user which would have been automatically created for you. Then, as gitois issue a:&lt;/p&gt;
&lt;pre&gt;
gitosis-init &amp;lt; /path_to/id_rsa.pub
&lt;/pre&gt;
&lt;p&gt;where id_rsa.pub is the public &lt;span class="caps"&gt;SSH&lt;/span&gt; key from your workstation user that you&amp;#8217;ve previously copied to the server. Make sure that the path to the public key file is accessible by the gitosis user.&lt;/p&gt;
&lt;p&gt;And then, because you&amp;#8217;ve initialized the gitosis configurarion with your public key, from your regular workstation, all you&amp;#8217;ll need to do is issue a:&lt;/p&gt;
&lt;pre&gt;
git clone gitosis@YOUR_SERVER_HOSTNAME:gitosis-admin.git
&lt;/pre&gt;
&lt;p&gt;and git will pull all the configuration files for gitosis to your local workstation! Obviously choose which workstation you&amp;#8217;re going to be using wisely &amp;#8211; for instance don&amp;#8217;t choose your workstation at work, thinking you can complete the rest of the configuration after hours &amp;#8211; until you&amp;#8217;ve added other administrators to the gitosis-admin repository you&amp;#8217;ll need access to the initial workstation and user account.&lt;/p&gt;
&lt;p&gt;The rest of the scie.nti.st tutorial is straight forward, because after that you&amp;#8217;ll need to create new repositories and add users to those repositories.&lt;/p&gt;
&lt;p&gt;One gotcha: for the users that I was adding to the repositories, I initially transferred the public keys of all of these users to the server, and not to the initial workstation. You don&amp;#8217;t add new users on the server (&lt;strong&gt;DO &lt;span class="caps"&gt;NOT&lt;/span&gt;&lt;/strong&gt; append to the public keys in the gitosis ~/.ssh/known_keys file on the server). In fact you&amp;#8217;re &lt;strong&gt;&lt;span class="caps"&gt;NOT&lt;/span&gt;&lt;/strong&gt; meant to configure gitosis further on the server. You do it on the first workstation that has got the cloned gitosis-admin repository by &amp;#8216;git add&amp;#8217;ing the users public keys and configuration there and then &amp;#8216;git push&amp;#8217;ing to the server. It&amp;#8217;s really simple, just slightly different to the way most of us are used to working.&lt;/p&gt;
&lt;p&gt;Oh and another gotcha!: I use a non-standard port for ssh to my server. So, instead of using port 22 to ssh into that host I use port 443. I couldn&amp;#8217;t find an obvious way to tell git to use a different port, but it is no problem really as you can tell ssh to use port 443 by putting the following in ~/.ssh/config:&lt;/p&gt;
&lt;pre&gt;
host  YOUR_SERVER_HOSTNAME
        Port 443
&lt;/pre&gt;
&lt;p&gt;All in all though, gitosis is a really neat idea, and it works well for the creation of private git repositories.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/fyQWuleaSJY" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 04 Jun 2009 15:56:19 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/2</guid>
      <dc:date>2009-06-04T15:56:19.407601+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/2</feedburner:origLink></item>
    <item>
      <title>Welcome to my new blog</title>
      <link>http://feedproxy.google.com/~r/Bloggroll/~3/GYDazbtQrwY/1</link>
      <description>&lt;p&gt;&lt;img src="/stat/doggy.jpg" class="r" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Welcome to my new blog &amp;#8211; it&amp;#8217;ll have all the sort of interesting &amp;#8216;tech&amp;#8217; &lt;span class="caps"&gt;GNU&lt;/span&gt;/Linux/&lt;span class="caps"&gt;OSS&lt;/span&gt;/Who-abbreviated-this posts that I&amp;#8217;d be most interested in reading about, the odd technical snippet that I&amp;#8217;ve found to be indispensable, and maybe an article or two about plants will creep in here as well. I also give you my word that I will try to only post items of quality here. Although as they say a man&amp;#8217;s word is never done&amp;#8230;.&lt;/p&gt;&lt;p&gt;Expect puns, and other plays. On words. And &lt;del&gt;satire&lt;/del&gt; parody.&lt;/p&gt;
&lt;p&gt;I know it&amp;#8217;s an eccentric, indefensible position to have, but reading other people&amp;#8217;s blogs has made me (1) dislike wordpress and (2) gain the belief that if you&amp;#8217;re writing a technical computer blog and can program, then you should write your own blogging engine. Or at least change wordpress enough so that it doesn&amp;#8217;t feel like wordpress. This blog uses it&amp;#8217;s own custom ruby blogging program written with Camping which I&amp;#8217;ll describe &lt;em&gt;ad nauseum&lt;/em&gt; in a later post.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve got a &lt;strong&gt;lot&lt;/strong&gt; of pent up &amp;#8220;creative&amp;#8221; computer related writing sitting in various text files on my hard drives and now in wiki&amp;#8217;s all over the world. So, as it looks to me now, there will be a whole lot of new technical posts on this blog in the coming months.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Bloggroll/~4/GYDazbtQrwY" height="1" width="1"/&gt;</description>
      <pubDate>Sun, 31 May 2009 14:38:53 +0200</pubDate>
      <guid isPermaLink="false">http://www.bloggroll.com/view/1</guid>
      <dc:date>2009-05-31T14:38:53.306202+02:00</dc:date>
    <feedburner:origLink>http://www.bloggroll.com/view/1</feedburner:origLink></item>
  </channel>
</rss>
