<?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-28403206</id><updated>2011-08-10T07:38:17.676-07:00</updated><category term='regex'/><category term='rdf'/><category term='sudoku'/><category term='spreadsheet'/><category term='rx4rdf'/><category term='cms'/><category term='chart'/><title type='text'>n01senet</title><subtitle type='html'>A community blog by the members of &lt;a href="http://n01se.net"&gt;n01se.net&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-28403206.post-8925684559996977541</id><published>2008-05-14T18:24:00.000-07:00</published><updated>2008-05-15T06:13:46.101-07:00</updated><title type='text'>An array of functions.</title><content type='html'>&lt;p&gt;Write a function (in your favorite language) that takes an integer and returns an array of that length, where each item in the array is a function that returns its own index in the array.&lt;/p&gt;

&lt;p&gt;I proposed the above as a challenge for some friends, and got a few nice responses.&lt;/p&gt;

&lt;h3&gt;bash&lt;/h3&gt;
&lt;p&gt;The first answer was in bash by agriffis.  After some adjustments, he settled on:&lt;/p&gt;
&lt;pre&gt;makearray() {
  declare x arr=$1
  eval "$arr=()"
  for ((x=0;x&lt;$2;x++)); do
    eval "${arr}_func_$x() { echo $x; }; $arr[x]=${arr}_func_$x"
  done
}&lt;/pre&gt;
&lt;p&gt;To use it, pass in an array name and your desired array size:&lt;/p&gt;
&lt;pre&gt;makearray myarray 10&lt;/pre&gt;

&lt;p&gt;This is a bit of a cheat in that it actually creates an array of function &lt;span style="font-weight:bold;"&gt;names&lt;/span&gt;, not functions or closures.  But it's bash, so you should be impressed it's even vaguely possible.  To call the function at index 3:&lt;/p&gt;
&lt;pre&gt;${myarray[3]}&lt;/pre&gt;
&lt;p&gt;...and that echoes 3 to stdout, just as it should.&lt;/p&gt;

&lt;h3&gt;Python&lt;/h3&gt;
&lt;p&gt;Brett wrote a couple solutions in Python, settling on:&lt;/p&gt;
&lt;pre&gt;lambda x : map(lambda y : lambda : y, range(x))&lt;/pre&gt;
&lt;p&gt;This is pretty compact, so let's replace a couple of the lambdas with named function definitions:&lt;/p&gt;
&lt;pre&gt;def makefunc( y ):
  return (lambda : y)

def makearray( x ):
  return map( makefunc, range(x) )&lt;/pre&gt;
&lt;p&gt;This does exactly the same thing as Brett's original solution, but takes up more space doing it.  &lt;code&gt;range(x)&lt;/code&gt; gives us a sequence of integers, each of which is their own index.  So now all we need to do is convert each of those integers into a function.  &lt;code&gt;map()&lt;/code&gt; helps us do this by passing each of the integers to &lt;code&gt;makefunc&lt;/code&gt;, and returning an array of the results.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;makefunc&lt;/code&gt;'s job is to take an integer &lt;code&gt;y&lt;/code&gt; and return a function.  The lambda in &lt;code&gt;makefunc&lt;/code&gt; has nothing to the left of its colon (&lt;code&gt;:&lt;/code&gt;), so the returned function needs no arguments.&lt;/p&gt;
&lt;pre&gt;my_array = makearray( 10 )
one_of_the_funcs = my_array[ 3 ]
one_of_the_funcs()  # returns 3&lt;/pre&gt;
&lt;p&gt;Or you can pack it all back together:&lt;/p&gt;
&lt;pre&gt;(lambda x : map(lambda y : lambda : y, range(x)))( 10 )[ 3 ]()&lt;/pre&gt;
&lt;h3&gt;JavaScript&lt;/h3&gt;
&lt;p&gt;I originally thought of this challenge as a way to test someone's skill with JavaScript, so I thought I'd better write a JavaScript solution:&lt;/p&gt;
&lt;pre&gt;function makearray(x) {
  function makefunc(y) {
    return function(){ return y; }
  }

  var a=[];
  for( var i = 0; i &lt; x; ++i ) {
    a[i] = makefunc(i);
  }
  return a;
}&lt;/pre&gt;
&lt;p&gt;This is a lot like the longer Python solution, but there's no special lambda syntax, so I have to use the "&lt;code&gt;function&lt;/code&gt;" and "&lt;code&gt;return&lt;/code&gt;" keywords everywhere.  Also you can't generally rely on there being a map function, so I have a for-loop that looks a lot like agriffis' bash solution.&lt;/p&gt;

&lt;p&gt;There's no particular benefit to putting the &lt;code&gt;makefunc&lt;/code&gt; definition inside &lt;code&gt;makearray&lt;/code&gt;, except that it hides that name so nothing outside &lt;code&gt;makearray&lt;/code&gt; can call it.  The syntax for using it is actually identical to Python's:&lt;/p&gt;
&lt;pre&gt;makearray(10)[3]()&lt;/pre&gt;
&lt;p&gt;Watch out, though, because JavaScript makes it easy to do closures incorrectly.  It might seem like we don't need &lt;code&gt;makefunc&lt;/code&gt; at all, and that this would work:&lt;/p&gt;
&lt;pre&gt;function makebadarray(x) {
  var a=[];
  for( var i = 0; i &lt; x; ++i ) {
    a[i] = function(){ return i; } // not what you want
  }
  return a;
}&lt;/pre&gt;
&lt;p&gt;The problem with this is that all of the functions in the array will be referring to the same variable &lt;code&gt;i&lt;/code&gt;, whose final value is 10.  So although we'll have 10 different functions, they'll all return the same value:&lt;/p&gt;
&lt;pre&gt;makebadarray(10)[3](); // returns 10 (not 3)&lt;/pre&gt;
&lt;h3&gt;Perl&lt;/h3&gt;
&lt;p&gt;I first heard about closures while learning Perl, so it's only polite to include it:&lt;/p&gt;
&lt;pre&gt;sub makearray{ map { my $y = $_; sub{$y} } (0..$_[0]-1) }&lt;/pre&gt;
&lt;p&gt;Perl's &lt;code&gt;map&lt;/code&gt; acts just like Python's, but it has special syntax so you can just say "&lt;code&gt;map {...}&lt;/code&gt;" instead of "&lt;code&gt;map( lambda y : ... )&lt;/code&gt;".  Unfortunately, instead of naming your own variable, the special &lt;code&gt;$_&lt;/code&gt; variable is set to each element of your sequence in turn.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sub{$y}&lt;/code&gt; in Perl means the same thing as &lt;code&gt;(lambda : y)&lt;/code&gt; in Python.&lt;/p&gt;

&lt;p&gt;Oh, and you don't get to name your function parameters either, so &lt;code&gt;makearray&lt;/code&gt;'s first parameter is called &lt;code&gt;$_[0]&lt;/code&gt;.  We pass this to the &lt;code&gt;..&lt;/code&gt; operator which is like the &lt;code&gt;range()&lt;/code&gt; function (in this case).&lt;/p&gt;

