<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>msnyder.info</title>
    <link>http://msnyder.info/</link>
    <description>the personal essays of Matthew Snyder</description>
    <language>en</language>
    <copyright>Copyright 2012 Matthew Snyder</copyright>
    <item>
      <title>iCloud Reminders in Org-mode: Talking to OS X with Emacs</title>
      <link>http://msnyder.info/posts/2012/05/icloud-reminders-orgmode/</link>
      <description>
&lt;p&gt;In this article I implement a library that allows one to synchronize
&lt;a href=&quot;http://orgmode.org&quot;&gt;Org-mode&lt;/a&gt; to-do items directly to Apple&apos;s iCal. More generally, I
describe a synchronization layer between OS X, Clozure Common Lisp,
and Emacs, and muse on its potential.
&lt;/p&gt;

&lt;div id=&quot;outline-container-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;Background &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;


&lt;p&gt;
It is a source of joy and pain to customize and extend Emacs. There
are many reasons for the attempt, however, and every person has
different reasons. I typically describe a few of mine as follows.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When tasks are performed alongside each other in Emacs, it is
  conceptually simpler to move between them. Most commands have a
  sort of &quot;Do What I Mean&quot; universality to them.

&lt;/li&gt;
&lt;li&gt;Passing data between membranes &amp;ndash; copying a URL in a web browser to
  a chat window, e-mailing a snippet of code to a mailing list, or
  writing an Org-mode outline before publishing it online &amp;ndash; is
  typically effortless.

&lt;/li&gt;
&lt;li&gt;Every mode and function in Emacs is another tool in your
  toolbox. You can easily combine tools in the Unix way to slice
  through work. When you have more tools at your disposal, you can
  solve more difficult or nuanced problems.
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;
On the other hand, I have an iPhone and an iCloud account, and don&apos;t
spend all my time in Emacs exclusively. I want to be able to use the
fantastic software outside of Emacs, but have the power and
flexibility of Emacs.
&lt;/p&gt;
&lt;p&gt;
I&apos;ve created a dual-language project. One half is in Emacs Lisp; the
other in Common Lisp. It uses the foreign function interface provided
by Clozure CL. From Emacs, I use SLIME to access Clozure&apos;s REPL, which
allows me to make calls to the storage APIs for iCal. Once I retrieve
the results I want, I can pass them back to Emacs. I can also make
changes using this API, allowing Emacs to inform iCal of what changes
have been made in my to-do lists.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;Environment Setup &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;


&lt;p&gt;
There is a one-time cost of a complex environment setup. You will need
a copy of OS X and Emacs. I am doing all this work on Lion, and I
don&apos;t know if earlier versions of OS X will have all the tools we
need. I am using Emacs 24:
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;GNU Emacs 24.0.90.1 (i386-apple-darwin11.2.0, NS apple-appkit-1138.23)
&lt;/pre&gt;


&lt;p&gt;
I should mention that Emacs 24 is incredibly stable. There is a lot of
activity and approval surrounding its use as a day-to-day text editor.
&lt;/p&gt;
&lt;p&gt;
Make sure you install Clozure Common Lisp. Clozure&apos;s Objective-C
support is a unique feature of its distribution. This article could
not have been written without the indispensable support of their &lt;a href=&quot;http://trac.clozure.com/ccl/wiki&quot;&gt;wiki&lt;/a&gt;
and &lt;a href=&quot;http://ccl.clozure.com/manual/&quot;&gt;manual&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
You can do this however you&apos;d like, but homebrew makes it easy.
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;$ brew update
$ brew install clozure-cl
&lt;/pre&gt;


&lt;p&gt;
You should have &lt;code&gt;ccl64&lt;/code&gt; in &lt;code&gt;/usr/local/bin&lt;/code&gt;, and it should be at
least version 1.7. Type &lt;code&gt;(quit)&lt;/code&gt; at the REPL to exit it.
&lt;/p&gt;
&lt;p&gt;
You will need SLIME, the essential Lisp IDE for Emacs. What I do is
open up my Lisp REPL in my shell, install SLIME through Quicklisp, and
then symbolically link the package into my Emacs directory (a tool
exists to do this, &lt;a href=&quot;https://github.com/quicklisp/quicklisp-slime-helper&quot;&gt;quicklisp-slime-helper&lt;/a&gt;, but out of habit I still do
it the more old-fashioned way):
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;$ ccl64 --load quicklisp.lisp
 
? (quicklisp-quickstart:install :path &quot;.quicklisp-ccl64/&quot;)
? (ql:add-to-init-file)
? (ql:quickload &apos;swank)
? (quit)
  
$ ln -s $HOME/.quicklisp-ccl64/dists/quicklisp/software/slime-*-cvs/ $HOME/.emacs.d/vendor/slime
&lt;/pre&gt;


&lt;p&gt;
I&apos;ve also built up a bit of a preparation function for initializing
SLIME, so I will reproduce that below as well.
&lt;/p&gt;



&lt;pre class=&quot;src src-elisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;quicklisp-slime-setup&lt;/span&gt; ()
  (add-to-list &apos;load-path (expand-file-name &lt;span class=&quot;org-string&quot;&gt;&quot;~/.emacs.d/vendor/slime&quot;&lt;/span&gt;))
  (add-to-list &apos;load-path (expand-file-name &lt;span class=&quot;org-string&quot;&gt;&quot;~/.emacs.d/vendor/slime/contrib&quot;&lt;/span&gt;))
  (setq inferior-lisp-program &lt;span class=&quot;org-string&quot;&gt;&quot;/usr/local/bin/ccl64&quot;&lt;/span&gt;)
  (setq slime-autodoc-mode t)
  (setq slime-net-coding-system &apos;utf-8-unix)
  (&lt;span class=&quot;org-keyword&quot;&gt;require&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;slime&lt;/span&gt;)
  (slime-setup &apos;(slime-repl slime-fancy)))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-3&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;Building &lt;code&gt;ffigen&lt;/code&gt; &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;


&lt;p&gt;
&lt;code&gt;ffigen&lt;/code&gt; is a utility that slurps up frameworks and provides foreign
function interfaces into &apos;intermediate forms&apos;; in this case, Lisp
forms. These instructions exist on the Clozure CL wiki. I&apos;m
reproducing them here since they&apos;re not easy to find and the wiki may change.
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;
Building a Leopard version with ObjC 2.0 support
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;# Note that the svn directory is misnamed; this is actually based on Apple GCC 5464 (not 6465).
$ svn co http://svn.clozure.com/publicsvn/ffigen4/branches/ffigen-apple-gcc-6465/ffigen4
 
$ cd ffigen4
$ make
  
$ sudo tar zxvf ffigen-apple-gcc-5465-intel-*.tar.gz -C /usr/local
&lt;/pre&gt;


&lt;p&gt;
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;Generating the Foreign Function Interface &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;


&lt;p&gt;
&lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/AppleApplications/Reference/CalendarStoreReference/_index.html&quot;&gt;Calendar Store&lt;/a&gt; is the name of the framework that Apple provides for
accessing calendar data. We need to generate its foreign function
interface for Clozure. I did so by copying the FFI generation script
from the &lt;code&gt;addressbook&lt;/code&gt; framework that Clozure provides access to, and
turning it into a script for the &lt;code&gt;calendarstore&lt;/code&gt; framework. The
script, &lt;code&gt;populate.sh&lt;/code&gt;, uses the &lt;code&gt;h-to-ffi.sh&lt;/code&gt; terminal command
installed by building &lt;code&gt;ffigen&lt;/code&gt; above.
&lt;/p&gt;
&lt;p&gt;
I should add that this works with the version of Xcode distributed by
the App Store, as well as any version of Xcode you may have in
&lt;code&gt;/Developer&lt;/code&gt;, but I&apos;m only documenting the former. The changes needed
for the latter should be self-evident.
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;&lt;span id=&quot;coderef-sdk&quot; class=&quot;coderef-off&quot;&gt;&lt;span class=&quot;linenr&quot;&gt; 1:  &lt;/span&gt;$ export SDK=/Applications/Xcode.app/Contents/Developer/Platforms/\&lt;/span&gt;
&lt;span class=&quot;linenr&quot;&gt; 2:  &lt;/span&gt;MacOSX.platform/Developer/SDKs/MacOSX10.6.sdk
&lt;span class=&quot;linenr&quot;&gt; 3:  &lt;/span&gt;
&lt;span class=&quot;linenr&quot;&gt; 4:  &lt;/span&gt;$ cd $SDK/System/Library/Frameworks/CalendarStore.framework/Headers
&lt;span class=&quot;linenr&quot;&gt; 5:  &lt;/span&gt;
&lt;span id=&quot;coderef-import1&quot; class=&quot;coderef-off&quot;&gt;&lt;span class=&quot;linenr&quot;&gt; 6:  &lt;/span&gt;$ sed &apos;1i\&lt;/span&gt;
&lt;span id=&quot;coderef-import2&quot; class=&quot;coderef-off&quot;&gt;&lt;span class=&quot;linenr&quot;&gt; 7:  &lt;/span&gt;#import &amp;lt;Foundation/Foundation.h&amp;gt;\&lt;/span&gt;
&lt;span id=&quot;coderef-import3&quot; class=&quot;coderef-off&quot;&gt;&lt;span class=&quot;linenr&quot;&gt; 8:  &lt;/span&gt;&apos; CalendarStore.h | sudo tee CalendarStore.ffi.h&lt;/span&gt;
&lt;span class=&quot;linenr&quot;&gt; 9:  &lt;/span&gt;
&lt;span class=&quot;linenr&quot;&gt;10:  &lt;/span&gt;$ cd /usr/local/Cellar/clozure-cl/1.8/ccl/darwin-x86-headers64
&lt;span class=&quot;linenr&quot;&gt;11:  &lt;/span&gt;$ mkdir -p calendarstore/C
&lt;span class=&quot;linenr&quot;&gt;12:  &lt;/span&gt;$ sed &apos;s/AddressBook/CalendarStore/;s/AddressBook/CalendarStore.ffi/&apos; \
&lt;span class=&quot;linenr&quot;&gt;13:  &lt;/span&gt;  addressbook/C/populate.sh &amp;gt; calendarstore/C/populate.sh
&lt;span class=&quot;linenr&quot;&gt;14:  &lt;/span&gt;$ sed -i &apos;&apos; &quot;s/^SDK.*/SDK=$SDK/&quot; calendarstore/C/populate.sh
&lt;span class=&quot;linenr&quot;&gt;15:  &lt;/span&gt;$ chmod +x calendarstore/C/populate.sh
&lt;span class=&quot;linenr&quot;&gt;16:  &lt;/span&gt;$ cd calendarstore/C
&lt;span class=&quot;linenr&quot;&gt;17:  &lt;/span&gt;$ sh populate.sh
&lt;/pre&gt;


