<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4667089059273258490</id><updated>2011-12-22T06:01:28.042-08:00</updated><category term='ruby'/><category term='mex'/><category term='quickies'/><category term='astro'/><category term='diy'/><category term='javascript'/><category term='apple'/><category term='actors'/><category term='programming'/><category term='light'/><category term='music'/><category term='selenium'/><category term='nature'/><category term='language'/><category term='chords'/><category term='art'/><category term='gridcomputing'/><category term='concurrent'/><category term='matlab'/><category term='urban'/><category term='tortoisesvn'/><category term='snark'/><category term='photo'/><category term='css'/><category term='food'/><category term='rails'/><category term='mac'/><category term='theron'/><category term='windows'/><category term='adverts'/><category term='guitar'/><category term='testing'/><category term='data'/><category term='prototype'/><category term='hardware'/><category term='science'/><category term='svn'/><title type='text'>Absurdly Certain</title><subtitle type='html'>Doubt is an unpleasant condition...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>26</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-6207776588878398397</id><published>2011-09-02T16:05:00.048-07:00</published><updated>2011-09-17T17:09:27.915-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theron'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='mex'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='matlab'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrent'/><title type='text'>HOWTO: deploy multithreading on Matlab with the Theron C++ Actors library</title><content type='html'>&lt;em&gt;&lt;strong&gt;Preamble:&lt;/strong&gt; What follows is a HOWTO guide for getting Theron-2.09 multithreaded C++ mex files built on Matlab. For my general musings on Matlab concurrency and Theron, see the &lt;a href="http://absurdlycertain.blogspot.com/2011/09/simpler-concurrent-matlab-programming.html"&gt;previous post&lt;/a&gt;.&lt;/em&gt;

&lt;h2&gt;Building multithreaded Matlab mex files with Theron&lt;/h2&gt;
&lt;p&gt;This was pretty straightforward on the Mac, somewhat tricky but not terrible on Linux.  I don't have any working C++ compiler with Matlab on Windows thanks to absolutely abysmal support from Microsoft and Mathworks (essentially Mathworks only supports Microsoft and Microsoft's compilers are impossible to get installed correctly).  But the notes below may help you get things working on Windows anyway and I added some Windows specific notes at the very bottom.  Before trying to get Theron working, I encourage you to write a simple C++ mex program (maybe a single-threaded version of your planned algorithm) and get it built on Matlab first, to confirm that your system is correctly set up for mex.&lt;/p&gt;

&lt;p&gt;I'm fairly confident most Mac users can get this working.  On Linux I have only tested on 2010 and 2011 64-bit versions of Matlab, and there are reasons to fear that earlier versions may have more trouble working.  Fair warning.&lt;/p&gt;

&lt;a name='more'&gt;&lt;/a&gt;

&lt;h2&gt;Building Theron on Mac or other static mex environments&lt;/h2&gt;