&lt;p&gt;The syntax for using this is &lt;span style="font-weight:bold;"&gt;not&lt;/span&gt; identical to Python's:&lt;/p&gt;
&lt;pre&gt;&amp;{(makearray(10))[3]}&lt;/pre&gt;
&lt;h3&gt;Clojure&lt;/h3&gt;
&lt;p&gt;I'm on a Clojure kick these days, so of course I had to write:&lt;/p&gt;
&lt;pre&gt;(defn makearray [x] (map #(fn [] %) (range x)))&lt;/pre&gt;
&lt;p&gt;The elements here should all be familiar from the Python solution, except the very compact syntax &lt;code&gt;#(fn [] %)&lt;/code&gt; which is just a shortcut for &lt;code&gt;(fn [y] (fn [] y))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A quick aside: It is tempting to say &lt;code&gt;(fn [y] #(y))&lt;/code&gt;, but &lt;code&gt;#(y)&lt;/code&gt; is a function that &lt;span style="font-style:italic;"&gt;executes&lt;/span&gt; the value of &lt;code&gt;y&lt;/code&gt; instead of simply returning it.&lt;/p&gt;

&lt;p&gt;Anyway, a more important detail is that this Clojure &lt;code&gt;makearray&lt;/code&gt; doesn't actually return an array. All the previous solutions we've looked at create all ten functions, regardless of which ones we end up calling. In contrast, the Clojure &lt;code&gt;makearray&lt;/code&gt; returns a lazy sequence, and doesn't create any functions at all until they're accessed.&lt;/p&gt;

&lt;p&gt;So our standard usage:&lt;/p&gt;
&lt;pre&gt;((nth (makearray 10) 3))&lt;/pre&gt;
&lt;p&gt;...returns 3 just as the others did, but it only had to create the functions up through the one we asked for.&lt;/p&gt;

&lt;p&gt;One practical way to take advantage of this is to change &lt;code&gt;makearray&lt;/code&gt; to no longer take an argument, and instead allow it to generate an un-ending series of functions.  To do this we simply replace the bounded &lt;code&gt;(range x)&lt;/code&gt; with &lt;code&gt;(iterate inc 0)&lt;/code&gt;.  Let's also call the function &lt;code&gt;makeseq&lt;/code&gt; since that's more accurate:&lt;/p&gt;
&lt;pre&gt;(defn makeseq [] (map #(fn [] %) (iterate inc 0)))&lt;/pre&gt;
&lt;p&gt;Now call it:&lt;/p&gt;
&lt;pre&gt;((nth (makeseq) 99))&lt;/pre&gt;
&lt;p&gt;...returns 99, and since no more functions are required (by &lt;code&gt;nth&lt;/code&gt; in this case), no more work is done.&lt;/p&gt;

&lt;p&gt;Just to drive this home, realize that since &lt;code&gt;makeseq&lt;/code&gt; takes no arguments, it's returning an equivalent sequence every time.  This means it doesn't need to be a function at all:&lt;/p&gt;
&lt;pre&gt;(def myseq (map #(fn [] %) (iterate inc 0)))&lt;/pre&gt;
&lt;p&gt;This sets &lt;code&gt;myseq&lt;/code&gt; to the potentially infinite sequence, but at this point none of the functions have actually been created yet.  The functions are created on demand:&lt;/p&gt;
&lt;pre&gt;((nth myseq 25))  ; returns 25
((first myseq))   ; returns 0
(second myseq)    ; returns a function that, when
                  ; called, will return 1&lt;/pre&gt;
&lt;p&gt;So how would you complete this challenge in your favorite language?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-8925684559996977541?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/8925684559996977541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=8925684559996977541' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/8925684559996977541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/8925684559996977541'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2008/05/array-of-functions.html' title='An array of functions.'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-2500730128598894269</id><published>2008-03-27T15:22:00.000-07:00</published><updated>2008-03-27T16:05:47.770-07:00</updated><title type='text'>Ubuntu java plugin on Debian Lenny amd64</title><content type='html'>&lt;p&gt;Things I tried today:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;apt-get install sun-java6-jre; no plugin included&lt;/li&gt;&lt;li&gt;apt-get install sun-java5-jre; no plugin inculded&lt;/li&gt;&lt;li&gt;apt-get install ia32-sun-java6-bin nspluginwrapper; this combination doesn't work because Java uses the OJI plugin API instead of the NPAPI that nspluginwrapper supports&lt;/li&gt;&lt;li&gt;download various packages from java.sun.com and install them using make-jpkg; oddly, this doesn't change the fact that Sun's Java doesn't provide an amd64 plugin, duh!&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Finally, thanks to Dave Medberry's suggestion, I downloaded the Ubuntu Blackdown amd64 package from &lt;a href="http://packages.ubuntu.com/hardy/j2re1.4"&gt;http://packages.ubuntu.com/hardy/j2re1.4&lt;/a&gt; and installed it directly with dpkg.  The final manual step was:&lt;/p&gt;
&lt;pre&gt;sudo ln -s /usr/lib/j2se/1.4/jre/plugin/amd64/mozilla/libjavaplugin_oji.so /usr/lib/iceweasel/plugins/&lt;/pre&gt;
&lt;p&gt;It might not be the latest version, but it works...!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-2500730128598894269?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/2500730128598894269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=2500730128598894269' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/2500730128598894269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/2500730128598894269'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2008/03/ubuntu-java-plugin-on-debian-lenny.html' title='Ubuntu java plugin on Debian Lenny amd64'/><author><name>agriffis</name><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-28403206.post-7487744608192269970</id><published>2008-03-12T08:45:00.000-07:00</published><updated>2008-03-12T10:46:20.591-07:00</updated><title type='text'>Why you want macros (even if you don't know it yet)</title><content type='html'>&lt;p&gt;&lt;small&gt;&lt;i&gt;This is a slightly edited transcript of a conversation
with my friend Brian.&lt;/i&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Let's say you want to write your own "or" function.  Let's say you're
not satisfied with C++'s &lt;code&gt;||&lt;/code&gt; because you want the actual value that is
true, not just the boolean "true".  You want to be able to say:
&lt;pre&gt;    QString x = y || "default";&lt;/pre&gt;
And to make things easy, let's not worry
about the goofy operator syntax.  You'd be happy with:
&lt;pre&gt;    QString x = my_or( y, "default" );&lt;/pre&gt;
Now, you could write that, right?  Let's assume
it only works on QStrings too, just to make things easy:
&lt;pre&gt;    QString my_or( const QString&amp; a, const QString&amp; b ) {
      return a.isEmpty() ? b : a;
    }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;But what if b
is a big ol' calculation:
&lt;pre&gt;    QString x = my_or( y, calculateDefault() );&lt;/pre&gt;
You want to short-circuit, and only call
&lt;code&gt;calculateDefault()&lt;/code&gt; if &lt;code&gt;y&lt;/code&gt; is
false. In C++ you're screwed.  Can't do it.&lt;/p&gt;
&lt;p&gt;Also screwed in Java, C# (as far as I know), perl, ruby, etc.  You
need macros, or something similar. &lt;i&gt;[See below for what I learned
about C#]&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Now, there are half measures that will let you squeak by in
this very simple case.  You can in fact use C pre-processor macros.
Gross, but you can:
&lt;pre&gt;    #define my_or( a, b )  ((a)?(a):(b))&lt;/pre&gt;
Oops, I just evaluated &lt;code&gt;a&lt;/code&gt; twice.&lt;/p&gt;
&lt;p&gt;In javascript (or perl or ruby) you can use
closures:
&lt;pre&gt;    function my_or( fa, fb ) {
      var a = fa();
      return a ? a : fb();
    }&lt;/pre&gt;
and then call it with this happy formulation:
&lt;pre&gt;    var x = my_or( function() { return y; },
                   function() { return calculateDefault(); } );&lt;/pre&gt;
ew.
&lt;/p&gt;
&lt;p&gt;Now if the only reason you want a macro
is for delayed evaluation (which is all you need in this case), Scala
gives you that one particular feature.
&lt;pre&gt;    def my_or( a: =&amp;gt; String, b: =&amp;gt; String ) = {
      if( a ) a; else b;
    }&lt;/pre&gt;
That tricky little &lt;code&gt;=&amp;gt;&lt;/code&gt; tossed in
there makes the argument "lazy" and gives us what we need in this
case.  But of course there are other things that macros provide that
the lazy argument feature does not.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;b&gt;Brian:&lt;/b&gt; So you would argue that macros should be part of every modern
computer language&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;oh.  Well... Hm, I'd never thought of phrasing it that way.&lt;/p&gt;
&lt;p&gt;Having macros makes a language much more flexible and powerful.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;b&gt;Brian:&lt;/b&gt; Are macros in other languages like lisp implemented in a
pre-processor fashion?&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Lisp macros can call any regular lisp function.  This a fundamental difference compared to, for example, C pre-proc macros which can't use anything except other pre-proc macros.
Usage of lisp macros are expanded before the result is evaluated,
so it's "pre" in that sense, but they can use other functions and
macros and in that sense they're very much mixed into the evaluation
system.&lt;/p&gt;
&lt;p&gt;It's interesting to note that Clojure, for example, &lt;a href="http://clojure.sourceforge.net/reference/evaluation.html"&gt;has no
interpreter&lt;/a&gt;. It compiles everything into Java bytecode on the fly
before it runs it.  But it still has full-on lisp macros.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;b&gt;Brian:&lt;/b&gt; It would be interesting to see what the Scala folks think about
macros&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Yeah, I whined about them quite a bit in the Scala IRC channel.
Somebody seemed to think someone was working on them.  *shrug*&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;b&gt;Brian:&lt;/b&gt; &lt;a href="http://themechanicalbride.blogspot.com/2007/03/runtime-macros-in-c-30.html"&gt;Runtime
macros in C# 3.0&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Interesting.&lt;/p&gt;
&lt;p&gt;So the two drawbacks of C#'s solution (compared to Clojure) are (1) special syntax for calling a "macro" and (2) expansion happens at runtime.
But it's a bit better off than say JavaScript which can't do C++
tricks because it has no pre-processor, and can't do C#'s tricks
because it doesn't have access to parse trees.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;b&gt;Brian:&lt;/b&gt; That's what you really want -- some sort of access to the parse
tree.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Right, access to the parse tree. exactly.&lt;/p&gt;
&lt;p&gt;For the record, Clojure's built in &lt;code&gt;or&lt;/code&gt; already does
what we want, and is in fact implemented as a macro.  You can find the
real version in Clojure's &lt;code&gt;boot.clj&lt;/code&gt; file.  That one's already pretty
simple, but here's a slightly simplified version
that handles just the two-argument examples above:
&lt;pre&gt;    (defmacro my-or [a b] `(let [av# ~a] (if av# av# ~b)))&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-7487744608192269970?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/7487744608192269970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=7487744608192269970' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/7487744608192269970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/7487744608192269970'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2008/03/why-you-want-macros-even-if-you-dont.html' title='Why you want macros (even if you don&apos;t know it yet)'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-6542105333764656710</id><published>2008-02-13T07:48:00.000-08:00</published><updated>2008-02-13T08:47:43.218-08:00</updated><title type='text'>clojure is the best lisp yet</title><content type='html'>&lt;p&gt;I've dabbled in a few lisp dialects, but I generally become
frustrated with some deficiency or other.  I had been holding out some
hope for Paul Graham's &lt;a href="http://arclanguage.org/"&gt;arc&lt;/a&gt;, but
when I tried it out, I wasn't exactly blown away.&lt;/p&gt;
&lt;p&gt;Common Lisp has a rather bloated library of functions, many with
disgustingly long names.  Arc has indeed successfully addressed this
problem, and so has clojure: the longest function name I could find in
Clojure's succinct and powerful library was the outlier
"clear-agent-errors".&lt;/p&gt;
&lt;p&gt;Lisp is old enough that many dialects have trouble with modern
character encodings.  Arc doesn't support anything but ASCII (so far
anyway), and although elisp does it seems to regard UTF-8 with
suspicion.  Clojure supports UTF-8 out of the box, even inlined in
your source code.&lt;/p&gt;
&lt;p&gt;Many lisps have a shocking shortage of useful library modules for
common tasks, especially related to networking or particular file
formats, when compared to Perl, Python, etc., and creating bindings
for existing C or other native libraries can be pretty tricky.
Clojure allows you to directly use any part of any existing Java
library, no special bindings needed.&lt;/p&gt;
&lt;p&gt;With a large variety of libraries comes name collisions.  Arc
apparently hasn't addressed this problem yet, while clojure has all
the namespace support you'll need.&lt;/p&gt;
&lt;p&gt;JavaScript and other modern languages have demonstrated to me the
power of hashes and the utility of being able to easily initialize
them with literals in my code, yet few lisps make this convenient.
Clojure has rich support for sorted maps, hash maps, and struct maps
(which allow you to efficiently store a large number of hashs with
common keys), including succinct syntax for creating new ones.&lt;/p&gt;
&lt;p&gt;Besides cleaning up some of lisp's historic weaknesses, clojure
provides several innovative new features.  For example, the idea of
data structure interfaces allows you to write code that can work the
same on a variety of concrete types.  The (conj ...) function adds an
item to a collection, whether that collection is a list, a vector, or
a hash.&lt;/p&gt;
&lt;p&gt;I also found it interesting that Clojure's built in data structures
are all immutable.  The API makes working with these convenient, and
should allow you to avoid common hassles when dealing with
concurrency.&lt;/p&gt;
&lt;p&gt;There are many other little details that clojure seems to have
tweaked for the better compared to older lisps.  The syntax for
defining macros is a little tidier, (cond... ) is a bit more succinct,
and it even has support for literal regular expressions.&lt;/p&gt;
&lt;p&gt;I don't know &lt;span style="font-weight: bold;"&gt;that&lt;/span&gt; many
lisps, and none of them very deeply.  But for what it's worth, &lt;a
href="http://clojure.sourceforge.net/"&gt;clojure&lt;/a&gt; is my favorite.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-6542105333764656710?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/6542105333764656710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=6542105333764656710' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/6542105333764656710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/6542105333764656710'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2008/02/clojure-is-best-lisp-yet.html' title='clojure is the best lisp yet'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-2730961321916870776</id><published>2008-02-07T06:35:00.000-08:00</published><updated>2008-02-07T08:12:18.296-08:00</updated><title type='text'>experimenting with vnc</title><content type='html'>&lt;p&gt;My home setup consists of a server in the basement with &lt;a
href="http://h10010.www1.hp.com/wwpc/us/en/sm/WF04a/12454-12454-321959-338927-89307.html"&gt;thin clients&lt;/a&gt;
in the upstairs office.  I love this setup because it means the office is
entirely solid state; no fans or disks to make noise.  It's the ultimate &lt;a
href="http://www.silentpcreview.com/"&gt;silent PC&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Method 1: XDMCP&lt;/h3&gt;

&lt;p&gt;I typically don't run applications on the thin clients, rather I run an
X server with -broadcast to get an XDMCP session from my server.  From that
point on, everything (gnome, window manager, browser, xterms, etc.) runs on the
server with $DISPLAY pointing at the thin client.  This is pretty simple to set
up, just change gdm.conf on the server:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
--- gdm.conf.dpkg-dist  2007-05-29 05:08:37.000000000 -0400
+++ gdm.conf    2008-02-07 09:56:42.000000000 -0500
@@ -59,2 +59,3 @@
 [xdmcp]
+Enable=true
 
@@ -74,2 +75,3 @@
 [servers]
+0=inactive
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;and on the thin client, in /etc/rc.local:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
X -broadcast
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;h3&gt;Method 2: VNC&lt;/h3&gt;

&lt;p&gt;Running X remotely, even on a 100 Mbit network, can get slow.  In particular,
Firefox just crawls.  Making a new tab (blank page), chug chug.  Rendering
pages, chug chug.  It's plenty usable, and you can get used to it, but it's
a shock to go back to a normal PC and see the speedup that local rendering buys.
(Xterms, btw, are plenty fast on remote X because they're just sending
characters to the server, which it then renders locally.)&lt;/p&gt;

&lt;p&gt;So I started experimenting with VNC.  To my delight, VNC restores Firefox's
rendering speed.  In fact, VNC is fast all around.  I see some very minor
latency in my xterms since they're now sending graphics over the link instead of
characters, but it's barely a price to pay for the overall speedup.&lt;/p&gt;

&lt;p&gt;Here's what I did to make this work.  First the server, I install &lt;tt&gt;apt-get
install vnc4server&lt;/tt&gt;, then create three entries in inetd.conf to correspond
to the screens I have attached to the thin clients:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
server # cat &amp;gt;&amp;gt; /etc/inetd.conf &amp;lt;&amp;lt;EOF
5910 stream tcp nowait nobody /usr/bin/Xvnc4 Xvnc4 -inetd \
  -depth 24 -geometry 1024x768 -fp tcp/oliva:7100 \
  -query localhost -once -securitytypes none
5912 stream tcp nowait nobody /usr/bin/Xvnc4 Xvnc4 -inetd \
  -depth 24 -geometry 1280x1024 -dpi 85 -fp tcp/oliva:7100 \
  -query localhost -once -securitytypes none
5919 stream tcp nowait nobody /usr/bin/Xvnc4 Xvnc4 -inetd \
  -depth 24 -geometry 1920x1200 -dpi 93 -fp tcp/oliva:7100 \
  -query localhost -once -securitytypes none
EOF
server # /etc/init.d/openbsd-inetd restart
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;On the thin client I &lt;tt&gt;apt-get install xvnc4viewer&lt;/tt&gt;, then replace the
-broadcast line in /etc/rc.local with:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
# this corresponds to the 1920x1200 entry, suitable for a 24" LCD
xinit /usr/bin/xvnc4viewer -fullcolor -fullscreen server:5919
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;h3&gt;Still investigating...&lt;/h3&gt;

&lt;p&gt;Not everything is perfect using VNC.  Here are a few problems I've run
into:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;caps-lock: I normally override caps-lock to be mod4 to control my window
  manager.  It turns out that xvnc4viewer doesn't forward the caps-lock to
  Xvnc4, instead it's handled on the thin client's X server.  That means that it
  can't be remapped inside the VNC session, instead I have to do it partly on
  the thin client: 
    &lt;tt&gt;ssh t5710 "xmodmap -e 'remove lock = Caps_Lock' -e
    'keysym Caps_Lock = Super_R'&lt;/tt&gt;
  then inside the VNC session: &lt;tt&gt;xmodmap -e 'add mod4 = Super_L Super_R'&lt;/tt&gt;.
  &lt;/li&gt;
  &lt;li&gt;mouse: My mouse has a bunch of buttons, which normally I can remap with
  xmodmap. With this setup, though, I only get 5 buttons (left, middle, right,
  scroll up, scroll down).  I haven't figured out a workaround for this yet.
  &lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-2730961321916870776?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/2730961321916870776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=2730961321916870776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/2730961321916870776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/2730961321916870776'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2008/02/experimenting-with-vnc.html' title='experimenting with vnc'/><author><name>agriffis</name><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-28403206.post-1204909640327374760</id><published>2007-07-06T17:30:00.000-07:00</published><updated>2007-07-06T13:19:29.249-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cms'/><category scheme='http://www.blogger.com/atom/ns#' term='rdf'/><category scheme='http://www.blogger.com/atom/ns#' term='rx4rdf'/><title type='text'>how to use a custom theme in rx4rdf</title><content type='html'>I've started experimenting with &lt;a href="http://rx4rdf.liminalzone.org/"&gt;rx4rdf&lt;/a&gt;, and although there are more useful things I could do first, I started trying to replace the default visual theme with a custom one just for &lt;a href="http://n01se.net/"&gt;n01se.net&lt;/a&gt;.  After much stumbling around, I found what I needed to add to the &lt;a href="http://rx4rdf.liminalzone.org/RhizomeManual?#id3054273900L"&gt;site-config.py&lt;/a&gt; file in order for my own XSLT (really &lt;a href="http://rx4rdf.liminalzone.org/RxSLT"&gt;RxSLT&lt;/a&gt;) and &lt;a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets"&gt;CSS&lt;/a&gt; stylesheets to work.

First I used __addItem__ to make rx4rdf aware of the two new stylesheet files, and how to treat each of them:
&lt;pre&gt;  __addItem__('n01senet-theme.xsl', loc="path:n01senet-theme.xsl",
    format='http://www.w3.org/1999/XSL/Transform',
    disposition='template'),

  __addItem__('n01senet-theme.css', loc="path:n01senet-theme.css",
    format='text', disposition='complete'),
&lt;/pre&gt;The server will now expect to find those files in my site's "content" directory.

Next I created a new "theme" made up of those two stylesheets:
&lt;pre&gt;  __addRxML__(replace = '@themes', contents = '''
  base:n01senet-theme:
    a: wiki:SiteTheme
    wiki:uses-css-stylesheet: base:n01senet-theme.css
    wiki:uses-site-template-stylesheet: base:n01senet-theme.xsl
    rdfs:comment: `custom theme for n01se.net
  ''')
&lt;/pre&gt;Note by using "replace =" above, I disabled the three themes that ship with rx4rdf.  That's ok with me, since I won't be needing them for this site.

Finally, I configured my sitevars to point to the new theme:
&lt;pre&gt;  __addRxML__(replace = '@sitevars', contents = '''
  base:site-template:
    wiki:header-image: `n01senet-logo2.png
    #wiki:header-text: `n01se.net rocks!
    wiki:footer-text: `© 2007 n01se.net
    wiki:uses-theme: base:n01senet-theme
    #wiki:uses-skin:  base:skin-lightblue.css
  ''')
&lt;/pre&gt;I also commented out the uses-skin predicate because I don't need another CSS file included.

This may not be the best way to do this, but since I couldn't find any existing documentation on how it &lt;span style="font-weight:bold;"&gt;should&lt;/span&gt; be done, I thought it would be worth writing up what worked for me.

I started off with n01senet-theme.css and .xsl files copied from rx4rdf-0.6.0/rhizome/themes/default/theme.css and .xsl files, and started modifying them to look like I want.  I'm not done yet, but it looks like I'll have all the flexibility I need (a.k.a. enough rope to hang myself)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-1204909640327374760?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/1204909640327374760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=1204909640327374760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/1204909640327374760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/1204909640327374760'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2007/07/how-to-use-custom-theme-in-rx4rdf.html' title='how to use a custom theme in rx4rdf'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-1731867990308492612</id><published>2007-05-08T19:15:00.000-07:00</published><updated>2007-05-09T15:51:22.349-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spreadsheet'/><category scheme='http://www.blogger.com/atom/ns#' term='sudoku'/><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><category scheme='http://www.blogger.com/atom/ns#' term='chart'/><title type='text'>regex engine timing charts</title><content type='html'>Charts by &lt;a href="http://spreadsheets.google.com/pub?key=p1hkQs__fVyY2x5Yp0saTXw"&gt;Google Spreadsheets&lt;/a&gt; (taller columns are worse):
&lt;br clear=all /&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_JhW7eztQN08/RkEzzY-SchI/AAAAAAAAAAc/MV_QLTasyzE/s1600-h/sudoku_regex_timing.png"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_JhW7eztQN08/RkEzzY-SchI/AAAAAAAAAAc/MV_QLTasyzE/s400/sudoku_regex_timing.png" alt="" id="BLOGGER_PHOTO_ID_5062384414111199762" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_JhW7eztQN08/RkE4XY-SciI/AAAAAAAAAAk/88N4QLyK3WQ/s1600-h/sudoku_regex_timing.png"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_JhW7eztQN08/RkE4XY-SciI/AAAAAAAAAAk/88N4QLyK3WQ/s400/sudoku_regex_timing.png" alt="" id="BLOGGER_PHOTO_ID_5062389430633001506" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-1731867990308492612?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/1731867990308492612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=1731867990308492612' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/1731867990308492612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/1731867990308492612'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2007/05/regex-engine-timing-charts.html' title='regex engine timing charts'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_JhW7eztQN08/RkEzzY-SchI/AAAAAAAAAAc/MV_QLTasyzE/s72-c/sudoku_regex_timing.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-5934224088894645588</id><published>2007-05-08T11:04:00.000-07:00</published><updated>2007-05-08T11:14:26.137-07:00</updated><title type='text'>regex engine timing</title><content type='html'>&lt;p&gt;Writing a regex-based sudoku solver with very little language-dependent code
opened the door to benchmarking the various PCRE engines.  Without much work,
I was able to test &lt;a href="http://perl.com"&gt;perl&lt;/a&gt;, 
&lt;a href="http://ruby-lang.org"&gt;ruby&lt;/a&gt;, &lt;a href="http://python.org"&gt;python&lt;/a&gt;
and &lt;a href="http://psyco.sf.net"&gt;python-psyco&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;Here are the results, unit is seconds:
&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
                sudre.pl  sudre.rb  sudre.py  sudre.psyco
empty.input     0.012     0.028     0.316     0.240
full.input      0.032     0.076     0.312     0.264
level-1.input1  0.028     0.072     0.328     0.268
level-1.input2  0.028     0.068     0.328     0.268
level-1.input3  0.024     0.052     0.328     0.248
level-1.input4  0.008     0.020     0.316     0.240
level-1.input5  0.008     0.016     0.308     0.236
level-2.input1  0.012     0.016     0.320     0.228
level-2.input2  0.112     0.300     0.400     0.356
level-2.input3  0.172     0.464     0.440     0.412
level-2.input4  0.016     0.048     0.316     0.252
level-2.input5  0.064     0.184     0.340     0.288
level-3.input1  0.212     0.552     0.484     0.424
level-3.input2  0.028     0.072     0.336     0.244
level-3.input3  1.404     3.564     1.428     1.492
level-3.input4  0.072     0.172     0.360     0.296
level-3.input5  3.676     8.725     3.044     3.332
level-4.input1  0.612     1.504     0.840     0.776
level-4.input2  1.580     4.036     1.604     1.736
level-4.input3  0.076     0.220     0.332     0.316
level-4.input4  0.052     0.140     0.352     0.284
level-4.input5  0.076     0.196     0.368     0.292
                -----     -----     -----     -----
          mean  0.377     0.933     0.600     0.568
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Some quick observations:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Perl is fastest on most of the puzzles, but python is far more consistent.
    My first guess is that python takes a lot longer to compile the regex,
    but may execute it faster after it's compiled.
&lt;li&gt;Ruby-1.8 (current stable) crashes with a stack overflow trying to compile
    the regex.  Ruby-1.9 was used for this test.
&lt;li&gt;It would be interesting to make some graphs out of this...  volunteers?
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-5934224088894645588?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/5934224088894645588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/5934224088894645588'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2007/05/regex-engine-timing.html' title='regex engine timing'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-2670462912192684072</id><published>2007-05-03T09:03:00.000-07:00</published><updated>2007-05-03T15:05:17.136-07:00</updated><title type='text'>sudoku by regex</title><content type='html'>&lt;p&gt;About a year ago, I proposed a contest on #noise to write a sudoku solver.
LIM wrote us a driver and generator.  Chouser, Mr_Bones_, and owend wrote
solvers.  I started one in LISP but never finished it, to my shame...
&lt;/p&gt;

&lt;p&gt;One question that's always been in my mind is "How could we use a regex to
solve a sudoku?"  The main problem seems to be the input: Regular expressions
are a language for searching, so you need the search space expressed in a way
that the regex can process it.  The naive approach expresses all the possible
puzzles on the input, which is way too much data.
&lt;/p&gt;

&lt;p&gt;I usually think of a sudoku like this, where zeros are squares that need to
be solved:
&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
0 0 0 4 0 0 0 0 0
0 0 0 0 0 2 0 7 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 4 1 0
0 0 9 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 6 7
0 0 0 0 0 0 0 0 0
0 7 6 3 0 0 0 0 0
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The problem with this representation is that the zeros aren't searchable.
The regular expression can't tell that they mean "any number 1 through 9".  So
for a first step, my solver replaces them:
&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
$puz =~ s{\d}{$&amp; ? $&amp;amp;.'        ' : '123456789'}ge;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;So the massaged input looks like this:
&lt;/p&gt;

&lt;blockquote&gt;&lt;font size=-1&gt;&lt;pre&gt;
123456789 123456789 123456789 4         123456789 123456789 123456789 123456789 123456789
123456789 123456789 123456789 123456789 123456789 2         123456789 7         123456789
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
123456789 123456789 123456789 123456789 123456789 123456789 4         1         123456789
123456789 123456789 9         123456789 123456789 123456789 123456789 123456789 123456789
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
123456789 123456789 123456789 123456789 123456789 123456789 123456789 6         7
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
123456789 7         6         3         123456789 123456789 123456789 123456789 123456789
&lt;/pre&gt;&lt;/font&gt;&lt;/blockquote&gt;

&lt;p&gt;Now each cell contains the full list of possibilities for that cell.  This is
searchable.  And with negative lookahead assertions, it doesn't have to waste
nearly as much time backtracking.
&lt;/p&gt;

&lt;p&gt;The final output, after the second substitution, is:
&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
9 8 7 4 6 5 3 2 1
6 5 4 1 3 2 9 7 8
3 2 1 9 8 7 6 5 4
8 6 5 7 9 3 4 1 2
7 4 9 8 2 1 5 3 6
2 1 3 6 5 4 7 8 9
5 3 8 2 4 9 1 6 7
1 9 2 5 7 6 8 4 3
4 7 6 3 1 8 2 9 5
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Neat, eh?  So finally, here are the two scripts implementing this solution.
The first script is the solver itself.  It accepts a puzzle on stdin formatted
like the input above, converts it internally to the searchable format, and
generates on stdout the solved puzzle.  The second script generates the regular
expression which is inserted into the first script.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://n01se.net/paste/jFa"&gt;sudre.pl&lt;/a&gt;
&lt;li&gt;&lt;a href="http://n01se.net/paste/6f"&gt;genre.pl&lt;/a&gt;
&lt;/ul&gt;

&lt;p&gt;By the way, while this isn't the fastest solver out there by any means (it's
just brute force, after all), it solves most puzzles in approximate 0.01
seconds.  That's 1/10 of the time genre.pl takes to generate the regular
expression in the first place.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-2670462912192684072?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/2670462912192684072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/2670462912192684072'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2007/05/sudoku-by-regex.html' title='sudoku by regex'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-117072248752444394</id><published>2007-02-05T16:39:00.000-08:00</published><updated>2007-02-05T17:08:12.523-08:00</updated><title type='text'>Scratching the mutt, part 2: Patch and configuration</title><content type='html'>&lt;p&gt;This is part 2 of a series that started 
&lt;a href="http://n01senet.blogspot.com/2006/10/scratching-mutt-part-1-introducing.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before jumping into the patch and configuration details for using sendbox, let's
take one step back and review the reasons for sending via IMAP.  Sending email
via IMAP gets mixed reviews in the community because it is non-standard, seldom
supported by mail user agents (such as mutt), and supported by few IMAP servers
(I'm only aware of Courier IMAP).  The argument is that mail should be sent via
SMTP and received via IMAP, and isn't that good enough?&lt;/p&gt;

&lt;p&gt;I think there are good reasons to consider using IMAP for sending:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;only a single connection to the server needed&lt;/li&gt;
  &lt;li&gt;avoid reconfiguring the local MTA to use the appropriate outgoing SMTP server to match my From address&lt;/li&gt;
  &lt;li&gt;avoid messing with SMTP-AUTH&lt;/li&gt;
  &lt;li&gt;avoid sending the message twice over the wire, i.e. once over SMTP and once over IMAP to put it in the "sent" folder&lt;/li&gt;
  &lt;li&gt;works well for offline situations, don't need to cook up separate offline methods for both IMAP and SMTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, these reasons trump the naysayers' arguments.  Overall, sending email
via IMAP is more elegant than splitting the operations between IMAP and SMTP,
and elegance in software attracts me irresistably.&lt;/p&gt;

&lt;p&gt;Let's start with the patch then talk about configuration details to make use of
it.  After all, the patch introduces latent functionality that won't take effect
unless you change your configuration.  But configuration is useless without the
patch.&lt;/p&gt;

&lt;h3&gt;Obtaining a patched mutt&lt;/h3&gt;

&lt;p&gt;Here are three options for obtaining a patched mutt:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you're on Gentoo, use mercurial to fetch the n01se.net overlay and use
emerge:

&lt;blockquote&gt;&lt;pre&gt;
hg clone &lt;a href="http://n01se.net/gentoo/overlay"&gt;http://n01se.net/gentoo/overlay&lt;/a&gt; overlay-noise
export PORTDIR_OVERLAY="$PWD/overlay-noise $PORTDIR_OVERLAY"
emerge mutt
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;/li&gt;

&lt;li&gt;If you're on Debian, use my n01se.net apt repository:

&lt;blockquote&gt;&lt;pre&gt;
echo deb &lt;a href="http://n01se.net/agriffis/debian"&gt;http://n01se.net/agriffis/debian&lt;/a&gt; sid main &amp;gt;&amp;gt; /etc/apt/sources.list
echo deb-src &lt;a href="http://n01se.net/agriffis/debian"&gt;http://n01se.net/agriffis/debian&lt;/a&gt; sid main &amp;gt;&amp;gt; /etc/apt/sources.list
apt-get update
apt-get install mutt
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;/li&gt;

&lt;li&gt;Apply the patches and build it yourself.  This patches was made on 1.5.12
but applies cleanly and works on 1.5.13 too.

&lt;blockquote&gt;&lt;pre&gt;
wget &lt;a href="http://n01se.net/agriffis/mutt/mutt-1.5.12-sendbox.patch"&gt;http://n01se.net/agriffis/mutt/mutt-1.5.12-sendbox.patch&lt;/a&gt;
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Configuring your Outbox in mutt&lt;/h3&gt;

&lt;p&gt;There are three ways to use Courier's Outbox (if you learn of another IMAP
server that supports the Outbox concept, I'd love to hear about it).  The first
way is to simply specify it in your configuration.  For an IMAP configuration,
that would be:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
set sendbox=imaps://imap.domain.com/INBOX/Outbox
set use_sendbox=yes
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This simplistic configuration works if the administrator of your mail server has
enabled Outbox by default.  Unfortunately this is seldom the case.  More
commonly, you'll need to the second way, which is to ssh into the server and
start imapd yourself to enable Outbox.  This is simpler than it sounds, just add
to the above:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
set &lt;a href="http://mutt.org/doc/devel/manual.html#tunnel"&gt;tunnel&lt;/a&gt;="ssh -q server.domain.com   env OUTBOX=.Outbox SENDMAIL=/usr/sbin/sendmail /usr/sbin/courier-imapd .maildir"
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;To make this work with multiple servers, you can use 
&lt;a href="http://mutt.org/doc/devel/manual.html#account-hook"&gt;account
hooks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're an &lt;a href="http://software.complete.org/offlineimap"&gt;offlineimap&lt;/a&gt; 
user, your offlineimaprc should have something like this:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
[Account email]
localrepository = local
remoterepository = remote

[Repository local]
type = Maildir
localfolders = ~/mail
sep = .

[Repository remote]
type = IMAP
preauthtunnel = ssh -q server.domain.com   'env OUTBOX=.Outbox SENDMAIL=/usr/sbin/sendmail /usr/sbin/courier-imapd .maildir'
nametrans = lambda foldername: re.sub('^INBOX\.', '', foldername)
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;and your muttrc can then contain simply:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
set sendbox=~/mail/Outbox
set use_sendbox=yes
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Just don't forget to run offlineimap after sending mail from mutt, otherwise
it won't leave your local Outbox!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-117072248752444394?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/117072248752444394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/117072248752444394'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2007/02/scratching-mutt-part-2-patch-and.html' title='Scratching the mutt, part 2: Patch and configuration'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-116235058335769262</id><published>2006-10-31T17:03:00.000-08:00</published><updated>2006-11-01T06:10:16.270-08:00</updated><title type='text'>Scratching the mutt, part 1: Introducing sendbox</title><content type='html'>&lt;p&gt;Two years ago I
&lt;a href="http://dev.gentoo.org/~agriffis/email/"&gt;documented my configuration&lt;/a&gt;
of
&lt;a href="http://mutt.org/"&gt;mutt&lt;/a&gt;,
&lt;a href="http://freshmeat.net/projects/offlineimap/"&gt;offlineimap&lt;/a&gt; and
&lt;a href="http://www.courier-mta.org/imap/"&gt;courier imap&lt;/a&gt;.  This combination
gave me complete offline access (critical on a laptop) including folders and
sending new messages.  Additionally it scaled painlessly to multiple servers and
clients, without my needing to think about keeping them in sync.  Life was
good, for a while...&lt;/p&gt;

&lt;p&gt;More recently, I decided that I'd like to use mutt with IMAP directly on some
client machines (workstations) and offlineimap on other machines (laptops).
I rewrote my muttrc to be preprocessed with
&lt;a href="http://www.gnu.org/software/m4/"&gt;m4&lt;/a&gt;, and everything was rosy,
except for sending via
&lt;a href="http://www.inter7.com/courierimap/INSTALL.html#imapsend"&gt;Outbox&lt;/a&gt;...
&lt;/p&gt;

&lt;p&gt;The method I was using depended on a helper script
(&lt;a href="http://dev.gentoo.org/~agriffis/email/mailout"&gt;mailout&lt;/a&gt;) which
called &lt;a href="http://jeenyus.net/~budney/linux/software/safecat.html"&gt;safecat&lt;/a&gt;
to deposit mail in the Outbox.  That script no longer suffices, because it needs
to save to IMAP rather than local
&lt;a href="http://cr.yp.to/proto/maildir.html"&gt;maildir&lt;/a&gt;.  Of course we want to
use mutt's existing connection to the server rather than create another
connection in the script!  So I needed to find a way to make it work within
mutt.&lt;/p&gt;

&lt;p&gt;What started as an elegant hack quickly turned ugly.  I tried setting
&lt;a href="http://mutt.org/doc/devel/manual.html#sendmail"&gt;$sendmail&lt;/a&gt;=/bin/true
and used &lt;a href="http://mutt.org/doc/devel/manual.html#record"&gt;$record&lt;/a&gt; to
fcc the message to the IMAP Outbox.  This hack generally worked.  The
&lt;a href="http://www.plumlocosoft.com/software/download/mutt-1.5.4-imap-fcc-status.patch"&gt;fcc-status
  patch&lt;/a&gt; is needed to prevent "Status: RO" (screws up the recipients that use
mboxes; the mail
&lt;a href="https://www.redhat.com/archives/fedora-devel-list/2006-July/msg00771.html"&gt;shows
  up as already-read&lt;/a&gt;).
Additionally mutt doesn't provide a method to fcc to more than one folder, so
to get an fcc other than the Outbox, I used the write-fcc function in the
compose menu.  That was borked though because it lacks the Message-ID,
encryption/signing, date, etc!&lt;/p&gt;

&lt;p&gt;Moreover it all falls apart when
&lt;a href="http://mutt.org/doc/devel/manual.html#forwarding-mail"&gt;bouncing
  (remailing)&lt;/a&gt; messages, because that code path calls mutt_invoke_sendmail
directly, and of course no fcc is done.&lt;/p&gt;

&lt;p&gt;Finally I realized that these hackish methods were going nowhere fast, so
I implemented Outbox support directly in mutt.  I call it "sendbox" because
I think that's more explicit.  Plus mutt already has an internal variable Outbox
that corresponds to the
&lt;a href="http://mutt.org/doc/devel/manual.html#record"&gt;$record&lt;/a&gt; setting, and
I wanted to avoid confusion.&lt;/p&gt;

&lt;p&gt;To use this feature, one does something like:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
set sendbox=imaps://imap.domain.com/INBOX/Outbox
set use_sendbox=yes
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;...then all mail is sent by saving it to the Outbox instead of calling
sendmail.&lt;/p&gt;

&lt;p&gt;Part 2 in this series will explain this configuration in more
detail and provide the patches to make it happen.  Later parts will document
some other interesting (at least to me) parts of my mutt setup.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-116235058335769262?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/116235058335769262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/116235058335769262'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/10/scratching-mutt-part-1-introducing.html' title='Scratching the mutt, part 1: Introducing sendbox'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-116122595273198072</id><published>2006-10-18T19:21:00.000-07:00</published><updated>2006-10-18T20:05:17.860-07:00</updated><title type='text'>JaM part 2: The token tree.</title><content type='html'>&lt;p&gt;This is part 2 of a series that started &lt;a href="http://n01senet.blogspot.com/2006/10/jam-lisp-like-macros-for-javascript.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, a quick correction: I claimed that Lisp macros didn't have the
ability change the basic syntax of Lisp.  I believed that because I
hadn't yet learned about "read" macros.  Using "read" macros in Lisp
you can indeed adjust some pretty basic syntax rules.  That can't be
done in JaM yet, but it's something that can probably be added in
later.&lt;/p&gt;

&lt;p&gt;So let's look more closely at the first stages of what JaM does.
As stated previously, &lt;code&gt;JaM.include("foo.js")&lt;/code&gt; fetches a
JavaScript source file as text.  It then passes that text to
&lt;code&gt;JaM.eval( ... )&lt;/code&gt;.  The &lt;code&gt;eval&lt;/code&gt; function does a
lexical analysis of the text (currently using code from &lt;a href="http://www.jslint.com/lint.html"&gt;JSLint&lt;/a&gt;) to generate a
JavaScript array of token objects.&lt;/p&gt;

&lt;p&gt;A JaM token object is basically just a JSLint token object.  For each
word read from the JavaScript source, it contains the word itself, the
line number and column where it was seen, and other bits of meta-data.
Here's a couple of examples:&lt;/p&gt;

&lt;table width="100%"&gt;&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;
{
  value: "function",
  line: 99,
  character: 16,
  reserved: true,
  identifier: true
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;pre&gt;
{
  value: "'bar'",
  line: 134,
  character: 32,
  type: '(string)'
}
&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;I'm not sure if all this will be needed or useful in the long run, but
JSLint produces it, and I have no good reason to throw any of it away.
So far the "value" has been the only part that is has regularly been
useful in the macros I've written.&lt;/p&gt;

&lt;p&gt;Next, &lt;code&gt;eval&lt;/code&gt; uses a few simple grouping rules to generate a
tree of nested arrays of token objects.  For example, the JavaScript
expression "alert('hi!');" would be translated into the following
tree:&lt;/p&gt;

&lt;pre&gt;
  [
    { value: "alert", ... },
    [
      { value: "(", ... }
      [
        [
          { value: "'hi!'", ... }
        ]
      ],
      { value: ")", ... }
    ],
    { value: ";", ... }
  ]
&lt;/pre&gt;

&lt;p&gt;These grouping rules have to be simple and loose because they must
correctly parse not only normal JavaScript but also the code which
will be the input to all our macros.  (This is the stage where we
could be using Lisp-like "read" macros instead of it being hardcoded
as it is in JaM currently).&lt;/p&gt;

&lt;p&gt;For example, if we plan to define a &lt;code&gt;unless&lt;/code&gt; macro, JaM at
this stage does not know what the word &lt;code&gt;unless&lt;/code&gt; means, but
it needs to generate an appropriate tree anyway.  So for this
expression:&lt;/p&gt;

&lt;pre&gt;
  unless( false ) { alert( 'hi' ); }
&lt;/pre&gt;

&lt;p&gt;JaM generates the tree below.  For brevity I'll show just the value of
each token object:&lt;/p&gt;

&lt;pre&gt;
  [
    "unless",
    ["(",[["false"]],")"],
    ["{",
      [
        [
          "alert",
          ["(",[["'hi'"]],")"],
          ";"
        ],
        []
      ],
    "}"]
  ]
&lt;/pre&gt;

&lt;p&gt;This nested tree of token objects is the data structure that JaM
macros operate on.  What exactly a macro might do with with this
structure will be covered in the next installment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-116122595273198072?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/116122595273198072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/116122595273198072'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/10/jam-part-2-token-tree.html' title='JaM part 2: The token tree.'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-116014629790806528</id><published>2006-10-10T12:30:00.000-07:00</published><updated>2006-10-10T09:43:32.143-07:00</updated><title type='text'>JaM: Lisp-like macros for JavaScript, part 1</title><content type='html'>&lt;p&gt;A couple weeks ago I was reading Paul Graham's excellent book &lt;a
href="http://www.paulgraham.com/onlisp.html"&gt;On Lisp&lt;/a&gt;, and I was
struck with the thought that many of the features of Lisp he seems to
really like are also provided by JavaScript.  These include dynamic
typing, lexical variable scoping, first-class functions, closures,
etc.  But macros are of course completely missing from JavaScript.&lt;/p&gt;

&lt;p&gt;How hard would it be to add Lisp-like macros to JavaScript, I
wondered?  I'm learning about Lisp macros for the first time here, so
I didn't really know, but I thought it would be fun to try.&lt;/p&gt;

&lt;p&gt;This will be the first of several posts describing "JaM", my
attempt to add Lisp-like macros to JavaScript.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;It seems to me there a few essential ingredients to make a macro
system for JavaScript that is as powerful as Lisp's:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Macros are written in JavaScript with access to all functions
  defined up to that point.&lt;/li&gt;
  &lt;li&gt;The source code that the macros read and write is in a format
  that is easy for JavaScript to manipulate, such as a
  &lt;a href="json.org"&gt;JSON&lt;/a&gt; parse tree, not just a big string.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Number 1 is important, because otherwise you end up with something
like C or C++ macros -- a weak mini-language that looks and acts
differently than the host language.  I suppose it's better than
nothing, but it doesn't have nearly the language-building power that
Lisp macros do.&lt;/p&gt;

&lt;p&gt;As for number 2, I suppose it would be possible to set up a system
where each macro could match based on a regex or something equally
flexible, but this would have a couple of drawback.  First, most
macros wouldn't need that flexibility and would end up reimplementing
the same patterns as other macros, including tricky things like
matching up pairs of parens, curly braces, etc.  Second, I don't want
to try to read code that's being worked over by macros that are that
flexible.  I'd like to be able to assume that each macro is
constrained in its scope, following roughly the same rules as the core
JavaScript language.  Lisp macros certainly have this restriction, so
I'm not worried about this causing my macro system to be too weak.&lt;/p&gt;

&lt;p&gt;Let's start off with a function &lt;code&gt;JaM.include("foo.js")&lt;/code&gt;,
which will fetch the JavaScript file, expand any macros in it, and
then run it through the regular JavaScript eval().  Except it's not
quite that simple because we want to be able to mix function
definitions and macro definitions after each other in any order so
they can build on each other.  So we'll need to split "foo.js" into
top-level expressions that can be correctly evaluated.  I'll leave the
details of this step for another time, but what's important is that
for each top-level expression we will expand any macros and then
evaluate it before moving on to the next expression.&lt;/p&gt;

&lt;p&gt;This will probably be very slow -- certainly slower than just
letting the JavaScript interpreter have at foo.js directly.  But if
that's the sort of thing that worries you, perhaps you'll be comforted
by these thoughts: First, as described here the parsing, macro
expansion, and separate evals happen once when a new source file is
being loaded.  Once the code is up and running there may be no need to
do further macro expansion.  Second, we could add another step to the
processing of each top-level expression: after expanding any macros in
an expression we could save the resulting code before evaluating it.
Doing this with each expression in turn would result in a file full of
fully-expanded normal JavaScript that browsers could run directly and
at full speed.&lt;/p&gt;

&lt;hr/&gt;
&lt;p&gt;Ok, that was pretty dull; perhaps I can whet your appetite with
some sample code?  Let's say you really like perl's
&lt;code&gt;unless&lt;/code&gt; keyword, and you wish JavaScript had something
similar.  With JaM, you can add it yourself:&lt;/p&gt;
&lt;pre&gt;
defMacro unless( expr, block: body ) {
  return {{
    if( ! ( #expr ) ) {
      #body
    }
  }};
}

unless( true == false ) {
  alert( 'Hello, macro-enabled world!' );
}
&lt;/pre&gt;
&lt;p&gt;It may not be the most useful example one can imagine, and even so
I feel I've got a fair bit more to explain before it'll make much
sense.  We'll build our way up to &lt;code&gt;defMacro&lt;/code&gt;,
&lt;code&gt;{{&lt;/code&gt; ... &lt;code&gt;}}&lt;/code&gt;, and the &lt;code&gt;#&lt;/code&gt; operator
over the next few posts. Hopefully, though, all of the above will be
sufficient for you to understand where I'm headed.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-116014629790806528?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://n01senet.blogspot.com/feeds/116014629790806528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28403206&amp;postID=116014629790806528' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/116014629790806528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/116014629790806528'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/10/jam-lisp-like-macros-for-javascript.html' title='JaM: Lisp-like macros for JavaScript, part 1'/><author><name>Chouser</name><uri>http://www.blogger.com/profile/01980936182490649442</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://site.gravatar.com/images/files/thumbs/120861.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-115314956655714837</id><published>2006-07-17T07:57:00.000-07:00</published><updated>2006-07-17T12:10:52.756-07:00</updated><title type='text'>encrypted /home</title><content type='html'>&lt;p&gt;I've done this now on a few systems, mostly laptops.  My reasoning is that any data I care about (particularly email) are stored in my home directory.  If the laptop were to get out of my possession, it would likely be shut off at the time, and I don't use suspend/resume.  So encrypting /home suffices to protect me if the laptop is lost or stolen.  It's also easier and more performance-friendly than encrypting the root dir or swap.
&lt;p&gt;When I installed my current laptop, I knew I'd encrypt /home eventually so I left a spare partition, hda3.  If you don't have one, you'll need to shrink a filesystem to create a new partition or logical volume.  When you're ready with that, the next step is to create the encrypted mapping.
&lt;blockquote&gt;&lt;pre&gt;modprobe aes # or aes-i586 on x86 systems
emerge cryptsetup-luks
cryptsetup --verify-passphrase luksFormat /dev/hda3
cryptsetup luksOpen /dev/hda3 home
mkfs.ext3 -j -m 1 -O dir_index,filetype,sparse_super /dev/mapper/home
&lt;/pre&gt;&lt;/blockquote&gt;Next copy the existing /home to the encrypted filesystem.  Be sure not to alter any important data in /home since you'll lose any changes made after the copy.  You can enforce this by switching to single user mode but I don't bother personally.
&lt;blockquote&gt;&lt;pre&gt;mkdir /mnt/newhome
mount /dev/mapper/home /mnt/newhome
cp -ax /home/. /mnt/newhome
umount /mnt/newhome
&lt;/pre&gt;&lt;/blockquote&gt;Next let Gentoo know about it, then reboot to start using the encrypted /home:
&lt;blockquote&gt;&lt;pre&gt;printf 'mount=home\nsource=/dev/hda3\ntype=luks\n' &gt;&gt; /etc/conf.d/cryptfs
echo '/dev/mapper/home /home ext3 noatime 0 0' &gt;&gt; /etc/fstab
echo 'aes' &gt;&gt; /etc/modules.autoload.d/kernel-2.6  # or aes-i586
mv /home /oldhome
mkdir /home
reboot
&lt;/pre&gt;&lt;/blockquote&gt;Finally, when you've verified that it's working, be sure to remove the old home which still contains unencrypted data!
&lt;blockquote&gt;&lt;pre&gt;rm -rf /oldhome
&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-115314956655714837?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/115314956655714837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/115314956655714837'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/07/encrypted-home.html' title='encrypted /home'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-115135428217430421</id><published>2006-06-26T13:21:00.000-07:00</published><updated>2006-07-17T12:21:35.796-07:00</updated><title type='text'>md + lvm2</title><content type='html'>&lt;p&gt;It's just beautiful what happens when you mix Linux md with lvm2.  I just added two 15K 146G disks to my system.  They show up as sdc and sdd.  Now I do this:
&lt;blockquote&gt;&lt;pre&gt;for x in sdc sdd; do
    parted /dev/$x mklabel msdos mkpart primary 0 100% set 1 raid on print quit
done
cd /dev; MAKEDEV md
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdc1 /dev/sdd1
pvcreate /dev/md0
vgcreate raid1 /dev/md0
for x in agriffis amg; do
    lvcreate -L 50G -n $x raid1
    mkfs.ext3 -L $x -O dir_index /dev/raid1/$x
    echo "LABEL=$x /home/$x ext3 noatime 1 2" &amp;gt;&amp;gt;/etc/fstab
done
mount -a&lt;/pre&gt;&lt;/blockquote&gt;That leaves nearly 50G of free space on the physical volume into which I can grow either filesystem eventually, or add a third, depending on future needs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-115135428217430421?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/115135428217430421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/115135428217430421'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/06/md-lvm2.html' title='md + lvm2'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-115014708733435585</id><published>2006-06-12T13:53:00.000-07:00</published><updated>2006-06-12T14:18:07.356-07:00</updated><title type='text'>Commentify contest</title><content type='html'>&lt;p&gt;A little while back (in April), we had a contest on #noise that started with &lt;a href="http://www.csee.wvu.edu/%7Edowen/2006_04_01_archive.html#114442645884093235"&gt;David's post&lt;/a&gt; regarding a script to comment out words in a C file. The general applicability of this script is questionable, but it was still a fun contest.  Here are the instructions:&lt;p&gt;&lt;ol&gt;&lt;li&gt;Write a command-line filter which will comment out all matches of a pattern given on the command-line, reading a C program from stdin and filtering to stdout. Whether the pattern is a literal, glob, regular expression is up to the contestant.&lt;/li&gt;&lt;li&gt;The filter should ignore matches that are already contained within a comment (including C++ style comments) or double-quoted string.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The existing gawk implementation on David's blog is an interesting starting point, though it doesn't fulfill all the requirements above.&lt;p&gt;Sample I/O:&lt;p&gt;&lt;ol&gt;&lt;li&gt;simple:&lt;a href="http://n01se.net/paste/FLa"&gt;input&lt;/a&gt; /&lt;a href="http://n01se.net/paste/YHN"&gt;output&lt;/a&gt; ("add")&lt;/li&gt;&lt;li&gt;wacky:&lt;a href="http://n01se.net/paste/xxd"&gt;input&lt;/a&gt; /&lt;a href="http://n01se.net/paste/XN"&gt;output&lt;/a&gt; ("wacky")&lt;/li&gt;&lt;li&gt;deranged:&lt;a href="http://n01se.net/paste/HhG"&gt;input&lt;/a&gt; /&lt;a href="http://n01se.net/paste/1x"&gt;output&lt;/a&gt; ("int")&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The final results are in now!  In order of longest to shortest:&lt;p&gt;&lt;ol&gt;&lt;li value=5&gt;&lt;a href="http://n01se.net/paste/9Cc"&gt;http://n01se.net/paste/9Cc&lt;/a&gt; (owen, awk, 169 chars)&lt;/li&gt;&lt;li value=3&gt;&lt;a href="http://n01se.net/paste/MX"&gt;http://n01se.net/paste/MX&lt;/a&gt; (chouser, perl, 91 chars)&lt;br&gt;&lt;a href="http://n01se.net/paste/Lf"&gt;http://n01se.net/paste/Lf&lt;/a&gt; (bob, perl, 91 chars)&lt;/li&gt;&lt;li value=2&gt;&lt;a href="http://n01se.net/paste/OI"&gt;http://n01se.net/paste/OI&lt;/a&gt; (agriffis, perl, 85 chars)&lt;/li&gt;&lt;li value=1&gt;&lt;a href="http://n01se.net/paste/Kf"&gt;http://n01se.net/paste/Kf&lt;/a&gt; (aaron+kanaka, sed+cpp, 52 chars)&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/28403206-115014708733435585?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/115014708733435585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/115014708733435585'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/06/commentify-contest.html' title='Commentify contest'/><author><name>agriffis</name><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></entry><entry><id>tag:blogger.com,1999:blog-28403206.post-114816274392604982</id><published>2006-05-20T15:04:00.000-07:00</published><updated>2006-05-20T15:05:43.926-07:00</updated><title type='text'>Placeholder post</title><content type='html'>Blogger requires me to make a post before I can preview the template or subscribe to the RSS feed. Is this fair enough or lame to the max? Discuss...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28403206-114816274392604982?l=n01senet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/114816274392604982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28403206/posts/default/114816274392604982'/><link rel='alternate' type='text/html' href='http://n01senet.blogspot.com/2006/05/placeholder-post.html' title='Placeholder post'/><author><name>Aaron</name><uri>http://www.blogger.com/profile/06857742057457049470</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></entry></feed>