&lt;p&gt;
Line &lt;a href=&quot;#coderef-sdk&quot; class=&quot;coderef&quot; onmouseover=&quot;CodeHighlightOn(this, &apos;coderef-sdk&apos;);&quot; onmouseout=&quot;CodeHighlightOff(this, &apos;coderef-sdk&apos;);&quot;&gt;1&lt;/a&gt; above assumes that you are using Xcode off of the App
Store. If not, the &lt;code&gt;SDKs/&lt;/code&gt; directory will be located in &lt;code&gt;/Developer&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
Lines &lt;a href=&quot;#coderef-import1&quot; class=&quot;coderef&quot; onmouseover=&quot;CodeHighlightOn(this, &apos;coderef-import1&apos;);&quot; onmouseout=&quot;CodeHighlightOff(this, &apos;coderef-import1&apos;);&quot;&gt;6&lt;/a&gt;, &lt;a href=&quot;#coderef-import2&quot; class=&quot;coderef&quot; onmouseover=&quot;CodeHighlightOn(this, &apos;coderef-import2&apos;);&quot; onmouseout=&quot;CodeHighlightOff(this, &apos;coderef-import2&apos;);&quot;&gt;7&lt;/a&gt;, and &lt;a href=&quot;#coderef-import3&quot; class=&quot;coderef&quot; onmouseover=&quot;CodeHighlightOn(this, &apos;coderef-import3&apos;);&quot; onmouseout=&quot;CodeHighlightOff(this, &apos;coderef-import3&apos;);&quot;&gt;8&lt;/a&gt; comprise a single command,
adding a missing import to the CalendarStore header file. Once we
populate the framework, we must then tell Clozure about it.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (&lt;span class=&quot;org-keyword&quot;&gt;require&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;parse-ffi&lt;/span&gt;)
CL-USER&amp;gt; (ccl::parse-standard-ffi-files &lt;span class=&quot;org-builtin&quot;&gt;:calendarstore&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
After this is done, we never have to do it again. From now on,
whenever we open up a Clozure REPL, we can just load up everything we
need.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (&lt;span class=&quot;org-keyword&quot;&gt;require&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;objc-support&lt;/span&gt;)
CL-USER&amp;gt; (objc:load-framework &lt;span class=&quot;org-string&quot;&gt;&quot;CalendarStore&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:calendarstore&lt;/span&gt;)
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;Explaining the Bridge &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;


&lt;p&gt;
There are a couple aspects of Objective-C and how they translate
through the Bridge that we need to be aware of.
&lt;/p&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5-1&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-5-1&quot;&gt;Methods in Objective-C &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-5-1&quot;&gt;


&lt;p&gt;
Objective-C uses a message passing syntax. Whereas languages like C++
bind method names to some code during compilation, Objective-C
resolves message receivers during runtime. Message names are typically
longer than method names because they also contain identifying
information about the message&apos;s parameters, separated by colons.
&lt;/p&gt;
&lt;p&gt;
Whereas in C++ you may call something like:
&lt;/p&gt;



&lt;pre class=&quot;src src-c++&quot;&gt;obj-&amp;gt;method(foo, bar)
&lt;/pre&gt;


&lt;p&gt;
In Objective-C you would call:
&lt;/p&gt;



&lt;pre class=&quot;src src-c++&quot;&gt;[obj method:foo andBar:bar]
&lt;/pre&gt;


&lt;p&gt;
And we&apos;d consider the message name to be &lt;code&gt;method:andBar:&lt;/code&gt;. Yes, even
the colons are part of the message name. In our bridge, that method
invocation would become:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(#/method:andBar: obj foo bar)
&lt;/pre&gt;


&lt;p&gt;
Now that we know this, we can start using Apple&apos;s API to pull objects
out of the runtime. Open up a REPL with Clozure CL as your inferior
Lisp. First we need to load up the bridge.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (&lt;span class=&quot;org-keyword&quot;&gt;require&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;objc-support&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
Many commonly used Foundation Framework objects are available for us
immediately. These objects start with the prefix &lt;code&gt;ns-&lt;/code&gt;. An NSDate
would become an &lt;code&gt;ns-date&lt;/code&gt;. An NSString would become an &lt;code&gt;ns-string&lt;/code&gt;.
Say we wanted to create an &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html&quot;&gt;NSDate&lt;/a&gt; with the current date and time, and
print its string representation. Let&apos;s put this functionality in a
function called &lt;code&gt;today_as_string&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
Take a look at the difference as to how methods are called in
Objective-C. &lt;code&gt;today_as_string&lt;/code&gt;, implemented in Objective-C, and then
Lisp.
&lt;/p&gt;



&lt;pre class=&quot;src src-c++&quot;&gt;&lt;span class=&quot;org-type&quot;&gt;NSString&lt;/span&gt;* &lt;span class=&quot;org-function-name&quot;&gt;today_as_string&lt;/span&gt;() {
  &lt;span class=&quot;org-type&quot;&gt;NSDate&lt;/span&gt; *&lt;span class=&quot;org-variable-name&quot;&gt;today&lt;/span&gt; = [NSDate date];
  &lt;span class=&quot;org-type&quot;&gt;NSString&lt;/span&gt; *&lt;span class=&quot;org-variable-name&quot;&gt;date_string&lt;/span&gt; = [today description];
  [today release];
  &lt;span class=&quot;org-keyword&quot;&gt;return&lt;/span&gt; date_string;
}
&lt;/pre&gt;



&lt;hr/&gt;




&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;today-as-string&lt;/span&gt; ()
  (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((today (#/date ns:ns-date))
         (date-string (#/description today)))
    (#/release today)
    date-string))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5-2&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-5-2&quot;&gt;Memory Management &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-5-2&quot;&gt;


&lt;p&gt;
Based on the &lt;a href=&quot;http://ccl.clozure.com/manual/chapter15.3.html#The-Application-Kit-and-Multiple-Threads&quot;&gt;Clozure documentation&lt;/a&gt; (§15.3.3), an autorelease pool is
created for us in the toplevel. This means as good citizens, we should
manually release the memory when we finish using it. Calling &lt;code&gt;[NSDate date]&lt;/code&gt; automatically calls &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;alloc&lt;/code&gt; on the instance, and the
&lt;code&gt;(#/release today)&lt;/code&gt; call above dovetails that by decreasing the
reference count.
&lt;/p&gt;
&lt;p&gt;
For more detail on reference counting, please see &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.pdf&quot;&gt;Apple&apos;s &quot;Advanced Memory Management Programming Guide&quot;&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5-3&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-5-3&quot;&gt;Miscellaneous &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-5-3&quot;&gt;


&lt;p&gt;
Here are some other things to note. We can get a reference to any
class by passing its camel-cased name to &lt;code&gt;@class&lt;/code&gt;.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (objc:@class &lt;span class=&quot;org-string&quot;&gt;&quot;NSString&quot;&lt;/span&gt;)
#&amp;lt;OBJC:OBJC-CLASS NS:NS-STRING (#x7FFF75FE69F8)&amp;gt;
&lt;/pre&gt;


&lt;p&gt;
We can determine if an object is a null pointer by using
&lt;code&gt;%null-ptr-p&lt;/code&gt;:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (%null-ptr-p (#/date ns:ns-date))
NIL
CL-USER&amp;gt; (%null-ptr-p (%null-ptr))
T
&lt;/pre&gt;


&lt;p&gt;
We are given a reader macro for generating NSStrings (prefix it with a
pound sign, &lt;code&gt;#&lt;/code&gt;), and we can get a Lisp string out of an NSString with
Clozure&apos;s &lt;code&gt;lisp-string-from-nsstring&lt;/code&gt; function:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (ccl::lisp-string-from-nsstring #@&lt;span class=&quot;org-string&quot;&gt;&quot;test&quot;&lt;/span&gt;)
&lt;span class=&quot;org-string&quot;&gt;&quot;test&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
The use of the pound sign in the above code (&lt;code&gt;(#/date ns:ns-date)&lt;/code&gt;) is
a reader macro as well. You can get a hint as to how it works by
checking the contents of the package &lt;code&gt;nextstep-functions&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-6&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-6&quot;&gt;Introducing &lt;code&gt;nsclasp&lt;/code&gt; &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-6&quot;&gt;


&lt;p&gt;
I&apos;ve written a small utility library for Common Lisp called
&lt;a href=&quot;http://github.com/ardekantur/nsclasp&quot;&gt;&lt;code&gt;nsclasp&lt;/code&gt;&lt;/a&gt;. It provides a set of functions that are very useful when
working with Apple&apos;s Foundation Framework. You can retrieve it by
cloning it into your Quicklisp installation&apos;s &lt;code&gt;local-projects&lt;/code&gt;
directory and refreshing the project list:
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;$ cd ~/.quicklisp-ccl64/local-projects
$ git clone git://github.com/ardekantur/nsclasp.git
&lt;/pre&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (ql:register-local-projects)
CL-USER&amp;gt; (ql:quickload &apos;nsclasp)
&lt;/pre&gt;


&lt;p&gt;
For more information, see the &lt;a href=&quot;https://github.com/ardekantur/nsclasp/blob/master/README.org&quot;&gt;project documentation&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-7&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-7&quot;&gt;Implementation &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-7&quot;&gt;


&lt;p&gt;
The most important aspect of iCalSync, the thing that makes this so
delightfully easy, is that Emacs Lisp can talk directly to the Clozure
instance. The key function is this:
&lt;/p&gt;





&lt;pre class=&quot;src src-elisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-capture-ccl-result&lt;/span&gt;
(command)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Convert a result from the SLIME Lisp&apos;s REPL into the Emacs\nLisp toplevel.&quot;&lt;/span&gt;
  (read
   (slime-eval
    `(swank::pprint-eval ,command))))
&lt;/pre&gt;


&lt;p&gt;
Using this, we can send code to Clozure&apos;s REPL, get the result back,
and turn it into a Lisp form.
&lt;/p&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-7-1&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-7-1&quot;&gt;First Steps: Retrieving Calendar Names &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-7-1&quot;&gt;


&lt;p&gt;
Let&apos;s make two useful functions for accessing the &lt;code&gt;CalendarStore&lt;/code&gt;,
then try to retrieve a list of calendar names from Clozure.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-cl-calendar-store&lt;/span&gt; ()
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Return the calendar store. Equivalent to&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;    [CalCalendarStore defaultCalendarStore].&quot;&lt;/span&gt;
  (#/defaultCalendarStore ns:cal-calendar-store))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-cl-all-calendars&lt;/span&gt; ()
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Return a list of all calendars in the default calendar&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;    store. Equivalent to [[CalCalendarStore defaultCalendarStore]&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;    calendars].&quot;&lt;/span&gt;
  (#/calendars (icalsync-cl-calendar-store)))

(&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((calendars (icalsync-cl-all-calendars)))
  (&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt; for i upto (1- (#/count calendars))
     for calendar = (#/objectAtIndex: calendars i)
     do (format t &lt;span class=&quot;org-string&quot;&gt;&quot;~A, &quot;&lt;/span&gt; (ccl::lisp-string-from-nsstring (#/title calendar)))))
&lt;/pre&gt;


&lt;pre class=&quot;example&quot;&gt;
Calendar, Matthew Snyder, Do, Buy, Inbox, Example, 
&lt;/pre&gt;


&lt;p&gt;
Our handling of the NSArray is a little clumsy. We can&apos;t just &lt;code&gt;mapcar&lt;/code&gt;
over it, we need to explicitly iterate over its elements by
index. That&apos;s why nsclasp is helpful, as it contains a method to make
this a little nicer:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((calendars (nsclasp:ns-array-&amp;gt;list (icalsync-cl-all-calendars))))
  (format t &lt;span class=&quot;org-string&quot;&gt;&quot;~{~a, ~}&quot;&lt;/span&gt; (mapcar (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (c) (ccl::lisp-string-from-nsstring (#/title c))) calendars)))
&lt;/pre&gt;


&lt;p&gt;
But no matter how you do it, you should have been able to retrieve all
your calendar names. As it turns out, this is an important piece of
information to have, as the Foundation Framework doesn&apos;t yet allow us
to create the kind of calendar that would sync with iCloud for us. For
the time being, we have to create the calendar we want our TODOs
synced to, in iCal.
&lt;/p&gt;
&lt;p&gt;
&lt;img src=&quot;/images/icloud-reminders-orgmode/new-calendar-list.png&quot;  alt=&quot;/images/icloud-reminders-orgmode/new-calendar-list.png&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-7-2&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-7-2&quot;&gt;First Steps: Creating a &lt;code&gt;CalTask&lt;/code&gt; &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-7-2&quot;&gt;


&lt;p&gt;
Now let&apos;s combine this on the tail end of creating an iCal reminder,
and sending it to a calendar.
&lt;/p&gt;
&lt;p&gt;
Tasks exist in iCal as instances of the &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/AppleApplications/Reference/CalendarStoreFramework/Classes/CalTask_Class/Reference/Reference.html&quot;&gt;&lt;code&gt;CalTask&lt;/code&gt;&lt;/a&gt; object of the
CalendarStore Framework. Every task has a title, UID, a parent
calendar, alarms, due dates, completed dates, notes, and other such
attributes. We have to describe a mapping. Our input function takes an
Emacs buffer and returns a list of parsed TODOs, and what calendar
they should be synced to.
&lt;/p&gt;





&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-el-transform-todos&lt;/span&gt; (buffer)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Turn an org mode buffer into a list of iCal tasks.&lt;/span&gt;

&lt;span class=&quot;org-doc&quot;&gt;A function that describes one way to retrieve all of the valid&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;TODOs from a buffer for turning into respective iCal tasks. You&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;can write a function that best suits your workflow. The function&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;is expected to take the name of a buffer, or a buffer, and return&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;a list of plists, each one representing a TODO item / iCal task.&lt;/span&gt;

&lt;span class=&quot;org-doc&quot;&gt;FIXME(msnyder): Use org-map-entries to make this easier.&quot;&lt;/span&gt;
  (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
   (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((calendar-uid (icalsync-el-calendar-name)) todos)
     (switch-to-buffer buffer)
     (beginning-of-buffer)
     (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (re-search-forward org-todo-line-regexp nil t)
      (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((todo-text (match-string-no-properties 3))
             (components (org-heading-components))
             (todo-state (nth 2 components))
             (headline (nth 4 components))
             (scheduled-time (org-get-scheduled-time (point)))
             todo-uid)
        (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (and todo-state
                 (funcall icalsync-el-valid-p-function todo-state todo-text))
            (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt; (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match org-todo-line-tags-regexp headline)
                       (setq headline (nth 4 (org-heading-components)))
                       (setq todos
                             (cons (list &lt;span class=&quot;org-builtin&quot;&gt;:buffer&lt;/span&gt;
                                         (buffer-file-name)
                                         &lt;span class=&quot;org-builtin&quot;&gt;:point&lt;/span&gt;
                                         (point)
                                         &lt;span class=&quot;org-builtin&quot;&gt;:calendar-uid&lt;/span&gt;
                                         calendar-uid
                                         &lt;span class=&quot;org-builtin&quot;&gt;:incomplete-p&lt;/span&gt;
                                         (funcall
                                          icalsync-el-incomplete-p-function
                                          todo-state)
                                         &lt;span class=&quot;org-builtin&quot;&gt;:title&lt;/span&gt;
                                         (org-trim headline)
                                         &lt;span class=&quot;org-builtin&quot;&gt;:scheduled&lt;/span&gt;
                                         (and
                                          scheduled-time
                                          (decode-time scheduled-time))
                                         &lt;span class=&quot;org-builtin&quot;&gt;:uid&lt;/span&gt;
                                         (cdr
                                          (assoc
                                           &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-UID&quot;&lt;/span&gt;
                                           (org-entry-properties)))
                                         &lt;span class=&quot;org-builtin&quot;&gt;:dt&lt;/span&gt;
                                         (and
                                          (cdr
                                           (assoc
                                            &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-DT&quot;&lt;/span&gt;
                                            (org-entry-properties)))
                                          (read
                                           (cdr
                                            (assoc
                                             &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-DT&quot;&lt;/span&gt;
                                             (org-entry-properties))))))
                                   todos)))))))
     todos)))
&lt;/pre&gt;


&lt;p&gt;
I&apos;ve created a basic Org file.
&lt;/p&gt;



&lt;pre class=&quot;src src-org&quot;&gt;&lt;span class=&quot;org-org-document-info-keyword&quot;&gt;#+TITLE:&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt; &lt;/span&gt;&lt;span class=&quot;org-org-document-title&quot;&gt;example.org&lt;/span&gt;

&lt;span class=&quot;org-org-level-1&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;org-org-todo&quot;&gt;TODO&lt;/span&gt;&lt;span class=&quot;org-org-level-1&quot;&gt; Recycling&lt;/span&gt;
  &lt;span class=&quot;org-org-special-keyword&quot;&gt;SCHEDULED:&lt;/span&gt; &lt;span class=&quot;org-org-date&quot;&gt;&amp;lt;2012-04-15 Sun&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-org-level-1&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;org-org-todo&quot;&gt;TODO&lt;/span&gt;&lt;span class=&quot;org-org-level-1&quot;&gt; Trash&lt;/span&gt;
&lt;span class=&quot;org-org-level-1&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;org-org-todo&quot;&gt;TODO&lt;/span&gt;&lt;span class=&quot;org-org-level-1&quot;&gt; Fix toilet&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
I run the function on it, and after getting asked which calendar I
want the items to belong to, I get the following list of lists.
&lt;/p&gt;



&lt;pre class=&quot;src src-elisp&quot;&gt;(icalsync-el-transform-todos &lt;span class=&quot;org-string&quot;&gt;&quot;example.org&quot;&lt;/span&gt;)
&lt;/pre&gt;


&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;caption&gt;&lt;/caption&gt;
&lt;colgroup&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;right&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;&lt;col class=&quot;left&quot; /&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;left&quot;&gt;:buffer&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;/&amp;hellip;/example.org&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:point&lt;/td&gt;&lt;td class=&quot;right&quot;&gt;78&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:calendar-uid&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;C854CB60&amp;hellip;&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:incomplete-p&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;t&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:title&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;Fix toilet&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:scheduled&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:uid&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:dt&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;left&quot;&gt;:buffer&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;/&amp;hellip;/example.org&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:point&lt;/td&gt;&lt;td class=&quot;right&quot;&gt;60&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:calendar-uid&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;C854CB60&amp;hellip;&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:incomplete-p&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;t&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:title&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;Trash&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:scheduled&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:uid&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:dt&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;left&quot;&gt;:buffer&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;/&amp;hellip;/example.org&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:point&lt;/td&gt;&lt;td class=&quot;right&quot;&gt;17&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:calendar-uid&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;C854CB60&amp;hellip;&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:incomplete-p&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;t&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:title&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;Recycling&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:scheduled&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;(0 0 0 15 4 2012 0 t -14400)&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:uid&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;:dt&lt;/td&gt;&lt;td class=&quot;left&quot;&gt;nil&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;


&lt;p&gt;
When we upload a task into the Calendar Store, we&apos;re going to provide
its title, deadline, and whether or not it&apos;s complete. There&apos;s also
priority, which would be nice, but not necessary for the time
being. Once the upload is successful, we&apos;re going to also retrieve the
task&apos;s UID, and its &lt;code&gt;dateStamp&lt;/code&gt; property, and save them in the
property drawer of the TODO, in order to make synchronization easier.
&lt;/p&gt;





&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-el-upload-todo&lt;/span&gt; (todo)
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; (todo-uid)
    (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
     (setq todo-uid
           (icalsync-capture-ccl-result
            (format &lt;span class=&quot;org-string&quot;&gt;&quot;(icalsync-cl-create-task &apos;%S)&quot;&lt;/span&gt; todo)))
     (find-file (getf todo &lt;span class=&quot;org-builtin&quot;&gt;:buffer&lt;/span&gt;)) (goto-char (getf todo &lt;span class=&quot;org-builtin&quot;&gt;:point&lt;/span&gt;))
     (goto-char (car (org-get-property-block nil nil t)))
     (org-set-property &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-UID&quot;&lt;/span&gt; todo-uid)
     (org-set-property &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-DT&quot;&lt;/span&gt; (current-time)))))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-el-upload-todos&lt;/span&gt; (todos)
  (&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt; for todo in todos do (icalsync-el-upload-todo todo)))
&lt;/pre&gt;


&lt;p&gt;
From here, all we need to do is run the Emacs Lisp functions needed to
transform all the TODOs and upload them into the Calendar Store. Keep
iCal open when you do this and make sure the Reminder list is
visible.
&lt;/p&gt;
&lt;p&gt;
&lt;img src=&quot;/images/icloud-reminders-orgmode/shown-calendar-list.png&quot;  alt=&quot;/images/icloud-reminders-orgmode/shown-calendar-list.png&quot; /&gt;
&lt;/p&gt;



&lt;pre class=&quot;src src-elisp&quot;&gt;(setq *todos* (icalsync-el-transform-todos &lt;span class=&quot;org-string&quot;&gt;&quot;example.org&quot;&lt;/span&gt;))
(icalsync-el-upload-todos *todos*)
&lt;/pre&gt;


&lt;p&gt;
Et voila!
&lt;/p&gt;
&lt;p&gt;
&lt;img src=&quot;/images/icloud-reminders-orgmode/new-reminders.png&quot;  alt=&quot;/images/icloud-reminders-orgmode/new-reminders.png&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-7-3&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-7-3&quot;&gt;First Steps: Retrieving Changes &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-7-3&quot;&gt;


&lt;p&gt;
So now you have your Org-mode tasks in a Reminder list on your
iPhone. Brilliant! You wander around the town, happily marking off the
items you&apos;ve completed. How can we make Org-mode aware of the items
that were checked off?
&lt;/p&gt;
&lt;p&gt;
This is a very rudimentary method, but it works. What we&apos;ll do is
update TODOs based on buffer, the same way we uploaded them to
iCal. For a given buffer, we&apos;ll walk through the TODOs, seeing if they
have a UID handed out by the calendar store. If so, we ask the
calendar store about it. We compare the time-stamp of the TODO to the
time-stamp of the reminder, and if the reminder has been changed more
recently, we update the TODO.
&lt;/p&gt;





&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-el-download-todo&lt;/span&gt; (todo)
  (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt; (find-file (getf todo &lt;span class=&quot;org-builtin&quot;&gt;:buffer&lt;/span&gt;))
   (goto-char (getf todo &lt;span class=&quot;org-builtin&quot;&gt;:point&lt;/span&gt;))
   (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((result
           (icalsync-capture-ccl-result
            (format &lt;span class=&quot;org-string&quot;&gt;&quot;(icalsync-cl-task-&amp;gt;plist (icalsync-cl-get-task %S))&quot;&lt;/span&gt;
                    (getf todo &lt;span class=&quot;org-builtin&quot;&gt;:uid&lt;/span&gt;))))
          (t1
           (apply &apos;encode-time
                  (read (cdr (assoc &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-DT&quot;&lt;/span&gt; (org-entry-properties))))))
          (t2 (apply &apos;encode-time (getf result &apos;datestamp))))
     (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (time-less-p t1 t2)
         (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt; (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (getf result &apos;completeddate) (org-todo &apos;done))
                (org-set-property &lt;span class=&quot;org-string&quot;&gt;&quot;ICALSYNC-DT&quot;&lt;/span&gt; (format &lt;span class=&quot;org-string&quot;&gt;&quot;%S&quot;&lt;/span&gt; t2)))))))

&lt;/pre&gt;


&lt;p&gt;
Not the use of the function &lt;code&gt;icalsync-cl-task-&amp;gt;plist&lt;/code&gt;. Since we can&apos;t
hand off a CalTask object from Clozure to Emacs Lisp, I&apos;ve written a
function that distills a task down to its most important parts.
&lt;/p&gt;





&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defvar&lt;/span&gt; &lt;span class=&quot;org-variable-name&quot;&gt;*task-properties*&lt;/span&gt; (list &lt;span class=&quot;org-string&quot;&gt;&quot;title&quot;&lt;/span&gt;
                                &lt;span class=&quot;org-string&quot;&gt;&quot;uid&quot;&lt;/span&gt;
                                &lt;span class=&quot;org-string&quot;&gt;&quot;priority&quot;&lt;/span&gt;
                                &lt;span class=&quot;org-string&quot;&gt;&quot;dueDate&quot;&lt;/span&gt;
                                &lt;span class=&quot;org-string&quot;&gt;&quot;dateStamp&quot;&lt;/span&gt;
                                &lt;span class=&quot;org-string&quot;&gt;&quot;completedDate&quot;&lt;/span&gt;))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;icalsync-cl-task-&amp;gt;plist&lt;/span&gt; (task)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Convert a CalTask to a plist of properties. The list of properties&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;    is described by *task-properties*.&quot;&lt;/span&gt;
  (&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt; for property in *task-properties*
        for value = (funcall (intern property &lt;span class=&quot;org-string&quot;&gt;&quot;NEXTSTEP-FUNCTIONS&quot;&lt;/span&gt;) task)
        append (list (intern (format nil &lt;span class=&quot;org-string&quot;&gt;&quot;~:@(~a~)&quot;&lt;/span&gt; property))
                     (icalsync-cl-coerce-value value))))

&lt;/pre&gt;


&lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-8&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-8&quot;&gt;Next Steps &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-8&quot;&gt;


&lt;p&gt;
There are a few things missing from this implementation. We don&apos;t
check for the existence of a task before creating it from the
corresponding TODO. Priority is not synced. Org-mode is not made aware
of items added to Reminders.app. We track where our TODOs are based on
the buffer name and their position in the buffer, which will quite
easily break if we shuffle our TODOs around. Only the reminder&apos;s
completion status is synced back to Emacs, but if its description or
due date changes, we should synchronize those as well. As a
proof-of-concept, however, I think this is a solid start.
&lt;/p&gt;
&lt;p&gt;
In addition, the behavior that you use to turn Org-mode files into
lists of reminders &amp;ndash; or vice versa &amp;ndash; is entirely up to you. There
are countless ways to do so. A conversion could, for example, take
each calendar, and make it a headline in an Org file, with each task
becoming a checklist item with a property drawer. Another conversion
could check the TODOs for a custom condition, i.e., only tell iCal
about TODOs which have a certain property in their drawer, or are
scheduled after a certain date.
&lt;/p&gt;
&lt;p&gt;
All the code written for this article is available in my &lt;a href=&quot;http://github.com/ardekantur/elstar&quot;&gt;&lt;code&gt;elstar&lt;/code&gt; GitHub repository&lt;/a&gt;. The &lt;code&gt;elstar&lt;/code&gt; name for my repository is a bannerhead
of sorts, an invitation for this method to be explored further, and to
collect the results in a shared place. I welcome any contributions.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-9&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-9&quot;&gt;Conclusion &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-9&quot;&gt;


&lt;p&gt;
The point of this article was not just to create a synchronization
layer for iCal to Org-mode, but to explore the method of
synchronization itself. For Emacs users on OS X, the potential
exists to fill in the gaps with their usage of operating system (and
associated mobile/cloud convenience) and text editor. Some other
ideas that may be worth pursuing:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Emacs mode for interfacing with iTunes

&lt;/li&gt;
&lt;li&gt;Functionality to convert Address Book entries into
    BBDB or &lt;code&gt;org-contacts&lt;/code&gt; entries

&lt;/li&gt;
&lt;li&gt;Turning events on calendars into Emacs diary entries
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;
I look forward to seeing what some enterprising Lisp hackers can come
up with.
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>msnyder.info:entry:icloud-reminders-orgmode.org</guid>
      <pubDate>Mon, 07 May 2012 00:00:00 EDT</pubDate>
    </item>
    <item>
      <title>On Web Sanity</title>
      <link>http://msnyder.info/posts/2012/04/on-web-sanity/</link>
      <description>
&lt;p&gt;When I browse the Internet, I always fight the temptation to waste
time by visiting distracting websites. By telling my computer what
sites are worth visiting, I&apos;ve offloaded that drain of willpower to
the machine.
&lt;/p&gt;

&lt;div id=&quot;outline-container-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;The DNS Level &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;


&lt;p&gt;
  There are a few sites that I &apos;block&apos; in &lt;code&gt;/etc/hosts&lt;/code&gt; because I have
  no desire for them, whatsoever. I will never want to &apos;cheat&apos;, and
  visit them, for any reason.
&lt;/p&gt;
&lt;p&gt;
  Here is the relevant section of my &lt;code&gt;/etc/hosts&lt;/code&gt;:
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;0.0.0.0 www.facebook.com
0.0.0.0 facebook.com
0.0.0.0 connect.facebook.net
0.0.0.0 facebook.net
0.0.0.0 fbcdn.net
0.0.0.0 www.fbcdn.net
0.0.0.0 badge.facebook.com
0.0.0.0 blog.facebook.com
0.0.0.0 en-gb.facebook.com
0.0.0.0 developers.facebook.com
0.0.0.0 touch.facebook.com
0.0.0.0 de-de.facebook.com
0.0.0.0 stories.facebook.com
0.0.0.0 it-it.facebook.com
0.0.0.0 hu-hu.facebook.com
0.0.0.0 peace.facebook.com
0.0.0.0 et-ee.facebook.com
0.0.0.0 az-az.facebook.com
0.0.0.0 0.facebook.com
0.0.0.0 apps.facebook.com
0.0.0.0 reddit.com
0.0.0.0 www.reddit.com
&lt;/pre&gt;


&lt;p&gt;
  I would love if there were a central repository of distracting
  sites, and if my hostsfile could be updated automatically against
  this repository.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;The Browser Level &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;


&lt;p&gt;
  Earlier on I used the &lt;a href=&quot;http://bumblebeesystems.dyndns.org/wastenotime/&quot;&gt;WasteNoTime&lt;/a&gt; Safari extension. It helped
  regulate the time I spent on distracting websites, in a reasonable
  way. The process went something like this:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I would make a list of websites to blacklist. There&apos;s a whitelist
     functionality, but I never figured out how to use it in a
     satisfactory way. I would necessarily exclude useful sites I was
     unaware of.

&lt;/li&gt;
&lt;li&gt;I would decide how long I would allow myself to visit the
     distracting websites in total. For example, I would allow myself
     45 minutes on each weekday, and then disable the timer on
     the weekends.

&lt;/li&gt;
&lt;li&gt;I would browse distracting websites until I ran out of time, and
     then go do work.
&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;
  This process isn&apos;t horrible. I imagine it would work for a lot of
  people. For me, however, it was simply too complicated, and invited
  distraction. Every time I wanted to add a site to the list, I would
  have to go to the existing list, and see all my personal vices there
  (Oh yeah! I haven&apos;t checked Hacker News today!)
&lt;/p&gt;
&lt;p&gt;
  And so I discovered &lt;a href=&quot;http://www.mindfulbrowsing.com&quot;&gt;Mindful Browsing&lt;/a&gt;. It works in a subtly different
  way. It&apos;s designed to encourage you to consider your decisions,
  rather than be put off by an admonishment page every time you try to
  access a distracting site.
&lt;/p&gt;
&lt;p&gt;
  It works like this. The extension defaults to always being in
  effect, though this can be modified. Then, while you&apos;re browsing,
  when you find yourself on a site that&apos;s distracting, you press a
  button. The site is added to a blacklist that you never see. That&apos;s
  it.
&lt;/p&gt;
&lt;p&gt;
  What makes it interesting is this: When you try and access a
  distracting website, you get a warning, and the option to
  temporarily allow it. This is fantastic in and of itself (sometimes
  I need to check a distracting forum which also contains useful news
  and information), but there&apos;s another variable: the button to enable
  the site temporarily is disabled for a configurable amount of
  time. I set mine to ten minutes.
&lt;/p&gt;
&lt;p&gt;
  So if I want to visit one of the distracting websites, I have ten
  minutes to either go do something useful and come back, or change my
  mind and close the tab. This is the eponymous &apos;mindful browsing&apos;:
  the ability to actively decide how you want to approach distracting
  websites, and the ability to give yourself time to set other goals.
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>msnyder.info:entry:on-web-sanity.org</guid>
      <pubDate>Sun, 15 Apr 2012 00:00:00 EDT</pubDate>
    </item>
    <item>
      <title>From Spec to Test Suite in Common Lisp: Mustache</title>
      <link>http://msnyder.info/posts/2011/12/common-lisp-mustache/</link>
      <description>
&lt;p&gt;Just a quick write-up for the holidays.
&lt;/p&gt;
&lt;p&gt;
In this article, I will walk you through writing a test suite in
Common Lisp based upon a specification of the software in
question. The software we&apos;ll be looking at is the excellent &lt;a href=&quot;http://mustache.github.com/&quot;&gt;mustache&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
This is a fairly basic Lisp article, but I will be glossing over a lot
of the details of the code I&apos;ve written &amp;ndash; partially because it should
be fairly intuitive, partially because I have no idea how idiomatic it
is. Take everything with a grain of salt, and enjoy the results.
&lt;/p&gt;

&lt;div id=&quot;outline-container-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;The Basics &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;


&lt;p&gt;
  Mustache was written as an example of &apos;logicless&apos; templating:
  providing the bare minimum of functionality needed to create template
  documents that can be interpolated with data. In this scenario, &apos;bare
  minimum&apos; is a complement: an explicit design decision to prevent
  spaghetti code in templates. Mustache templates essentially consist of
  three primitive constructs:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;b&gt;data&lt;/b&gt; construct: if data exists with the name given in the
    token, replace the token with the data.
&lt;/li&gt;
&lt;li&gt;The &lt;b&gt;loop&lt;/b&gt; construct: if the name points to data that is
    &apos;list-like&apos;, render this part of the template for each element in
    the list.
&lt;/li&gt;
&lt;li&gt;The &lt;b&gt;inverted&lt;/b&gt; construct: if the name points to data that is
    non-existent, or &apos;false-like&apos;, render something.
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;
  Nearly all features that Mustache provides can be narrowed down into
  one of these categories. It&apos;s elegantly simple, but implementations,
  depending on their language, may vary in difficulty to express.
&lt;/p&gt;
&lt;p&gt;
  I think it&apos;s interesting that if you ignore that Mustache was
  designed for &apos;hash table&apos;-like contexts, Common Lisp already
  provides a complete implementation of Mustache with its &lt;code&gt;FORMAT&lt;/code&gt;
  directives, specifically the &lt;a href=&quot;http://www.lispworks.com/documentation/lw51/CLHS/Body/22_cda.htm&quot;&gt;aesthetic&lt;/a&gt;, &lt;a href=&quot;http://www.lispworks.com/documentation/lw51/CLHS/Body/22_cgd.htm&quot;&gt;iteration&lt;/a&gt;, and &lt;a href=&quot;http://www.lispworks.com/documentation/lw51/CLHS/Body/22_cgb.htm&quot;&gt;conditional expression&lt;/a&gt; directives. Right out of the gate you can do most of what
  you&apos;d want to do in Mustache, as long as you use lists instead of
  hash tables, and get used to the esoteric syntax. But this isn&apos;t
  good enough for us: we want a rigorous implementation of the
  Mustache language, and for that, we need to test our implementation
  against the &lt;a href=&quot;https://github.com/mustache/spec&quot;&gt;spec&lt;/a&gt;. And here&apos;s where it gets interesting.
&lt;/p&gt;
&lt;p&gt;
  Mustache&apos;s spec was written in YAML, and is also provided as JSON,
  making it machine-parseable. It is divided up into &lt;i&gt;files&lt;/i&gt;. Each
  file is a discrete section of the spec. Each &lt;i&gt;file&lt;/i&gt; contains an
  &lt;i&gt;overview&lt;/i&gt; describing the file, and &lt;i&gt;tests&lt;/i&gt;. Each &lt;i&gt;test&lt;/i&gt; contains a
  &lt;i&gt;name&lt;/i&gt;, &lt;i&gt;description&lt;/i&gt;, &lt;i&gt;context data&lt;/i&gt;, &lt;i&gt;template&lt;/i&gt;, and &lt;i&gt;expected   result&lt;/i&gt;.
&lt;/p&gt;
&lt;p&gt;
  Using this information we can construct an automated test suite: one
  that provides our implementation as an input, uses the context and
  template in each test case, and compares it against the expected
  result. This is absolutely by design and a wonderful thought on the
  part of the Mustache &apos;working group&apos; (for want of a term to describe
  the various contributors to the language).
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;Parsing the Spec &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;


&lt;p&gt;
  First things first. Let&apos;s grab a copy of the spec.
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;$ git clone git://github.com/mustache/spec.git ~/Projects/mustache.spec/
&lt;/pre&gt;


&lt;p&gt;
  Pop open an REPL. I&apos;m going to load the libraries I know we&apos;ll be
  using, in advance, as well as some helper variables and functions:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(ql:quickload &apos;(fiveam cl-json cl-who))

&lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;courtesy http://rosettacode.org/wiki/Walk_a_directory/Non-recursively#Common_Lisp&lt;/span&gt;
(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;walk-directory&lt;/span&gt; (directory pattern)
  (directory (merge-pathnames pattern directory)))

(setq *spec-directory* #P&lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/mustache.spec/&quot;&lt;/span&gt;)

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;utf8-json-decode&lt;/span&gt; (pathname)
  (&lt;span class=&quot;org-keyword&quot;&gt;with-open-file&lt;/span&gt; (stream pathname
                          &lt;span class=&quot;org-builtin&quot;&gt;:direction&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:input&lt;/span&gt;
                          &lt;span class=&quot;org-builtin&quot;&gt;:external-format&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:utf-8&lt;/span&gt;)
    (json:decode-json-from-source stream)))
&lt;/pre&gt;


&lt;p&gt;
  These forms should be fairly self-explanatory. We provide a helper
  function to glob over the spec files we want, set the spec directory
  to a top-level name, and mix our JSON parsing function with a helper
  that ensures the input stream is UTF-8.
&lt;/p&gt;
&lt;p&gt;
  So now:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (walk-directory #P&lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/mustache.spec/&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;specs/*.json&quot;&lt;/span&gt;)

(#P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/comments.json&quot;&lt;/span&gt;
 #P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/delimiters.json&quot;&lt;/span&gt;
 #P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/interpolation.json&quot;&lt;/span&gt;
 #P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/inverted.json&quot;&lt;/span&gt;
 #P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/partials.json&quot;&lt;/span&gt;
 #P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/sections.json&quot;&lt;/span&gt;
 #P&lt;span class=&quot;org-string&quot;&gt;&quot;/Users/msnyder/Projects/mustache.spec/specs/~lambdas.json&quot;&lt;/span&gt;)

(setq *all-specs* 
      (mapcar #&apos;utf8-json-decode (walk-directory *spec-directory* &lt;span class=&quot;org-string&quot;&gt;&quot;specs/*.json&quot;&lt;/span&gt;)))
&lt;/pre&gt;


&lt;p&gt;
  Let&apos;s confirm each loaded file in the spec has the same basic
  structure.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (mapcar (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (x) (mapcar #&apos;car x)) *all-specs*)

((&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;) (&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;)
 (&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;) (&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;)
 (&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;) (&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;)
 (&lt;span class=&quot;org-builtin&quot;&gt;:----+ATTN--&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:OVERVIEW&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:TESTS&lt;/span&gt;))

&lt;/pre&gt;


&lt;p&gt;
  Brilliant.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-3&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;Our Implementation &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;


&lt;p&gt;
  &amp;hellip; sucks. No really. All it does is return the template,
  un-interpolated.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;mustache-render&lt;/span&gt; (template data)
  template)
&lt;/pre&gt;


&lt;p&gt;
  But this will work for our purposes. All we need is something we can
  pass the arguments into, and get a result. It doesn&apos;t have to be the
  right result, just yet.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;The Test Suite &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;


&lt;p&gt;
  FiveAM is my go-to unit test library for Common Lisp. It&apos;s simple,
  elegant, and designed to provide test results in a format that can
  easily be transformed for any purpose.
&lt;/p&gt;
&lt;p&gt;
  What we&apos;d like to do is generate this test suite by iterating over
  each test in the spec, and creating a unit test for it.
&lt;/p&gt;
&lt;p&gt;
  To give you an idea of the basic structure of a test, here&apos;s one of
  the imported tests from the spec.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;courtesy http://aima.cs.berkeley.edu/lisp/utilities/utilities.lisp&lt;/span&gt;
(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;random-element&lt;/span&gt; (list)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Return some element of the list, chosen at random.&quot;&lt;/span&gt;
  (nth (random (length list)) list))

CL-USER&amp;gt; (random-element (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:tests&lt;/span&gt; (random-element *all-specs*))))

((&lt;span class=&quot;org-builtin&quot;&gt;:NAME&lt;/span&gt; . &lt;span class=&quot;org-string&quot;&gt;&quot;Falsey&quot;&lt;/span&gt;) (&lt;span class=&quot;org-builtin&quot;&gt;:DATA&lt;/span&gt; (&lt;span class=&quot;org-builtin&quot;&gt;:BOOLEAN&lt;/span&gt;))
 (&lt;span class=&quot;org-builtin&quot;&gt;:EXPECTED&lt;/span&gt; . &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot;This should be rendered.\&quot;&quot;&lt;/span&gt;)
 (&lt;span class=&quot;org-builtin&quot;&gt;:TEMPLATE&lt;/span&gt; . &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot;{{^boolean}}This should be rendered.{{/boolean}}\&quot;&quot;&lt;/span&gt;)
 (&lt;span class=&quot;org-builtin&quot;&gt;:DESC&lt;/span&gt; . &lt;span class=&quot;org-string&quot;&gt;&quot;Falsey sections should have their contents rendered.&quot;&lt;/span&gt;))
&lt;/pre&gt;


&lt;p&gt;
  Versus its counterpart in the YAML spec:
&lt;/p&gt;



&lt;pre class=&quot;src src-yaml&quot;&gt;- &lt;span class=&quot;org-variable-name&quot;&gt;name&lt;/span&gt;: Falsey
   &lt;span class=&quot;org-variable-name&quot;&gt;desc&lt;/span&gt;: Falsey sections should have their contents rendered.
   &lt;span class=&quot;org-variable-name&quot;&gt;data&lt;/span&gt;: { &lt;span class=&quot;org-variable-name&quot;&gt;boolean&lt;/span&gt;: false }
   &lt;span class=&quot;org-variable-name&quot;&gt;template&lt;/span&gt;: &lt;span class=&quot;org-string&quot;&gt;&apos;&quot;{{^boolean}}This should be rendered.{{/boolean}}&quot;&apos;&lt;/span&gt;
   &lt;span class=&quot;org-variable-name&quot;&gt;expected&lt;/span&gt;: &lt;span class=&quot;org-string&quot;&gt;&apos;&quot;This should be rendered.&quot;&apos;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
  It&apos;s hard to see from this example, but our JSON importer turned the
  data context into an association list, which we should use in the
  implementation as the type for our context argument. In this case,
  &lt;code&gt;(cdr (assoc :boolean (cdr (assoc :data test))))&lt;/code&gt; would return nil,
  a &apos;falsey&apos; value.
&lt;/p&gt;
&lt;p&gt;
  So for each spec, we have a bunch of tests. For each test, we want
  to make a unit test in our test suite. Simple enough.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(fiveam:def-suite &lt;span class=&quot;org-builtin&quot;&gt;:mustache-specs&lt;/span&gt;)
(fiveam:in-suite &lt;span class=&quot;org-builtin&quot;&gt;:mustache-specs&lt;/span&gt;)

(&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt; for spec in *all-specs*
   do (&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt; for test in (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:tests&lt;/span&gt; spec))
         do (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((name (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:name&lt;/span&gt; test)))
                  (desc (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:desc&lt;/span&gt; test)))
                  (data (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:data&lt;/span&gt; test)))
                  (template (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:template&lt;/span&gt; test)))
                  (expected (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:expected&lt;/span&gt; test))))
              (fiveam:test name
                desc
                (fiveam:is (string= expected (mustache-render template data)))))))
&lt;/pre&gt;


&lt;p&gt;
  Try it out.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (fiveam:run &lt;span class=&quot;org-builtin&quot;&gt;:mustache-specs&lt;/span&gt;)

&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;in: LAMBDA ()&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(MUSTACHE-RENDER TEMPLATE DATA)&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;caught WARNING:&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;undefined variable: DATA&lt;/span&gt;

&lt;span class=&quot;org-comment-delimiter&quot;&gt;;     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(LAMBDA ()&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;       &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;DESC&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;       &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(IT.BESE.FIVEAM:IS (STRING= EXPECTED (MUSTACHE-RENDER TEMPLATE DATA))))&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;caught WARNING:&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;undefined variable: DESC&lt;/span&gt;

&lt;span class=&quot;org-comment-delimiter&quot;&gt;;     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(IT.BESE.FIVEAM:IS (STRING= EXPECTED (MUSTACHE-RENDER TEMPLATE DATA)))&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;==&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(LET ((#:E-0 EXPECTED) (#:A-1 (MUSTACHE-RENDER TEMPLATE DATA)))&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(IF (PROGN (STRING= #:E-0 #:A-1))&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;         &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(IT.BESE.FIVEAM::ADD-RESULT &apos;IT.BESE.FIVEAM::TEST-PASSED :TEST-EXPR&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;&apos;(STRING= EXPECTED&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                               &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(MUSTACHE-RENDER TEMPLATE DATA)))&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;         &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(IT.BESE.FIVEAM::PROCESS-FAILURE :REASON&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                          &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(FORMAT NIL&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                                  &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;&quot;~S evaluated to ~S, which is not ~S to ~S.&quot;&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                                  &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;&apos;(MUSTACHE-RENDER TEMPLATE&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                                                    &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;DATA)&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                                  &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;#:A-1 &apos;STRING= #:E-0)&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                          &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;:TEST-EXPR&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                          &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;&apos;(STRING= EXPECTED&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                                    &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(MUSTACHE-RENDER TEMPLATE&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;                                                                     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;DATA)))))&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;caught WARNING:&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;undefined variable: EXPECTED&lt;/span&gt;

&lt;span class=&quot;org-comment-delimiter&quot;&gt;;     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(MUSTACHE-RENDER TEMPLATE DATA)&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;caught WARNING:&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;undefined variable: TEMPLATE&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;compilation unit finished&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Undefined variables:&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;     &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;DATA DESC EXPECTED TEMPLATE&lt;/span&gt;
&lt;span class=&quot;org-comment-delimiter&quot;&gt;;   &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;caught 4 WARNING conditions&lt;/span&gt;
X
(#&amp;lt;IT.BESE.FIVEAM::UNEXPECTED-TEST-FAILURE {10037A5781}&amp;gt;)
&lt;/pre&gt;


&lt;p&gt;
  What the hell happened? Why is there only one test? Why were all
  those variables in the loop considered undefined?
&lt;/p&gt;
&lt;p&gt;
  Well. FiveAM&apos;s &lt;code&gt;test&lt;/code&gt; form is a &lt;b&gt;macro&lt;/b&gt;. It is evaluated and
  expanded before the rest of the code, and, in this case, evaluated
  when none of the variables used in it are actually bound to a
  value. This means that for every test in the spec, we created a test
  called &apos;name&apos;, instead of a test called whatever the &apos;name&apos; variable
  pointed to. So we are out of luck, in terms of this approach.
&lt;/p&gt;
&lt;p&gt;
  But it doesn&apos;t mean we&apos;re out of luck, period. Knowing that &lt;code&gt;test&lt;/code&gt;
  is a macro, we can reformulate our problem. We don&apos;t want to iterate
  over the specs and tests, and create test cases for each one. We
  want to write a macro which &lt;b&gt;expands&lt;/b&gt; into code which does that. And
  we can.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(fiveam:def-suite &lt;span class=&quot;org-builtin&quot;&gt;:mustache-specs&lt;/span&gt;)      &lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;redefining a test suite empties it&lt;/span&gt;
(fiveam:in-suite &lt;span class=&quot;org-builtin&quot;&gt;:mustache-specs&lt;/span&gt;)

(&lt;span class=&quot;org-keyword&quot;&gt;defmacro&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;mustache-spawn-test-suite&lt;/span&gt; (specs)
  `(&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
     ,@(&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt; 
         for spec in (eval specs)
         append (&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt;
               for test in (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:tests&lt;/span&gt; spec))
               for name = (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:name&lt;/span&gt; test))
               for template = (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:template&lt;/span&gt; test))
               for data = (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:data&lt;/span&gt; test))
               for expected = (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:expected&lt;/span&gt; test))
               for desc = (cdr (assoc &lt;span class=&quot;org-builtin&quot;&gt;:desc&lt;/span&gt; test))
               collect `(fiveam:test ,(intern name) ,desc
                          (fiveam:is (string= ,expected (mustache-render ,template ,data))))))))

&lt;/pre&gt;


&lt;p&gt;
  Our macro doesn&apos;t look too different from our first attempt, but
  what it does is something quite wonderful.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;CL-USER&amp;gt; (macroexpand &apos;(mustache-spawn-test-suite *all-specs*))

(&lt;span class=&quot;org-keyword&quot;&gt;PROGN&lt;/span&gt;
 (IT.BESE.FIVEAM:TEST |Inline|
   &lt;span class=&quot;org-string&quot;&gt;&quot;Comment blocks should be removed from the template.&quot;&lt;/span&gt;
   (IT.BESE.FIVEAM:IS
    (STRING= &lt;span class=&quot;org-string&quot;&gt;&quot;1234567890&quot;&lt;/span&gt;
             (MUSTACHE-RENDER &lt;span class=&quot;org-string&quot;&gt;&quot;12345{{! Comment Block! }}67890&quot;&lt;/span&gt; NIL))))
 (IT.BESE.FIVEAM:TEST |Multiline|
   &lt;span class=&quot;org-string&quot;&gt;&quot;Multiline comments should be permitted.&quot;&lt;/span&gt;
   (IT.BESE.FIVEAM:IS
    (STRING= &lt;span class=&quot;org-string&quot;&gt;&quot;1234567890&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;
             (MUSTACHE-RENDER &lt;span class=&quot;org-string&quot;&gt;&quot;12345{{!&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;  This is a&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;  multi-line comment...&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;}}67890&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;
                              NIL))))
  &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
  By writing a macro, we&apos;ve written a tiny amount of code which
  generates a lot of code. This code does precisely what we want:
  iterates over the list of tests in the Mustache spec, and creates a
  test suite for each and every one of them.
&lt;/p&gt;
&lt;p&gt;
  (Lispers &lt;a href=&quot;http://www.faqs.org/faqs/lisp-faq/part3/section-13.html&quot;&gt;frown&lt;/a&gt; on the use of &lt;code&gt;eval&lt;/code&gt; as above. Can you rewrite
  the macro to avoid its use?)
&lt;/p&gt;
&lt;p&gt;
  Now we can execute the macro, passing in our list of specifications,
  and generate the test suite that we really want.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(mustache-spawn-test-suite *all-specs*)
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;Reporting Results &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;


&lt;p&gt;
  When we use &lt;code&gt;fiveam:run!&lt;/code&gt; to run the test suite, we get back results
  in a very nice printed format. This works well if you&apos;re at the
  REPL, but what if you wanted something to display to the world?
  Something half-continuous integration, half-implementation progress
  bar? Using &lt;code&gt;fiveam:run&lt;/code&gt; and the excellent &lt;a href=&quot;http://weitz.de/cl-who/&quot;&gt;CL-WHO&lt;/a&gt;, we can do just
  that.
&lt;/p&gt;
&lt;p&gt;
  First, run the tests.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(setq *results* (fiveam:run &lt;span class=&quot;org-builtin&quot;&gt;:mustache-specs&lt;/span&gt;))
&lt;/pre&gt;


&lt;p&gt;
  Then, let&apos;s provide a simple transformation of the test results.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;pretty-result&lt;/span&gt; (test-result)
  (&lt;span class=&quot;org-keyword&quot;&gt;flet&lt;/span&gt; ((result-type (result) (format nil &lt;span class=&quot;org-string&quot;&gt;&quot;~(~A~)&quot;&lt;/span&gt; (symbol-name (type-of result)))))
    (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((test-case (fiveam::test-case test-result)))
      (list (symbol-name (fiveam::name test-case))
            (fiveam::description test-case)
            (result-type test-result)))))

&lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;then, try it out:&lt;/span&gt;
CL-USER&amp;gt; (pretty-result (nth 0 *results*))
(&lt;span class=&quot;org-string&quot;&gt;&quot;Inline&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;Comment blocks should be removed from the template.&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;test-failure&quot;&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
  Perfect. Running &lt;code&gt;pretty-result&lt;/code&gt; on one of the test results produces
  a simple list consisting of the name of the test, the description of
  the test, and a token representing a passed/failed/skipped test.
&lt;/p&gt;
&lt;p&gt;
  Now just wrap it in some CL-WHO, fire up Emacs&apos; &lt;a href=&quot;https://github.com/jrhbailey/emacs-http-server&quot;&gt;httpd-server&lt;/a&gt;, and
  navigate over to the generated HTML file.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;with-open-file&lt;/span&gt; (stream #P&lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/results.html&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:direction&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:output&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:if-exists&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:supersede&lt;/span&gt;)
  (&lt;span class=&quot;org-keyword&quot;&gt;cl-who:with-html-output&lt;/span&gt; (stream)
    (&lt;span class=&quot;org-builtin&quot;&gt;:style&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;text/css&quot;&lt;/span&gt; 
            &lt;span class=&quot;org-string&quot;&gt;&quot;.test-passed { background-color: #0f0; }&quot;&lt;/span&gt;
            &lt;span class=&quot;org-string&quot;&gt;&quot;.test-failure { background-color: #f00; }&quot;&lt;/span&gt;
            &lt;span class=&quot;org-string&quot;&gt;&quot;.unexpected-test-failure { background-color: #ff0; }&quot;&lt;/span&gt;)
    (&lt;span class=&quot;org-builtin&quot;&gt;:table&lt;/span&gt;
     (&lt;span class=&quot;org-keyword&quot;&gt;loop&lt;/span&gt;
        for (name description result) in (mapcar #&apos;pretty-result *results*)
        do (cl-who:htm 
            (&lt;span class=&quot;org-builtin&quot;&gt;:tr&lt;/span&gt; 
             (&lt;span class=&quot;org-builtin&quot;&gt;:td&lt;/span&gt; (cl-who:fmt name))
             (&lt;span class=&quot;org-builtin&quot;&gt;:td&lt;/span&gt; (cl-who:fmt description))
             (&lt;span class=&quot;org-builtin&quot;&gt;:td&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:class&lt;/span&gt; result (cl-who:fmt result))))))))
&lt;/pre&gt;


&lt;p&gt;
&lt;img src=&quot;/images/common-lisp-mustache/test-suite-results.png&quot;  alt=&quot;/images/common-lisp-mustache/test-suite-results.png&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;
Pretty impressive, yeah? Fifty source lines of code from start to
finish, including our non-existent implementation of
&lt;code&gt;mustache-render&lt;/code&gt;. At any point that the definition of
&lt;code&gt;mustache-render&lt;/code&gt; changes, all you need to do to re-generate the test
suite results is re-run &lt;code&gt;(setq *results* (fiveam:run :mustache-specs))&lt;/code&gt; and then the above snippet of
CL-WHO-infused Lisp.
&lt;/p&gt;
&lt;p&gt;
And there you have it! The next step, of course, is to write a Lisp
package that meets the spec, and causes all those red table cells in
the generated output to turn green. But, as a wise computer science
book once asserted, &quot;this is left as an exercise to the reader.&quot;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>msnyder.info:entry:common-lisp-mustache.org</guid>
      <pubDate>Thu, 29 Dec 2011 00:00:00 EST</pubDate>
    </item>
    <item>
      <title>Introducing gopher.el</title>
      <link>http://msnyder.info/posts/2011/11/introducing-gopher.el/</link>
      <description>
&lt;p&gt;&lt;img src=&quot;/images/introducing-gopher.el/gopher-screenshot.png&quot;  alt=&quot;/images/introducing-gopher.el/gopher-screenshot.png&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;
Gopher is an internet protocol, like the one your web browser uses. It
is designed to do a few things well. Gopher makes browsing and sharing
information very simple. While it is not in very widespread use
anymore, it is still an excellent way to discover and share.
&lt;/p&gt;
&lt;p&gt;
The above screenshot shows a Gopher listing. A listing is a directory,
but instead of files, it contains links: links to directories, text
documents, images, and other sites.
&lt;/p&gt;
&lt;p&gt;
gopher.el is a Gopher client for Emacs.
&lt;/p&gt;

&lt;div id=&quot;outline-container-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;Getting it &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;


&lt;p&gt;
  The package is available on Marmalade.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(add-to-list &apos;package-archives &apos;(&lt;span class=&quot;org-string&quot;&gt;&quot;marmalade&quot;&lt;/span&gt; . &lt;span class=&quot;org-string&quot;&gt;&quot;http://marmalade-repo.org/packages/&quot;&lt;/span&gt;))
(package-install &apos;gopher)
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;Using it &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;


&lt;p&gt;
  &lt;code&gt;M-x gopher&lt;/code&gt; prompts you for an address. &lt;code&gt;TAB&lt;/code&gt; and &lt;code&gt;M-TAB&lt;/code&gt; jump
  between directory links, while &lt;code&gt;[&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt; jump between text
  links. &lt;code&gt;ENTER&lt;/code&gt; opens the link at the cursor&apos;s position. There&apos;s no
  history yet, but you can navigate up the directory tree with &lt;code&gt;u&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-3&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;Contributing &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;


&lt;p&gt;
 The source code may be forked, and issues may be filed, by visiting
  &lt;code&gt;gopher.el&lt;/code&gt;&apos;s &lt;a href=&quot;http://github.com/ardekantur/gopher.el&quot;&gt;GitHub page&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;The Future &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;


&lt;p&gt;
  There are several unimplemented features, the most important of
  which is HTML viewing. This feature is coming soon.
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>msnyder.info:entry:introducing-gopher.el.org</guid>
      <pubDate>Mon, 07 Nov 2011 00:00:00 EST</pubDate>
    </item>
    <item>
      <title>Clozure CL and Xcode 4</title>
      <link>http://msnyder.info/posts/2011/09/clozure-cl-and-xcode-4/</link>
      <description>
&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Manually modifying the Homebrew formula for Clozure is
 unnecessary as of &lt;a href=&quot;https://github.com/jerjanssen/homebrew/commit/5f5f7ab4c88c7ff69a89600be2bbb980a1a540a7&quot;&gt;November 2011&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
I just learned about &lt;a href=&quot;http://ccl.clozure.com/&quot;&gt;Clozure CL&lt;/a&gt;, a Common Lisp implementation with a
very friendly bridge for Cocoa. The idea of using Lisp to write
pseudo-&apos;native&apos; apps for OS X intrigued me, so I modified my
Homebrew&apos;s formula (changing &lt;code&gt;1.6&lt;/code&gt; to &lt;code&gt;1.7&lt;/code&gt; in the URL and changing
the MD5 checksum to &lt;code&gt;4f7d8c48abc9355c69946ef125fa2aa5&lt;/code&gt; and installed
it. Getting it into SLIME was no issue, and soon I was working on
reproducing some of the example projects. I was using a tutorial from
within Clozure&apos;s &lt;code&gt;contrib&lt;/code&gt; directory entitled &lt;a href=&quot;http://trac.clozure.com/ccl/export/13390/trunk/source/contrib/krueger/InterfaceProjects/Documentation/InterfaceBuilderWithCCLTutorial.pdf&quot;&gt;Cocoa Interfaces Using the Apple Interface Builder and Clozure Common Lisp&lt;/a&gt;, written by
Dr. Paul Krueger.
&lt;/p&gt;
&lt;p&gt;
This is where I ran into problems. The general gist of the tutorial
(creating a window that takes two inputs, and sums them when a button
is pressed) is that the interface can be designed in Apple&apos;s Interface
Builder, and the backing code written in Lisp. Fair enough. Except
Interface Builder really doesn&apos;t &lt;i&gt;exist&lt;/i&gt; anymore. It has been rolled
up into Xcode 4, a component that works seamlessly with the IDE
itself. I don&apos;t begrudge Apple for improving their software&apos;s
workflow; in fact, I applaud it. The trouble is that one of the steps
the tutorial relies on no longer works the same way.
&lt;/p&gt;
&lt;p&gt;
My understanding of Cocoa is a little spotty so I will explain it the
best that I can. Objective-C incorporates message-passing-style
object-orientation, and one of the ways it uses this to great effect
is by creating delegates of components of the UI to send and receive
different messages from. Since the instance that interacts with the UI
controls must exist before the UI itself gets loaded, a representation
of that instance, called &quot;File&apos;s Owner&quot;, exists in the Interface
Builder. In Xcode 3, the exact object type of the File&apos;s Owner did not
need to exist in code, because a mechanism existed for generating the
object you described when switching between Interface Builder and the
Editor.
&lt;/p&gt;
&lt;p&gt;
In Xcode 4, no such mechanism exists. Instead, you can literally drag
the connection from your UI into a source code file, and the
connections (called &apos;actions&apos; or &apos;outlets&apos; depending on their
function) will be autowritten for you. A nice touch, if you actually
are working in a full-fledged Cocoa project.
&lt;/p&gt;
&lt;p&gt;
You kind of have to do something like that from now on when creating
nibs for Clozure-CL projects, as far as I can tell.
&lt;/p&gt;
&lt;p&gt;
In the example of the &lt;code&gt;simplesum&lt;/code&gt; project in the above PDF, after
creating your UI, create a new &apos;Cocoa Objective-C class&apos;, with
implementation and header files, and call it &lt;code&gt;SumWindowOwn&lt;/code&gt;. In its
header file, you&apos;ll be handwriting the connections you&apos;d like.
&lt;/p&gt;
&lt;p&gt;
Where the PDF says:
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;
In the Class Outlets part of the window click the &quot;+&quot; button to add a
new outlet. Edit the name to be &quot;input1&quot; and the type to be
NSTextField.
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;p&gt;
We will instead add a line of code in the &lt;code&gt;@interface&lt;/code&gt; of &lt;code&gt;SumWindowOwn&lt;/code&gt;:
&lt;/p&gt;



&lt;pre class=&quot;src src-C&quot;&gt;@property (assign) IBOutlet &lt;span class=&quot;org-type&quot;&gt;NSTextField&lt;/span&gt; *&lt;span class=&quot;org-variable-name&quot;&gt;input1&lt;/span&gt;;
&lt;/pre&gt;


&lt;p&gt;
Where the PDF says:
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;
Click the &quot;+&quot; button and add a new action. Edit the &quot;MyAction1:&quot; name
that is generated and change it to &quot;doSum:&quot;.
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;p&gt;
We will instead add a function interface:
&lt;/p&gt;



&lt;pre class=&quot;src src-C&quot;&gt;- (&lt;span class=&quot;org-type&quot;&gt;IBAction&lt;/span&gt;)doSum:(&lt;span class=&quot;org-type&quot;&gt;id&lt;/span&gt;)sender;
&lt;/pre&gt;


&lt;p&gt;
Do this for the other outlets in the tutorial, and then you can
&lt;code&gt;CTRL&lt;/code&gt;-drag  the UI controls onto &lt;b&gt;the lines you just wrote&lt;/b&gt;. Not
between, or after, literally onto.
&lt;/p&gt;
&lt;p&gt;
At this point I was able to load the nib using &lt;code&gt;iu:loadnib&lt;/code&gt; without
issue.
&lt;/p&gt;
&lt;p&gt;
I recognize some or all of my explanation above may be vague,
oversimplified, or flat-out wrong. I will happily consider corrections
to my understanding of the situation.
&lt;/p&gt;</description>
      <guid>msnyder.info:entry:clozure-cl-and-xcode-4.org</guid>
      <pubDate>Sat, 10 Sep 2011 00:00:00 EDT</pubDate>
    </item>
    <item>
      <title>Introducing Narcissus: An Org Mode Blogger</title>
      <link>http://msnyder.info/posts/2011/07/introducing-narcissus/</link>
      <description>
&lt;p&gt;In this article, I attempt to both describe and implement, through
literate programming, a set of tools that will allow me to use Org
Mode to publish my blog, the way I want and following the rules I
want.
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;NOTE:&lt;/b&gt; The source code listings in this file have been hidden with a
 CSS rule. In order to examine the entirety of the source presented in
 this article, disable CSS.
&lt;/p&gt;

&lt;div id=&quot;outline-container-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;Description and Requirements (Progress [33%]) &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;

&lt;p&gt;This is an attempt to put together a set of tools that will allow me
to create a sort of static blog with Org Mode. There are several
pieces of behavior that I am considering necessary for this to be
successful:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[&amp;nbsp;]&lt;/code&gt; Can re-use components from old site
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;nbsp;]&lt;/code&gt; HTML5 Generation
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[X]&lt;/code&gt; Preserves existing URL structure
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;nbsp;]&lt;/code&gt; Rsync-like publishing
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;nbsp;]&lt;/code&gt; Uploading of resources
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[X]&lt;/code&gt; Preview exported HTML before publish
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;nbsp;]&lt;/code&gt; Mark entries as drafts and don&apos;t publish
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;nbsp;]&lt;/code&gt; Mark scraps to publish on separate pages
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[X]&lt;/code&gt; RSS Generation
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;
Some general thoughts. &lt;code&gt;org-publish&lt;/code&gt; seems to be the most reasonable
way to attempt this, and indeed an existing org blogging system called
blorg is defunct until the author completes a rewrite that is
dependent on &lt;code&gt;org-publish&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;org-publish-project-alist&lt;/code&gt; takes a parameter &lt;code&gt;:publishing-function&lt;/code&gt;,
which in most stock cases appears to be a tiny function that calls
&lt;code&gt;org-publish-org-as&lt;/code&gt; with a format. For example:
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;org-publish-org-to-html&lt;/span&gt; (plist filename pub-dir)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Publish an org file to HTML.&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;See `&lt;/span&gt;&lt;span class=&quot;org-doc&quot;&gt;&lt;span class=&quot;org-constant&quot;&gt;org-publish-org-to&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-doc&quot;&gt;&apos; to the list of arguments.&quot;&lt;/span&gt;
  (org-publish-with-aux-preprocess-maybe
    (org-publish-org-to &lt;span class=&quot;org-string&quot;&gt;&quot;html&quot;&lt;/span&gt; plist filename pub-dir)))
&lt;/pre&gt;


&lt;p&gt;
Within &lt;code&gt;org-publish-org-to&lt;/code&gt;, the format is appended to a string that
becomes the function name for whatever is actually processing Org mode
files. For example, &lt;code&gt;(org-publish-org-to &quot;html&quot; ...)&lt;/code&gt; calls the
function &lt;code&gt;org-export-as-html&lt;/code&gt;. 
&lt;/p&gt;
&lt;p&gt;
I&apos;m going to call this project &lt;b&gt;Narcissus&lt;/b&gt;. It&apos;s fitting that a set of
tools that allows me to broadcast my innermost bullshit to the world
is named after a dude that couldn&apos;t stop staring at his own
reflection.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;Reusing Components &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;


&lt;p&gt;
  This is a pseudo-requirement of sorts. Basically, not much work
  should be done to preserve both the structure of the web pages that
  make up the old site, and the stylesheets that make up the old site.
&lt;/p&gt;
&lt;p&gt;
  Here are some variables set in order to preserve the existing look
  and feel of the site.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(setq org-export-html-style &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;link rel=&apos;stylesheet&apos; type=&apos;text/css&apos; href=&apos;/css/site.css&apos;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;link rel=&apos;alternate&apos; type=&apos;application/rss+xml&apos; title=&apos;msnyder.info RSS&apos; href=&apos;http://msnyder.info/rss.xml&apos;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;link rel=&apos;stylesheet&apos; type=&apos;text/css&apos; href=&apos;/css/code.css&apos;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;link rel=&apos;stylesheet&apos; href=&apos;http://fonts.googleapis.com/css?family=Inconsolata&apos; type=&apos;text/css&apos; media=&apos;screen, projection&apos; /&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;link rel=&apos;stylesheet&apos; href=&apos;http://fonts.googleapis.com/css?family=Raleway:100&apos; type=&apos;text/css&apos; media=&apos;screen, projection&apos; /&amp;gt;&quot;&lt;/span&gt;)

(setq org-export-html-preamble &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;h1&amp;gt;&amp;lt;a href=&apos;/&apos;&amp;gt;msnyder&amp;lt;span&amp;gt;&amp;amp;#9879;&amp;lt;/span&amp;gt;info&amp;lt;/a&amp;gt;&amp;lt;/h1&amp;gt;&quot;&lt;/span&gt;)
(setq org-export-html-postamble &lt;span class=&quot;org-string&quot;&gt;&quot;Copyright &amp;amp;copy; MMXII &amp;lt;a href=&apos;/about/&apos;&amp;gt;Matthew Snyder.&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;)
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-3&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;HTML5 Generation &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;


&lt;p&gt;
  HTML5 generation should be straightforward. It doesn&apos;t explicitly
  need to &lt;b&gt;be&lt;/b&gt; HTML5 generation, it just needs to be standard org-mode
  exporting into templates with any content in them, as far as I can
  tell. Writing a function like &lt;code&gt;org-export-as-narcissus-html&lt;/code&gt; is
  basically the ticket.
&lt;/p&gt;
&lt;p&gt;
  And here it is. This function is almost entirely cribbed from
  &lt;code&gt;org-publish&lt;/code&gt;&apos;s &lt;code&gt;org-export-as-html&lt;/code&gt;. Where changes have been made
  for this project, I&apos;ve prepended them with a comment starting with
  &lt;code&gt;NARCISSUS:&lt;/code&gt;.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;org-export-as-narcissus-html&lt;/span&gt; (arg &lt;span class=&quot;org-type&quot;&gt;&amp;amp;optional&lt;/span&gt; hidden ext-plist
                                     to-buffer body-only pub-dir)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Export the outline as a pretty HTML file.&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;If there is an active region, export only the region.  The prefix&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;ARG specifies how many levels of the outline should become&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;headlines.  The default is 3.  Lower levels will become bulleted&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;lists.  HIDDEN is obsolete and does nothing.&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;EXT-PLIST is a property list with external parameters overriding&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;org-mode&apos;s default settings, but still inferior to file-local&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;settings.  When TO-BUFFER is non-nil, create a buffer with that&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;name and export to that buffer.  If TO-BUFFER is the symbol&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;org-doc&quot;&gt;&lt;span class=&quot;org-constant&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-doc&quot;&gt;&apos;, don&apos;t leave any buffer behind but just return the&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;resulting HTML as a string.  When BODY-ONLY is set, don&apos;t produce&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;the file header and footer, simply return the content of&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;&amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;, without even the body tags themselves.  When&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;PUB-DIR is set, use this as the publishing directory.&quot;&lt;/span&gt;
  (interactive &lt;span class=&quot;org-string&quot;&gt;&quot;P&quot;&lt;/span&gt;)
  (run-hooks &apos;org-export-first-hook)

  &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Make sure we have a file name when we need it.&lt;/span&gt;
  (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and (not (or to-buffer body-only))
             (not buffer-file-name))
    (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (buffer-base-buffer)
        (org-set-local &apos;buffer-file-name
                       (&lt;span class=&quot;org-keyword&quot;&gt;with-current-buffer&lt;/span&gt; (buffer-base-buffer)
                         buffer-file-name))
      (&lt;span class=&quot;org-warning&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;Need a file name to be able to export&quot;&lt;/span&gt;)))

  (message &lt;span class=&quot;org-string&quot;&gt;&quot;Exporting...&quot;&lt;/span&gt;)
  (setq-default org-todo-line-regexp org-todo-line-regexp)
  (setq-default org-deadline-line-regexp org-deadline-line-regexp)
  (setq-default org-done-keywords org-done-keywords)
  (setq-default org-maybe-keyword-time-regexp org-maybe-keyword-time-regexp)
  (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((opt-plist
          (org-export-process-option-filters
           (org-combine-plists (org-default-export-plist)
                               ext-plist
                               (org-infile-export-plist))))
         (body-only (or body-only (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:body-only&lt;/span&gt;)))
         (style (concat (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:style-include-default&lt;/span&gt;)
                            org-export-html-style-default)
                        (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:style&lt;/span&gt;)
                        (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:style-extra&lt;/span&gt;)
                        &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;
                        (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:style-include-scripts&lt;/span&gt;)
                            org-export-html-scripts)))
         (html-extension (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:html-extension&lt;/span&gt;))
         valid thetoc have-headings first-heading-pos
         (odd org-odd-levels-only)
         (region-p (org-region-active-p))
         (rbeg (and region-p (region-beginning)))
         (rend (and region-p (region-end)))
         (subtree-p
          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:ignore-subtree-p&lt;/span&gt;)
              nil
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; region-p
              (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
                (goto-char rbeg)
                (and (org-at-heading-p)
                     (&amp;gt;= (org-end-of-subtree t t) rend))))))
         (level-offset (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; subtree-p
                           (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
                             (goto-char rbeg)
                             (+ (funcall outline-level)
                                (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; org-odd-levels-only 1 0)))
                         0))
         (opt-plist (setq org-export-opt-plist
                          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; subtree-p
                              (org-export-add-subtree-options opt-plist rbeg)
                            opt-plist)))
         &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;The following two are dynamically scoped into other&lt;/span&gt;
         &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;routines below.&lt;/span&gt;
         (org-current-export-dir
          (or pub-dir (org-export-directory &lt;span class=&quot;org-builtin&quot;&gt;:html&lt;/span&gt; opt-plist)))
         (org-current-export-file buffer-file-name)
         (level 0) (line &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;) (origline &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;) txt todo
         (umax nil)
         (umax-toc nil)
         &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: Allow EXPORT_FILE_NAME to exist in publish settings&lt;/span&gt;
         (concat-thing (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
                        ((and subtree-p 
                              (org-entry-get (region-beginning) &lt;span class=&quot;org-string&quot;&gt;&quot;EXPORT_FILE_NAME&quot;&lt;/span&gt; t)
                              (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt;))
                         (concat (org-entry-get (region-beginning) &lt;span class=&quot;org-string&quot;&gt;&quot;EXPORT_FILE_NAME&quot;&lt;/span&gt; t) &lt;span class=&quot;org-string&quot;&gt;&quot;/&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt;)))
                        (t (or 
                            (concat
                             (narcissus-entry-published-location opt-plist)
                             (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt;))
                            (and subtree-p
                                 (org-entry-get (region-beginning) &lt;span class=&quot;org-string&quot;&gt;&quot;EXPORT_FILE_NAME&quot;&lt;/span&gt; t))
                            (file-name-nondirectory buffer-file-name)))))
         (filename (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; to-buffer nil
                     (expand-file-name
                      (concat
                       (file-name-sans-extension concat-thing) &lt;span class=&quot;org-string&quot;&gt;&quot;.&quot;&lt;/span&gt; html-extension)
                      (file-name-as-directory
                       (or pub-dir (org-export-directory &lt;span class=&quot;org-builtin&quot;&gt;:html&lt;/span&gt; opt-plist))))))
         (current-dir (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; buffer-file-name
                          (file-name-directory buffer-file-name)
                        default-directory))
         (buffer (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; to-buffer
                     (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
                      ((eq to-buffer &apos;string) (get-buffer-create &lt;span class=&quot;org-string&quot;&gt;&quot;*Org HTML Export*&quot;&lt;/span&gt;))
                      (t (get-buffer-create to-buffer)))
                   (find-file-noselect filename)))
         (org-levels-open (make-vector org-level-max nil))
         (date (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:date&lt;/span&gt;))
         (author      (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:author&lt;/span&gt;))
         (html-validation-link (or org-export-html-validation-link &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
         (title       (org-html-expand
                       (or (and subtree-p (org-export-get-title-from-subtree))
                           (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:title&lt;/span&gt;)
                           (and (not body-only)
                                (not
                                 (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:skip-before-1st-heading&lt;/span&gt;))
                                (org-export-grab-title-from-buffer))
                           (and buffer-file-name
                                (file-name-sans-extension
                                 (file-name-nondirectory buffer-file-name)))
                           &lt;span class=&quot;org-string&quot;&gt;&quot;UNTITLED&quot;&lt;/span&gt;)))
         (link-up (and (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-up&lt;/span&gt;)
                       (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\S-&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-up&lt;/span&gt;))
                       (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-up&lt;/span&gt;)))
         (link-home (and (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-home&lt;/span&gt;)
                         (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\S-&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-home&lt;/span&gt;))
                         (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-home&lt;/span&gt;)))
         (dummy (setq opt-plist (plist-put opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:title&lt;/span&gt; title)))
         (html-table-tag (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:html-table-tag&lt;/span&gt;))
         (quote-re0   (concat &lt;span class=&quot;org-string&quot;&gt;&quot;^[ \t]*&quot;&lt;/span&gt; org-quote-string &lt;span class=&quot;org-string&quot;&gt;&quot;\\&amp;gt;&quot;&lt;/span&gt;))
         (quote-re    (concat &lt;span class=&quot;org-string&quot;&gt;&quot;^&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\*+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t]+&quot;&lt;/span&gt; org-quote-string &lt;span class=&quot;org-string&quot;&gt;&quot;\\&amp;gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;))
         (inquote     nil)
         (infixed     nil)
         (inverse     nil)
         (email       (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:email&lt;/span&gt;))
         (language    (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:language&lt;/span&gt;))
         (keywords    (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:keywords&lt;/span&gt;))
         (description (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:description&lt;/span&gt;))
         (num         (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:section-numbers&lt;/span&gt;))
         (lang-words  nil)
         (head-count  0) cnt
         (start       0)
         (coding-system (and (boundp &apos;buffer-file-coding-system)
                             buffer-file-coding-system))
         (coding-system-for-write (or org-export-html-coding-system
                                      coding-system))
         (save-buffer-coding-system (or org-export-html-coding-system
                                        coding-system))
         (charset (and coding-system-for-write
                       (fboundp &apos;coding-system-get)
                       (coding-system-get coding-system-for-write
                                          &apos;mime-charset)))
         (region
          (buffer-substring
           (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; region-p (region-beginning) (point-min))
           (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; region-p (region-end) (point-max))))
         (org-export-have-math nil)
         (org-export-footnotes-seen nil)
         (org-export-footnotes-data (org-footnote-all-labels &apos;with-defs))
         (lines
          (org-split-string
           (org-export-preprocess-string
            region
            &lt;span class=&quot;org-builtin&quot;&gt;:emph-multiline&lt;/span&gt; t
            &lt;span class=&quot;org-builtin&quot;&gt;:for-backend&lt;/span&gt; &apos;html
            &lt;span class=&quot;org-builtin&quot;&gt;:skip-before-1st-heading&lt;/span&gt;
            (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:skip-before-1st-heading&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:drawers&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:drawers&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:todo-keywords&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:todo-keywords&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:tasks&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:tasks&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:tags&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:tags&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:priority&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:priority&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:footnotes&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:footnotes&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:timestamps&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:timestamps&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:archived-trees&lt;/span&gt;
            (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:archived-trees&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:select-tags&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:select-tags&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:exclude-tags&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:exclude-tags&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:add-text&lt;/span&gt;
            (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:text&lt;/span&gt;)
            &lt;span class=&quot;org-builtin&quot;&gt;:LaTeX-fragments&lt;/span&gt;
            (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:LaTeX-fragments&lt;/span&gt;))
           &lt;span class=&quot;org-string&quot;&gt;&quot;[\r\n]&quot;&lt;/span&gt;))
         (mathjax
          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (or (eq (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:LaTeX-fragments&lt;/span&gt;) &apos;mathjax)
                  (and org-export-have-math
                       (eq (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:LaTeX-fragments&lt;/span&gt;) t)))

              (org-export-html-mathjax-config
               org-export-html-mathjax-template
               org-export-html-mathjax-options
               (or (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:mathjax&lt;/span&gt;) &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
            &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
         table-open
         table-buffer table-orig-buffer
         ind
         rpl path attr desc descp desc1 desc2 link
         snumber fnc
         footnotes footref-seen
         href
         )

    (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((inhibit-read-only t))
      (org-unmodified
       (remove-text-properties (point-min) (point-max)
                               &apos;(&lt;span class=&quot;org-builtin&quot;&gt;:org-license-to-kill&lt;/span&gt; t))))

    (message &lt;span class=&quot;org-string&quot;&gt;&quot;--&amp;gt; Exporting %s... to %s&quot;&lt;/span&gt; org-current-export-file filename)

    (make-directory 
     (concat (or pub-dir (org-export-directory &lt;span class=&quot;org-builtin&quot;&gt;:html&lt;/span&gt; opt-plist))
             (narcissus-entry-published-location opt-plist)) t)

    (setq org-min-level (org-get-min-level lines level-offset))
    (setq org-last-level org-min-level)
    (org-init-section-numbers)

    (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
     ((and date (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;%&quot;&lt;/span&gt; date))
      (setq date (format-time-string date)))
     (date)
     (t (setq date (format-time-string &lt;span class=&quot;org-string&quot;&gt;&quot;%Y-%m-%d %T %Z&quot;&lt;/span&gt;))))

    &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Get the language-dependent settings&lt;/span&gt;
    (setq lang-words (or (assoc language org-export-language-setup)
                         (assoc &lt;span class=&quot;org-string&quot;&gt;&quot;en&quot;&lt;/span&gt; org-export-language-setup)))

    &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Switch to the output buffer&lt;/span&gt;
    (set-buffer buffer)
    (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((inhibit-read-only t)) (erase-buffer))
    (fundamental-mode)
    (org-install-letbind)

    (and (fboundp &apos;set-buffer-file-coding-system)
         (set-buffer-file-coding-system coding-system-for-write))

    (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((case-fold-search nil)
          (org-odd-levels-only odd))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;create local variables for all options, to make sure all called&lt;/span&gt;
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;functions get the correct information&lt;/span&gt;
      (mapc (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (x)
              (set (make-local-variable (nth 2 x))
                   (plist-get opt-plist (car x))))
            org-export-plist-vars)
      (setq umax (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; arg (prefix-numeric-value arg)
                   org-export-headline-levels))
      (setq umax-toc (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (integerp org-export-with-toc)
                         (min org-export-with-toc umax)
                       umax))
      (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; body-only
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;File header&lt;/span&gt;

        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: Provide an HTML5 DOCTYPE and other&lt;/span&gt;
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;headers for exported files.&lt;/span&gt;
        (insert (format
                 &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;html lang=\&quot;%s\&quot;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;title&amp;gt;%s&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;meta charset=\&quot;%s\&quot; /&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;%s&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;%s&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;%s&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;
                 language
                 title
                 (or charset &lt;span class=&quot;org-string&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;)
                 style
                 mathjax
                 (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (or link-up link-home)
                     (concat
                      (format org-export-html-home/up-format
                              (or link-up link-home)
                              (or link-home link-up))
                      &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)
                   &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;)))

        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;insert html preamble&lt;/span&gt;
        (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:html-preamble&lt;/span&gt;)
          (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((html-pre (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:html-preamble&lt;/span&gt;)))
            (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;%s id=\&quot;&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:preamble-wrap-tag&lt;/span&gt;)) (nth 0 org-export-html-divs) &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot;&amp;gt;\n&quot;&lt;/span&gt;)
            (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt; ((stringp html-pre)
                   (insert
                    (format-spec html-pre `((?t . ,title) (?a . ,author)
                                            (?d . ,date) (?e . ,email)))))
                  ((functionp html-pre)
                   (funcall html-pre))
                  (t
                   (insert
                    (format-spec
                     (or (cadr (assoc (nth 0 lang-words)
                                      org-export-html-preamble-format))
                         (cadr (assoc &lt;span class=&quot;org-string&quot;&gt;&quot;en&quot;&lt;/span&gt; org-export-html-preamble-format)))
                     `((?t . ,title) (?a . ,author)
                       (?d . ,date) (?e . ,email))))))
            (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;/%s&amp;gt;\n&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:preamble-wrap-tag&lt;/span&gt;)))))

        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;begin wrap around body&lt;/span&gt;
        (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;%s id=\&quot;%s\&quot;&amp;gt;&quot;&lt;/span&gt; 
                        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: use body wrap tag&lt;/span&gt;
                        (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:body-wrap-tag&lt;/span&gt;)
                        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;FIXME org-export-html-content-div is obsolete since 7.7&lt;/span&gt;
                        (or org-export-html-content-div 
                            (nth 1 org-export-html-divs)))))
                &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;FIXME this should go in the preamble but is here so&lt;/span&gt;
                &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;that org-infojs can still find it&lt;/span&gt;
        (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:insert-title-into-body&lt;/span&gt;)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;h1 class=\&quot;title\&quot;&amp;gt;&quot;&lt;/span&gt; title &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/h1&amp;gt;\n&quot;&lt;/span&gt;))

      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;insert body&lt;/span&gt;
      (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (and org-export-with-toc (not body-only))
          (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
            (push (format &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;h%d&amp;gt;%s&amp;lt;/h%d&amp;gt;\n&quot;&lt;/span&gt;
                          org-export-html-toplevel-hlevel
                          (nth 3 lang-words)
                          org-export-html-toplevel-hlevel)
                  thetoc)
            (push &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;div id=\&quot;text-table-of-contents\&quot;&amp;gt;\n&quot;&lt;/span&gt; thetoc)
            (push &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;ul&amp;gt;\n&amp;lt;li&amp;gt;&quot;&lt;/span&gt; thetoc)
            (setq lines
                  (mapcar 
                   #&apos;(&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (line)
                       (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (and (string-match org-todo-line-regexp line)
                                (not (get-text-property 0 &apos;org-protected line)))
                           &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;This is a headline&lt;/span&gt;
                           (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                             (setq have-headings t)
                             (setq level (- (match-end 1) (match-beginning 1)
                                            level-offset)
                                   level (org-tr-level level)
                                   txt (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
                                         (org-html-expand
                                          (org-export-cleanup-toc-line
                                           (match-string 3 line))))
                                   todo
                                   (or (and org-export-mark-todo-in-toc
                                            (match-beginning 2)
                                            (not (member (match-string 2 line)
                                                         org-done-keywords)))
                                        &lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;TODO, not DONE&lt;/span&gt;
                                       (and org-export-mark-todo-in-toc
                                            (= level umax-toc)
                                            (org-search-todo-below
                                             line lines level))))
                             (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match
                                  (org-re &lt;span class=&quot;org-string&quot;&gt;&quot;[ \t]+:&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[[:alnum:]_@:]+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;:[ \t]*$&quot;&lt;/span&gt;) txt)
                                 (setq txt (replace-match  
                                            &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;span class=\&quot;tag\&quot;&amp;gt; \\1&amp;lt;/span&amp;gt;&quot;&lt;/span&gt; t nil txt)))
                             (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match quote-re0 txt)
                                 (setq txt (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t txt)))
                             (setq snumber (org-section-number level))
                             (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (and num (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (integerp num)
                                              (&amp;gt;= num level)
                                            num))
                                 (setq txt (concat snumber &lt;span class=&quot;org-string&quot;&gt;&quot; &quot;&lt;/span&gt; txt)))
                             (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&amp;lt;= level (max umax umax-toc))
                                 (setq head-count (+ head-count 1)))
                             (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&amp;lt;= level umax-toc)
                                 (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                                   (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&amp;gt; level org-last-level)
                                       (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                                         (setq cnt (- level org-last-level))
                                         (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (&amp;gt;= (setq cnt (1- cnt)) 0)
                                           (push &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;ul&amp;gt;\n&amp;lt;li&amp;gt;&quot;&lt;/span&gt; thetoc))
                                         (push &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt; thetoc)))
                                   (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&amp;lt; level org-last-level)
                                       (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                                         (setq cnt (- org-last-level level))
                                         (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (&amp;gt;= (setq cnt (1- cnt)) 0)
                                           (push &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/li&amp;gt;\n&amp;lt;/ul&amp;gt;&quot;&lt;/span&gt; thetoc))
                                         (push &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt; thetoc)))
                                   &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Check for targets&lt;/span&gt;
                                   (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (string-match org-any-target-regexp line)
                                     (setq line (replace-match
                                                 (concat &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;span class=\&quot;target\&quot;&amp;gt;&quot;&lt;/span&gt; 
                                                         (match-string 1 line) &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;/span&amp;gt; &quot;&lt;/span&gt;)
                                                 t t line)))
                                   (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;amp;lt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;amp;lt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;amp;gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;amp;gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;+&quot;&lt;/span&gt; txt)
                                     (setq txt (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t txt)))
                                   (setq href
                                         (replace-regexp-in-string
                                          &lt;span class=&quot;org-string&quot;&gt;&quot;\\.&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;-&quot;&lt;/span&gt; (format &lt;span class=&quot;org-string&quot;&gt;&quot;sec-%s&quot;&lt;/span&gt; snumber)))
                                   (setq href (org-solidify-link-text 
                                               (or (cdr (assoc href 
                                                               org-export-preferred-target-alist)) href)))
                                   (push
                                    (format
                                     (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; todo
                                         &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;&amp;lt;a href=\&quot;#%s\&quot;&amp;gt;&amp;lt;span class=\&quot;todo\&quot;&amp;gt;%s&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;
                                       &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;&amp;lt;a href=\&quot;#%s\&quot;&amp;gt;%s&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;)
                                     href txt) thetoc)

                                   (setq org-last-level level)))))
                       line)
                   lines))
            (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (&amp;gt; org-last-level (1- org-min-level))
              (setq org-last-level (1- org-last-level))
              (push &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/li&amp;gt;\n&amp;lt;/ul&amp;gt;\n&quot;&lt;/span&gt; thetoc))
            (push &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/div&amp;gt;\n&quot;&lt;/span&gt; thetoc)
            (setq thetoc (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; have-headings (nreverse thetoc) nil))))

      (setq head-count 0)
      (org-init-section-numbers)

      (org-open-par)

      (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (setq line (pop lines) origline line)
        (&lt;span class=&quot;org-keyword&quot;&gt;catch&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt;

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;end of quote section?&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and inquote (string-match org-outline-regexp-bol line))
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/pre&amp;gt;\n&quot;&lt;/span&gt;)
            (org-open-par)
            (setq inquote nil))
          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;inside a quote section?&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; inquote
            (insert (org-html-protect line) &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Fixed-width, verbatim lines (examples)&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and org-export-with-fixed-width
                     (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^[ \t]*:&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t]&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;.*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt; line))
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (not infixed)
              (setq infixed t)
              (org-close-par-maybe)

              (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;pre class=\&quot;example\&quot;&amp;gt;\n&quot;&lt;/span&gt;))
            (insert (org-html-protect (match-string 3 line)) &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (or (not lines)
                      (not (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^[ \t]*:&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t]&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;.*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;
                                         (car lines))))
              (setq infixed nil)
              (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/pre&amp;gt;\n&quot;&lt;/span&gt;)
              (org-open-par))
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Protected HTML&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and (get-text-property 0 &apos;org-protected line)
                     &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Make sure it is the entire line that is protected&lt;/span&gt;
                     (not (&amp;lt; (or (next-single-property-change
                                  0 &apos;org-protected line) 10000)
                             (length line))))
            (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; (par (ind (get-text-property 0 &apos;original-indentation line)))
              (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (re-search-backward
                     &lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t\r\n]*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\=&quot;&lt;/span&gt; (- (point) 100) t)
                (setq par (match-string 1))
                (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\2\n&quot;&lt;/span&gt;))
              (insert line &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)
              (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (and lines
                          (or (= (length (car lines)) 0)
                              (not ind)
                              (equal ind (get-text-property 0 &apos;original-indentation (car lines))))
                          (or (= (length (car lines)) 0)
                              (get-text-property 0 &apos;org-protected (car lines))))
                (insert (pop lines) &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;))
              (and par (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p&amp;gt;\n&quot;&lt;/span&gt;)))
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Blockquotes, verse, and center&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (equal &lt;span class=&quot;org-string&quot;&gt;&quot;ORG-BLOCKQUOTE-START&quot;&lt;/span&gt; line)
            (org-close-par-maybe)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;blockquote&amp;gt;\n&quot;&lt;/span&gt;)
            (org-open-par)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (equal &lt;span class=&quot;org-string&quot;&gt;&quot;ORG-BLOCKQUOTE-END&quot;&lt;/span&gt; line)
            (org-close-par-maybe)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;/blockquote&amp;gt;\n&quot;&lt;/span&gt;)
            (org-open-par)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (equal &lt;span class=&quot;org-string&quot;&gt;&quot;ORG-VERSE-START&quot;&lt;/span&gt; line)
            (org-close-par-maybe)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;p class=\&quot;verse\&quot;&amp;gt;\n&quot;&lt;/span&gt;)
            (setq org-par-open t)
            (setq inverse t)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (equal &lt;span class=&quot;org-string&quot;&gt;&quot;ORG-VERSE-END&quot;&lt;/span&gt; line)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/p&amp;gt;\n&quot;&lt;/span&gt;)
            (setq org-par-open nil)
            (org-open-par)
            (setq inverse nil)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (equal &lt;span class=&quot;org-string&quot;&gt;&quot;ORG-CENTER-START&quot;&lt;/span&gt; line)
            (org-close-par-maybe)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;div style=\&quot;text-align: center\&quot;&amp;gt;&quot;&lt;/span&gt;)
            (org-open-par)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (equal &lt;span class=&quot;org-string&quot;&gt;&quot;ORG-CENTER-END&quot;&lt;/span&gt; line)
            (org-close-par-maybe)
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;/div&amp;gt;&quot;&lt;/span&gt;)
            (org-open-par)
            (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
          (run-hooks &apos;org-export-html-after-blockquotes-hook)
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; inverse
            (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((i (org-get-string-indentation line)))
              (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&amp;gt; i 0)
                  (setq line (concat (mapconcat &apos;identity
                                                (make-list (* 2 i) &lt;span class=&quot;org-string&quot;&gt;&quot;\\nbsp&quot;&lt;/span&gt;) &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;)
                                     &lt;span class=&quot;org-string&quot;&gt;&quot; &quot;&lt;/span&gt; (org-trim line))))
              (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\\\\\\\[ \t]*$&quot;&lt;/span&gt; line)
                (setq line (concat line &lt;span class=&quot;org-string&quot;&gt;&quot;\\\\&quot;&lt;/span&gt;)))))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;make targets to anchors&lt;/span&gt;
          (setq start 0)
          (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (string-match
                  &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;&amp;lt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-negation-char&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;lt;&amp;gt;]*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;gt;&amp;gt;&amp;gt;?&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;(INVISIBLE)&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;?[ \t]*\n?&quot;&lt;/span&gt; line start)
            (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
             ((get-text-property (match-beginning 1) &apos;org-protected line)
              (setq start (match-end 1)))
             ((match-end 2)
              (setq line (replace-match
                          (format
                           &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;a name=\&quot;%s\&quot; id=\&quot;%s\&quot;&amp;gt;@&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;
                           (org-solidify-link-text (match-string 1 line))
                           (org-solidify-link-text (match-string 1 line)))
                          t t line)))
             ((and org-export-with-toc (equal (string-to-char line) ?*))
              &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;FIXME: NOT DEPENDENT on TOC?????????????????????&lt;/span&gt;
              (setq line (replace-match
                          (concat &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;span class=\&quot;target\&quot;&amp;gt;&quot;&lt;/span&gt;
                                  (match-string 1 line) &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;/span&amp;gt; &quot;&lt;/span&gt;)
                          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;(concat &quot;@&amp;lt;i&amp;gt;&quot; (match-string 1 line) &quot;@&amp;lt;/i&amp;gt; &quot;)&lt;/span&gt;
                          t t line)))
             (t
              (setq line (replace-match
                          (concat &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;a name=\&quot;&quot;&lt;/span&gt;
                                  (org-solidify-link-text (match-string 1 line))
                                  &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot; class=\&quot;target\&quot;&amp;gt;&quot;&lt;/span&gt; (match-string 1 line)
                                  &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;/a&amp;gt; &quot;&lt;/span&gt;)
                          t t line)))))

          (setq line (org-html-handle-time-stamps line))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;replace &quot;&amp;amp;&quot; by &quot;&amp;amp;amp;&quot;, &quot;&amp;lt;&quot; and &quot;&amp;gt;&quot; by &quot;&amp;amp;lt;&quot; and &quot;&amp;amp;gt;&quot;&lt;/span&gt;
          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;handle @&amp;lt;..&amp;gt; HTML tags (replace &quot;@&amp;amp;gt;..&amp;amp;lt;&quot; by &quot;&amp;lt;..&amp;gt;&quot;)&lt;/span&gt;
          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Also handle sub_superscripts and checkboxes&lt;/span&gt;
          (or (string-match org-table-hline-regexp line)
              (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^[ \t]*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[+]-&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;|[ ]&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[-+ |]*[+|][ \t]*$&quot;&lt;/span&gt; line)
              (setq line (org-html-expand line)))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Format the links&lt;/span&gt;
          (setq line (narcissus-html-handle-links line opt-plist))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;TODO items&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (and (string-match org-todo-line-regexp line)
                   (match-beginning 2))

              (setq line
                    (concat (substring line 0 (match-beginning 2))
                            &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;span class=\&quot;&quot;&lt;/span&gt;
                            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (member (match-string 2 line)
                                        org-done-keywords)
                                &lt;span class=&quot;org-string&quot;&gt;&quot;done&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;todo&quot;&lt;/span&gt;)
                            &lt;span class=&quot;org-string&quot;&gt;&quot; &quot;&lt;/span&gt; (match-string 2 line)
                            &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot;&amp;gt; &quot;&lt;/span&gt; (org-export-html-get-todo-kwd-class-name
                                    (match-string 2 line))
                            &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/span&amp;gt;&quot;&lt;/span&gt; (substring line (match-end 2)))))

          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Does this contain a reference to a footnote?&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; org-export-with-footnotes
            (setq start 0)
            (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-negation-char&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;* \t].*?&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\[&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[0-9]+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\]&quot;&lt;/span&gt; line start)
              &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Discard protected matches not clearly identified as&lt;/span&gt;
              &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;footnote markers.&lt;/span&gt;
              (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (or (get-text-property (match-beginning 2) &apos;org-protected line)
                      (not (get-text-property (match-beginning 2) &apos;org-footnote line)))
                  (setq start (match-end 2))
                (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((n (match-string 2 line)) extra a)
                  (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (setq a (assoc n footref-seen))
                      (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                        (setcdr a (1+ (cdr a)))
                        (setq extra (format &lt;span class=&quot;org-string&quot;&gt;&quot;.%d&quot;&lt;/span&gt; (cdr a))))
                    (setq extra &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;)
                    (push (cons n 1) footref-seen))
                  (setq line
                        (replace-match
                         (concat
                          (format
                           (concat &lt;span class=&quot;org-string&quot;&gt;&quot;%s&quot;&lt;/span&gt;
                                   (format org-export-html-footnote-format
                                           (concat &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;a class=\&quot;footref\&quot; name=\&quot;fnr.%s%s\&quot; href=\&quot;#fn.%s\&quot;&amp;gt;%s&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;)))
                           (or (match-string 1 line) &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;) n extra n n)
                          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;If another footnote is following the&lt;/span&gt;
                          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;current one, add a separator.&lt;/span&gt;
                          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
                                (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\`\\[[0-9]+\\]&quot;&lt;/span&gt;
                                              (substring line (match-end 0))))
                              org-export-html-footnote-separator
                            &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
                         t t line))))))

          (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
           ((string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\*+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t]+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;.*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt; line)
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;This is a headline&lt;/span&gt;
            (setq level (org-tr-level (- (match-end 1) (match-beginning 1)
                                         level-offset))
                  txt (match-string 2 line))
            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match quote-re0 txt)
                (setq txt (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t txt)))
            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (&amp;lt;= level (max umax umax-toc))
                (setq head-count (+ head-count 1)))
            (setq first-heading-pos (or first-heading-pos (point)))
            (org-html-level-start level txt umax
                                  (and org-export-with-toc (&amp;lt;= level umax))
                                  head-count opt-plist)

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;QUOTES&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (string-match quote-re line)
              (org-close-par-maybe)
              (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;pre&amp;gt;&quot;&lt;/span&gt;)
              (setq inquote t)))

           ((and org-export-with-tables
                 (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t]*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\+-+\\+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt; line))
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (not table-open)
              &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;New table starts&lt;/span&gt;
              (setq table-open t table-buffer nil table-orig-buffer nil))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Accumulate lines&lt;/span&gt;
            (setq table-buffer (cons line table-buffer)
                  table-orig-buffer (cons origline table-orig-buffer))
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (or (not lines)
                      (not (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[ \t]*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\+-+\\+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;
                                         (car lines))))
              (setq table-open nil
                    table-buffer (nreverse table-buffer)
                    table-orig-buffer (nreverse table-orig-buffer))
              (org-close-par-maybe)
              (insert (org-format-table-html table-buffer table-orig-buffer))))

           &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Normal lines&lt;/span&gt;

           (t
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;This line either is list item or end a list.&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (get-text-property 0 &apos;list-item line)
              (setq line (org-html-export-list-line
                          line
                          (get-text-property 0 &apos;list-item line)
                          (get-text-property 0 &apos;list-struct line)
                          (get-text-property 0 &apos;list-prevs line))))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Horizontal line&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^[ \t]*-\\{5,\\}[ \t]*$&quot;&lt;/span&gt; line)
              (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; org-par-open
                  (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;/p&amp;gt;\n&amp;lt;hr/&amp;gt;\n&amp;lt;p&amp;gt;\n&quot;&lt;/span&gt;)
                (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;hr/&amp;gt;\n&quot;&lt;/span&gt;))
              (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Empty lines start a new paragraph.  If hand-formatted lists&lt;/span&gt;
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;are not fully interpreted, lines starting with &quot;-&quot;, &quot;+&quot;, &quot;*&quot;&lt;/span&gt;
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;also start a new paragraph.&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^ [-+*]-&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;^[ \t]*$&quot;&lt;/span&gt; line) (org-open-par))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Is this the start of a footnote?&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; org-export-with-footnotes
              (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and (boundp &apos;footnote-section-tag-regexp)
                         (string-match (concat &lt;span class=&quot;org-string&quot;&gt;&quot;^&quot;&lt;/span&gt; footnote-section-tag-regexp)
                                       line))
                &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;ignore this line&lt;/span&gt;
                (&lt;span class=&quot;org-keyword&quot;&gt;throw&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;nextline&lt;/span&gt; nil))
              (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^[ \t]*\\[&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[0-9]+&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\]&quot;&lt;/span&gt; line)
                (org-close-par-maybe)
                (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((n (match-string 1 line)))
                  (setq org-par-open t
                        line (replace-match
                              (format
                               (concat &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p class=\&quot;footnote\&quot;&amp;gt;&quot;&lt;/span&gt;
                                       (format org-export-html-footnote-format
                                               &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;a class=\&quot;footnum\&quot; name=\&quot;fn.%s\&quot; href=\&quot;#fnr.%s\&quot;&amp;gt;%s&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;))
                               n n n) t t line)))))
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Check if the line break needs to be conserved&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
             ((string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\\\\\\\[ \t]*$&quot;&lt;/span&gt; line)
              (setq line (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;br/&amp;gt;&quot;&lt;/span&gt; t t line)))
             (org-export-preserve-breaks
              (setq line (concat line &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;br/&amp;gt;&quot;&lt;/span&gt;))))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Check if a paragraph should be started&lt;/span&gt;
            (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((start 0))
              (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (and org-par-open
                          (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\\\par\\&amp;gt;&quot;&lt;/span&gt; line start))
                &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Leave a space in the &amp;lt;/p&amp;gt; so that the footnote matcher&lt;/span&gt;
                &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;does not see this.&lt;/span&gt;
                (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (not (get-text-property (match-beginning 0)
                                            &apos;org-protected line))
                    (setq line (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/p &amp;gt;&amp;lt;p &amp;gt;&quot;&lt;/span&gt; t t line)))
                (setq start (match-end 0))))

            (insert line &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)))))

      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Properly close all local lists and other lists&lt;/span&gt;
      (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; inquote
        (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/pre&amp;gt;\n&quot;&lt;/span&gt;)
        (org-open-par))

      (org-html-level-start 1 nil umax
                            (and org-export-with-toc (&amp;lt;= level umax))
                            head-count opt-plist)
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;the &amp;lt;/div&amp;gt; to close the last text-... div.&lt;/span&gt;
      (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and (&amp;gt; umax 0) first-heading-pos) (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/div&amp;gt;\n&quot;&lt;/span&gt;))

      (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
        (goto-char (point-min))
        (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (re-search-forward
                &lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&amp;lt;p class=\&quot;footnote\&quot;&amp;gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-negation-char&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\000]*?&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\2&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;\\&apos;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt;
                nil t)
          (push (match-string 1) footnotes)
          (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\4&quot;&lt;/span&gt; t nil)
          (goto-char (match-beginning 0))))
      (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; footnotes
        (insert (format org-export-html-footnotes-section
                        (nth 4 lang-words)
                        (mapconcat &apos;identity (nreverse footnotes) &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;))
                &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;))
      (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((bib (org-export-html-get-bibliography)))
        (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; bib
          (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt; bib &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)))

      (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; body-only
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;end wrap around body&lt;/span&gt;
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: use body-wrap-tag again&lt;/span&gt;
        (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/%s&amp;gt;\n&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:body-wrap-tag&lt;/span&gt;)))

        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;export html postamble&lt;/span&gt;
        (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((html-post (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:html-postamble&lt;/span&gt;))
              (email
               (mapconcat (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt;(e)
                            (format &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;a href=\&quot;mailto:%s\&quot;&amp;gt;%s&amp;lt;/a&amp;gt;&quot;&lt;/span&gt; e e))
                          (split-string email &lt;span class=&quot;org-string&quot;&gt;&quot;,+ *&quot;&lt;/span&gt;)
                          &lt;span class=&quot;org-string&quot;&gt;&quot;, &quot;&lt;/span&gt;))
              (creator-info
               (concat &lt;span class=&quot;org-string&quot;&gt;&quot;Org version &quot;&lt;/span&gt; org-version &lt;span class=&quot;org-string&quot;&gt;&quot; with Emacs version &quot;&lt;/span&gt;
                       (number-to-string emacs-major-version))))

          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:html-postamble&lt;/span&gt;)
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: Use postamble-wrap-tag&lt;/span&gt;
            (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;%s id=\&quot;&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:postamble-wrap-tag&lt;/span&gt;)) (nth 2 org-export-html-divs) &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot;&amp;gt;\n&quot;&lt;/span&gt;)
            (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt; ((stringp html-post)
                   (insert (format-spec html-post
                                        `((?a . ,author) (?e . ,email)
                                          (?d . ,date)   (?c . ,creator-info)
                                          (?v . ,html-validation-link)))))
                  ((functionp html-post)
                   (funcall html-post))
                  ((eq html-post &apos;auto)
                   &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;fall back on default postamble&lt;/span&gt;
                   (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:time-stamp-file&lt;/span&gt;)
                     (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p class=\&quot;date\&quot;&amp;gt;&quot;&lt;/span&gt; (nth 2 lang-words) &lt;span class=&quot;org-string&quot;&gt;&quot;: &quot;&lt;/span&gt; date &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/p&amp;gt;\n&quot;&lt;/span&gt;))
                   (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:author-info&lt;/span&gt;) author)
                       (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p class=\&quot;author\&quot;&amp;gt;&quot;&lt;/span&gt; (nth 1 lang-words) &lt;span class=&quot;org-string&quot;&gt;&quot;: &quot;&lt;/span&gt; author &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/p&amp;gt;\n&quot;&lt;/span&gt;))
                   (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:email-info&lt;/span&gt;) email)
                     (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p class=\&quot;email\&quot;&amp;gt;&quot;&lt;/span&gt; email &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/p&amp;gt;\n&quot;&lt;/span&gt;))
                   (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:creator-info&lt;/span&gt;)
                     (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p class=\&quot;creator\&quot;&amp;gt;&quot;&lt;/span&gt;
                             (concat &lt;span class=&quot;org-string&quot;&gt;&quot;Org version &quot;&lt;/span&gt; org-version &lt;span class=&quot;org-string&quot;&gt;&quot; with Emacs version &quot;&lt;/span&gt;
                                     (number-to-string emacs-major-version) &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/p&amp;gt;\n&quot;&lt;/span&gt;)))
                   (insert html-validation-link &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;))
                  (t
                   (insert (format-spec
                            (or (cadr (assoc (nth 0 lang-words)
                                             org-export-html-postamble-format))
                                (cadr (assoc &lt;span class=&quot;org-string&quot;&gt;&quot;en&quot;&lt;/span&gt; org-export-html-postamble-format)))
                            `((?a . ,author) (?e . ,email)
                              (?d . ,date)   (?c . ,creator-info)
                              (?v . ,html-validation-link))))))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: Use postamble-wrap-tag again&lt;/span&gt;
            (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;/%s&amp;gt;&quot;&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:postamble-wrap-tag&lt;/span&gt;))))))

      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;FIXME `&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;&lt;span class=&quot;org-constant&quot;&gt;org-export-html-with-timestamp&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;&apos; has been declared&lt;/span&gt;
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;obsolete since Org 7.7 -- don&apos;t forget to remove this.&lt;/span&gt;
      (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; org-export-html-with-timestamp
          (insert org-export-html-html-helper-timestamp))

      (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; body-only (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&amp;lt;/body&amp;gt;\n&amp;lt;/html&amp;gt;\n&quot;&lt;/span&gt;))

      (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:buffer-will-be-killed&lt;/span&gt;)
        (normal-mode)
        (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (eq major-mode (default-value &apos;major-mode))
            (html-mode)))

      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;insert the table of contents&lt;/span&gt;
      (goto-char (point-min))
      (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; thetoc
        (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (or (re-search-forward
                 &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p&amp;gt;\\s-*\\[TABLE-OF-CONTENTS\\]\\s-*&amp;lt;/p&amp;gt;&quot;&lt;/span&gt; nil t)
                (re-search-forward
                 &lt;span class=&quot;org-string&quot;&gt;&quot;\\[TABLE-OF-CONTENTS\\]&quot;&lt;/span&gt; nil t))
            (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
              (goto-char (match-beginning 0))
              (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
          (goto-char first-heading-pos)
          (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (looking-at &lt;span class=&quot;org-string&quot;&gt;&quot;\\s-*&amp;lt;/p&amp;gt;&quot;&lt;/span&gt;)
            (goto-char (match-end 0))
            (insert &lt;span class=&quot;org-string&quot;&gt;&quot;\n&quot;&lt;/span&gt;)))
        (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;div id=\&quot;table-of-contents\&quot;&amp;gt;\n&quot;&lt;/span&gt;)
        (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((beg (point)))
          (mapc &apos;insert thetoc)
          (insert &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;/div&amp;gt;\n&quot;&lt;/span&gt;)
          (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (re-search-backward &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;li&amp;gt;[ \r\n\t]*&amp;lt;/li&amp;gt;\n?&quot;&lt;/span&gt; beg t)
            (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;remove empty paragraphs&lt;/span&gt;
      (goto-char (point-min))
      (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (re-search-forward &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;p&amp;gt;[ \r\n\t]*&amp;lt;/p&amp;gt;&quot;&lt;/span&gt; nil t)
        (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
      (goto-char (point-min))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Convert whitespace place holders&lt;/span&gt;
      (goto-char (point-min))
      (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; (beg end n)
        (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (setq beg (next-single-property-change (point) &apos;org-whitespace))
          (setq n (get-text-property beg &apos;org-whitespace)
                end (next-single-property-change beg &apos;org-whitespace))
          (goto-char beg)
          (delete-region beg end)
          (insert (format &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;span style=\&quot;visibility:hidden;\&quot;&amp;gt;%s&amp;lt;/span&amp;gt;&quot;&lt;/span&gt;
                          (make-string n ?x)))))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Remove empty lines at the beginning of the file.&lt;/span&gt;
      (goto-char (point-min))
      (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (looking-at &lt;span class=&quot;org-string&quot;&gt;&quot;\\s-+\n&quot;&lt;/span&gt;) (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Remove display properties&lt;/span&gt;
      (remove-text-properties (point-min) (point-max) &apos;(display t))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Run the hook&lt;/span&gt;
      (run-hooks &apos;org-export-html-final-hook)
      (or to-buffer (save-buffer))
      (goto-char (point-min))
      (or (org-export-push-to-kill-ring &lt;span class=&quot;org-string&quot;&gt;&quot;HTML&quot;&lt;/span&gt;)
          (message &lt;span class=&quot;org-string&quot;&gt;&quot;... done exporting.&quot;&lt;/span&gt;))
      (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (eq to-buffer &apos;string)
          (&lt;span class=&quot;org-keyword&quot;&gt;prog1&lt;/span&gt; (buffer-substring (point-min) (point-max))
            (kill-buffer (current-buffer)))
        (current-buffer)))))
&lt;/pre&gt;


&lt;p&gt;
  I use the following functions to publish the index and entries of the
  blog.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-publish-entries&lt;/span&gt; (plist filename pub-dir)
  (org-publish-org-to &lt;span class=&quot;org-string&quot;&gt;&quot;narcissus-html&quot;&lt;/span&gt; plist filename pub-dir))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-publish-index&lt;/span&gt; (plist filename pub-dir)
  (org-publish-org-to &lt;span class=&quot;org-string&quot;&gt;&quot;narcissus-html&quot;&lt;/span&gt; plist filename pub-dir))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;RSS Generation &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;


&lt;p&gt;
  RSS generation is actually fairly simple: I&apos;ve written the below
  function, &lt;code&gt;narcissus-publish-rss&lt;/code&gt;, which takes the first element of
  the &lt;code&gt;:include&lt;/code&gt; property in its publishing alist, and considers the
  file a list of links for which to generate RSS metadata for. Scraps
  are ignored as they don&apos;t have a publishing date.
&lt;/p&gt;
&lt;p&gt;
  I&apos;ve also added a bunch of properties to the publishing alist for
  the channel metadata for the RSS feed. They should be self evident:
  &lt;code&gt;:rss-title&lt;/code&gt;, &lt;code&gt;:rss-language&lt;/code&gt;, &lt;code&gt;:rss-description&lt;/code&gt;, &lt;code&gt;:rss-link&lt;/code&gt;, and
  &lt;code&gt;:rss-copyright&lt;/code&gt;.
&lt;/p&gt;



&lt;pre class=&quot;src src-elisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;require&lt;/span&gt; &apos;&lt;span class=&quot;org-constant&quot;&gt;rss&lt;/span&gt;)

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;current-time-format-&amp;gt;rfc822&lt;/span&gt; (time)
  (format-time-string &lt;span class=&quot;org-string&quot;&gt;&quot;%a, %d %b %Y %H:%M:%S %Z&quot;&lt;/span&gt; time))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-publish-rss&lt;/span&gt; (plist filename pub-dir)
  (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((index (concat (getf plist &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt;)
                       (nth 0 (getf plist &lt;span class=&quot;org-builtin&quot;&gt;:include&lt;/span&gt;))))
         (index-buffer (find-file index))
         (rss-link (getf plist &lt;span class=&quot;org-builtin&quot;&gt;:rss-link&lt;/span&gt;))
         (scraps-directory (getf plist &lt;span class=&quot;org-builtin&quot;&gt;:scraps-directory&lt;/span&gt;))
         (rss (make-rss)))
    (rss-channel rss
                 `(title nil ,(getf plist &lt;span class=&quot;org-builtin&quot;&gt;:rss-title&lt;/span&gt;))
                 `(link nil ,rss-link)
                 `(language nil ,(getf plist &lt;span class=&quot;org-builtin&quot;&gt;:rss-language&lt;/span&gt;))
                 `(description nil ,(getf plist &lt;span class=&quot;org-builtin&quot;&gt;:rss-description&lt;/span&gt;))
                 `(copyright nil ,(getf plist &lt;span class=&quot;org-builtin&quot;&gt;:rss-copyright&lt;/span&gt;)))
    (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
      (switch-to-buffer index-buffer)
      (beginning-of-buffer)
      (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (re-search-forward org-bracket-link-regexp nil &lt;span class=&quot;org-builtin&quot;&gt;:return-t-if-found-and-nil-otherwise&lt;/span&gt;)
        (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((link (match-string-no-properties 1))
              (title (match-string-no-properties 3))
              html scrap-p)
          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^file:&quot;&lt;/span&gt; link)
              (setq link (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t link)))
          (&lt;span class=&quot;org-keyword&quot;&gt;save-current-buffer&lt;/span&gt;
            (setq scrap-p (string-match scraps-directory link))
            (message &lt;span class=&quot;org-string&quot;&gt;&quot;File: %s Scrap? %s&quot;&lt;/span&gt; (current-buffer) scrap-p)
            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (not scrap-p)
              (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                (set-buffer (find-file link))
                (&lt;span class=&quot;org-keyword&quot;&gt;save-current-buffer&lt;/span&gt;
                  (setq html (org-export-as-narcissus-html nil nil nil &apos;string t)))
                (rss-add-item rss
                              `(attrs
                                (link nil ,(concat rss-link (narcissus-entry-published-location)))
                                (title nil ,(org-publish-find-title (buffer-file-name)))
                                (pubDate nil ,(current-time-format-&amp;gt;rfc822 (org-publish-find-date buffer-file-name)))
                                (guid nil ,(concat &lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:entry:&quot;&lt;/span&gt; link))
                                (description nil ,html)))))))))
    (rss-write-file rss (concat (getf plist &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt;)
                                (getf plist &lt;span class=&quot;org-builtin&quot;&gt;:rss-output-filename&lt;/span&gt;)))))