&lt;p&gt;For this discussion, the fundamental difference between Mac and Linux versions of Matlab is how they handle mex compilation.  When you mex a C++ source file on the Mac (confirmed up to Matlab 7.12), the system generates statically linked output (a statically linked executable I think, but it could be a static library; it doesn't really matter).  On Linux, mex generates a shared library instead, which complicates things significantly when your build depends on the boost_thread library (see below).&lt;/p&gt;

&lt;p&gt;For now, let's assume you are on a Mac or some other Matlab system that generates static mex files.  One way to confirm this is to run mex on something simple with the -v option; this will show the gcc or g++ commands that mex is using.  As long as the linking step doesn't include the -shared flag, you're okay.&lt;/p&gt;

&lt;p&gt;In this case, your first step is to follow the getting started instructions on the &lt;a href="http://theron.ashtonmason.net/"&gt;Theron site&lt;/a&gt;: download Theron and build it, linking against your choice of Boost threads library.  If you're not sure whether you have Boost threads installed already, you can try the &lt;tt&gt;locate libboost_thread&lt;/tt&gt; command, possibly after running &lt;tt&gt;sudo updatedb&lt;/tt&gt; if your locate database is out of date.  If you don't have Boost threads already, the simplest way to get it is to use Macports.  Once you have Macports installed, it's as simple as: &lt;tt&gt;sudo port install boost&lt;/tt&gt;.  Currently this gives you a very up-to-date boost version 1.47.&lt;/p&gt;

&lt;p&gt;Theron is currently a little Windows-centric, so you'll need to tweak the makefile a little to get it to build.  Theron author Ashton Mason tells me the next release should make things smoother for Gnu (non-Windows) people.  First, as detailed in the Theron guide, you need to edit the makefile to point to your Boost installation.  If you got Boost from Macports, this will probably look like this:&lt;/p&gt;

&lt;pre class="brush: bash" name="code"&gt;
BOOST_INCLUDE_PATH = /opt/local/include/
BOOST_LIB_PATH = /opt/local/lib/
BOOST_RELEASE_LIB = boost_thread-mt
BOOST_DEBUG_LIB = boost_thread-mt
&lt;/pre&gt;

&lt;p&gt;If you want to be able to run &lt;tt&gt;make clean&lt;/tt&gt; to start over with the build process, I recommend also changing the following lines:&lt;/p&gt;

&lt;pre class="brush: bash" name="code"&gt;RM = rm -f

...

clean:
  ${RM} ${BUILD}$/*.o
  ${RM} ${BUILD}$/*.a
  ${RM} ${BUILD}$/*.ilk
  ${RM} ${BIN}$/*.pdb
  ${RM} ${BIN}$/*.ilk
  ${RM} ${BIN}$/*.exe
  ${RM} ${LIB}$/*.a
  ${RM} ${LIB}$/*.lib
&lt;/pre&gt;

&lt;p&gt;I think that should be it, so go ahead and build.  If you are only planning to use Theron from Matlab you only need the library, so I would use &lt;tt&gt;make library mode=release&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;If all goes well, your build should finish pretty fast and you should now have the &lt;tt&gt;libtheron.a&lt;/tt&gt; library in your &lt;tt&gt;THERONPATH/Lib&lt;/tt&gt; folder.  Now boot up Matlab and try to build a simple mex file.  A Theron test program might look something like:&lt;/p&gt;

&lt;pre name="code" class="brush: cpp"&gt;// theron_test.cpp
#include "mex.h"
#define THERON_USE_BOOST_THREADS 1
#include "Theron/Framework.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  Theron::Framework theron;
}
&lt;/pre&gt;

&lt;p&gt;This looks simple, but actually the call to initialize the Theron Framework involves a fair amount of background stuff getting setup, so it should give you an indication of whether things are working.  To compile this from Matlab, you'll need a little more than a simple &lt;tt&gt;mex theron_test.cpp&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Do not put spaces in any of these mex options; no space after the "D".  First you need to tell the compiler what Theron function calls look like.  You do this by pointing it to the Theron header files with the &lt;tt&gt;-I/THERONPATH/Include/&lt;/tt&gt; directive.&lt;/p&gt;

&lt;p&gt;Next you need to tell mex to pull in the theron and boost_thread libraries.  The standard way to do this is with the -L and -l options to the linker, but I find it cleaner to just include the full paths to the library files after your C++ file name; this tells the linker to look through the object files in the libraries when resolving the calls to Theron in your code.  I also like using the -v option so I can see exactly what mex is up to.&lt;/p&gt;

&lt;p&gt;So your full build command should look something like:&lt;/p&gt;
&lt;pre name="code"&gt;mex -v -I/THERONPATH/Include/ theron_test.cpp /THERONPATH/Lib/libtheron.a /LIBPATH/libboost_thread.so
&lt;/pre&gt;

&lt;p&gt;If you got Boost from Macports, then the libboost part above should be &lt;tt&gt;/opt/local/include/libboost_thread-mt.dylib&lt;/tt&gt;.  You could also use &lt;tt&gt;libboost_thread-my.a&lt;/tt&gt; if you want; I don't think it matters much.&lt;/p&gt;

&lt;p&gt;Did it build?  Hope so...  Now try running &lt;tt&gt;theron_test&lt;/tt&gt; from the Matlab command line.  You should see nothing; nothing is good.  Now go ahead and code up your algorithm using the Theron tutorial as a guide and enjoy simple Matlab concurrency!&lt;/p&gt;

&lt;h2&gt;Building Theron on Linux or other shared library mex environments&lt;/h2&gt;
&lt;p&gt;The process is a bit more complicated for Linux users.  The upside is, you probably don't have to worry about getting your own Boost implementation (although chances are you already have one...).  The issue is that in Linux, Matlab mex files are built as shared libraries instead of statically linked.  This causes two problems.  The immediate problem is that Matlab needs you to build Theron with the &lt;tt&gt;-fPIC&lt;/tt&gt; option turned on so that it can use the Theron library in a shared build.  This is not a big problem; just add &lt;tt&gt;-fPIC&lt;/tt&gt; to the &lt;tt&gt;CFLAGS&lt;/tt&gt; in the Theron makefile.&lt;/p&gt;

&lt;p&gt;The second problem is the deal breaker: Matlab uses libboost_thread internally and has its own copy hidden away in its internal distribution folders.  Since your mex file got built as a shared library, it will try to pull the boost_thread library in at runtime, and it will find Matlab's version (1_40_0) instead of your external version (1_42_0 currently in apt-get).  This causes a segfault.&lt;/p&gt;

&lt;p&gt;So there are two approaches to solving this.  The better one would be to find some way to tell your mex file not to use Matlab's boost_thread.  I found &lt;a href="http://www.mathworks.com/matlabcentral/answers/12648-matlab-library-initialization-failing-due-to-i-suspect-multiple-versions-of-boost-thread-library"&gt;a discussion of this on MatlabCentral&lt;/a&gt;, but did not get this working; it seems like it might require rewriting parts of Theron to use &lt;tt&gt;dlopen&lt;/tt&gt;; not very nice.  I still feel like there should be some other way to get Matlab to behave, but I didn't find it.  (For completeness: it does not work to point Matlab's internal boost_thread to an updated one; duh why did I even try that?)&lt;/p&gt;

&lt;p&gt;So there is option 2: throw in the towel and build Theron against Matlab's internal boost_thread.  This works at least for 64-bit Matlab 2010 or 2011, which has boost_thread 1.40.0 internally.  I don't know that it will work for earlier or 32-bit versions of Matlab, which I believe use earlier versions.  (A very old version of Matlab might not have this issue at all, as I think it was around 2007 that MathWorks started multithreading Matlab internal code in the first place.  If you're using a very old Matlab, check the internal distribution folders for libboost_thread to see if it's there.  &lt;tt&gt;locate&lt;/tt&gt; should be your friend.)&lt;/p&gt;

&lt;p&gt;Building Theron against Matlab's internal boost_thread is not too hard.  The only trick is that Matlab doesn't have the header files in the distribution (at least I didn't find them).  So you'll have to &lt;a href="http://www.boost.org/users/history/"&gt;download boost_1_40_0&lt;/a&gt; (or whatever version Matlab has internally on your system) and point Theron to those headers.  If you use the wrong headers, you'll get segfaults.  Theron's makefile should look something like:&lt;/p&gt;

&lt;pre class="brush: bash" name="code"&gt;BOOST_INCLUDE_PATH = /Downloads/boost_1_40_0/
BOOST_LIB_PATH = /usr/local/MATLAB/R2011a/bin/glnxa64/
BOOST_RELEASE_LIB = boost_thread
BOOST_DEBUG_LIB = boost_thread

...

CFLAGS += -c -Wall -fPIC
&lt;/pre&gt;

&lt;p&gt;(The libboost_thread in the Matlab folder is only the versioned filename, not the soname, so I would have thought you might need to symlink a soname but that didn't seem to be necessary.)&lt;/p&gt;

&lt;p&gt;If this builds correctly, you should be good to build your mex file from Matlab; the command is the same as above for Mac, except you point it to the internal Matlab boost_thread:&lt;/p&gt;
&lt;pre class="matlab" name="code"&gt;mex -v -I/THERONPATH/Include/ theron_test.cpp /THERONPATH/Lib/libtheron.a /MATLABLIBPATH/libboost_thread.so.1.40
&lt;/pre&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;This was a little bit of a pain, mostly because of Matlab's questionable decision to use shared libraries internally without (apparently) providing for situations where users build their mex files against the same libraries.  The process is especially annoying if you have Mac and Linux machines that both need to be able to build your mex.  Some steps would be a little smoother if Theron were less Windows-centric; Theron has a new release coming that should improve on this.&lt;/p&gt;

&lt;p&gt;I think the current solution is stable, although it's tricky to be locked into the Matlab internal boost_thread version.  The benefit is clear.  Using Theron to multithread a simple algorithm, I got about 4.5x speedup using 6 cores, and 6x speedup using 12 threads on 6 cores with hyperthreading.  This was a simple algorithm that didn't really require an Actors model, but it was great that I could get this done quickly (once I figured out the Matlab setup tricks) and without having to deal with low-level threads and mutexes at all.&lt;/p&gt;



&lt;h2&gt;Building Theron on Windows&lt;/h2&gt;
&lt;p&gt;As noted, I have not gotten any Windows compiler to work with mex, so these are purely hypothetical guidelines.  If you are building on Windows you will probably find it simpler to use the Windows thread library instead of Boost.  So just leave out the THERON_USE_BOOST_THREADS define and it should revert to using Windows threads instead.  This means you should be safe from the internal Matlab shared library conflict problem that Linux has.  But you may still need the -fPIC option added to your CFLAGS depending on whether Windows mex is setup to create static or shared libraries (I don't know).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-6207776588878398397?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/6207776588878398397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/09/preamble-what-follows-is-guide.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6207776588878398397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6207776588878398397'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/09/preamble-what-follows-is-guide.html' title='HOWTO: deploy multithreading on Matlab with the Theron C++ Actors library'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-5678648008382962664</id><published>2011-09-02T14:15:00.018-07:00</published><updated>2011-09-07T17:07:56.529-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theron'/><category scheme='http://www.blogger.com/atom/ns#' term='actors'/><category scheme='http://www.blogger.com/atom/ns#' term='mex'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='matlab'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrent'/><title type='text'>Simple(r) concurrent Matlab programming with Theron</title><content type='html'>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Preamble: &lt;/strong&gt;What follows are my (long-winded) musings on the current (Sep. 2011) state of concurrent programming in Matlab.  For a specific guide to using the Theron C++ library for Actors concurrency in Matlab, see &lt;a href="http://absurdlycertain.blogspot.com/2011/09/preamble-what-follows-is-guide.html"&gt;the following post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Concurrent Matlab&lt;/h2&gt;

&lt;p&gt;Matlab is a standard programming environment for scientific calculations.  In our lab, we use it for a lot of analysis, especially prototyping new analyses.  Eventually, some of the performance critical stuff gets ported over to Java, but we still have plenty of things we need to run that are Matlab-only and need to be fast.&lt;/p&gt;

&lt;p&gt;As personal computers add more and more cores without improving clock speeds much, there is more and more need for parallelized (AKA concurrent, multithreaded) software.  Matlab is not a very popular language for supercomputing, but high-performance clusters also of course demand parallelized software.  Matlab has some support for multithreading internally, so depending on which Matlab internal functions you use, you may see significant multicore use on your machine.  But there is currently no support for explicitly writing multithreaded programs in vanilla Matlab.&lt;/p&gt;

&lt;a name='more'&gt;&lt;/a&gt;

&lt;p&gt;One solution is to start multiple instances of Matlab and use communication abstractions like sockets (also not supported in vanilla Matlab) or the file system to interact between the processes.  This is an okay solution for coarsely (AKA embarrassingly) parallel algorithms.  Several nicely abstracted solutions exist.  Matlab's own &lt;a href="http://www.mathworks.com/products/parallel-computing/"&gt;Parallel Computing Toolbox&lt;/a&gt; with its &lt;tt&gt;parfor&lt;/tt&gt; construct for example.  Free solutions include the &lt;a href="http://www.mathworks.com/matlabcentral/fileexchange/13775"&gt;multicore package from MatlabCentral FileExchange&lt;/a&gt;, and &lt;a href="http://www.ll.mit.edu/mission/isr/matlabmpi/matlabmpi.html"&gt;MatlabMPI&lt;/a&gt;/&lt;a href="http://www.ll.mit.edu/mission/isr/pmatlab/pmatlab.html"&gt;pMatlab&lt;/a&gt; from MIT.  Multicore and pMatlab both use the file system for interprocess communication.  (They have somewhat different abstraction models that make them appropriate for somewhat different styles of multithreading.)  One upside to using the file system for interprocess multithreading is that it is trivial to use a network file system to make your code not only multiprocess but actually distributed to multiple machines.&lt;/p&gt;

&lt;p&gt;But what if you need more finely grained parallelism, for example you want to code algorithms that flexibly break a problem into hundreds of sub-tasks and maximally exploit available hardware concurrency?  At present, this seems to require you to either give up on Matlab entirely, or else write lower-level code that links into Matlab.  The two methods I'm familiar with for linking lower-level code into Matlab are to write Java, which Matlab communicates with fairly smoothly, or else write C/C++/Fortran and bring it in with Matlab's "mex" functionality.&lt;/p&gt;

&lt;p&gt;Java core concurrency is established, but based around low level threads and locks.  It's a minefield of synchronization issues.  There are libraries available for more abstracted approaches, but I haven't worked with them.  And if a contained segment of code is &lt;em&gt;really&lt;/em&gt; performance critical, writing it in native C/C++ makes sense.&lt;/p&gt;

&lt;p&gt;So what are the capabilities for writing concurrent C++ and linking it into Matlab?  Unfortunately current C++ compilers do not have native concurrency support.  But this is expected to change in the not-too-distant future.  C++11, the new standard, was approved last month with a new thread library based on the threading in the popular Boost distribution.  Unfortunately, the C++11 threading standard looks a lot like Java core concurrency, built around low-level threads and mutexes with no support for higher-level, safer, simpler concurrency abstractions.  Luckily, there are libraries available offering concurrency abstractions for C++.  The one I'd like to highlight today is &lt;a href="http://theron.ashtonmason.net/"&gt;Theron&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Theron&lt;/h2&gt;
&lt;p&gt;Theron is a concurrency library for C++ based on the Actors model, in which most of the low-level thread/mutex concurrency implementation details are hidden from the user.  It is not a strict Actors model based tightly on the academic definition of Actors, but it is in that spirit.  It offers an Actors abstraction based on a backing thread pool, so that creating new Actors is cheaper than actually creating new threads, allowing you to trivially have hundreds or thousands of Actors in one program.  The pool of worker threads services the Actors efficiently, allowing high exploitation of available hardware concurrency.  Actors are also defined to communicate only through message passing and not through shared memory, eliminating most of the booby traps that make low level concurrent programming such a pain.  (There are ways to pass shared memory between Theron Actors if you really need to, e.g. if you have large input data structures you don't want to copy into messages.  It's then up to the user to ensure that the Actors interact with the shared memory in well defined, safe ways.  Nevertheless I have found that the Actors abstraction is very helpful for simplifying concurrent code even if some degree of shared memory is slipped in.)&lt;/p&gt;

&lt;p&gt;Another nice feature of Theron is that it is designed to allow easy swapping in of different underlying thread models.  Currently it has wrappers for native Win32 threading as well as Boost threads.  The expectation is that as C++11 std::thread compilers become available, it will be easy to adapt Theron to use the standard threading.  Theron also has a very nice website with clear documentation of the simple, powerful API, a clear tutorial, getting started guide, and good user support.  Although Theron has historically been somewhat Windows-centric, I was able to download Theron, build it on my work Mac, and get a multithreaded program running in Matlab in about a day.  Getting it working in Linux took longer, but I think I have it figured out now too; see next post for details.&lt;/p&gt;


&lt;h2&gt;Update: libcppa&lt;/h2&gt;
&lt;p&gt;I recently came across another C++ Actors project, &lt;a href="http://libcppa.blogspot.com/"&gt;libcppa&lt;/a&gt;.  This is much less mature than Theron, and relies on a lot of C++11 features for its core functionality, but it looks interesting.  It's hosted on GitHub, so could be easy to dig into despite not a lot of documentation.  But Theron is clearly the choice for the time being.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-5678648008382962664?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/5678648008382962664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/09/simpler-concurrent-matlab-programming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/5678648008382962664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/5678648008382962664'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/09/simpler-concurrent-matlab-programming.html' title='Simple(r) concurrent Matlab programming with Theron'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-4006703875187495086</id><published>2011-08-04T10:37:00.007-07:00</published><updated>2011-10-06T10:29:16.072-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Broken Mac OS 10.6 Java</title><content type='html'>&lt;p&gt;Apple has a pretty lousy history with Java support, but this still surprised me.  If you are having trouble getting programs to compile with older Java versions (e.g. for backward compatibility), you might want to take a look in this directory:  &lt;tt&gt;/System/Library/Frameworks/JavaVM.framework/Versions&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;Here's what I found on my OS 10.6 system:&lt;/p&gt;

&lt;pre&gt;
lrwxrwxr-x   1 root  wheel    5 Jun 29 13:37 1.3 -&gt; 1.3.1
drwxr-xr-x   3 root  wheel  102 Feb 11  2010 1.3.1
lrwxrwxr-x   1 root  wheel   10 Jun 29 13:37 1.4 -&gt; CurrentJDK
lrwxrwxr-x   1 root  wheel   10 Jun 29 13:37 1.4.2 -&gt; CurrentJDK
lrwxrwxr-x   1 root  wheel   10 Jun 29 13:37 1.5 -&gt; CurrentJDK
lrwxrwxr-x   1 root  wheel   10 Jun 29 13:37 1.5.0 -&gt; CurrentJDK
lrwxrwxr-x   1 root  wheel   10 Jun 29 13:37 1.6 -&gt; CurrentJDK
lrwxrwxr-x   1 root  wheel   10 Jun 29 13:37 1.6.0 -&gt; CurrentJDK
lrwxrwxr-x   1 root  wheel   59 Jun 29 13:37 CurrentJDK -&gt; /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents
&lt;/pre&gt;

&lt;p&gt;I kept trying to get Eclipse to compile with 1.5 and kept getting incompatible binaries.  Thanks Apple!  YMMV, but I found &lt;a href="http://chxor.chxo.com/post/183013153/installing-java-1-5-on-snow-leopard"&gt;this post&lt;/a&gt; a good guide to getting a &lt;em&gt;real&lt;/em&gt; Java 1.5 installation.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-4006703875187495086?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/4006703875187495086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/08/broken-mac-os-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/4006703875187495086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/4006703875187495086'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/08/broken-mac-os-java.html' title='Broken Mac OS 10.6 Java'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-3179483813985568577</id><published>2011-07-28T14:03:00.010-07:00</published><updated>2011-10-06T10:27:04.867-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Mac OS 10.6.8 breaks OpenSSL dev compatibility</title><content type='html'>&lt;p&gt;&lt;em&gt;Update (2011-07-29): &lt;a href="http://globus.org/toolkit/"&gt;Globus Toolkit&lt;/a&gt; devs have told me that this is a frequent problem with Mac OS updates.  Thanks Apple.  So they recommend running with the --without-openssl-header-check flag if you don't want to go to the trouble of actually installing compatible headers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are trying to build anything that requires OpenSSL on Mac OS 10.6 and have updated to 10.6.8, you may run into the following complaint:&lt;/p&gt;
&lt;pre&gt;
checking OpenSSL header version... 9080cf (OpenSSL 0.9.8l 5 Nov 2009)
checking OpenSSL library version... 90812f (OpenSSL 0.9.8r 8 Feb 2011)
checking whether OpenSSL's headers match the library... no
configure: error: Your OpenSSL headers do not match your library. Check config.log for details.
If you are sure your installation is consistent, you can disable the check by running "./configure --without-openssl-header-check".
Also see contrib/findssl.sh for help identifying header/library mismatches.
&lt;/pre&gt;

&lt;p&gt;For some reason, when Apple &lt;a href="http://support.apple.com/kb/HT4723"&gt;upgraded to OpenSSL 0.9.8r to address security issues&lt;/a&gt; they failed to update the headers, so now there is a version mismatch (i.e. header version is 0.9.8l but library version is 0.9.8r).&lt;/p&gt;

&lt;p&gt;If you want to track this issue in more detail, you can find a copy of the findssl.sh script, either on your system somewhere or just find it online.  If you download it online, you will probably have to hack the script to find Mac's .dylib shared library files instead of the Linux standard .so files.  Alternatively, just try these commands:&lt;/p&gt;
&lt;pre&gt;
locate opensslv.h
locate libcrypto.dylib
&lt;/pre&gt;

&lt;p&gt;That should show you where the different versions of headers and libs are respectively.  Then you can look inside the opensslv.h file in /usr/include and confirm that it is 0.9.8l instead of 0.9.8r.&lt;/p&gt;

&lt;p&gt;In any case, the solution seems to be:
&lt;ol&gt;
&lt;li&gt;Get OpenSSL 0.9.8r from &lt;a href="http://www.openssl.org/source/"&gt;http://www.openssl.org/source/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Untar, copy the include/openssl directory to somewhere like /usr/include/openssl-0.9.8r&lt;/li&gt;
&lt;li&gt;Point your build to these new headers.  I decided to just blast the incompatible headers, so I moved my old /usr/include/openssl to /usr/include/openssl-0.9.8l and then symlinked openssl to openssl-0.9.8r.&lt;/li&gt;
&lt;li&gt;Now it builds!&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-3179483813985568577?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/3179483813985568577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/07/mac-os-1068-breaks-openssl-dev.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/3179483813985568577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/3179483813985568577'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/07/mac-os-1068-breaks-openssl-dev.html' title='Mac OS 10.6.8 breaks OpenSSL dev compatibility'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-4720623752465544072</id><published>2011-04-22T17:16:00.007-07:00</published><updated>2011-04-22T18:49:22.412-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data'/><category scheme='http://www.blogger.com/atom/ns#' term='food'/><title type='text'>Combining USDA SR23 with glycemic index data</title><content type='html'>&lt;p&gt;USDA provides a &lt;a href="http://www.ars.usda.gov/Services/docs.htm?docid=8964"&gt;National Nutrient Database for Standard Reference&lt;/a&gt; currently in Version 23 (SR23), which has loads of nutritional data on a good selection of food products.  On my wishlist would be cross-referencing with UPC bar codes, as well as some additional data that are currently missing, such as glycemic index and separate soluble vs. insoluble fiber values.&lt;/p&gt;

&lt;p&gt;I did find one website that has done a pretty job with glycemic index already: &lt;a href="http://nutritiondata.self.com/"&gt;nutritiondata.self.com&lt;/a&gt;.  In addition to pulling in glycemic index data, they've also calculated glycemic load and then built a statistical model to try to infer/impute glycemic load for foods that don't have published glycemic index data.  And they also have some other summary statistics that they've developed in-house such as "Fullness Factor" and an overall healthiness rating.  Kudos to them, but I wanted to play with these data myself.  Also I didn't see a fiber breakdown there.&lt;/p&gt;

&lt;p&gt;One data source I found that has both glycemic load and soluble vs. insoluble fiber (at least for some entries) is the &lt;a href="http://riskfactor.cancer.gov/dhq2/"&gt;Diet History Questionnaire II (DHQ2)&lt;/a&gt;.  The DHQ is available to download as a single giant table.  I plan to play with this.&lt;/p&gt;

&lt;p&gt;Another option is to link the glycemic index data derived for the DHQ back to SR23.  This appears to be possible thanks to a couple of additional tables.  First, DHQ provides their &lt;a href="http://riskfactor.cancer.gov/DHQ/database/gi_values.csfii_94-96_foodcodes.csv"&gt;glycemic index data&lt;/a&gt; in a table referenced against food codes from the USDA Continuing Survey of Food Intakes by Individuals (CSFII).  These codes match the food codes used in the &lt;a href="http://www.ars.usda.gov/services/docs.htm?docid=12089"&gt;USDA Food and Nutrient Database for Dietary Studies (FNDDS)&lt;/a&gt;.  The FNDDS database includes a table that links selected FNDDS/CSFII codes back to one or more SR23 codes.  (Since my main interest in glycemic index is to compare glycemic index to sugar composition, and FNDDS only has a value for total sugar not individual components, I'm not too interested in FNDDS by itself.)&lt;/p&gt;

&lt;p&gt;I'll be exploring DHQ vs. SR23 (augmented with glycemic indices linked from FNDDS+DHQ) and will report back.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-4720623752465544072?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/4720623752465544072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/04/combining-usda-sr23-with-glycemic-index.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/4720623752465544072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/4720623752465544072'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/04/combining-usda-sr23-with-glycemic-index.html' title='Combining USDA SR23 with glycemic index data'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-6260884597386401419</id><published>2011-02-20T11:46:00.004-08:00</published><updated>2011-03-14T15:43:52.624-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><category scheme='http://www.blogger.com/atom/ns#' term='gridcomputing'/><title type='text'>Globus Toolkit 5.0.3 on Cygwin 1.7</title><content type='html'>&lt;p&gt;Cygwin patches (see &lt;a href="http://absurdlycertain.blogspot.com/2010/09/globus-toolkit-502-on-cygwin-17.html"&gt;earlier post&lt;/a&gt;) did not make it into GT5.0.3.  The patch requirement is therefore the same as for GT5.0.2 (see &lt;a href="http://absurdlycertain.blogspot.com/2010/09/globus-toolkit-502-on-cygwin-17.html"&gt;earlier post&lt;/a&gt;).  These patches may make it into future distributions.&lt;/p&gt;

&lt;p&gt;I took slightly more detailed notes during the 5.0.3 build process, so you can now find more details about which packages require patches &lt;a href="http://lists.globus.org/pipermail/gt-dev/2011-February/001964.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-6260884597386401419?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/6260884597386401419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/02/globus-toolkit-503-on-cygwin-17.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6260884597386401419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6260884597386401419'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/02/globus-toolkit-503-on-cygwin-17.html' title='Globus Toolkit 5.0.3 on Cygwin 1.7'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-5447743157761174299</id><published>2011-02-14T13:06:00.009-08:00</published><updated>2011-03-14T17:38:10.640-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><category scheme='http://www.blogger.com/atom/ns#' term='diy'/><category scheme='http://www.blogger.com/atom/ns#' term='food'/><title type='text'>DIY KitchenAid attachments</title><content type='html'>&lt;p&gt;&lt;em&gt;Update: (2011-03-14): So this does not quite fit perfectly into the Attachment Hub, but it is good enough that with a housing for the shaft I'm pretty sure it will work.  I'll take more precise measurements and post any updates.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (2011-02-18): Arrived no problem from Mending Shed; Parcel Post was quite fast actually.  Don't have the KitchenAid here with me right now so will not be able to test at all for a few weeks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our KitchenAid stand mixer is probably the fanciest piece of hardware we own other than our car.  I've been thinking for a while that there really ought to be a DIY modding community around this appliance; it's a powerful, well built kitchen motor waiting to be exploited (plus planetary gearing if that is helpful).  But I haven't found much so far.  &lt;a href="http://www.saschameinrath.com/2010/apr/27/diy_kitchenaid_powered_bike_gear_enhanced_lamb_rotisserie"&gt;Here's one nice rotisserie mod I found&lt;/a&gt;, and that's about it.&lt;/p&gt;

&lt;p&gt;KitchenAid makes a number of official attachments.  Some of them attach to the bottom head where the planetary gearing is, while others attach to a port on the front (the "Attachment Hub") that accepts square shafted ("Power Shaft") attachments.  I searched around a little and was able to find a part that I'm &lt;em&gt;pretty sure&lt;/em&gt; will fit the attachment hub: KitchenAid 9709315, the "clutch shaft".  &lt;a href="http://www.amazon.com/dp/B000PJ7YK0"&gt;Amazon sells it.&lt;/a&gt; &lt;/p&gt;

&lt;img src="http://ecx.images-amazon.com/images/I/21S4n6iZ6kL._SL500_AA300_.jpg" /&gt;

&lt;p&gt;Note that this doesn't include the shaft housing that will allow you to lock it into place; figuring out a way to hack this together will be the first job before anyone can really use this thing for DIY projects.  I'm wondering if putting something together in plastic through &lt;a href="http://www.ponoko.com/"&gt;Ponoko&lt;/a&gt; or the like will get the job done.  It probably requires some bearings too.&lt;/p&gt;

&lt;p&gt;I &lt;a href="http://store.mendingshed.com/kaclutch.html"&gt;ordered one from Mending Shed&lt;/a&gt; (slightly cheaper than Amazon and will ship Parcel Post), will update with progress.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-5447743157761174299?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/5447743157761174299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2011/02/diy-kitchenaid-attachments.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/5447743157761174299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/5447743157761174299'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2011/02/diy-kitchenaid-attachments.html' title='DIY KitchenAid attachments'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-7688786588588519305</id><published>2010-11-19T14:52:00.007-08:00</published><updated>2011-09-03T13:36:09.952-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='matlab'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Faster median calculation and generic rank selections in MatLab via nth_element</title><content type='html'>&lt;em&gt;&lt;strong&gt;Update (2011-09-03):&lt;/strong&gt; I've added new functions to the release that edit the arrays in-place.  This is not good Matlab style but gives significant speedups for the very performance conscious.  It appears it may be useful for me to add a multithreaded version as well, so this may come in an upcoming release.&lt;/em&gt;

&lt;p&gt;C++ &lt;tt&gt;std::nth_element&lt;/tt&gt; is a standard specification for an efficient &lt;a href="http://en.wikipedia.org/wiki/Selection_algorithm"&gt;rank selection algorithm&lt;/a&gt;.  This algorithm can be used to solve a number of rank selection problems efficiently.&lt;/p&gt;

&lt;p&gt;One example is median finding.  A naive median finding algorithm, as implemented in MatLab (at least up to R2010a) is to sort the entire list of values and then just take the value in the middle position.  But sorting the entire list is overkill; it is more efficient to do a sort of partial sort just to the point where the desired value is in the correct position.  The version of this typically implemented in &lt;tt&gt;nth_element&lt;/tt&gt; is known as quickselect or Hoare's Selection Algorithm.  See &lt;a href="http://en.wikipedia.org/wiki/Selection_algorithm"&gt;Wikipedia: Selection algorithm&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;I find that a MatLab &lt;tt&gt;fast_median&lt;/tt&gt; function based on &lt;tt&gt;nth_element&lt;/tt&gt; runs about twice as fast as the native MatLab &lt;tt&gt;median&lt;/tt&gt; function based on &lt;tt&gt;sort&lt;/tt&gt;. Theoretically, the average complexity of quickselect is O(n), while the best performance complexity of the sort based method is O(n log n).&lt;/p&gt;

&lt;p&gt;Finding median values is central to &lt;a href="http://en.wikipedia.org/wiki/Robust_statistics"&gt;robust statistics&lt;/a&gt;, for example calculating the &lt;a href="http://en.wikipedia.org/wiki/Median_absolute_deviation"&gt;Median Absolute Deviation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are interested, my MatLab wrapping of &lt;tt&gt;nth_element&lt;/tt&gt; and an example implementation of &lt;tt&gt;fast_median&lt;/tt&gt; are available at &lt;a href="http://www.mathworks.de/matlabcentral/fileexchange/29453-nthelement"&gt;MatLab Central File Exchange&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-7688786588588519305?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/7688786588588519305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/11/faster-median-calculation-and-generic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/7688786588588519305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/7688786588588519305'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/11/faster-median-calculation-and-generic.html' title='Faster median calculation and generic rank selections in MatLab via nth_element'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-1303357053244674757</id><published>2010-10-14T10:18:00.008-07:00</published><updated>2011-09-16T20:01:14.861-07:00</updated><title type='text'>Startup GNU Screen with multiple regions (split screen)</title><content type='html'>&lt;p&gt;Since I've been doing a lot of work remotely lately I've been brushing up my &lt;a href="http://www.gnu.org/software/screen/"&gt;GNU Screen&lt;/a&gt; skillz.&lt;/p&gt;

&lt;p&gt;One thing I'd like is to be able to reattach a screen with a number of regions (AKA split screens) setup automatically.  Screen is supposed to get this in the next release, but it's been a while.&lt;/p&gt;

&lt;p&gt;In the meantime, the following kludge seems to work well enough: &lt;tt&gt;(sleep 0.1; screen -X split) &amp; screen -r&lt;/tt&gt;.  Basically, this says: "reattach to my screen and at the same time in the background wait a fraction of a second and then send the split command to screen from a separate thread".&lt;/p&gt;

&lt;p&gt;This was a common enough pattern that I wrote it into a little shell script:
&lt;pre name="code" class="brush: bash"&gt;
#!/bin/sh

splits=$1
if [ -z $splits ] ; then
  splits=1
fi

sleep=$2
if [ -z $sleep ] ; then
  sleep=0.1
fi

sleep $sleep
i=0
while [ $i -lt $splits ] ; do
  screen -X split
  screen -X focus bottom
  screen -X select `expr $i + 1`
  i=`expr $i + 1`
done
&lt;/pre&gt;

which is used: &lt;tt&gt;splitscreen 4 &amp; screen -r&lt;/tt&gt;.
&lt;/p&gt;

&lt;p&gt;There's plenty of room for improvement.  A more principled replacement for the call to &lt;tt&gt;sleep&lt;/tt&gt; would be to monitor the socket files.  In my Mac OS 10.5 these are under &lt;tt&gt;/tmp/uscreens/...&lt;/tt&gt;.  (I believe the standard location is &lt;tt&gt;/usr/tmp/screens/...&lt;/tt&gt;)  This is purely empirical, but it appears the user permission on the socket file changes from -x to +x (i.e. becomes executable) when the screen is attached.  So instead of &lt;tt&gt;sleep&lt;/tt&gt; we should be able to do a wait until that permission change occurs.&lt;/p&gt;

In principle I think this could even be used to save and restore region settings.  For example, rebind the split key to not only split but also save a flag to filesystem indicating how many regions, then read this flag when reattaching.  Or we could just wait for the next release...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-1303357053244674757?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/1303357053244674757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/10/startup-gnu-screen-with-multiple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1303357053244674757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1303357053244674757'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/10/startup-gnu-screen-with-multiple.html' title='Startup GNU Screen with multiple regions (split screen)'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-6458474326557252675</id><published>2010-10-07T20:35:00.004-07:00</published><updated>2010-10-07T20:45:19.372-07:00</updated><title type='text'>Bluegiga WT12 Breakout Board V0.2</title><content type='html'>&lt;p&gt;I just got my first ever printed circuit boards back from BatchPCB.  Pretty exciting!  One of the boards is a Toyota audio system interface, but it needs to have a chip replaced and the pinout is different, so that board is not totally usable.  The other board is this breakout board for the Bluegiga WT12 bluetooth module.&lt;/p&gt;

&lt;a href="http://www.flickr.com/photos/chinasaur/5061634450/" title="Bluegiga WT12 Breakout Board V0.2 by Chinasaur, on Flickr"&gt;&lt;img src="http://farm5.static.flickr.com/4104/5061634450_f5b8cedf31.jpg" width="386" height="500" alt="Bluegiga WT12 Breakout Board V0.2" /&gt;&lt;/a&gt;

&lt;p&gt;This breaks out all the pins so you have complete freedom, and it's still pretty small.  I have another version I will probably release that breaks out only the UART pins and is compatible with the BlueSmirf pinout.  That one is much smaller.&lt;/p&gt;

&lt;a href="http://www.flickr.com/photos/chinasaur/5061023129/" title="Bluegiga WT12 Breakout Board V0.2 by Chinasaur, on Flickr"&gt;&lt;img src="http://farm5.static.flickr.com/4090/5061023129_4b3221a79c.jpg" width="384" height="500" alt="Bluegiga WT12 Breakout Board V0.2" /&gt;&lt;/a&gt;

&lt;p&gt;The WT12 has iWrap4 firmware that is a very simple interface to a variety of common Bluetooth profiles.  It's quite affordable; please see my &lt;a href="http://www.flickr.com/photos/chinasaur/5061634450/in/photostream/"&gt;Flickr page&lt;/a&gt; and &lt;a href="http://batchpcb.com/index.php/Products/41820"&gt;BatchPCB page&lt;/a&gt; for more information and ordering.&lt;/p&gt;

&lt;a href="http://www.flickr.com/photos/chinasaur/5061023309/" title="Bluegiga WT12 Breakout Board V0.2 by Chinasaur, on Flickr"&gt;&lt;img src="http://farm5.static.flickr.com/4151/5061023309_824cacb690.jpg" width="500" height="375" alt="Bluegiga WT12 Breakout Board V0.2" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-6458474326557252675?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/6458474326557252675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/10/bluegiga-wt12-breakout-board-v02.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6458474326557252675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6458474326557252675'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/10/bluegiga-wt12-breakout-board-v02.html' title='Bluegiga WT12 Breakout Board V0.2'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4104/5061634450_f5b8cedf31_t.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-6767398796438844647</id><published>2010-10-01T00:51:00.013-07:00</published><updated>2010-10-01T02:50:58.738-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chords'/><category scheme='http://www.blogger.com/atom/ns#' term='guitar'/><category scheme='http://www.blogger.com/atom/ns#' term='music'/><title type='text'>Chords: "Holiday" by the Kinks</title><content type='html'>The chords posted around online are a bit wrong.  And it's such a great, simple song!  Fixed it up a little:

&lt;pre&gt;
Artist-The Kinks
Song-Holiday
Album-Muswell Hillbillies
Writer-Ray Davies
Tabbed by S. McNally, Peter H. Li


Intro
A-F#-B7-E7


Verse 1
A     F#     B7
Holiday,
          E7     A     F#
Oh what a lovely day today,
B7        E7        A       F#
I'm oh so glad they sent me away,
   B7            E7   A    F#   Bm Eb E
To have a little holiday today, holiday.

Verse 2
A     F#
Holiday,
B7           E7              A        F#  
And I'm just standing on the end of a pier,
B7          E7      A        F#
Hoping and dreaming you were here,
B7          E7     A            (turnaround: A F E C A ???)
To share my little holiday.


Verse 3 (type II)
A              F#        B7         E7
Lookin' in the sky for a gap in the clouds,
A           F#                   B7           E7
Sometimes I think that sun ain't never coming out,
        A         A7/G              D          B7
But I'd rather be here than in that dirty old town,
  E                                             (E+)
I had to leave the city cos it really brought me down.


Verse 4
Oh holiday, oh what a lovely day today,
I think I'll get down on my little ol' knees and pray, thank you Lord,
Thank heaven for this holiday today, holiday.


Bridge
    D           B7       A
I'm leaving insecurity behind me,
    D             B7               A
The environmental pressures got me down,
C#              C#7          D       B7
I don't need no sedatives to pull me round,
E                                              (E+)
I don't need no sleeping pills to help me sleep sound.


Verse 5
Oh holiday,
Oh what a lovely day today,
I think I'll get down on my little ol' knees and pray,
That's what I'll do,
Thank heaven for this holiday.

Verse 6 (type II)
Lying on the beach with my back burned rare,
The salt gets in my blisters and the sand gets in my hair,
And the sea's an open sewer,
But I really couldn't care,
I'm breathing through my mouth so I don't have to sniff the air.

Verse 7
Oh holiday,
Oh what a lovely day today,
I'm so glad they sent me away,
To have a little holiday. 
&lt;/pre&gt;

(I sure miss &lt;a href="http://www.olga.net/"&gt;OLGA&lt;/a&gt; sometimes...)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-6767398796438844647?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/6767398796438844647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/10/chords-holiday-by-kinks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6767398796438844647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6767398796438844647'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/10/chords-holiday-by-kinks.html' title='Chords: &quot;Holiday&quot; by the Kinks'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-2998907598886742748</id><published>2010-09-29T14:39:00.013-07:00</published><updated>2011-02-20T11:43:33.241-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><category scheme='http://www.blogger.com/atom/ns#' term='gridcomputing'/><title type='text'>Globus Toolkit 5.0.2 on Cygwin 1.7</title><content type='html'>&lt;p&gt;&lt;em&gt;Updates (2011-02-20): Cygwin patches did not make it into GT5.0.3, but they may make it into a future release.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updates (2010-12-08): Binghamton University TeraGrid has written up &lt;a href="http://internet2.binghamton.edu/teragrid/readdoc.cgi?fname=0_1_GlobusInstall.txt"&gt;instructions for applying the patches and getting GT compiled&lt;/a&gt;. Also, it appears new versions of GT will be coming out over the next few months. I plan to check them out for Cygwin compatibility.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are interested in compiling &lt;a href="http://www.globus.org/toolkit/"&gt;Globus Toolkit&lt;/a&gt; 5.0.2 on Cygwin, I have some simple patches that seem to get the job done.  Perhaps they will make it into the next release.  For now: &lt;a href="http://lists.globus.org/pipermail/gt-dev/2010-September/001885.html"&gt;http://lists.globus.org/pipermail/gt-dev/2010-September/001885.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that I built this on Cygwin 1.7; Cygwin 1.5 will probably not work.  Also you must have the &lt;tt&gt;gcc4.x&lt;/tt&gt; Cygwin packages (C and C++) installed.  Getting GT to build on &lt;tt&gt;gcc3.x&lt;/tt&gt; is probably not much more work, but going with &lt;tt&gt;gcc4&lt;/tt&gt; is easier than worrying about unrecognized compiler flags all over the place.&lt;/p&gt;

&lt;p&gt;You also need to specify the flag: &lt;tt&gt;--with-buildopts="-static=1"&lt;/tt&gt; when running the main configure script.  Building GT on Cygwin with dynamic linking is certainly beyond me, and is a pretty big undertaking, so this tells it to use only static linking.  I recommend &lt;tt&gt;--with-buildopts="-verbose -static=1"&lt;/tt&gt; so you can also see what is going on.&lt;/p&gt;

&lt;p&gt;(For the record, on dynamic linking: I tried adding some flags to &lt;tt&gt;configure.ac&lt;/tt&gt; or &lt;tt&gt;configure.in&lt;/tt&gt; to let &lt;tt&gt;autoconf&lt;/tt&gt; know that we wanted to make DLLs and do dynamic linking.  But trying to run a modern version of &lt;tt&gt;autoreconf&lt;/tt&gt; generated configure scripts that don't work with the GT package.  Even if the build worked, this probably wouldn't be a good idea as making DLLs properly requires going through all the source and making sure data exports are handled correctly.  At least one package (&lt;tt&gt;globus_libtool&lt;/tt&gt;) is DLL ready and already generates a DLL and RTL properly, so we know it all works theoretically once the individual libraries are DLL ready.  There may be other subpackages that are DLL ready, but they will probably have to be handled one at a time.  Unfortunately, GPT doesn't really offer a method to build the whole Globus Toolkit with some parts statically linked and some dynamic.)&lt;/p&gt;

&lt;p&gt;If you get a build failure with an error like "&lt;tt&gt;fork()&lt;/tt&gt;" or "&lt;tt&gt;vfork()&lt;/tt&gt;" "&lt;tt&gt;resource temporarily unavailable&lt;/tt&gt;", this means your machine ran out of processes while building (due to what I'm going to call a "process leak" bug).  Basically just rerun &lt;tt&gt;make&lt;/tt&gt; and it should get farther each time before crashing, until finally it gets all the way through.  Or build GT in smaller chunks; if you are just trying to get proxy certificate running you only really need "&lt;tt&gt;make gsi-myproxy gsi-openssh&lt;/tt&gt;".&lt;/p&gt;

&lt;p&gt;You may also have to circumvent GPT's somewhat outdated Perl libraries.  If you have a problem getting &lt;tt&gt;Archive::Tar&lt;/tt&gt; to open some of the source packages, then you should install the Cygwin CPAN package and then use that to install an updated version of &lt;tt&gt;Archive::Tar&lt;/tt&gt;.  You may then need to hide GPT's versions under &lt;tt&gt;$GLOBUS_LOCATION/sbin/perl&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to ping me with any questions/thoughts.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-2998907598886742748?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/2998907598886742748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/09/globus-toolkit-502-on-cygwin-17.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/2998907598886742748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/2998907598886742748'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/09/globus-toolkit-502-on-cygwin-17.html' title='Globus Toolkit 5.0.2 on Cygwin 1.7'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-478091122481377408</id><published>2010-08-18T00:13:00.002-07:00</published><updated>2010-08-18T00:17:52.471-07:00</updated><title type='text'>Eclipse Windows 7 Plugin Problems</title><content type='html'>Wow, &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; is really a piece of work.  I wasted an hour trying to get it to behave reasonably with multiple plugins installed on Windows 7.  Online forums were little help until I finally came across the suggestion to install Eclipse into a user directory, i.e. one that doesn't require administrator privileges.  Finally fixed; what a waste of time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-478091122481377408?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/478091122481377408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/08/eclipse-windows-7-plugin-problems.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/478091122481377408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/478091122481377408'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/08/eclipse-windows-7-plugin-problems.html' title='Eclipse Windows 7 Plugin Problems'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-2086503478753039317</id><published>2010-08-07T14:54:00.009-07:00</published><updated>2011-09-16T20:00:08.558-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Compiling GnuCAP in CygWin</title><content type='html'>&lt;p&gt;&lt;em&gt;Update: GnuCAP is now available as an official CygWin package, as is some dialect of SPICE.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Very simple patch to get recent development snapshots of GnuCAP to compile in CygWin:

&lt;pre name="code" class="brush: cpp"&gt;
--- md.h.bak    2010-03-19 00:21:26.030900000 -0700
+++ md.h        2010-03-19 00:34:18.810900000 -0700
@@ -100,6 +100,12 @@
  #define MS_DLL
#endif
/*--------------------------------------------------------------------------*/
+#ifdef __CYGWIN__
+  #ifndef RTLD_LOCAL
+    #define RTLD_LOCAL 0
+  #endif
+#endif
+/*--------------------------------------------------------------------------*/
/* some convenient names */
typedef std::complex&lt;double&gt; COMPLEX;
typedef std::pair&lt;double,double&gt; DPAIR; 
&lt;/pre&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-2086503478753039317?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/2086503478753039317/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/08/compiling-gnucap-in-cygwin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/2086503478753039317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/2086503478753039317'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/08/compiling-gnucap-in-cygwin.html' title='Compiling GnuCAP in CygWin'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-1028434914331851884</id><published>2010-05-13T07:53:00.033-07:00</published><updated>2011-09-16T19:58:12.176-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Mac-style wheel zoom, Exposé/Switcher on Windows 7</title><content type='html'>&lt;p&gt;Having a Mac at work has been a mixed blessing, mostly good.  There are some great OS features that I've become addicted to.  Happily, I have discovered ways to duplicate them on my Windows 7 home machine, and with better customizability even.&lt;/p&gt;

&lt;h4&gt;Wheel zoom&lt;/h4&gt;
&lt;p&gt;On Mac OS, holding command and using the mouse wheel zooms you in and out of your screen view.  This is on the operating system level, so it works in any application.  Windows 7 has a similar (i.e. copied) feature where holding the windows key and pushing plus/minus zooms.  Obviously it's nicer to use the mouse wheel.  Luckily, with &lt;a href="http://www.autohotkey.com/"&gt;AutoHotKey&lt;/a&gt; it's easy to set this up on Windows and even make it better.&lt;/p&gt;

&lt;p&gt;After installing AutoHotKey, run the following script:
&lt;pre name="code" class="brush: js"&gt;
; Only one instance running at a time
#SingleInstance force


; Mac-like zooming
~LCtrl &amp; WheelUp::
  sendinput #{NumpadAdd}
return

~LCtrl &amp; WheelDown::
  sendinput #-
return

~LWin &amp; WheelUp::
  sendinput #{NumpadAdd}
return

~LWin &amp; WheelDown::
  sendinput #-
return 
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;I derived this from &lt;a href="http://wandersick.blogspot.com/p/aerozoom-for-windows-7-magnifier.html"&gt;AeroZoom by wandersick&lt;/a&gt;, which is an excellent set of shortcuts for presentations.  I pulled out just the very simple zooming functionality and made it duplicate the Mac functionality more.  Thanks to wandersick for putting his tool out with the source!&lt;/p&gt;

&lt;p&gt;My mouse has side buttons that I usually use just for forward/back.  I added the following so that now I can do the wheel zoom without the keyboard at all, just by holding the left side button and wheeling:
&lt;pre name="code" class="brush: js"&gt;
; Additional mouse-only zooming
~XButton1 &amp; WheelUp::
  sendinput #{NumpadAdd}
return

~XButton1 &amp; WheelDown::
  sendinput #-
return 
&lt;/pre&gt;&lt;/p&gt;

&lt;h4&gt;Exposé/Switcher&lt;/h4&gt;
&lt;p&gt;Exposé is the Mac OS feature that makes it easy to find windows when you have a thousand different things open at once.  There is a very similar application for Windows called &lt;a href="http://insentient.net/"&gt;Switcher&lt;/a&gt;.  I like having Mac OS setup so that when you push the middle button (the wheel) it calls up Exposé.  With AutoHotKey, of course, it was simple to set up identical functionality on Windows 7 via Switcher.&lt;/p&gt;

&lt;p&gt;On my home mouse, I find it easier to push both side buttons simultaneously than to push the wheel down, so I set it up that way.  I also had trouble getting this to work with Switcher's default activation button (windows-`), so I added an additional Switcher hotkey (Switcher is very nicely customizable too) and then just setup AutoHotKey to trigger that:
&lt;pre name="code" class="brush: js"&gt;
; Mac-like expose, hooking into switcher
~XButton1 &amp; XButton2::
  send #s
return
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Hope that helps some other people suffering from Mac lust.  Enjoy!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-1028434914331851884?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/1028434914331851884/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/05/mac-style-wheel-zoom-exposeswitcher-on.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1028434914331851884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1028434914331851884'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/05/mac-style-wheel-zoom-exposeswitcher-on.html' title='Mac-style wheel zoom, Exposé/Switcher on Windows 7'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-8116371559732855753</id><published>2010-05-13T07:50:00.002-07:00</published><updated>2010-05-13T07:52:39.060-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='photo'/><category scheme='http://www.blogger.com/atom/ns#' term='nature'/><category scheme='http://www.blogger.com/atom/ns#' term='quickies'/><category scheme='http://www.blogger.com/atom/ns#' term='astro'/><title type='text'>Cloud patterns from space</title><content type='html'>WiReD has a &lt;a href="http://www.wired.com/wiredscience/2010/05/gallery-clouds/"&gt;cool gallery of satellite cloud photos&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-8116371559732855753?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/8116371559732855753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/05/cloud-patterns-from-space.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/8116371559732855753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/8116371559732855753'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/05/cloud-patterns-from-space.html' title='Cloud patterns from space'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-7442281584219164811</id><published>2010-01-20T16:16:00.009-08:00</published><updated>2010-01-23T23:56:55.657-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='urban'/><category scheme='http://www.blogger.com/atom/ns#' term='nature'/><title type='text'>Mourning dove feeding</title><content type='html'>&lt;p&gt;Finally got around to posting a video of the mourning doves that lived in our tomato plant last summer.  I was working from home at the time, and this was the window right next to my desk, so I have a lot of videos and photos, but this is one of the more interesting ones: feeding time!&lt;/p&gt;

&lt;p&gt;&lt;object width="425" height="344"&gt;
&lt;param name="movie" value="http://www.youtube.com/v/lTDk1gAsgXI&amp;hl=en_US&amp;fs=1&amp;rel=0" /&gt;
&lt;param name="allowFullScreen" value="true" /&gt;
&lt;param name="allowscriptaccess" value="always" /&gt;
&lt;embed src="http://www.youtube.com/v/lTDk1gAsgXI&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-7442281584219164811?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/7442281584219164811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2010/01/mourning-dove-feeding.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/7442281584219164811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/7442281584219164811'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2010/01/mourning-dove-feeding.html' title='Mourning dove feeding'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-1839843894617055813</id><published>2009-12-03T16:53:00.041-08:00</published><updated>2009-12-28T00:03:26.181-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='art'/><category scheme='http://www.blogger.com/atom/ns#' term='nature'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><category scheme='http://www.blogger.com/atom/ns#' term='light'/><title type='text'>Dapple</title><content type='html'>&lt;p&gt;On vacation in Paris last month we visited the &lt;i&gt;Musee D'Orsay&lt;/i&gt; to see some of the classics of Impressionism.  One of my current favorites (and &lt;a href="http://en.wikipedia.org/wiki/List_of_most_expensive_paintings"&gt;one of the most expensive paintings ever sold&lt;/a&gt;) is Renoir's &lt;a href="http://en.wikipedia.org/wiki/Bal_du_moulin_de_la_Galette"&gt;&lt;i&gt;Bal du Moulin de la Galette&lt;/i&gt;&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;
&lt;img style="width: 95%; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://upload.wikimedia.org/wikipedia/commons/thumb/2/21/Pierre-Auguste_Renoir%2C_Le_Moulin_de_la_Galette.jpg/500px-Pierre-Auguste_Renoir%2C_Le_Moulin_de_la_Galette.jpg" border="0" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;What I particularly like about this painting is Renoir's careful depiction of sunlight dappling through trees.  Look at the man in the foreground, facing away from us, with the curious round dabs of sunlight across his back.  If you focus on this point and think about it, the appearance of the dapples seems a little strange, yet holistically it &lt;em&gt;feels&lt;/em&gt; right.&lt;/p&gt;

&lt;p&gt;In fact, what Renoir has captured here is a true optical curiosity.  As 
&lt;a href="http://books.google.com/books?id=4WCNAW7r_5MC&amp;pg=PA1"&gt;discussed by Marcel Minnaert in &lt;i&gt;Light and Color in the Outdoors&lt;/i&gt;&lt;/a&gt;, sunlight dappling through trees often produces these beautiful, perfectly round or elliptical spots of light:&lt;br /&gt;&lt;br /&gt;
&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand; width: 75%" src="http://3.bp.blogspot.com/_6wq3kreXb7E/SxhoebHjr_I/AAAAAAAACBo/zAn-YoJXi7U/s320/dapples.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5411189824170471410" /&gt;&lt;br /&gt;
As Minnaert points out: "the surprising thing is that all these images have the same shape, although it is obviously impossible that all the holes and slits in the foliage happen to have the same shape."
&lt;/p&gt;

&lt;p&gt;This happens because holes in foliage that are sufficiently small result in dapples whose shape is dominated by the image of the sun, i.e. a disc, rather than the shape of the hole.  If the sun were a mere point source rather than having a significant diameter, we would not see this effect.  (I believe that the shape of the spot of light produced is essentially just the image of the sun, scaled by the projection throw length and then &lt;a href="http://en.wikipedia.org/wiki/Convolution"&gt;convolved&lt;/a&gt; with the shape of the hole, neglecting diffraction effects...)&lt;/p&gt;

&lt;p&gt;This effect is most dramatic when something distorts or obscures the image of the sun.  A classic example is the change in the appearance of tree dapples during a solar eclipse: as the sun becomes obscured, its image becomes crescent shaped, as do its dapples through the trees:&lt;br /&gt;&lt;br /&gt;

&lt;object width="384" height="313"&gt;
&lt;param name="movie" value="http://www.youtube.com/v/UDLdj3bJXVk&amp;hl=en_US&amp;fs=1" /&gt;
&lt;param name="allowFullScreen" value="true" /&gt;
&lt;param name="allowscriptaccess" value="always" /&gt;
&lt;param name="audio" value="no" /&gt;
&lt;embed src="http://www.youtube.com/v/UDLdj3bJXVk&amp;hl=en_US&amp;fs=1" type="application/x-shockwave-flash" width="384" height="313" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;
&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;

&lt;span style="font-style:italic;"&gt;Update:&lt;/span&gt; new eclipse photo, this time at annular stage:

&lt;a href="http://www.panoramio.com/photo/1953914"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 500px" src="http://static.panoramio.com/photos/original/1953914.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-1839843894617055813?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/1839843894617055813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/12/dapples.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1839843894617055813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1839843894617055813'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/12/dapples.html' title='Dapple'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_6wq3kreXb7E/SxhoebHjr_I/AAAAAAAACBo/zAn-YoJXi7U/s72-c/dapples.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-4720977512401472687</id><published>2009-09-14T21:08:00.006-07:00</published><updated>2009-09-14T21:11:34.832-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quickies'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>Gifts for etymologists, pt. 1</title><content type='html'>&lt;a href="http://www.piratemerch.com/images/jolly_roger_bbq_sauce.jpg"&gt;&lt;img width="200px" src="http://www.piratemerch.com/images/jolly_roger_bbq_sauce.jpg" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-4720977512401472687?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/4720977512401472687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/09/gifts-for-etymologists-pt-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/4720977512401472687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/4720977512401472687'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/09/gifts-for-etymologists-pt-1.html' title='Gifts for etymologists, pt. 1'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-6817804240626615986</id><published>2009-08-19T06:41:00.008-07:00</published><updated>2009-08-19T19:00:16.904-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quickies'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>In the Styx</title><content type='html'>&lt;p&gt;In &lt;i&gt;The Amazing Adventures of Kavalier and Clay&lt;/i&gt;, Michael Chabon uses the idiom "&lt;a href="http://en.wiktionary.org/w/index.php?title=in_the_sticks&amp;oldid=6397584"&gt;out in the sticks&lt;/a&gt;", meaning "in the boondocks", "in the middle of nowhere".  &lt;a href="http://www.etymonline.com/index.php?term=stick"&gt;According to EtymOnline&lt;/a&gt;, this idiom arose around 1905, simply from the meaning of sticks as in trees as in a rural place.&lt;/p&gt;

&lt;p&gt;I've heard the phrase plenty of times, but this must be the first time I've seen it (or at least first time I've noted it) in print.  Without really thinking about it, my mental image of this phrase had always been "out in the &lt;a href="http://en.wikipedia.org/w/index.php?title=Styx&amp;oldid=306071851"&gt;Styx&lt;/a&gt;".  Which of course, now that I actually think about it, seems pretty unlikely.  Definitely more fun my way though...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-6817804240626615986?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/6817804240626615986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/in-styx.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6817804240626615986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/6817804240626615986'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/in-styx.html' title='In the Styx'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-9072159263780248712</id><published>2009-08-13T21:37:00.008-07:00</published><updated>2009-09-14T21:29:38.271-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quickies'/><category scheme='http://www.blogger.com/atom/ns#' term='adverts'/><category scheme='http://www.blogger.com/atom/ns#' term='snark'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>Marketing Coup</title><content type='html'>&lt;p&gt;Overdone sales mailer from &lt;i&gt;The Economist&lt;/i&gt;: "Handle with care.  Contents may inspire."&lt;/p&gt;

&lt;p&gt;Roget's Thesaurus:&lt;br /&gt;
&lt;blockquote&gt;&lt;i&gt;Inspire&lt;/i&gt;: to breathe in&lt;br /&gt;
Synonyms: inhale, gasp, &lt;span style="color:white"&gt;suck&lt;/span&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-9072159263780248712?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/9072159263780248712/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/marketing-coup.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/9072159263780248712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/9072159263780248712'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/marketing-coup.html' title='Marketing Coup'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-1904488624811984384</id><published>2009-08-06T08:32:00.011-07:00</published><updated>2011-09-16T19:46:37.026-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Work around Selenium IDE's iteration deficiency with Prototype JavaScript evals</title><content type='html'>&lt;p&gt;Selenium IDE, the FireFox testing plugin, is a nice tool.  One of its limitations is the lack of straightforward methods for iterating or doing other control flow during tests.  This is one reason to switch to writing tests in Selenium RC.  However, it is sometimes possible to work around the limitations from within Selenium IDE by evaluating arbitrary JavaScript.  In particular, Rails applications using the standard Prototype JavaScript library have available some nice ways to iterate over elements.&lt;/p&gt;

&lt;p&gt;For example, I recently wanted to write a Selenium IDE test to clear the shopping cart for a web app.  To do this, I needed to iterate over all the elements in the cart, set their quantity to 0, and then update the cart.  To accomplish the iterative set quantity to 0, we can use the &lt;tt&gt;getEval&lt;/tt&gt; method to run arbitrary JavaScript: &lt;tt&gt;selenium.browserbot.getUserWindow().document.body.select('input[id^="line_item_"][id$="_quantity"]').each(function(elem){elem.value = 0})&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Going through this piece by piece:

&lt;pre name="code" class="brush: js"&gt;
  // This gets us the user window.  
  // Older versions might use getCurrentWindow() instead.
  selenium.browserbot.getUserWindow()
  
  // Gets us down to the document body
  // Because this is a standard Rails app, 
  // body has already been extended with Prototype.
  // select() invokes Prototype's $$() CSS selector.
  document.body.select
  
  // These are CSS3 attribute selectors
  // Basically we want to match id="line_item_*_quantity".
  // May require FireFox &gt;= 3
  input[id^="line_item_"][id$="_quantity"]
  
  // Prototype's Enumerable.each() does the iteration,
  // with an anonymous function setting the values.
  each(function(elem){elem.value = 0})
&lt;/pre&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-1904488624811984384?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/1904488624811984384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/work-around-selenium-ides-iteration.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1904488624811984384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1904488624811984384'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/work-around-selenium-ides-iteration.html' title='Work around Selenium IDE&apos;s iteration deficiency with Prototype JavaScript evals'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-570713713870513012</id><published>2009-08-05T15:18:00.012-07:00</published><updated>2011-09-16T19:44:40.324-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Getting Selenium to wait for Ajax requests</title><content type='html'>&lt;p&gt;&lt;em&gt;Update: See &lt;a href="http://davidvollbracht.com/2008/6/4/30-days-of-tech-day-3-waitforajax"&gt;here&lt;/a&gt; for one caveat in using Ajax.activeRequestCount.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Using Selenium IDE to test Ajax, you can usually use a &lt;tt&gt;waitFor&lt;/tt&gt; condition reflecting on DOM elements to tell you when Ajax calls have returned.  However, if you just want to wait until all Ajax requests have returned without relying on testing against page elements, there is this approach:

&lt;pre name="code" class="brush: js"&gt;
Command: waitForCondition
Target:  selenium.browserbot.getUserWindow().Ajax.activeRequestCount == 0
Value:   10000
&lt;/pre&gt;
This works for Prototype based Ajax pages, e.g. standard Rails. If you're using a different JavaScript library, you'll need to use a different call; see &lt;a href="http://i-proving.ca/space/Dion+Lew/blog/2008-10-23_1"&gt;here&lt;/a&gt; for some possibilities.&lt;/p&gt;

&lt;p&gt;(For earlier versions of Selenium, &lt;a href="http://crschmidt.net/blog/348/selenium-ide-getcurrentwindow-problems/"&gt;you might need to use &lt;tt&gt;getCurrentWindow()&lt;/tt&gt; instead&lt;/a&gt;.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-570713713870513012?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/570713713870513012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/getting-selenium-to-wait-for-ajax.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/570713713870513012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/570713713870513012'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/getting-selenium-to-wait-for-ajax.html' title='Getting Selenium to wait for Ajax requests'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-7696321677982740241</id><published>2009-08-05T10:20:00.001-07:00</published><updated>2009-08-05T10:21:47.559-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tortoisesvn'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Getting revision number in Tortoise Svn</title><content type='html'>&lt;a href="http://stackoverflow.com/questions/89741/can-i-see-the-currently-checked-out-revision-number-in-tortoise-svn"&gt;http://stackoverflow.com/questions/89741/can-i-see-the-currently-checked-out-revision-number-in-tortoise-svn&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-7696321677982740241?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://stackoverflow.com/questions/89741/can-i-see-the-currently-checked-out-revision-number-in-tortoise-svn' title='Getting revision number in Tortoise Svn'/><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/7696321677982740241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/getting-revision-number-in-tortoise-svn.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/7696321677982740241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/7696321677982740241'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/getting-revision-number-in-tortoise-svn.html' title='Getting revision number in Tortoise Svn'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-273563085052739753</id><published>2009-08-05T09:50:00.011-07:00</published><updated>2009-08-10T11:44:07.550-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Going back to earlier revisions in Subversion</title><content type='html'>There are basically two different scenarios where you will want to rewind (AKA roll back, revert) your code base to an earlier version.

&lt;ol&gt;&lt;li&gt;You just want to have an earlier version of the code, but don't need to work-on / commit-against the earlier revision.&lt;/li&gt;&lt;li&gt;You actually want to roll your project back to an earlier version and then work-on / commit-against the project with the earlier revision as your starting point.&lt;/li&gt;&lt;/ol&gt;

To accomplish #1, you simply &lt;tt&gt;update&lt;/tt&gt; your code back to the earlier revision (yeah, it's an &lt;tt&gt;update&lt;/tt&gt; operation even though you're going backwards).  Alternatively, if you want to be very antiseptic, you could &lt;tt&gt;checkout&lt;/tt&gt; the earlier revision.

&lt;p&gt;#2 is considerably more complicated.  There are hacky ways to handle it, but the "proper" method is described here: &lt;a href="http://jacwright.com/blog/75/how-to-roll-back-changes-using-subversion/"&gt;http://jacwright.com/blog/75/how-to-roll-back-changes-using-subversion/&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-273563085052739753?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/273563085052739753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/getting-back-to-earlier-revisions-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/273563085052739753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/273563085052739753'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/getting-back-to-earlier-revisions-in.html' title='Going back to earlier revisions in Subversion'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4667089059273258490.post-1550914031005518088</id><published>2009-08-03T22:48:00.044-07:00</published><updated>2011-09-16T19:31:23.653-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>next as a way to return from a block</title><content type='html'>&lt;p&gt;In Ruby, you can't return from a block with &lt;tt&gt;return&lt;/tt&gt;; this will instead return from the enclosing method; if there is no enclosing method (i.e. you are at toplevel), this will throw an error.&lt;/p&gt;

&lt;p&gt;However, the Ruby &lt;tt&gt;next&lt;/tt&gt; statement takes an argument, and seems to work as a means to return from a block without breaking out of any enclosing context.&lt;/p&gt;

&lt;p&gt;Demonstration:
&lt;pre class="brush: ruby"&gt;
def yielder
 ret = yield
 puts 'After yield'
 return ret
end
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Now from irb:
&lt;pre name="code" class="brush: ruby"&gt;
&gt;&gt; VERSION
=&gt; "1.8.6"

&gt;&gt; yielder{1}
After yield
=&gt; 1

&gt;&gt; yielder{return 1} # This tries to return from toplevel...
LocalJumpError: unexpected return

&gt;&gt; yielder{break 1} # This breaks completely out of the call to yielder...
=&gt; 1

&gt;&gt; yielder{next 1; puts 'In block'} # Aha! This breaks out of the block but stays in the method!
After yield
=&gt; 1
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;
As an example of how this can be useful:
&lt;pre class="brush: ruby"&gt;
  mixed_collection.sort do |x,y|
    next x.class.name &lt;=&gt; y.class.name if x.class != y.class
    x &lt;=&gt; y
  end
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;My main question at this point is, does this work in Ruby 1.9?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Works in Ruby 1.9.1&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4667089059273258490-1550914031005518088?l=absurdlycertain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://absurdlycertain.blogspot.com/feeds/1550914031005518088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/next-as-way-to-return-from-block.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1550914031005518088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4667089059273258490/posts/default/1550914031005518088'/><link rel='alternate' type='text/html' href='http://absurdlycertain.blogspot.com/2009/08/next-as-way-to-return-from-block.html' title='next as a way to return from a block'/><author><name>Peter</name><uri>http://www.blogger.com/profile/12008031568467006349</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