&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;Preserves existing URL structure &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;


&lt;p&gt;
  I&apos;m not keeping tables of redirects, I&apos;m not moving my content. This
  is 2011. There&apos;s no reason I shouldn&apos;t be able to graft this system
  onto the trunk of the old one.
&lt;/p&gt;
&lt;p&gt;
  In order to correctly fit into the existing directory structure, we
  should be able to look at a blog entry and determine, from its
  filename and its metadata, where it belongs in the directory tree.
&lt;/p&gt;
&lt;p&gt;
  First, we make sure we can generate the directory structure from the
  file we&apos;re in.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-entry-published-location&lt;/span&gt; (&lt;span class=&quot;org-type&quot;&gt;&amp;amp;optional&lt;/span&gt; plist)
  (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((plist (or plist (org-infile-export-plist)))
         (date (plist-get plist &lt;span class=&quot;org-builtin&quot;&gt;:date&lt;/span&gt;))
         (filename (plist-get plist &lt;span class=&quot;org-builtin&quot;&gt;:macro-input-file&lt;/span&gt;)))
    (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; date
        (&lt;span class=&quot;org-keyword&quot;&gt;destructuring-bind&lt;/span&gt; (_ _ _ _ month year _ _ _)
            (org-parse-time-string date)
          (concat 
           (file-name-as-directory &lt;span class=&quot;org-string&quot;&gt;&quot;posts&quot;&lt;/span&gt;)
           (file-name-as-directory (format &lt;span class=&quot;org-string&quot;&gt;&quot;%02d&quot;&lt;/span&gt; year))
           (file-name-as-directory (format &lt;span class=&quot;org-string&quot;&gt;&quot;%02d&quot;&lt;/span&gt; month))
           (file-name-as-directory (file-name-nondirectory (file-name-sans-extension filename)))))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;TODO(msnyder): Simple hack for index file.&lt;/span&gt;
      (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string= filename &lt;span class=&quot;org-string&quot;&gt;&quot;index.org&quot;&lt;/span&gt;)
          &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;
        (concat
         (file-name-as-directory (file-name-nondirectory (file-name-sans-extension filename))))))))
&lt;/pre&gt;


&lt;p&gt;
&lt;code&gt;narcissus-entry-published-location&lt;/code&gt; assumes, for the time being, that
all entries are in the root of the content folder, and that there is
no subdirectorial relationship between them, which are reasonable
assumptions to make. In the Webby form of this site, the posts are
organized by the directory structure we&apos;re generating after the fact
in Narcissus. There&apos;s no reason not to just stick all the org files in
the same place.
&lt;/p&gt;
&lt;p&gt;
This doesn&apos;t stop &lt;code&gt;org-publish&lt;/code&gt; from giving the generated file the
same name as the org file. &lt;code&gt;org-publish&lt;/code&gt; has an &lt;code&gt;EXPORT_FILE_NAME&lt;/code&gt;
parameter, but it&apos;s only used for marking a subtree for export. We
will be commandeering it later for use in our HTML generation function
as a project-wide publishing option.
&lt;/p&gt;
&lt;p&gt;
This also doesn&apos;t fail nicely if the entry in question doesn&apos;t have a
&lt;code&gt;DATE&lt;/code&gt; option.
&lt;/p&gt;
&lt;p&gt;
The second part of this is ensuring that links to other org files are
mutated correctly. Right now, the index will simply transform the
link &lt;code&gt;foo.org&lt;/code&gt; into &lt;code&gt;foo.html&lt;/code&gt;, which is no longer correct. What
should happen is something like &lt;code&gt;foo.org&lt;/code&gt; becomes
&lt;code&gt;/posts/2011/07/foo/index.html&lt;/code&gt;. &lt;code&gt;org-publish&lt;/code&gt; uses the function
&lt;code&gt;org-html-handle-links&lt;/code&gt; to perform this transformation, so we&apos;ll write
our own function, and replace its use within the HTML export function.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-html-handle-links&lt;/span&gt; (line opt-plist)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Return LINE with markup of Org mode links.&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;OPT-PLIST is the export options list.&quot;&lt;/span&gt;
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((start 0)
        (current-dir (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; buffer-file-name
                         (file-name-directory buffer-file-name)
                       default-directory))
        (link-validate (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:link-validation-function&lt;/span&gt;))
        type id-file fnc
        rpl path attr desc descp desc1 desc2 link)
    (&lt;span class=&quot;org-keyword&quot;&gt;while&lt;/span&gt; (string-match org-bracket-link-analytic-regexp++ line start)
      (setq start (match-beginning 0))
      (setq path (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt; (org-link-unescape
                                   (match-string 3 line))))
      (setq type (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
                  ((match-end 2) (match-string 2 line))
                  ((&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
                     (or (file-name-absolute-p path)
                         (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^\\.\\.?/&quot;&lt;/span&gt; path)))
                   &lt;span class=&quot;org-string&quot;&gt;&quot;file&quot;&lt;/span&gt;)
                  (t &lt;span class=&quot;org-string&quot;&gt;&quot;internal&quot;&lt;/span&gt;)))
      (setq path (org-extract-attributes (org-link-unescape path)))
      (setq attr (get-text-property 0 &apos;org-attributes path))
      (setq desc1 (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (match-end 5) (match-string 5 line))
            desc2 (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (match-end 2) (concat type &lt;span class=&quot;org-string&quot;&gt;&quot;:&quot;&lt;/span&gt; path) path)
            descp (and desc1 (not (equal desc1 desc2)))
            desc (or desc1 desc2))
      &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Make an image out of the description if that is so wanted&lt;/span&gt;
      (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (and descp (org-file-image-p
                        desc org-export-html-inline-image-extensions))
        (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^file:&quot;&lt;/span&gt; desc)
              (setq desc (substring desc (match-end 0)))))
        (setq desc (org-add-props
                       (concat &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;lt;img src=\&quot;&quot;&lt;/span&gt; desc &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot; alt=\&quot;&quot;&lt;/span&gt; 
                               (file-name-nondirectory desc) &lt;span class=&quot;org-string&quot;&gt;&quot;\&quot;/&amp;gt;&quot;&lt;/span&gt;)
                       &apos;(org-protected t))))
      (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt;
       ((equal type &lt;span class=&quot;org-string&quot;&gt;&quot;internal&quot;&lt;/span&gt;)
        (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt;
            ((frag-0
              (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (= (string-to-char path) ?#)
                  (substring path 1)
                path)))
          (setq rpl
                (org-html-make-link
                 opt-plist
                 &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;
                 &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;
                 (org-solidify-link-text
                  (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt; (org-link-unescape frag-0))
                  nil)
                 desc attr nil))))
       ((and (equal type &lt;span class=&quot;org-string&quot;&gt;&quot;id&quot;&lt;/span&gt;)
             (setq id-file (org-id-find-id-file path)))
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;This is an id: link to another file (if it was the same file,&lt;/span&gt;
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;it would have become an internal link...)&lt;/span&gt;
        (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
          (setq id-file (file-relative-name
                         id-file
                         (file-name-directory org-current-export-file)))
          (setq rpl
                (org-html-make-link opt-plist
                                    &lt;span class=&quot;org-string&quot;&gt;&quot;file&quot;&lt;/span&gt; id-file
                                    (concat (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (org-uuidgen-p path) &lt;span class=&quot;org-string&quot;&gt;&quot;ID-&quot;&lt;/span&gt;) path)
                                    desc
                                    attr
                                    nil))))
       ((member type &apos;(&lt;span class=&quot;org-string&quot;&gt;&quot;http&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;https&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;gopher&quot;&lt;/span&gt;))
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;standard URL, can inline as image&lt;/span&gt;
        (setq rpl
              (org-html-make-link opt-plist
                                  type path nil
                                  desc
                                  attr
                                  (org-html-should-inline-p path descp))))
       ((member type &apos;(&lt;span class=&quot;org-string&quot;&gt;&quot;ftp&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;mailto&quot;&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;news&quot;&lt;/span&gt;))
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;standard URL, can&apos;t inline as image&lt;/span&gt;
        (setq rpl
              (org-html-make-link opt-plist
                                  type path nil
                                  desc
                                  attr
                                  nil)))

       ((string= type &lt;span class=&quot;org-string&quot;&gt;&quot;coderef&quot;&lt;/span&gt;)
        (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt;
            ((coderef-str (format &lt;span class=&quot;org-string&quot;&gt;&quot;coderef-%s&quot;&lt;/span&gt; path))
             (attr-1
              (format &lt;span class=&quot;org-string&quot;&gt;&quot;class=\&quot;coderef\&quot; onmouseover=\&quot;CodeHighlightOn(this, &apos;%s&apos;);\&quot; onmouseout=\&quot;CodeHighlightOff(this, &apos;%s&apos;);\&quot;&quot;&lt;/span&gt;
                      coderef-str coderef-str)))
          (setq rpl
                (org-html-make-link opt-plist
                                    type &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; coderef-str
                                    (format
                                     (org-export-get-coderef-format
                                      path
                                      (and descp desc))
                                     (cdr (assoc path org-export-code-refs)))
                                    attr-1
                                    nil))))

       ((functionp (setq fnc (nth 2 (assoc type org-link-protocols))))
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;The link protocol has a function for format the link&lt;/span&gt;
        (setq rpl
              (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
                (funcall fnc (org-link-unescape path) desc1 &apos;html))))

       ((string= type &lt;span class=&quot;org-string&quot;&gt;&quot;file&quot;&lt;/span&gt;)
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;FILE link&lt;/span&gt;
        (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt;
          (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt;
              ((components
                (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt;
                    (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;::&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;.*&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-backslash&quot;&gt;\\&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&lt;span class=&quot;org-regexp-grouping-construct&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-string&quot;&gt;&quot;&lt;/span&gt; path)
                    (list
                     (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t nil path)
                     (match-string 1 path))
                  (list path nil)))

               &lt;span class=&quot;org-comment-delimiter&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;The proper path, without a fragment&lt;/span&gt;
               (path-1
                (first components))

               &lt;span class=&quot;org-comment-delimiter&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;The raw fragment&lt;/span&gt;
               (fragment-0
                (second components))

               &lt;span class=&quot;org-comment-delimiter&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Check the fragment.  If it can&apos;t be used as&lt;/span&gt;
               &lt;span class=&quot;org-comment-delimiter&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;target fragment we&apos;ll pass nil instead.&lt;/span&gt;
               (fragment-1
                (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt;
                    (and fragment-0
                         (not (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^[0-9]*$&quot;&lt;/span&gt; fragment-0))
                         (not (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^\\*&quot;&lt;/span&gt; fragment-0))
                         (not (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^/.*/$&quot;&lt;/span&gt; fragment-0)))
                    (org-solidify-link-text
                     (org-link-unescape fragment-0))
                  nil))
               (desc-2
                &lt;span class=&quot;org-comment-delimiter&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Description minus &quot;file:&quot; and &quot;.org&quot;&lt;/span&gt;
                (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^file:&quot;&lt;/span&gt; desc)
                    (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt;
                        ((desc-1 (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t desc)))
                      (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\.org$&quot;&lt;/span&gt; desc-1)
                          (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t desc-1)
                        desc-1))
                  desc)))

            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;NARCISSUS: Retrieve the full path of the Org file we&apos;re&lt;/span&gt;
            &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;linking to&lt;/span&gt;
            (setq schema &lt;span class=&quot;org-string&quot;&gt;&quot;file&quot;&lt;/span&gt;)
            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;\\.org$&quot;&lt;/span&gt; path-1)
                (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
                  (find-file (concat (plist-get opt-plist &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt;) path-1))
                  (setq path-1 (concat (narcissus-entry-published-location))))
              (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^\\.&quot;&lt;/span&gt; path-1)
                  (&lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
                    (setq path-1 (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t path-1))
                    (setq schema &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))))

            (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; fragment-0
                (&lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((f-head (car components))
                       (f-tail (cadr components))
                       (exact-heading (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (string-match &lt;span class=&quot;org-string&quot;&gt;&quot;^\*+&quot;&lt;/span&gt; f-tail)
                                          (replace-match &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt; t t f-tail)
                                        nil)))
                  (&lt;span class=&quot;org-keyword&quot;&gt;save-excursion&lt;/span&gt;
                    (find-file (expand-file-name f-head))
                    (goto-char (org-find-exact-heading-in-directory exact-heading))
                    (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (org-entry-get (point-marker) &lt;span class=&quot;org-string&quot;&gt;&quot;SCRAP&quot;&lt;/span&gt;)
                        (setq path-1 (concat &lt;span class=&quot;org-string&quot;&gt;&quot;scraps/&quot;&lt;/span&gt; (org-entry-get (point-marker) &lt;span class=&quot;org-string&quot;&gt;&quot;EXPORT_FILE_NAME&quot;&lt;/span&gt;) &lt;span class=&quot;org-string&quot;&gt;&quot;/&quot;&lt;/span&gt;))))))

            (setq rpl
                  (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt;
                      (and
                       (functionp link-validate)
                       (not (funcall link-validate path-1 current-dir)))
                      desc
                    (org-html-make-link opt-plist
                                        schema path-1 fragment-1 desc-2 attr
                                        (org-html-should-inline-p path-1 descp)))))))

       (t
        &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;just publish the path, as default&lt;/span&gt;
        (setq rpl (concat &lt;span class=&quot;org-string&quot;&gt;&quot;@&amp;lt;i&amp;gt;&amp;amp;lt;&quot;&lt;/span&gt; type &lt;span class=&quot;org-string&quot;&gt;&quot;:&quot;&lt;/span&gt;
                          (&lt;span class=&quot;org-keyword&quot;&gt;save-match-data&lt;/span&gt; (org-link-unescape path))
                          &lt;span class=&quot;org-string&quot;&gt;&quot;&amp;amp;gt;@&amp;lt;/i&amp;gt;&quot;&lt;/span&gt;))))
      (setq line (replace-match rpl t t line)
            start (+ start (length rpl))))
    line))

&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-6&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-6&quot;&gt;Rsync-like publishing &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-6&quot;&gt;


&lt;p&gt;
  This is as good a section as any to describe the actual
  &lt;code&gt;org-publish&lt;/code&gt; project listing I&apos;m using.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(setq org-publish-project-alist 
      &apos;(
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:entries&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:preamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;header&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:postamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;footer&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/msnyder.info/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;org&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;index&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:insert-title-into-body&lt;/span&gt; t
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; narcissus-publish-entries
         &lt;span class=&quot;org-builtin&quot;&gt;:exclude&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;index.org&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:body-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;article&quot;&lt;/span&gt;)
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:css&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/msnyder.info/css/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;css&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/css&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; org-publish-attachment)
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:assets&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/msnyder.info/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;png&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:recursive&lt;/span&gt; t
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; org-publish-attachment)
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:index&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/msnyder.info/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:index-title&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;index&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:body-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;div&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:preamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;header&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:postamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;footer&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:include&lt;/span&gt; (&lt;span class=&quot;org-string&quot;&gt;&quot;index.org&quot;&lt;/span&gt;)
         &lt;span class=&quot;org-builtin&quot;&gt;:insert-title-into-body&lt;/span&gt; nil
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; narcissus-publish-index)
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:index.rss&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/msnyder.info/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:include&lt;/span&gt; (&lt;span class=&quot;org-string&quot;&gt;&quot;index.org&quot;&lt;/span&gt;)
         &lt;span class=&quot;org-builtin&quot;&gt;:insert-title-into-body&lt;/span&gt; nil
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:scraps-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Documents/Org/Notes/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:rss-output-filename&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;rss.xml&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:rss-title&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:rss-link&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;http://msnyder.info/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:rss-language&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;en&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:rss-description&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;the personal essays of Matthew Snyder&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:rss-copyright&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;Copyright 2012 Matthew Snyder&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; narcissus-publish-rss)
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:scraps&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Documents/Org/Notes/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;org&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:body-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;article&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;index&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:insert-title-into-body&lt;/span&gt; t
         &lt;span class=&quot;org-builtin&quot;&gt;:postamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;footer&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:preamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;header&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/public_html/scraps/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; narcissus-publish-scraps
         &lt;span class=&quot;org-builtin&quot;&gt;:recursive&lt;/span&gt; nil)
        (&lt;span class=&quot;org-string&quot;&gt;&quot;msnyder.info:entries.txt&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:preamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;header&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:postamble-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;footer&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/Projects/msnyder.info/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:base-extension&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;org&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-directory&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;~/msnyder.org.txt/&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:insert-title-into-body&lt;/span&gt; t
         &lt;span class=&quot;org-builtin&quot;&gt;:publishing-function&lt;/span&gt; org-publish-org-to-ascii
         &lt;span class=&quot;org-builtin&quot;&gt;:exclude&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;index.org&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:body-wrap-tag&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;article&quot;&lt;/span&gt;
         &lt;span class=&quot;org-builtin&quot;&gt;:export-file-name&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;index&quot;&lt;/span&gt;)))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-7&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-7&quot;&gt;Uploading of resources &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-7&quot;&gt;


&lt;p&gt;
  Everything that a set of entries uses in terms of stylesheets and
  images should be uploaded intelligently by the tools.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-8&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-8&quot;&gt;Preview exported HTML before publish &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-8&quot;&gt;


&lt;p&gt;
  What it says on the tin. I should be able to use the same set of
  tools to both publish the blog locally for preview (maybe even
  self-updating) as well as for public consumption.
&lt;/p&gt;
&lt;p&gt;
  I&apos;ve come up with a fairly sneaky way to do this: uploading
  &lt;code&gt;emacs-httpd&lt;/code&gt; to the Marmalade ELPA repo and installing it. Then,
  when my site gets published to &lt;code&gt;~/public_html&lt;/code&gt;, it&apos;s available in
  the browser at &lt;code&gt;http://0.0.0.0:8080&lt;/code&gt;. This is a completely
  reasonable approach, since we&apos;re using a generic tool instead of
  writing something specific for this purpose.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-9&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-9&quot;&gt;Mark entries as drafts and don&apos;t publish. &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-9&quot;&gt;


&lt;p&gt;
  Even if a blog entry is in the right directory, all the right tags,
  etc., a draft property should be introduced that refuses to publish
  the entry, no matter what.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-10&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-10&quot;&gt;Mark scraps to publish on separate pages. &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-10&quot;&gt;


&lt;p&gt;
  Any node should be markable as a &apos;scrap&apos;, which then gets published on
  a separate page and included in an accessible table of contents.
&lt;/p&gt;



&lt;pre class=&quot;src src-emacs-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-get-scrap&lt;/span&gt; (plist filename pub-dir)
  (&lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (org-entry-get (point-marker) &lt;span class=&quot;org-string&quot;&gt;&quot;SCRAP&quot;&lt;/span&gt;)
      (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((export-file-name (org-entry-get (point-marker) &lt;span class=&quot;org-string&quot;&gt;&quot;EXPORT_FILE_NAME&quot;&lt;/span&gt;)))
        (org-mark-subtree)
        (org-export-as-narcissus-html 3 t plist nil nil pub-dir))))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-publish-scraps&lt;/span&gt; (plist filename pub-dir)
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((buffer (find-file filename)))
    (org-map-entries (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; () (narcissus-get-scrap plist filename pub-dir)) t &apos;file)
    (kill-buffer buffer)))

(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;narcissus-publish-scraps-attachments&lt;/span&gt; (plist filename pub-dir)
  &lt;span class=&quot;org-doc&quot;&gt;&quot;Publish a file with no transformation of any kind.&lt;/span&gt;
&lt;span class=&quot;org-doc&quot;&gt;See `&lt;/span&gt;&lt;span class=&quot;org-doc&quot;&gt;&lt;span class=&quot;org-constant&quot;&gt;org-publish-org-to&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;org-doc&quot;&gt;&apos; to the list of arguments.&quot;&lt;/span&gt;
  &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;make sure eshell/cp code is loaded&lt;/span&gt;
  (message &lt;span class=&quot;org-string&quot;&gt;&quot;Plist: %s&quot;&lt;/span&gt; plist)
  (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; (file-directory-p pub-dir)
    (make-directory pub-dir t))
  (or (equal (expand-file-name (file-name-directory filename))
         (file-name-as-directory (expand-file-name pub-dir)))
      (copy-file filename
         (expand-file-name (file-name-nondirectory filename) pub-dir)
         t)))

&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-11&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-11&quot;&gt;Miscellaneous &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-11&quot;&gt;



&lt;/div&gt;

&lt;div id=&quot;outline-container-11-1&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-11-1&quot;&gt;Syntax Highlighting in Code Blocks &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-11-1&quot;&gt;


&lt;p&gt;   
   Getting code blocks to be properly syntax highlighted requires the
   program &lt;code&gt;htmlize&lt;/code&gt; to be installed. It can be installed through
   Emacs&apos;s package manager. It also makes sense for the variable
   &lt;code&gt;org-export-htmlize-output-type&lt;/code&gt; to be set to &lt;code&gt;css&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-11-2&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-11-2&quot;&gt;Removing Section Numbers &lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-11-2&quot;&gt;


&lt;p&gt;
   Section numbers seem legalistic and aren&apos;t really necessary. Set
   &lt;code&gt;org-export-with-section-numbers&lt;/code&gt; to &lt;code&gt;nil&lt;/code&gt;. This can also be set as
   the parameter &lt;code&gt;:section-numbers&lt;/code&gt; in &lt;code&gt;org-publish-project-alist&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-12&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-12&quot;&gt;Conclusion &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-12&quot;&gt;


&lt;p&gt;
  In general, I feel like there is an impedance mismatch of sorts
  between content that Org mode wants to keep track of, and content as
  it is typically organized for the web. Time after time I came across
  situations where Org mode wanted a resource of some kind to be
  located in a certain place, when web development experience said it
  belonged somewhere else, and these assumptions were typically deeply
  ingrained in Org mode. For example, I&apos;d like all the assets (images,
  javascript) for my website to be in one place, organized by
  subdirectories. However, Org mode decides that an image is
  unreachable if it can&apos;t find it, during linkification, exactly where
  it was in the filesystem structure. I fought the battles I thought
  were worth seeing through, and left other ones alone for the time
  being.
&lt;/p&gt;
&lt;p&gt;
  While I love the idea of using Org mode to not only describe the code
  I&apos;m writing but actually contain that code, there are a few immediate
  quirks that make it difficult to endorse:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Describing the code in text is equivalent to commenting, which comes
    with its own maintenance costs and the risk of getting out of sync
    with the code its describing.

&lt;/li&gt;
&lt;li&gt;Attempting to alter an existing piece of code is a little hacky,
    as you can see above: I&apos;ve placed comments throughout the existing
    code indicating where I&apos;ve made changes. I would prefer a more
    aware kind of system. Something where the existing code is in some
    repo, and I can refer to it, make my own changes, and the diff is
    automatically generated for publication. As it stands, if the
    functions I based Narcissus on change within Org mode, I won&apos;t be
    able to keep up with development unless I take the code from this
    file and throw it into a repository.
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>msnyder.info:entry:introducing-narcissus.org</guid>
      <pubDate>Sun, 31 Jul 2011 00:00:00 EDT</pubDate>
    </item>
    <item>
      <title>Lisp for the Web, Part II</title>
      <link>http://msnyder.info/posts/2011/07/lisp-for-the-web-part-ii/</link>
      <description>
&lt;p&gt;In this article, I hope to extend Adam Petersen&apos;s article &lt;a href=&quot;http://www.adampetersen.se/articles/lispweb.htm&quot;&gt;&lt;i&gt;Lisp for the Web&lt;/i&gt;&lt;/a&gt;, bringing up for discussion some of the aspects of web
programming that most of us are familiar with.
&lt;/p&gt;
&lt;p&gt;
[TABLE-OF-CONTENTS]
&lt;/p&gt;

&lt;div id=&quot;outline-container-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;What to Expect &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;


&lt;p&gt;
  Adam Petersen wrote an awesome article called &lt;a href=&quot;http://www.adampetersen.se/articles/lispweb.htm&quot;&gt;Lisp for the Web&lt;/a&gt;. In
  it, he walks readers through creating a simple web application using
  Common Lisp (hereinafter Lisp). It&apos;s a fantastic article, and I
  recently sat down with it (and &lt;a href=&quot;http://landoflisp.com&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;http://www.ccs.neu.edu/home/matthias/BTLS/&quot;&gt;other&lt;/a&gt; resources) to finally
  write some code in Lisp.
&lt;/p&gt;
&lt;p&gt;
  So what I&apos;d like to do here is take some of the things that were
  left out (with good reason) of the original article, and flesh out
  the experience of developing for the web with Lisp. At the end of
  the article, Mr. Petersen writes that
&lt;/p&gt;
&lt;blockquote&gt;


&lt;p&gt;
Due to the dynamic and interactive nature of Lisp it&apos;s a perfect fit
for prototyping. And because Lisp programs are so easy to evolve,
that prototype may end up as a full-blown product one day.
&lt;/p&gt;

&lt;/blockquote&gt;



&lt;p&gt;  
  It&apos;s my hope that in continuing his tutorial in this way I can show
  readers how that process from prototype to production may take
  place; in an organic way that showcases Lisp&apos;s &apos;evolutionary&apos;
  abilities.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;The Original Program &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;


&lt;p&gt;
The original program can be found at the &lt;a href=&quot;http://www.adampetersen.se/articles/lispweb.htm&quot;&gt;Lisp for the Web&lt;/a&gt; article. I
made some changes to it in order to fit some specific criteria:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The original article recommends using BerkeleyDB for its backend,
  accessed through the Lisp library &lt;a href=&quot;http://common-lisp.net/project/elephant/&quot;&gt;Elephant&lt;/a&gt;. I&apos;m still using
  Elephant, though I believe there may be more &quot;Lispy&quot; serialization
  libraries available &amp;mdash; Elephant requires a lot of dips into foreign
  functions. BerkeleyDB, however, has been swapped out for
  SQLite. This makes deployment a lot easier, and avoids the &lt;a href=&quot;http://en.wikipedia.org/wiki/Berkeley_DB#Licensing&quot;&gt;licensing hassles&lt;/a&gt; that seem to follow BerkeleyDB around.

&lt;/li&gt;
&lt;li&gt;We are binding the Elephant store to a variable, namely &lt;code&gt;*store*&lt;/code&gt;,
  in case we want to change databases during top-level interaction.

&lt;/li&gt;
&lt;li&gt;The syntax for starting a server in Hunchentoot has changed since
  the original article. We now make an instance of a Hunchentoot
  &lt;a href=&quot;http://weitz.de/hunchentoot/#acceptor&quot;&gt;acceptor&lt;/a&gt; in order to get the server bound and running.

&lt;/li&gt;
&lt;li&gt;The original article uses URLs which end in &lt;code&gt;.htm&lt;/code&gt;. For example, the
  index page is located at &lt;code&gt;/retro-games.htm&lt;/code&gt;. There&apos;s no reason for
  this to not simply be &lt;code&gt;/retro-games&lt;/code&gt;, and I&apos;ve changed all URLs to
  follow this convention. Remember, kids, &lt;a href=&quot;http://www.w3.org/Provider/Style/URI&quot;&gt;cool URIs&lt;/a&gt; don&apos;t reveal their
  implementation!

&lt;/li&gt;
&lt;li&gt;To be a bit more inclusive, we are no longer just voting on retro
  games. Now you can add votes for any game you wish! (This is not
  really a necessary change, but I don&apos;t know many very old games, so
  at the very least it makes coming up with examples easier.)
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;  
So the first thing we&apos;re going to do is make these transformations to
the original file, and then we can continue working from there.
&lt;/p&gt;
&lt;p&gt;
If you&apos;d like the diff so you can start off with these changes, I&apos;ve
posted it to Gist: &lt;a href=&quot;http://gist.github.com/1024814&quot;&gt;game-voter.patch&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src=&quot;/images/lisp-for-the-web-ii/main-page.png&quot;  alt=&quot;/images/lisp-for-the-web-ii/main-page.png&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-3&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;Your Lisp Environment &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;


&lt;p&gt;
  The original article, quite wisely, avoids discussing the actual
  environment in which its Lisp is set up. It&apos;s not useful to anyone to
  have an obsolete description of a Lisp installation. In this case,
  however, I&apos;d like to take a snapshot of the state of Lisp in certain
  ways; I am going to describe, to some extent, my setup.
&lt;/p&gt;
&lt;p&gt;
  Running OS X 10.6.7, with &lt;a href=&quot;http://www.sbcl.org&quot;&gt;Steel Bank Common Lisp&lt;/a&gt; installed through
  the excellent &lt;a href=&quot;http://mxcl.github.com/homebrew/&quot;&gt;homebrew&lt;/a&gt; package management system. My editor, REPL,
  and general Lisp interaction environment is Emacs 23.3, compiled for
  the Mac by &lt;a href=&quot;http://emacsformacosx.com/&quot;&gt;David Caldwell&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  The package manager I&apos;m using is the fantastic &lt;a href=&quot;http://www.quicklisp.org/&quot;&gt;Quicklisp&lt;/a&gt;. I&apos;ve
  tried installing packages for Common Lisp before with ASDF, and
  Quicklisp is so much more simple, capable, and promising it&apos;s scary.
&lt;/p&gt;
&lt;p&gt;
  Within a REPL, the following command did everything I expected and
  nothing I didn&apos;t: installed the libraries (often called &lt;b&gt;systems&lt;/b&gt;) I
  needed without complaining or breaking, and providing the packages in
  the top-level.
&lt;/p&gt;



&lt;pre class=&quot;example&quot;&gt;
CL-USER&amp;gt; (ql:quickload &apos;(cl-who hunchentoot parenscript elephant fiveam css-lite cl-json))

&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;Smarter Routes &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;


&lt;p&gt;
There was one thing I noticed almost immediately as I was playing
around with the program. If I wanted to make a change to a
&apos;controller&apos;, i.e. any of the functions defined by &lt;code&gt;define-url-fn&lt;/code&gt;,
re-evaluating it would simply push another route onto the
&lt;code&gt;hunchentoot:*dispatch-table*&lt;/code&gt;. This isn&apos;t a huge problem &lt;b&gt;per se&lt;/b&gt;,
but it is unnecessary computation, and after having pushed a hundred
or so different versions of a controller dispatch onto the
&lt;code&gt;*dispatch-table*&lt;/code&gt;, I desired a more practical way of describing the
routes in my site. In addition, using a macro such as &lt;code&gt;define-url-fn&lt;/code&gt;
to describe the routes means that Emacs doesn&apos;t recognize that
controller function as a valid symbol. It&apos;s a silly convenience, but
the more I use &lt;code&gt;defmacro&lt;/code&gt; and &lt;code&gt;defun&lt;/code&gt;, the easier I can find the code
I&apos;m looking for with Emacs&apos; symbol lookup.
&lt;/p&gt;
&lt;p&gt;
So for example, the controller for adding a game goes from this:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;define-url-fn&lt;/span&gt; (game-added)
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((name (parameter &lt;span class=&quot;org-string&quot;&gt;&quot;name&quot;&lt;/span&gt;)))
    (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; (or (null name) (zerop (length name))) &lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;In case JavaScript is turned off.&lt;/span&gt;
      (add-game name))
    (redirect &lt;span class=&quot;org-string&quot;&gt;&quot;/games&quot;&lt;/span&gt;))) &lt;span class=&quot;org-comment-delimiter&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Display the front page.&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
To this:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;controller-game-added&lt;/span&gt; ()
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((name (parameter &lt;span class=&quot;org-string&quot;&gt;&quot;name&quot;&lt;/span&gt;)))
    (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; (or (null name) (zerop (length name)))
      (add-game name))
    (redirect &lt;span class=&quot;org-string&quot;&gt;&quot;/retro-games&quot;&lt;/span&gt;)))
&lt;/pre&gt;


&lt;p&gt;
Now with a handful of functions, I manually set the &lt;code&gt;*dispatch-table*&lt;/code&gt;
to the list of routes I desired, using Hunchentoot&apos;s dispatcher
creation functions.
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;hunchentoot:create-regex-dispatcher&lt;/code&gt; is a function that takes a
regular expression for an endpoint, and runs the function named by the
second argument upon execution.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(setq *dispatch-table*
 (list
  (create-regex-dispatcher &lt;span class=&quot;org-string&quot;&gt;&quot;^/index&quot;&lt;/span&gt; &apos;controller-index)
  (create-regex-dispatcher &lt;span class=&quot;org-string&quot;&gt;&quot;^/vote&quot;&lt;/span&gt; &apos;controller-vote)
  (create-regex-dispatcher &lt;span class=&quot;org-string&quot;&gt;&quot;^/game-added&quot;&lt;/span&gt; &apos;controller-game-added)
  (create-regex-dispatcher &lt;span class=&quot;org-string&quot;&gt;&quot;^/new-game&quot;&lt;/span&gt; &apos;controller-new-game)))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-5&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;Writing CSS in Lisp &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;


&lt;p&gt;
The original tutorial never supplies the CSS it used to style the
website. As you can see, I provided some of my own CSS to pretty
things up a bit &amp;ndash; but you won&apos;t see that if you&apos;ve made it this far
into the article. Why? Because we&apos;ve overwritten the contents of
&lt;code&gt;*dispatch-table*&lt;/code&gt; with the four routes we&apos;ve defined above. What
we&apos;re going to do is define another route for the CSS, but provide the
CSS in a Lisp form that then gets translated into CSS for us. This
provides us a little bit of flexibility and can help reduce some of
the redundancy that CSS tends to accumulate, without resorting to some
CSS extension (like &lt;a href=&quot;http://sass-lang.com/&quot;&gt;Sass&lt;/a&gt; or &lt;a href=&quot;http://lesscss.org/&quot;&gt;LESS&lt;/a&gt;).
&lt;/p&gt;
&lt;p&gt;
The CSS goes in a controller function, just like the other dynamically
created pages on the site.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;controller-css&lt;/span&gt; ()
  (setf (hunchentoot:content-type* hunchentoot:*reply*) &lt;span class=&quot;org-string&quot;&gt;&quot;text/css&quot;&lt;/span&gt;)
  &lt;span class=&quot;org-string&quot;&gt;&quot;...&quot;&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
We set the &lt;code&gt;content-type&lt;/code&gt; header to &quot;text/css&quot;, which lets web
browsers know that the file we&apos;re sending is meant to be interpreted
as a stylesheet. I&apos;ve put together a style, and I&apos;ll be using some
aspects of it to exemplify some points with Lisp, but you&apos;re free to
style up the site however you&apos;d like. Either way, replace the ellipsis
in the code sample above with your style. You can use your CSS
verbatim, explicitly using multiple newlines in one string. Lisp
strings understand multiple lines without any special indicator:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(setq *some-string* &lt;span class=&quot;org-string&quot;&gt;&quot;This is a string that&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;spans&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;multiple&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;lines.&quot;&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
My CSS style is reproduced at the following link: &lt;a href=&quot;https://gist.github.com/1062278&quot;&gt;game-voter.css&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
We&apos;ll be using the &lt;a href=&quot;http://www.cliki.net/css-lite&quot;&gt;css-lite&lt;/a&gt; library to generate our CSS. This
library exposes one primary method, &lt;code&gt;css&lt;/code&gt;, which takes a list of
lists, and from them, generates our CSS. Within this list parameter,
every other list describes a set of selectors, and the following list
is an associated list of css attributes to values. My first
translation into &lt;code&gt;css-lite&lt;/code&gt;&apos;s format looks something like this:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;controller-css&lt;/span&gt; ()
  (setf (hunchentoot:content-type* hunchentoot:*reply*) &lt;span class=&quot;org-string&quot;&gt;&quot;text/css&quot;&lt;/span&gt;)
  (css-lite:css
    ((&lt;span class=&quot;org-string&quot;&gt;&quot;body&quot;&lt;/span&gt;)
     (&lt;span class=&quot;org-builtin&quot;&gt;:width&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;70%&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:margin&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;0 auto&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:font-family&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;sans-serif&quot;&lt;/span&gt;
      &lt;span class=&quot;org-builtin&quot;&gt;:border-left&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;1px solid #ccc&quot;&lt;/span&gt;
      &lt;span class=&quot;org-builtin&quot;&gt;:border-right&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;1px solid #ccc&quot;&lt;/span&gt;
      &lt;span class=&quot;org-builtin&quot;&gt;:border-bottom&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;1px solid #ccc&quot;&lt;/span&gt;))
    ((&lt;span class=&quot;org-string&quot;&gt;&quot;h1&quot;&lt;/span&gt;)
     (&lt;span class=&quot;org-builtin&quot;&gt;:font-size&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;140%&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:text-align&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;center&quot;&lt;/span&gt;))
    ((&lt;span class=&quot;org-string&quot;&gt;&quot;h2&quot;&lt;/span&gt;)
     (&lt;span class=&quot;org-builtin&quot;&gt;:color&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;#000&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:background-color&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;#cef&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:margin&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;0 auto&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:padding&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;4px 0&quot;&lt;/span&gt;))
    ((&lt;span class=&quot;org-string&quot;&gt;&quot;#header&quot;&lt;/span&gt;)
     (&lt;span class=&quot;org-builtin&quot;&gt;:background-color&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;#cef&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:padding&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;8px&quot;&lt;/span&gt;))
    ((&lt;span class=&quot;org-string&quot;&gt;&quot;#header .logo&quot;&lt;/span&gt;)
      (&lt;span class=&quot;org-builtin&quot;&gt;:display&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;block&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:margin&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;0 auto&quot;&lt;/span&gt;))
    ((&lt;span class=&quot;org-string&quot;&gt;&quot;#header .strapline&quot;&lt;/span&gt;)
     (&lt;span class=&quot;org-builtin&quot;&gt;:display&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;block&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:text-align&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;center&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:font-size&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;80%&quot;&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:font-style&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;italic&quot;&lt;/span&gt;))

    &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;and so on ...&lt;/span&gt;

&lt;/pre&gt;


&lt;p&gt;
So the first thing that stands out is the repetition in describing the
border for the &lt;code&gt;body&lt;/code&gt; selector. I&apos;m sure there&apos;s some CSS way to
describe the border, but as an example, we&apos;re going to use a variable
to encapsulate the border description.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((border &lt;span class=&quot;org-string&quot;&gt;&quot;1px solid #ccc&quot;&lt;/span&gt;))
  (css-lite:css ((&lt;span class=&quot;org-string&quot;&gt;&quot;body&quot;&lt;/span&gt;)
                 (&lt;span class=&quot;org-builtin&quot;&gt;:border-left&lt;/span&gt; border
                  &lt;span class=&quot;org-builtin&quot;&gt;:border-right&lt;/span&gt; border
                  &lt;span class=&quot;org-builtin&quot;&gt;:border-bottom&lt;/span&gt; border))))
&lt;/pre&gt;


&lt;p&gt;
Simple enough, but what if we wanted to reduce some more complicated
piece of CSS? For example, some CSS3 attributes that are initialized
differently for each browser?
&lt;/p&gt;
&lt;p&gt;
The gradient property currently has several different
implementations. Here are the selectors provided by a popular CSS3
gradient generator, Alex Sirota&apos;s excellent and comprehensive
&lt;a href=&quot;http://www.colorzilla.com/gradient-editor/&quot;&gt;Ultimate CSS Gradient Generator&lt;/a&gt;:
&lt;/p&gt;




&lt;pre class=&quot;src src-css&quot;&gt;&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: #1e5799; &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Old browsers &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: -moz-linear-gradient(top, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%); &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;FF3.6+ &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(50%,#2989d8), color-stop(51%,#207cca), color-stop(100%,#7db9e8)); &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Chrome,Safari4+ &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: -webkit-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Chrome10+,Safari5.1+ &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: -o-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;Opera11.10+ &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: -ms-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;IE10+ &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;org-css-property&quot;&gt;background&lt;/span&gt;: linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); &lt;span class=&quot;org-comment-delimiter&quot;&gt;/* &lt;/span&gt;&lt;span class=&quot;org-comment&quot;&gt;W3C &lt;/span&gt;&lt;span class=&quot;org-comment-delimiter&quot;&gt;*/&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
What we&apos;d like to do is describe our CSS as having a gradient, and
having Lisp do the work of translating it into all the browsers that
we want to support.
&lt;/p&gt;
&lt;p&gt;
The first thing to observe is that a lot of the rules use the same
basic format &amp;ndash; that of the W3C recommendation. It should be easy to
apply those rules while just changing the name of the CSS
function. Two other things that should jump out at you are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We should use a fallthrough background of the first color in the
  pattern for browsers that don&apos;t support the gradient at all.

&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;-webkit-gradient&lt;/code&gt; rule reverses the order of the arguments:
  instead of taking a color and a percentage, it takes a percentage
  and a color.
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;
The function should return a flattened list of CSS selectors and
values. We then pass it to an internal &lt;code&gt;css-lite&lt;/code&gt; function,
&lt;code&gt;make-css-function&lt;/code&gt;, with an identifier that we can use in the &lt;code&gt;css&lt;/code&gt;
macro.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;css-linear-gradient&lt;/span&gt; (colors-and-positions)
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((default-background (caar colors-and-positions)))
    (&lt;span class=&quot;org-keyword&quot;&gt;flet&lt;/span&gt; ((w3c-spec (name)
             (format nil &lt;span class=&quot;org-string&quot;&gt;&quot;~A(top, ~{~{~A ~A%~}~^, ~})&quot;&lt;/span&gt; name colors-and-positions))
           (webkit-gradient ()
             (format nil &lt;span class=&quot;org-string&quot;&gt;&quot;-webkit-gradient(linear, left top, left bottom, ~{color-stop(~{~A%, ~A~})~^, ~})&quot;&lt;/span&gt;
               (mapcar #&apos;reverse colors-and-positions))))
      (list
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; default-background
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; (w3c-spec &lt;span class=&quot;org-string&quot;&gt;&quot;-moz-linear-gradient&quot;&lt;/span&gt;)
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; (webkit-gradient)
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; (w3c-spec &lt;span class=&quot;org-string&quot;&gt;&quot;-webkit-linear-gradient&quot;&lt;/span&gt;)
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; (w3c-spec &lt;span class=&quot;org-string&quot;&gt;&quot;-o-linear-gradient&quot;&lt;/span&gt;)
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; (w3c-spec &lt;span class=&quot;org-string&quot;&gt;&quot;-ms-linear-gradient&quot;&lt;/span&gt;)
       &lt;span class=&quot;org-builtin&quot;&gt;:background&lt;/span&gt; (w3c-spec &lt;span class=&quot;org-string&quot;&gt;&quot;linear-gradient&quot;&lt;/span&gt;)))))

(css-lite::make-css-func
  linear-gradient (colors-and-positions) (css-linear-gradient colors-and-positions))
&lt;/pre&gt;


&lt;p&gt;
This works roughly the way we expect, generating the different
combinations of gradient methods above.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(css-lite:css
  ((&lt;span class=&quot;org-string&quot;&gt;&quot;body&quot;&lt;/span&gt;)
   (linear-gradient &apos;((&lt;span class=&quot;org-string&quot;&gt;&quot;#1e5799&quot;&lt;/span&gt; 0) (&lt;span class=&quot;org-string&quot;&gt;&quot;#2989d8&quot;&lt;/span&gt; 50) (&lt;span class=&quot;org-string&quot;&gt;&quot;#207cca&quot;&lt;/span&gt; 51) (&lt;span class=&quot;org-string&quot;&gt;&quot;#7db9e8&quot;&lt;/span&gt; 100)))))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-6&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-6&quot;&gt;Using jQuery &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-6&quot;&gt;


&lt;p&gt;
The original article used some Javascript to prevent the user from
submitting the Game submission form if they tried entering the empty
string for the name of the game. It was written in &lt;code&gt;parenscript&lt;/code&gt;, a
library that translates Lisp code into the appropriate JavaScript. It
was a fairly rudimentary implementation, reproduced below:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps-inline
             (&lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; (= name.value &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;)
               (alert &lt;span class=&quot;org-string&quot;&gt;&quot;Please enter a name.&quot;&lt;/span&gt;)
               (&lt;span class=&quot;org-keyword&quot;&gt;return&lt;/span&gt; false)))
&lt;span class=&quot;org-string&quot;&gt;&quot;javascript:if (name.value === \&quot;\&quot;) {&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;    alert(\&quot;Please enter a name.\&quot;);&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;    return false;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;}&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
Modal alert boxes such at this one aren&apos;t a horrible idea, but there&apos;s
a more elegant, expected way to handle this sort of behavior: display
an inline message to the user on form submission; and what better way
to do that than jQuery?
&lt;/p&gt;
&lt;p&gt;
Parenscript is a fantastic library, but it may require some thought
and time to get accustomed to its idioms. Most of them make sense in
retrospect, but not before you&apos;ve used them for a while. The good news
is, it works perfectly with jQuery once you&apos;ve put this work in, and
Lisp macros can help bridge the gap and make your life easier.
&lt;/p&gt;
&lt;p&gt;
The primary macro used with Parenscript is &lt;code&gt;ps&lt;/code&gt;, especially if you&apos;ll
be injecting the contents of your code directly into &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;
tags. Most of Parenscript consists of &apos;translators&apos; of a kind, turning
lisp forms into the appropriate Javascript verbiage. The
&lt;a href=&quot;http://common-lisp.net/project/parenscript/reference.html&quot;&gt;Parenscript reference&lt;/a&gt; is the canonical bible of these
translations, succinctly explaining all of these rules and how they
may be applied. For now we will take a look at the ones that are
relevant to us.
&lt;/p&gt;
&lt;p&gt;
Simple functions have their obvious counterparts.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps (+ 1 2))

&lt;span class=&quot;org-string&quot;&gt;&quot;1 + 2;&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
Attempting to call a function by name is similarly obvious. It&apos;s also
here that we&apos;re pointing out one of Parenscript&apos;s transformative
properties: to take hyphenated symbols and turn them into a valid
Javascript identifier, capitalizing the letters right after the
hyphens. This is a necessary change as symbols in Lisp are interned in
all capitals.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps (makeFunnyNoise))

&lt;span class=&quot;org-string&quot;&gt;&quot;makefunnynoise();&quot;&lt;/span&gt;

GAME-VOTER&amp;gt; (ps (make-funny-noise))

&lt;span class=&quot;org-string&quot;&gt;&quot;makeFunnyNoise();&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;
Most jQuery programming is accomplished by the passing of anonymous
functions. In Parenscript, these functions are created through &amp;ndash; how
else? &amp;ndash; the use of &lt;code&gt;lambda&lt;/code&gt;.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (foo bar) (+ foo bar)))

&lt;span class=&quot;org-string&quot;&gt;&quot;function (foo, bar) {&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;    return foo + bar;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;};&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
Variables may be defined in various ways; the way that makes the most
sense to us is the use of a &lt;code&gt;let&lt;/code&gt; binding, which works in much the way
you&apos;d expect. This is the best part of Parenscript: it is
predictable. You don&apos;t have to alter many habits to start using it.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((a 1) (b 2)) (+ a b)))

&lt;span class=&quot;org-string&quot;&gt;&quot;var a = 1;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;var b = 2;&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;a + b;&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
Objects can be created with the &lt;code&gt;create&lt;/code&gt; operator.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps (create &lt;span class=&quot;org-builtin&quot;&gt;:url&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;http://example.com&quot;&lt;/span&gt;))

&lt;span class=&quot;org-string&quot;&gt;&quot;{ &apos;url&apos; : &apos;http://example.com&apos; };&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
If we had a (Javascript) Object named &lt;code&gt;foo&lt;/code&gt;, and wanted to call its
&lt;code&gt;bar&lt;/code&gt; function, we would have to use the &apos;chain&apos; operator in
Parenscript, denoted by the &lt;code&gt;@&lt;/code&gt; symbol. We then surround the chain
operator with another set of parentheses to indicate that we are
calling the result. This is where we also show you that any
not-understood symbol is left unmolested, such as &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps (@ foo bar))

&lt;span class=&quot;org-string&quot;&gt;&quot;foo.bar;&quot;&lt;/span&gt;

GAME-VOTER&amp;gt; (ps ((@ foo bar)))

&lt;span class=&quot;org-string&quot;&gt;&quot;foo.bar();&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;     
This is one of the ways that we would need to access jQuery core
function, i.e. to call functions hanging directly off of it, such as
&lt;code&gt;$.ajax()&lt;/code&gt;. Parameters can be put into the outer parentheses of the
chained call.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps ((@ $ ajax)))

&lt;span class=&quot;org-string&quot;&gt;&quot;$.ajax();&quot;&lt;/span&gt;

GAME-VOTER&amp;gt; (ps ((@ $ ajax) (create &lt;span class=&quot;org-builtin&quot;&gt;:url&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;http://example.com&quot;&lt;/span&gt;)))

&lt;span class=&quot;org-string&quot;&gt;&quot;$.ajax({ &apos;url&apos; : &apos;http://example.com&apos; });&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
The other way is to call the jQuery selector, for manipulating
elements on the page.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps ((@ ($ &lt;span class=&quot;org-string&quot;&gt;&quot;div.foo&quot;&lt;/span&gt;) fade-in)))

&lt;span class=&quot;org-string&quot;&gt;&quot;$(&apos;div.foo&apos;).fadeIn();&quot;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;    
With all these things in mind, let&apos;s take a look at the jQuery we want
to produce on the page:
&lt;/p&gt;



&lt;pre class=&quot;src src-javascript&quot;&gt;$(document).ready(&lt;span class=&quot;org-keyword&quot;&gt;function&lt;/span&gt; () {
    $(&lt;span class=&quot;org-string&quot;&gt;&apos;input.btn&apos;&lt;/span&gt;).click(&lt;span class=&quot;org-keyword&quot;&gt;function&lt;/span&gt; () {
        &lt;span class=&quot;org-keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;org-variable-name&quot;&gt;text&lt;/span&gt; = $(&lt;span class=&quot;org-string&quot;&gt;&apos;input.txt&apos;&lt;/span&gt;).val().trim();
        &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (text == &lt;span class=&quot;org-string&quot;&gt;&apos;&apos;&lt;/span&gt;) {
            $(&lt;span class=&quot;org-string&quot;&gt;&apos;#error&apos;&lt;/span&gt;).fadeIn();
            &lt;span class=&quot;org-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;org-constant&quot;&gt;false&lt;/span&gt;;
        };
    });
});
&lt;/pre&gt;


&lt;p&gt;
This is my first go at translating it into Parenscript.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps ((@ ($ document) ready)
                 (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; ()
                   ((@ ($ &lt;span class=&quot;org-string&quot;&gt;&quot;input.btn&quot;&lt;/span&gt;) click)
                    (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; ()
                      (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((text (chain ($ &lt;span class=&quot;org-string&quot;&gt;&quot;input.txt&quot;&lt;/span&gt;) (val) (trim))))
                        (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt; ((equal text &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;) 
                               ((@ ($ &lt;span class=&quot;org-string&quot;&gt;&quot;#error&quot;&lt;/span&gt;) fade-in))
                               (&lt;span class=&quot;org-keyword&quot;&gt;return&lt;/span&gt; false)))))))))
&lt;/pre&gt;


&lt;p&gt;
We have some duplication with the code required to prepare an event
handler: two lines for &lt;code&gt;document.ready&lt;/code&gt; and two lines for
&lt;code&gt;$(&quot;input.btn&quot;).click&lt;/code&gt;. Using Parenscript, we can write a Lisp macro
and &apos;install&apos; it into Parenscript&apos;s translator, like so.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defmacro&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;$$&lt;/span&gt; ((selector event-binding) &lt;span class=&quot;org-type&quot;&gt;&amp;amp;body&lt;/span&gt; body)
  =((@ ($ ,selector) ,event-binding) (&lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; () ,@body)))

(import-macros-from-lisp &apos;$$)
&lt;/pre&gt;


&lt;p&gt;
&lt;code&gt;import-macros-from-lisp&lt;/code&gt; is described in the &lt;a href=&quot;http://common-lisp.net/project/parenscript/reference.html#section-macros&quot;&gt;macro section&lt;/a&gt; of the
Parenscript documentation. This allows our second attempt to be a lot cleaner.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;GAME-VOTER&amp;gt; (ps ($$ (document ready)
                  ($$ (&lt;span class=&quot;org-string&quot;&gt;&quot;input.btn&quot;&lt;/span&gt; click)
                    (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((text (chain ($ &lt;span class=&quot;org-string&quot;&gt;&quot;input.txt&quot;&lt;/span&gt;) (val) (trim))))
                      (&lt;span class=&quot;org-keyword&quot;&gt;cond&lt;/span&gt; ((equal text &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;) 
                             ((@ ($ &lt;span class=&quot;org-string&quot;&gt;&quot;#error&quot;&lt;/span&gt;) fade-in))
                             (&lt;span class=&quot;org-keyword&quot;&gt;return&lt;/span&gt; false)))))))
&lt;/pre&gt;


&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-7&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-7&quot;&gt;Writing a Test Suite &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-7&quot;&gt;


&lt;p&gt;
By this point, your little web application should be looking pretty
fantastic. It&apos;s simple, but powerful and extensible. The refactoring
we&apos;ve done, while fairly cursory, has gone a long way to making sure
that more work on the system is possible and easy. There&apos;s one section
where we&apos;re lacking, however, and that&apos;s a test suite. Most
programmers today have gotten onboard the unit testing bus in some
capacity or another. It is possible to go overboard &amp;ndash; my feeling is
that test suites should contain absurdly small amounts of logic, and
be comprised of one or two assertions per unit test. Even then, it&apos;s
very easy to start testing the wrong behavior, or writing specious
tests.
&lt;/p&gt;
&lt;p&gt;
With these thoughts in mind, we&apos;re going to write a small, efffective
test suite. We will be doing so using the &lt;a href=&quot;http://common-lisp.net/project/bese/FiveAM.html&quot;&gt;FiveAM&lt;/a&gt; library. FiveAM
is attractive for a few reasons:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It encapsulates tests into logical units, called &lt;b&gt;suites&lt;/b&gt;, much like
  functions, macros, and classes are broken up into packages.

&lt;/li&gt;
&lt;li&gt;The assertion operator is simple. &lt;code&gt;is&lt;/code&gt; takes a form and if the form
  evalutates to non-nil, then the assertion passes. If the form
  evaluates to &lt;code&gt;nil&lt;/code&gt;, the assertion fails.

&lt;/li&gt;
&lt;li&gt;It allows for the use of a wrapping macro called a &lt;b&gt;fixture&lt;/b&gt;. While
  other testing suites use the term &apos;fixture&apos; to describe
  pre-constructed data, such as records in a database, FiveAM extends
  the notion to include the setup and teardown of tests.
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;  
The first thing you should do is create a place to put the tests. Off
of my main directory, I&apos;ve simply touched
&lt;code&gt;test/test-game-voter.lisp&lt;/code&gt;. &lt;code&gt;test-game-voter&lt;/code&gt; will be another
package, so declare it:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defpackage&lt;/span&gt; &lt;span class=&quot;org-type&quot;&gt;test-game-voter&lt;/span&gt;
  (&lt;span class=&quot;org-builtin&quot;&gt;:use&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:cl&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:game-voter&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:elephant&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:fiveam&lt;/span&gt;))

(&lt;span class=&quot;org-keyword&quot;&gt;in-package&lt;/span&gt; &lt;span class=&quot;org-builtin&quot;&gt;:test-game-voter&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
And we&apos;ll write a test to make sure everything works as expected. Make
sure to enter the package.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;TEST-GAME-VOTER&amp;gt; (test sanity
                   (is (= 4 (+ 2 2))))

TEST-GAME-VOTER&amp;gt; (run!)
.
 Did 1 check.
    Pass: 1 (100%)
    Skip: 0 ( 0%)
    Fail: 0 ( 0%)
&lt;/pre&gt;


&lt;p&gt;
Pretty nice, eh? Extremely simple. The single period in the output
after the &lt;code&gt;run!&lt;/code&gt; command is the single passed test, similar to what
you&apos;d see in xUnit derivatives. Now let&apos;s see what happens when a
test fails.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;TEST-GAME-VOTER&amp;gt; (test more-sanity
                   (is (= 4 (+ 2 4))))

TEST-GAME-VOTER&amp;gt; (run!)
.f
 Did 2 checks.
    Pass: 1 (50%)
    Skip: 0 ( 0%)
    Fail: 1 (50%)

 Failure Details:
 --------------------------------
 MORE-SANITY []: 
      (+ 2 4) evaluated to 6, which is not = to 4..
 --------------------------------
&lt;/pre&gt;


&lt;p&gt;
Again, a huge amount of detail. Now, remove those tests from the suite
with &lt;code&gt;(rem-test &apos;sanity)&lt;/code&gt; and &lt;code&gt;(rem-test &apos;more-sanity)&lt;/code&gt;. We have real
tests to write.
&lt;/p&gt;
&lt;p&gt;
The first unit tests we&apos;re going to tackle are on the model level --
making sure the game class we created in the first tutorial works the
way we expect. However, it&apos;s a persistent class, and we want to make
sure we&apos;re saving test instances somewhere else other than our public
database. So that&apos;s the first step: defining an Elephant
configuration and controller to house this new data. The second step is
making sure we compartmentalize our model tests into a model suite.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defparameter&lt;/span&gt; &lt;span class=&quot;org-variable-name&quot;&gt;*test-database-config*&lt;/span&gt;
  &apos;(&lt;span class=&quot;org-builtin&quot;&gt;:clsql&lt;/span&gt; (&lt;span class=&quot;org-builtin&quot;&gt;:sqlite3&lt;/span&gt; &lt;span class=&quot;org-string&quot;&gt;&quot;test-store&quot;&lt;/span&gt;))
  &lt;span class=&quot;org-string&quot;&gt;&quot;The connection information and filename of the database used in the&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;test suite.&quot;&lt;/span&gt;)

(&lt;span class=&quot;org-keyword&quot;&gt;defparameter&lt;/span&gt; &lt;span class=&quot;org-variable-name&quot;&gt;*test-database-controller*&lt;/span&gt;
  (open-store *test-database-config*)
  &lt;span class=&quot;org-string&quot;&gt;&quot;The database controller for the test suite. We open one here so&lt;/span&gt;
&lt;span class=&quot;org-string&quot;&gt;that every test run doesn&apos;t open more.&quot;&lt;/span&gt;)

(def-suite &lt;span class=&quot;org-builtin&quot;&gt;:suite-game-voter-model&lt;/span&gt;)
(in-suite &lt;span class=&quot;org-builtin&quot;&gt;:suite-game-voter-model&lt;/span&gt;)
&lt;/pre&gt;


&lt;p&gt;
The next part is going to be a little tricky. We don&apos;t want every
single test adding its own results to the database, and then using
that dirtied database in the next test. Elephant exposes database
transaction management to us, but that&apos;s not quite good enough. We
need to be able to specify that the transaction should be
aborted. This is going to involve diving into the internals of what
makes Elephant go: the clsql-sys and db-clsql packages.
&lt;/p&gt;
&lt;p&gt;
Without getting too much into it, I will say
this. &lt;code&gt;*test-database-controller*&lt;/code&gt; is our instance of the data
store. Stored on it is the information used to track transactions,
including the status of the transaction. This field can be set
manually, and if Elephant attempts to close a transaction and finds
that it has failed, it rolls it back entirely. How does it know if it&apos;s
failed? It checks to see if the transaction status is &lt;code&gt;:aborted&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
With that explanation in mind, here&apos;s what we&apos;re looking at in terms
of code. This may not be the most elegant way of dealing with it, but
it works nicely for our purposes.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(def-fixture db-fixtures ()
  (&lt;span class=&quot;org-keyword&quot;&gt;with-transaction&lt;/span&gt; (&lt;span class=&quot;org-builtin&quot;&gt;:store-controller&lt;/span&gt; *test-database-controller*)
    (&lt;span class=&quot;org-type&quot;&gt;&amp;amp;body&lt;/span&gt;)
    (setf (clsql-sys::transaction-status
           (clsql-sys::transaction
            (db-clsql::controller-db *test-database-controller*))) &lt;span class=&quot;org-builtin&quot;&gt;:aborted&lt;/span&gt;)))
&lt;/pre&gt;


&lt;p&gt;
&lt;code&gt;def-fixture&lt;/code&gt; is a FiveAM macro. It works almost exactly like
&lt;code&gt;defmacro&lt;/code&gt;, instead placing the described macro into FiveAM&apos;s own
repertoire of fixtures. &lt;code&gt;with-transaction&lt;/code&gt; is within Elephant&apos;s
namespace, and takes an associated list of options. In this case we
want to make sure the transaction is occuring on our test
controller. The &lt;code&gt;&amp;amp;body&lt;/code&gt; tag is implicit with &lt;code&gt;def-fixture&lt;/code&gt;, so we
don&apos;t need to provide it in the argument list. Finally, we &lt;code&gt;setf&lt;/code&gt; the
status of the transaction we&apos;re in to &lt;code&gt;:aborted&lt;/code&gt;. When
&lt;code&gt;with-transaction&lt;/code&gt; hits the end of this form, it will see the
transaction &apos;failed&apos;, and roll back everything we&apos;ve done in the body.
&lt;/p&gt;
&lt;p&gt;
Now let&apos;s begin writing some tests! Off the top of my head, I can
think of a couple things we&apos;d like to test: adding a game, voting for
a game, getting a game based on its name, and ensuring we can tell if
a game is stored by passing its name. We&apos;ll start with adding a game.
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(test test-add-game-name
    (&lt;span class=&quot;org-keyword&quot;&gt;with-fixture&lt;/span&gt; db-fixtures ()
      (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((game (game-voter::add-game &lt;span class=&quot;org-string&quot;&gt;&quot;test game&quot;&lt;/span&gt;)))
        (is (equal &lt;span class=&quot;org-string&quot;&gt;&quot;test game&quot;&lt;/span&gt; (game-voter::name game))))))

(test test-add-game-votes
    (&lt;span class=&quot;org-keyword&quot;&gt;with-fixture&lt;/span&gt; db-fixtures ()
      (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((game (game-voter::add-game &lt;span class=&quot;org-string&quot;&gt;&quot;test game&quot;&lt;/span&gt;)))
        (is (= 0 (game-voter::votes game))))))
&lt;/pre&gt;


&lt;p&gt;
Call &lt;code&gt;run!&lt;/code&gt; again and check out the results. Did you get two passing
checks? Notice that &lt;code&gt;run!&lt;/code&gt; reports the total number of checks, or
assertions, and not the number of tests. This is because FiveAM will
continue through a test even if a check fails, and report the passing
status of all the checks in a test.
&lt;/p&gt;
&lt;p&gt;
Note that we have to use the double-colon notation for our game
functions, since we haven&apos;t made them externally visible from our
&lt;code&gt;game-voter&lt;/code&gt; package.
&lt;/p&gt;
&lt;p&gt;
This is looking good, but we can remove just a sliver of duplication
by writing a macro for tests we know will be using the database. To
wit:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defmacro&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;db-test&lt;/span&gt; (test-name &lt;span class=&quot;org-type&quot;&gt;&amp;amp;body&lt;/span&gt; body)
  `(test ,test-name
     (&lt;span class=&quot;org-keyword&quot;&gt;with-fixture&lt;/span&gt; db-fixtures ()
       ,@body)))

(db-test test-add-game-name
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((game (game-voter::add-game &lt;span class=&quot;org-string&quot;&gt;&quot;test game&quot;&lt;/span&gt;)))
    (is (equal &lt;span class=&quot;org-string&quot;&gt;&quot;test game&quot;&lt;/span&gt; (game-voter::name game)))))
&lt;/pre&gt;


&lt;p&gt;
Write some more tests. Make sure that &lt;code&gt;game-from-name&lt;/code&gt; returns correct
values for games that are or aren&apos;t in the system. Make sure adding a
game with a duplicate name fails. Then, write something like this:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(db-test test-sanitized-game-name
  (game-voter::add-game &lt;span class=&quot;org-string&quot;&gt;&quot;Foo&quot;&lt;/span&gt;)
  (game-voter::add-game &lt;span class=&quot;org-string&quot;&gt;&quot;  Foo  &quot;&lt;/span&gt;)
  (is (= 1 (length (game-voter::games)))))
&lt;/pre&gt;


&lt;p&gt;
Well, that fails! We aren&apos;t sanitizing our input! This isn&apos;t even
caught on the client side. This is what writing good tests is about --
finding small pieces of behavior that fail in unexpected ways.
&lt;/p&gt;
&lt;p&gt;
We can ensure that the server takes care of extra padding around the
game name by trimming it. &lt;code&gt;string-trim&lt;/code&gt; takes a string called a &lt;b&gt;char bag&lt;/b&gt;, and then the string you wish to trim. Since all strings are
array of characters, &lt;code&gt;string-trim&lt;/code&gt; walks through the char bag and
removes instances of each character from both sides of your argument.
&lt;/p&gt;
&lt;p&gt;
We can modify the &lt;code&gt;add-game&lt;/code&gt; function as below:
&lt;/p&gt;



&lt;pre class=&quot;src src-lisp&quot;&gt;(&lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;org-function-name&quot;&gt;add-game&lt;/span&gt; (name)
  (&lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((sanitized-name (string-trim &lt;span class=&quot;org-string&quot;&gt;&quot; &quot;&lt;/span&gt; name)))
    (&lt;span class=&quot;org-keyword&quot;&gt;with-transaction&lt;/span&gt; ()
      (&lt;span class=&quot;org-keyword&quot;&gt;unless&lt;/span&gt; (game-stored? sanitized-name)
        (make-instance &apos;persistent-game &lt;span class=&quot;org-builtin&quot;&gt;:name&lt;/span&gt; sanitized-name)))))
&lt;/pre&gt;


&lt;p&gt;
Once the new function is evaluated, running the test suite again
should pass.
&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div id=&quot;outline-container-8&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-8&quot;&gt;Conclusion &lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-8&quot;&gt;


&lt;p&gt;
There&apos;s a lot of places to go from here. The CSS we wrote gets
generated on every load. A caching mechanism would be nice. There&apos;s no
way to delete entries, or to make sure unscrupulous people aren&apos;t
voting more than once. It would be cool if we added some information
to the games, such as publisher, year, and so on &amp;ndash; maybe even box
art and screenshots, which would mean dealing with file uploads. We
don&apos;t have tests for our controller functions.
&lt;/p&gt;
&lt;p&gt;
However, we&apos;ve brought our little game voter a little closer to a
solid, robust modern web application. I hope I&apos;ve managed to show off
how easy it is to extend and refactor a small Lisp project, and have
piqued your interest into giving it a try for web development. You&apos;ll
be amazed how easy it is to start thinking in Lisp.
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
      <guid>msnyder.info:entry:lisp-for-the-web-part-ii.org</guid>
      <pubDate>Fri, 29 Jul 2011 00:00:00 EDT</pubDate>
    </item>
    <item>
      <title>The Myth of the Heartbeat Friend or: How I Learned to Stop Worrying And Tell Facebook to Fuck Off</title>
      <link>http://msnyder.info/posts/2011/05/heartbeat-friend/</link>
      <description>
&lt;p&gt;I am done with Facebook. This is for several reasons, most of them
uninteresting and pedantic. However, I’d like to take this time to
express some thoughts on Facebook and social networks in general.
&lt;/p&gt;
&lt;p&gt;
Facebook is just one random website that we all choose to flock
to. There is nothing special about it, nothing specific. Just as
everybody once had AIM or Yahoo! chat accounts, just as everybody uses
Gmail; everyone uses Facebook now. It has grown to occupy a
non-trivial amount of space in our shared culture. It is also
demeaning, patronizing, and a dangerous threat to our privacy.
&lt;/p&gt;
&lt;p&gt;
It already has an air of staleness about it, and once our children
grow up and start looking for ways to social network, they will find
it filled with out-of-touch, older people (that’s us, by the way) and
find another avenue to express themselves. Facebook will never die
completely, but rather fade off into obscurity while newer, more
modern sources of social interaction pop up. People will be urged to
join the latest and greatest social network, fragmenting their on-line
identities even more. I am perturbed by the idea of having an ‘on-line
identity’ in the first place; if I must, I’d rather have as much
control over it as possible.
&lt;/p&gt;
&lt;p&gt;
So what is to be done? I shall explain the route I am taking, as an
example. I will fill my Facebook with random data. I’ll probably do
this two or three times, in case Facebook’s database keeps profile
changes past one or two revisions. I will edit my comments when
possible, and remove them when necessary. Then I will delete my
account completely.
&lt;/p&gt;
&lt;p&gt;
After this, I will direct people to my personal website:
&lt;a href=&quot;http://msnyder.info&quot;&gt;http://msnyder.info&lt;/a&gt;. On this site is and will be everything that is
important to me: cogent entries, a photo gallery, links to compelling
websites and essays. Everything I use Facebook for, under my own
purview and my own ‘privacy controls’. The work I’m doing on this site
is far from complete, but I am optimistic I will be able to create a
safe space for myself, the people who care about me, and those who are
passionate about the same things as I.
&lt;/p&gt;
&lt;p&gt;
The communication aspect of Facebook is the more difficult one. Social
networks encourage a specific kind of social interaction. This kind is
public, curt, succinct, and transient. It does not encourage reasoned
discussion, articulation, or privacy. This is because Facebook is not
interested in friendship as people typically define it. Facebook is
interested in friendship because a group of friends forms a graph, and
the more nodes they connect with relationships, the more explicit the
graph, the more money is made off of these relationships. With
Facebook, friendship is a unit of currency; moreso, it devalues the
actual value of friendship in favor of a heartbeat system: pulses in a
news feed ensuring that the people we care about and cherish are still
updating their feeds. This isn’t friendship. This isn’t even social
interaction. It’s an addiction to updates, a demand for the dopamine
that floods our system when we see a post on our wall, or an update in
our feed.
&lt;/p&gt;
&lt;p&gt;
So while I am foregoing this instant-gratification syndrome that
Facebook has cultivated, I still wish to hear from people. How? Any
way! Text messages, IMs, rambling e-mails, handwritten letters. I
desire a return to the form of writing that has worked perfectly well
for thousands of years. If you want to write me a letter, send me a
message; I’ll happily reply with my snail-mail address. In the past
the collected letters of authors, playwrights, artists, and
politicians were bound and published as meaningful and visceral
insights into their lives. I doubt anyone will ever do the same for
their status updates.
&lt;/p&gt;
&lt;p&gt;
Some people may take umbrage with my opinion of Facebook. One argument
which has already surfaced is, “But what about Gmail? Google could be
reading your e-mail and you’re not doing anything about it, and you’re
certainly not writing winding blog entries about &lt;i&gt;that&lt;/i&gt;.” Yes, I will
continue to use Gmail. Why? Because I &lt;i&gt;trust&lt;/i&gt; Gmail. This is not the
case with Facebook. If and when Gmail violates that trust, I will
enact &lt;a href=&quot;http://en.wikipedia.org/wiki/Pretty_Good_Privacy&quot;&gt;PGP&lt;/a&gt; privacy controls, I will look to another e-mail provider,
and eventually host my own e-mail server, if it becomes
necessary. That’s one of the main issues in this whole crazy game:
trust. Facebook and its partners have already proved time and time
again that they care very little for the privacy and well-being of its
users, and not at all for the trust that is nurtured between users and
service providers.
&lt;/p&gt;
&lt;p&gt;
So, adieu. If you’d like to get in touch with me after this, and don’t
know how to at the moment, you can find my e-mail address quite easily
by visiting my website. Just remember: m snyder dot info. Simple.
&lt;/p&gt;
&lt;p&gt;
And remember, in Facebook, as on other social networks, and all
different paths of life: &lt;a href=&quot;http://twitter.com/petterihiisila/status/22602545109&quot;&gt;&quot;If you&apos;re not paying for it, you&apos;re not the customer; you are the product being sold.&quot;&lt;/a&gt;
&lt;/p&gt;</description>
      <guid>msnyder.info:entry:heartbeat-friend.org</guid>
      <pubDate>Sat, 28 May 2011 00:00:00 EDT</pubDate>
    </item>
    <item>
      <title>Fallout 2 Journal Part I</title>
      <link>http://msnyder.info/posts/2010/10/fallout-2-journal-part-one/</link>
      <description>
&lt;p&gt;&lt;b&gt;Note: It should be more than obvious that I will be discussing  Fallout 2 in such a way that involves spoilers. Don&apos;t read this article, or any article in this series, if you intend on a spoiler-free Fallout 2 experience.&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;
I finally decided to sit down and put some time into Fallout 2. I
anticipated a quirky, post-apocalyptic romp through an America stuck
in the bizarro 1950s, punctuated with engaging gunfights. In effect,
the only thing I knew about the game was that it was an isometric RPG,
and the only thing i knew about the canon and atmosphere was informed
by Fallout 3. My expectations were almost immediately shot down, and I
couldn&apos;t be happier.
&lt;/p&gt;
&lt;p&gt;
Fallout 2 is unforgiving. It is stark, desolate, at once brutal and
sensitive, at once expansive and detailed. I haven&apos;t put more than ten
hours or so into it, and it is easily one of the most difficult games
I have ever played. Once again, I couldn&apos;t be happier.
&lt;/p&gt;
&lt;p&gt;
I downloaded Fallout 2 off of Steam and applied Killap&apos;s &lt;a href=&quot;http://www.killap.net&quot;&gt;Restoration Project&lt;/a&gt;, more for the ability to play at higher resolution than for
the patched content, which I glanced at in summary but didn&apos;t
absorb. The patch accommodated my request to play at 1680x1050 but I
found it difficult to read the HUD text at that size, and switched to
a more reasonable 1024x768.
&lt;/p&gt;
&lt;p&gt;
The impression that you get from Fallout 3 is that the America
affected by the nuclear war was flash-frozen in a psuedo-1950s, and
that the recovering civilization from then on was simmered in that
specific atmosphere. In Fallout 2&amp;mdash;at least in my playthrough so
far&amp;mdash;this couldn&apos;t be further from the truth. Your character hails
from what can only be described as savage. The places you visit don&apos;t
have enough set pieces to simulate any kind of ambiance. The basic
descriptive language is: &quot;dry, rotting, dirty, low&quot;. Even cities that
have been touched by industry follow this pattern; hollowed out husks
of buildings, drug-addled vagrants wandering the streets mumbling to
themselves in chemical hazes. In Fallout 3 the happy-go-lucky Galaxy
News Radio and the lost-in-the-Golden-era residents were an ironic
counterpoint to the world they inhabited. In Fallout 2, there is no
room for irony. These are people for which every day in a struggle,
and any day could be their last. The stage is appropriately set.
&lt;/p&gt;
&lt;p&gt;
I spent about an hour in the introductory temple, and got my ass
handed to me so consistently I swore it was an incongruity in how I
rolled my character. I rolled again, taking care to pay attention to
the attributes I enhanced, and the abilities I tagged. The next time
through was a little easier, but I still saved before and after every
single fight, and used most of my action points per turn running away
from my enemies so they wouldn&apos;t have points left, after catching up
to me, to get in an attack.
&lt;/p&gt;
&lt;p&gt;
The artificial economy is incredibly well done. I wandered into my
first city loaded up with Radscorpion tails, wondering what kind of
firearms I&apos;d be able to barter for. The answer? None. There were none
of any kind available. At best I was able to steal a basic rifle: a
pop gun in comparison to my foes. Even after I had trudged through the
quests of the first city, and made my way to the second one, there was
at most one pistol and one machine gun available for purchase. The
pistol was 30 times more expensive than the cash I had on hand; the
machine gun, even more expensive than that. It gave the impression of
a deserted, empty world. This wasn&apos;t Fallout 3, with spare rifles and
grenades around every corner.
&lt;/p&gt;
&lt;p&gt;
As unprepared as I was for the combat and difficulty, I was even
more so for how the game reacted to me. I traipsed into a bar looking
for information and trade. The bartender had nothing to trade but
women and whiskey, the latter being 20 dollars a glass. On a whim, I
chose a dialog option insulting him for the steep price of his
booze. He got into a fight with me about it. I said something else
stupid, and we left the dialog screen and entered combat when he
punched me in the gut. By about this time, I had had enough of people
trying to beat me up for whatever arbitrary reason, so I kicked him in
the groin and shot the fucker. If you&apos;ve had any experience with
Fallout 3, this would be the time when you reloaded, since killing a
member of a community typically sets that whole community against
you. In Fallout 2, in this case: no one moved. The entire bar was
docile, staring into their glasses. Steeped in roleplay, I imagined
this was just another day of reckless violence for them. There were no
loyalties; there was another bar where they could drink. When I
returned to the town some time later, a sign had been placed over the
entrance to the bar: &lt;i&gt;Out of Business&lt;/i&gt;. That was incredible to me.
&lt;/p&gt;
&lt;p&gt;
My playthrough ended, for the time being, based on my own stupidity. I
fell through a trap rug in a deserted farm, to find a group of people
who had eked an existence out underground. They asked me to return a
letter to the surface, and I dropped it somewhere in a
cornfield. After spending about twenty or so minutes clicking around
trying to find it, I gave up, and discovered I hadn&apos;t saved in the
past half hour.
&lt;/p&gt;
&lt;p&gt;
I&apos;m probably going to roll again, and pay much more attention to the
things I&apos;m trying to accomplish in the game. I&apos;ll chronicle that in
another entry. For now, some final thoughts and advice:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Combat is a bitch, and you need to pare it down at the beginning
  just to survive. You will be running away, a lot, from things you
  believe you are equipped to handle. Combat is also monumentally
  frustrating at the default speed. Change it before you go insane.

&lt;/li&gt;
&lt;li&gt;It helps to actually equip your party.

&lt;/li&gt;
&lt;li&gt;Use of healing powder includes a dent to your Perception skill. Only
  use it when you know you can sacrifice the hit. Maybe there&apos;s
  another drug to counteract that effect, but then you introduce
  addiction, etc.
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <guid>msnyder.info:entry:fallout-2-journal-part-one.org</guid>
      <pubDate>Sun, 17 Oct 2010 00:00:00 EDT</pubDate>
    </item>
  </channel>
</rss>