<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Paul Legato</title>
	
	<link>http://www.paullegato.com</link>
	<description />
	<lastBuildDate>Sat, 07 Aug 2010 23:28:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PaulLegato" /><feedburner:info uri="paullegato" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>PaulLegato</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Dell PowerEdge BIOS Upgrade on Linux</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/DbyaiBtXMqc/</link>
		<comments>http://www.paullegato.com/blog/dell-poweredge-bios-linux/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 05:13:59 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=372</guid>
		<description><![CDATA[How to flash the BIOS on a Linux Dell PowerEdge system without having to use MS Windows.]]></description>
			<content:encoded><![CDATA[<p>Dell only provides certain PowerEdge BIOS flash upgrades in the form of Windows-only self-extracting archives (despite the facts that they claim to officially support Linux and that the BIOS flash utility itself is a DOS program.) Ordinary <code>unzip</code> won&#8217;t open the self-extracting archive. You need to run it on a Windows system, which I don&#8217;t have. Here&#8217;s how to flash your PowerEdge BIOS without Windows.</p>
<p>Dell provides the <a href="http://linux.dell.com/projects.shtml#biosdisk">biosdisk utility</a> to make a bootable FreeDOS image with the BIOS upgrade executable on it, but it doesn&#8217;t work with the Windows-only PowerEdge 4400 BIOS upgrade, since that won&#8217;t run on FreeDOS. They claim that <code>biosdisk</code> isn&#8217;t intended for PowerEdge systems, since they all have Linux BIOS flashes available; this does not seem to actually be the case for the 4400.</p>
<p>The Windows self-extractor <em>does</em> run under WINE, but it demands an actual floppy drive device to write to, which my computer doesn&#8217;t have. WINE also doesn&#8217;t seem to support mounting an image file as a floppy device, for some reason. You&#8217;ll need to use something like VMWare or a computer with a physical floppy drive to get this to extract itself.</p>
<p>Once you have a floppy image, here&#8217;s how to flash without biosdisk or Windows available: <span id="more-372"></span></p>
<ol>
<li><strong>Use <a href="http://wiki.winehq.org/FrontPage">WINE</a> to extract the archive.</strong> For maximum fun, the upgrade I have refuses to just extract itself; instead, it requires that it has access to a floppy drive to write to directly. Sigh. Ok. Working on that. Updates to come. <code>winecfg</code>
<li><strong>Install <a href="http://syslinux.zytor.com/wiki/index.php/The_Syslinux_Project">syslinux</a>.</strong>  (<code>apt-get install syslinux</code>). We are going to use <a href="http://syslinux.zytor.com/wiki/index.php/MEMDISK">memdisk</a>, a boot loader that creates a RAM drive and then loads an operating system, to load FreeDOS.</li>
<li><strong>Get a<a href="http://www.fdos.org/bootdisks/" class="broken_link"> FreeDOS boot disk image</a> and add your flashing .exe to it.</strong>Mount with something like <code>mount -t vfat /path/to/freedos.img /mnt -o loop</code>, then just <code>cp</code> your flashing .exe to <code>/mnt</code>. (If you got a gzipped image, <code>gunzip</code> it first.</li>
<li><strong>Edit /etc/grub.d/40_custom to add a boot menu entry for memdisk/FreeDOS.</strong>
<pre class="brush: plain;">
menuentry &quot;FreeDOS&quot; {
    set root=(hd0,2) #### &lt;--- Change this to your /boot partition!
    linux16 /memdisk floppy
    initrd16 /freedos.img
}
</pre>
<p>As noted, change the root entry to point to your actual /boot partition, so GRUB can find the images. Also note that the partition normally mounted at <code>/boot</code> will be mounted as the root directory (/) at boot time, so it&#8217;s not necessary to prefix <code>/boot</code> before the image file names.</p>
<p>Then, reboot and select FreeDos from the GRUB menu. Run your DOS-based flash program, and all is well.</p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=372&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/dell-poweredge-bios-linux/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/DbyaiBtXMqc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/dell-poweredge-bios-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/dell-poweredge-bios-linux/</feedburner:origLink></item>
		<item>
		<title>Swing-Clojure GUI for the Black-Scholes Option Modeler</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/SO-9Bo6Ctgc/</link>
		<comments>http://www.paullegato.com/blog/swing-clojure-gui-black-scholes/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 07:55:56 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[finance]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=352</guid>
		<description><![CDATA[Now that we have implemented Black-Scholes in Clojure, let&#8217;s make a Swing GUI for it. The Swing GUI will have text boxes for all the necessary inputs, and calculate prices and Greeks when the button is pressed. It&#8217;s a simple and straightforward way to get started in Swing GUI programming in Clojure. Here&#8217;s what it [...]]]></description>
			<content:encoded><![CDATA[<p>Now that we have implemented <a href="http://www.paullegato.com/blog/black-scholes-clojure/">Black-Scholes in Clojure</a>, let&#8217;s make <a href="http://github.com/pjlegato/clojure_options">a Swing GUI for it</a>. The Swing GUI will have text boxes for all the necessary inputs, and calculate prices and Greeks when the button is pressed. It&#8217;s a simple and straightforward way to get started in Swing GUI programming in Clojure. Here&#8217;s what it looks like. <a href="http://www.paullegato.com/wp-content/uploads/2010/07/Swing-GUI-Clojure-Black-Scholes.png"><img src="http://www.paullegato.com/wp-content/uploads/2010/07/Swing-GUI-Clojure-Black-Scholes.png" alt="Screenshot of the Swing GUI for the Black-Scholes option modeler, implemented in Clojure" title="Swing-GUI-Clojure-Black-Scholes" width="569" height="355" class="alignright size-full wp-image-354" /></a></p>
<p>The GUI is written entirely in Clojure with the Swing toolkit. Calculation state is stored in a series of atoms. Watches are used to update the output table automatically when an atom changes, <a href="http://kotka.de/blog/2010/05/Decoupling_Logic_and_GUI.html">an idea from Kotka</a>. I used the excellent <a href="http://www.miglayout.com/">MiG Layout</a> for general layout functionality, and generic Swing widgets (JTextFields and a JTable) for the input and output.<br />
<span id="more-352"></span></p>
<h2>Clojure code</h2>
<p>The Black-Scholes GUI is launched with the<code>main</code> function. The Swing GUI is actually created in the <code>initialize-gui</code> function, but since <a href="http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html">Swing widgets are not threadsafe</a>, we must use the <code>do-swing*</code> helper function from Clojure Contrib to spin off the real GUI creation code into the Swing event thread.</p>
<pre class="brush: clojure;">
(defn initialize-gui
  []
  (let [frame (JFrame. &quot;Black-Scholes Option Modeler&quot;)]

    (doto frame
      (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
      (-&gt; .getContentPane
          (.add (miglayout (JPanel.)

                           (input-panel
                            (fn [_]
                              (do-swing
                               (doto frame
                                 (.setVisible false)
                                 (.dispose)))))

                           (result-table)

                           )))

      (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
      (.pack)
      (.setVisible true))
     ))

(defn main
  []
  (do-swing* :now initialize-gui))
</pre>
<p>This is pretty straightforward. We make a (locally scoped) JFrame to be the main container at line 3. Within the context of the <code>let</code>, we add a JPane using MiG Layout to its content area (starting at line 8). The JPanel itself contains two subwidgets, which are those returned from the <code>input-panel</code> and <code>result-table</code> functions.</p>
<p>Note that we are passing an anonymous function to <code>input-panel</code> at line 11. The input panel contains the &#8220;Quit&#8221; button, and that button needs to know what to do when it&#8217;s pressed. We want it to close the GUI; that is, it should destroy the outer JFrame. To do that, it needs a reference to it. However, as a local variable in <code>initialize-gui</code>, the JFrame is not in scope elsewhere; we have to pass it in. The given function closes over the JFrame reference (line 13) and transports it to <code>input-panel</code>, where that function will be called as an event listener when the &#8220;Quit&#8221; button is pressed.</p>
<p>We could also have simply passed the bare JFrame rather than a function, and moved the frame-closing code into <code>input-panel</code>, but that would imply that the input panel must always be in a JFrame, which will not necessarily the case. Passing in an external anonymous function to be activated by the &#8220;Quit&#8221; button allows the input panel to be used generically in any sort of container, with the container deciding what to do when &#8220;Quit&#8221; is pressed.</p>
<h3>The Input Panel</h3>
<pre class="brush: clojure;">

(defn- input-panel [quit-action]
    (let [
          ;; Fields
          spot (doto (JFormattedTextField. (NumberFormat/getNumberInstance))
                 (.setColumns 6)
                 (.setValue @*spot*))

          strike (doto (JFormattedTextField. (NumberFormat/getNumberInstance))
                   (.setColumns 6)
                   (.setValue @*strike*))

          days-till-expiry (doto (JFormattedTextField. (NumberFormat/getIntegerInstance))
                             (.setColumns 6)
                             (.setValue @*days-till-expiry*))

          riskfree (doto (JFormattedTextField. (NumberFormat/getNumberInstance))
                     (.setColumns 6)
                     (.setValue @*riskfree*))

          volatility (doto (JFormattedTextField. (NumberFormat/getNumberInstance))
                       (.setColumns 6)
                       (.setValue @*volatility*))

          ;; Buttons
          calculate (JButton. &quot;Calculate&quot;)
          quit (JButton. &quot;Quit&quot;)
          ]

      (add-action-listener
       calculate
       (fn [_]
         (update-all-calculations
          (Double/parseDouble (.getText spot))
          (/ (Integer/parseInt (.getText days-till-expiry)) *trading-days-per-year*)
          (Double/parseDouble (.getText strike))
          (Double/parseDouble (.getText riskfree))
          (Double/parseDouble (.getText volatility)))))

      (add-action-listener
       quit
       quit-action)

      (miglayout (JPanel.)
                 :layout  [:wrap 2 ]

                 (JLabel. &quot;Spot&quot;) [:align &quot;right&quot;]
                 spot

                 (JLabel. &quot;Strike&quot;) [:align &quot;right&quot;]
                 strike

                 (JLabel. &quot;Risk-free rate&quot;) [:align &quot;right&quot;]
                 riskfree

                 (JLabel. &quot;Volatility&quot;) [:align &quot;right&quot;]
                 volatility

                 (JLabel. &quot;Days till expiry&quot;) [:align &quot;right&quot;]
                 days-till-expiry

                 calculate
                 quit)))
</pre>
<p>The input widgets are local variables in the input panel function, along with the two buttons. The widgets are initialized from the state atoms (which are then unused again; see discussion below.) The &#8220;Quit&#8221; button is given the event callback passed in as an argument (so it can manipulate the enclosing JFrame as per above.) The &#8220;Calculate&#8221; button is given an event callback that calls the <code>update-all-calculations</code> function with the values in the input widgets.</p>
<p>The lot are then stuffed into a JPanel with a MiG Layout and returned.</p>
<h3>The Output Table</h3>
<pre class="brush: clojure;">
(defn- update-cell
  &quot;Updates the given AbstractTableModel cell and fires a change event for that cell.&quot;
  [model data row col]
  (.setValueAt model data row col)
  (.fireTableCellUpdated model row col))

(defn- result-table []
  (let [
        column-names [&quot;&quot; &quot;Call&quot; &quot;Put&quot;]
        row-names [&quot;Price&quot; &quot;Delta&quot; &quot;Theta&quot; &quot;Rho&quot; &quot;Gamma&quot; &quot;Vega&quot;]
        table-model (proxy [AbstractTableModel] []
                      (getColumnCount [] (count column-names))
                      (getRowCount [] (count row-names))
                      (isCellEditable [] false)
                      (getColumnName [col] (nth column-names col))
                      (getValueAt [row col]
                                  (condp = col
                                      0 (nth row-names row) ;; Return the row name for column zero
                                      (condp = [row col]
                                          [0 1] @*call-price*
                                          [0 2] @*put-price*

                                          [1 1] @*call-delta*
                                          [1 2] @*put-delta*

                                          [2 1] @*call-theta*
                                          [2 2] @*put-theta*

                                          [3 1] @*call-rho*
                                          [3 2] @*put-rho*

                                          [4 1] @*gamma*
                                          [4 2] &quot;==&quot;

                                          [5 1] @*vega*
                                          [5 2] &quot;==&quot;

                                          nil))))

        table (doto (JTable. table-model)
                (.setGridColor java.awt.Color/DARK_GRAY))
        ]

    (add-watch *call-price* ::update-call-price (fn [_ _ _ newprice] (update-cell table-model newprice 0 1)))
    (add-watch *put-price* ::update-put-price (fn [_ _ _ newprice] (update-cell table-model newprice 0 2)))

    (add-watch *call-delta* ::update-call-delta (fn [_ _ _ newval] (update-cell table-model newval 1 1)))
    (add-watch *put-delta* ::update-put-delta (fn [_ _ _ newval] (update-cell table-model newval 1 2)))

    (add-watch *call-theta* ::update-call-theta (fn [_ _ _ newval] (update-cell table-model newval 2 1)))
    (add-watch *put-theta* ::update-put-theta (fn [_ _ _ newval] (update-cell table-model newval 2 2)))

    (add-watch *call-rho* ::update-call-rho (fn [_ _ _ newval] (update-cell table-model newval 3 1)))
    (add-watch *put-rho* ::update-put-rho (fn [_ _ _ newval] (update-cell table-model newval 3 2)))

    (add-watch *gamma* ::update-gamma (fn [_ _ _ newval] (update-cell table-model newval 4 1)))
    (add-watch *vega* ::update-vega (fn [_ _ _ newval] (update-cell table-model newval 5 1)))

    ;; This shrinks the table's preferred viewport down to its actual size.
    ;; (The default is to make a huge viewport, even though the table is small.)
    (.setPreferredScrollableViewportSize table (.getPreferredSize table))

    (JScrollPane. table)
    ))
</pre>
<p>The output table itself is a standard JTable. Its model is initialized from the output state atoms. The watches at lines 44-57 are the most interesting part; they allow arbitrary code to be called when the output state atoms change. This allows the Black-Scholes calculation to happen independently of the output widget. When one of those atoms is changed, it self-updates automatically via the watches.</p>
<p>The helper function at lines 1-5 updates the appropriate model cell and fires an event to tell the JTable to repaint it.</p>
<p>The scrollable viewport business at line 61 is to work around a questionable Java design decision where a JTable, by default, tells its container to make its viewport enormous, even though it have very little data. (That&#8217;s not an error, that&#8217;s subjunctive.)</p>
<h2>Design considerations</h2>
<h3>GUI and business logic decoupling</h3>
<p>Above all, the GUI has to be decoupled from the model itself. Internal changes to one should never affect the other, and the two should be independently testable. In such a simple application, this was easy enough. A more complex app that requires several information round trips would be trickier. We now have a good foundation for such an app. No business calculations are performed in the GUI code namespace. The sole point of connection is in the update-all-calculations function:</p>
<pre class="brush: clojure;">

(defn- update-all-calculations [spot timeleft strike riskfree sigma]
  (swap! *call-price* (fn [_] (bs/call spot timeleft strike riskfree sigma)))
  (swap! *put-price* (fn [_] (bs/put spot timeleft strike riskfree sigma)))

  (swap! *call-delta* (fn [_] (bs/call-delta spot timeleft strike riskfree sigma)))
  (swap! *put-delta* (fn [_] (bs/put-delta spot timeleft strike riskfree sigma)))

  (swap! *call-theta* (fn [_] (bs/call-theta spot timeleft strike riskfree sigma)))
  (swap! *put-theta* (fn [_] (bs/put-theta spot timeleft strike riskfree sigma)))

  (swap! *call-rho* (fn [_] (bs/call-rho spot timeleft strike riskfree sigma)))
  (swap! *put-rho* (fn [_] (bs/put-rho spot timeleft strike riskfree sigma)))

  (swap! *vega* (fn [_] (bs/vega spot timeleft strike riskfree sigma)))
  (swap! *gamma* (fn [_] (bs/gamma spot timeleft strike riskfree sigma))))
</pre>
<h3>Atoms to hold state</h3>
<p>As we can see above, set of atoms holds state for the GUI, in keeping with the general Clojure principle of isolating state into transactional memory. (Actually, I cheated a bit. Our full state consists of the input values and the results of our Black-Scholes calculations. Although I created atoms for the input state values as well, I calculate the results directly from the widgets. It is a trivial exercise to alter the &#8220;Calculate&#8221; button callback to use the atoms. This would be more useful in the case where changes to a widget fire an event that triggers recalculation, which is not done in this demo as per below. I would use the atoms in a real application.)</p>
<p>I/O is inherently stateful, as are GUIs. There was therefore the temptation to use the Swing widget objects themselves as state-holders, and in fact it requires extra code to shuttle data back and forth between the widgets and the atoms. In such a simple app as this, using the GUI widgets as state-holders does not make much practical difference, but in a more complex app, a well designed set of state atoms and watches can automate much of the tedious GUI logic.</p>
<p>Using the widgets directly as state holders implies a tight coupling between the input widgets, the business logic, and the output widgets. Changing any one of them would invariably have required changes to the linking logic.</p>
<p>For example, suppose we were using widgets-as-state, and we changed the &#8220;days left till expiry&#8221; input to a slider rather than a text box, or suppose we wanted to read it from a file or from an API. We would have to update the code that reads it, calculates the model, and puts the results into the output table. Touching that code implies a non-zero likelihood of breaking it. Why even introduce the potential for breaking something that is unrelated to the task at hand, in this case the business logic and output code?</p>
<p>Again, this seems trivial with such a very small application that is only a few lines long, but the design principle is what&#8217;s important. Imagine applying it to a much larger application with hundreds of inputs spread across 4 windows, 3 databases, and 6 web feeds to see why this is a good idea.</p>
<h3>Auto-updating results when input changes</h3>
<p>I wanted the results to auto-update anytime an input is changed, without resorting to a &#8220;Calculate&#8221; button. Having the button trigger the calculation and output update allows the state of the input and the output to become decoupled, which can be confusing for the user. Worse, it could be unnoticed by a user who is doing other things at the same time.</p>
<p>Due to typical Java overengineering, there is no straightforward way to simply <code>(add-action-listener)</code> on the JTextField and get notifications when it changes. Instead, <a href="http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/uiswing/components/generaltext.html#document">each Swing widget implements full-blown model-view separation</a>, and so you have to get the document underlying the JTextField. Yes, the view components of your MVC application themselves contain both models and views. Each and every field contains an entire implementation of the document object and associated cruft, all for itself. If you want to monitor changes in the widget, you need to build out a <code>DocumentListener</code> to watch for such events.</p>
<p>In a real application, I&#8217;d bite the bullet and implement it, but it&#8217;s not worth the extra time for the purposes of this demo, so we are left with a &#8220;Calculate&#8221; button and manual updating.</p>
<h2>Clojure-Options on Github</h2>
<p>The entire package so far is now <a href="http://github.com/pjlegato/clojure_options">available on my GitHub page</a>. Patches are welcome. Atomizing the input widgets and adding the appropriate event callbacks and watches to eliminate the &#8220;Calculate&#8221; button is particularly welcome. <img src='http://www.paullegato.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=352&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/swing-clojure-gui-black-scholes/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/SO-9Bo6Ctgc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/swing-clojure-gui-black-scholes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/swing-clojure-gui-black-scholes/</feedburner:origLink></item>
		<item>
		<title>Black-Scholes in Clojure</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/98UPP2DNxMU/</link>
		<comments>http://www.paullegato.com/blog/black-scholes-clojure/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 00:51:27 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[finance]]></category>
		<category><![CDATA[quant]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=345</guid>
		<description><![CDATA[The Black-Scholes option pricing model, implemented in Clojure based on the description at Wikipedia and these code samples. ;; ;; Black-Scholes option pricing model ;; ;; Copyright (C) 2010 Paul Legato. All rights reserved. ;; Licensed under the New BSD License. See the README file for details. ;; ;; Disclaimer: This code comes with NO [...]]]></description>
			<content:encoded><![CDATA[<p>The Black-Scholes option pricing model, implemented in Clojure based on <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Black–Scholes">the description at Wikipedia</a> and <a href="http://www.espenhaug.com/black_scholes.html">these code samples</a>.<br />
<span id="more-345"></span></p>
<pre class="brush: clojure;">
;;
;; Black-Scholes option pricing model
;;
;; Copyright (C) 2010 Paul Legato. All rights reserved.
;; Licensed under the New BSD License. See the README file for details.
;;
;; Disclaimer: This code comes with NO WARRANTY, express or implied.
;; There may be any number of bugs. Use at your own risk.
;;
;; References:
;; - https://secure.wikimedia.org/wikipedia/en/wiki/Black%E2%80%93Scholes
;; - http://www.espenhaug.com/black_scholes.html

(ns clojure-options.black-scholes
  (:require incanter.distributions))

(defn d1
  [spot timeleft strike riskfree sigma]
  (/
   (+ (Math/log (/ spot strike))
      (* (+ riskfree (/ (* sigma sigma) 2))
         timeleft))
   (* sigma (Math/sqrt timeleft))))

(defn d2
  [spot timeleft strike riskfree sigma]
  (- (d1 spot timeleft strike riskfree sigma) (* sigma (Math/sqrt timeleft))))

(defn- n [val] (incanter.distributions/cdf (incanter.distributions/normal-distribution) val))

(defn call
  &quot;Returns the theoretic value of a European call option on the given underlying based on the Black-Scholes model.

 * spot - spot price of the underlying
 * timeleft - time to expiration, in years
 * strike - option strike price
 * riskfree - annual continuous risk-free interest rate
 * sigma - volatility of the underlying

&quot;
  [spot timeleft strike riskfree sigma]
  (- (* spot (n (d1 spot timeleft strike riskfree sigma)))
     (* strike
        (Math/exp (* (- riskfree) timeleft))
        (n (d2 spot timeleft strike riskfree sigma)))))

(defn put
  &quot;Returns the theoretic value of a European put option on the given underlying based on the Black-Scholes model.

 * spot - spot price of the underlying
 * timeleft - time to expiration, in years
 * strike - option strike price
 * riskfree - annual continuous risk-free interest rate
 * sigma - volatility of the underlying

&quot;
  [spot timeleft strike riskfree sigma]
  (- (* strike
        (Math/exp (* (- riskfree) timeleft))
        (n (- (d2 spot timeleft strike riskfree sigma))))
     (* spot (n (- (d1 spot timeleft strike riskfree sigma))))))

(defn call-delta
  [spot timeleft strike riskfree sigma]
  (n (d1 spot timeleft strike riskfree sigma)))

(defn put-delta
  [spot timeleft strike riskfree sigma]
  (- (n (d1 spot timeleft strike riskfree sigma)) 1))

(defn- nprime [val] (incanter.distributions/pdf (incanter.distributions/normal-distribution) val))

(defn gamma
  [spot timeleft strike riskfree sigma]
  (/ (nprime (d1 spot timeleft strike riskfree sigma))
     (* spot sigma (Math/sqrt timeleft))))

(defn vega
  [spot timeleft strike riskfree sigma]
  (* spot (nprime (d1 spot timeleft strike riskfree sigma)) (Math/sqrt timeleft)))

(defn call-theta
  [spot timeleft strike riskfree sigma]
  (-
   (- (/ (* spot (nprime (d1 spot timeleft strike riskfree sigma)) sigma)
         (* 2 (Math/sqrt timeleft))))
   (* riskfree strike (Math/exp (* (- riskfree) timeleft)) (n (d2 spot timeleft strike riskfree sigma)))))

(defn put-theta
  [spot timeleft strike riskfree sigma]
  (-
   (- (/ (* spot (nprime (d1 spot timeleft strike riskfree sigma)) sigma)
         (* 2 (Math/sqrt timeleft))))
   (* riskfree strike (Math/exp (* (- riskfree) timeleft)) (n (- (d2 spot timeleft strike riskfree sigma))))))

(defn call-rho
  [spot timeleft strike riskfree sigma]
  (* strike timeleft (Math/exp (* (- riskfree) timeleft)) (n (d2 spot timeleft strike riskfree sigma))))

(defn put-rho
  [spot timeleft strike riskfree sigma]
  (* (- strike) timeleft (Math/exp (* (- riskfree) timeleft)) (n (- (d2 spot timeleft strike riskfree sigma)))))
</pre>
<p>This code uses the new <a href="http://liebke.github.com/incanter/distributions-api.html">Incanter Distributions module</a>, which hasn&#8217;t been released yet, so it requires the latest master version from Github.</p>
<p>Most of the values agree with those produced at <a href="http://www.blobek.com/black-scholes.html">BloBek&#8217;s calculator</a>, with the exception of theta. I imagine this has to do with the units used for the &#8220;days left to expiration&#8221; field; my calculator uses fractions of a year, while BloBek doesn&#8217;t specify whether his days are to be trading days or calendar days. It could also be a bug in one of our implementations.</p>
<p>In Part 2, I&#8217;ll build a simple Swing GUI for the calculator.<br />
<b>Update:</b> <a href="http://www.paullegato.com/blog/swing-clojure-gui-black-scholes/">Part 2, with the Swing GUI</a>, is now available. You can also get <a href="http://github.com/pjlegato/clojure_options">the entire project&#8217;s source code</a> from GitHub.</p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=345&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/black-scholes-clojure/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/98UPP2DNxMU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/black-scholes-clojure/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/black-scholes-clojure/</feedburner:origLink></item>
		<item>
		<title>A Rebuttal for Kartik Athreya</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/SjtK_AjmzSE/</link>
		<comments>http://www.paullegato.com/blog/kartik-athreya-rebuttal/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 11:19:48 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Economics]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=321</guid>
		<description><![CDATA[Kartik Athreya&#8217;s article deriding the unwashed, mouth-breathing public for presumptuously daring to have an opinion about his area of expertise is making the rounds, predictably being slammed by those of us with the audacity to hold an opinion about some subject in which we lack a PhD. I list reasons why professional &#8220;expert&#8221; economists are [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.scribd.com/doc/33655771/Economics-is-Hard">Kartik Athreya&#8217;s article</a> deriding the unwashed, mouth-breathing public for presumptuously daring to have an opinion about his area of expertise is <a href="http://www.economist.com/blogs/freeexchange/2010/06/economics_2">making</a> the <a href="http://www.zerohedge.com/article/fed-has-lost-it-publishes-essay-bashing-bloggers-tells-general-public-broadly-ignore-those-w">rounds</a>, predictably <a href="http://www.themoneyillusion.com/?p=5834">being</a> <a href="http://yglesias.thinkprogress.org/2010/06/do-i-have-anything-interesting-to-say/">slammed</a> by those of us with the audacity to hold an opinion about some subject in which we lack a PhD. I list reasons why professional &#8220;expert&#8221; economists are useless or even dangerous, and why Athreya&#8217;s real problem is American culture.</p>
<ol>
<li><strong>Economists&#8217; general failure to have made many useful predictions in the past, as a profession.</strong> How many trained, qualified PhD economists warned us about the onset of the Great Recession in 2006? Right. About as many as predicted the Great Depression or the Panic of 1873 or the end of the gold standard or the &#8217;70s oil shocks or the &#8217;87 stock market crash or &#8230;
<p>I own <em>Business Fluctuations</em>, a 1952 textbook by UC Berkeley economics professor <a href="http://www.jstor.org/stable/2534264?cookieSet=1">Robert Aaron Gordon</a>, which has a quaint section entitled &#8220;IS THE BUSINESS CYCLE OBSOLETE?&#8221;</p>
<p>How about bona fide, credentialed economist <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Irving_Fisher">Irving Fisher</a>&#8216;s famous 1929 pronouncement that <em>&#8220;Stock prices have reached what looks like a permanently high plateau&#8221;</em>? </p>
<p>It&#8217;s not just that one or a few fringe economists occasionally make wacky analyses of the economy that turn out to be totally false; <em>the profession as a whole</em> does it, and has been doing it repeatedly for as long as anyone can remember. These guys were not fringe nutjobs. These views were reasonably mainstream at the time they expressed them.</p>
<p><a href="http://en.wikipedia.org/wiki/Critical_rationalism">Theories that do not make falsifiable, testable predictions are pseudoscience</a>. A theory cannot explain every possible outcome, else there is no way to test it and it is not falsifiable.</p>
<p>Embracing their theories as expert advice even after their repeated failure to demonstrate any accurate predictive ability is worse than useless. It&#8217;s dangerous. Remember that Alan Greenspan guy? What was his profession, again?
</li>
<li><strong>The vast incidence of massively contradictory economic paradigms held by various &#8220;experts&#8221;.</strong> Keynes versus Friedman springs to mind at once, and let&#8217;s not even touch Marx or Soros. Efficient market hypothesis, anyone? Ask 10 economists today merely whether and why we will see deflation or inflation in the US, and you will get 10 contradictory, mutually exclusive answers.
<p>To extend Athreya&#8217;s cancer analogy, it&#8217;s as if one oncologist expert says cancer is caused by genes and requires gene therapy; another says it&#8217;s caused by fluoride in the water and needs wholesale tooth extraction; a third says it&#8217;s caused by ragweed pollen and just requires an antihistamine; a fourth says the patient&#8217;s <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Humorism">bodily humours</a> are merely imbalanced, but bloodletting with leeches is a sure cure in his vast and storied professional experience; and yet another says that cancer is caused by Mars having passed too close to Sagittarius on the patient&#8217;s birthday, so nothing can be done except perhaps a sacrifice to the gods. And still none of them can predict with any accuracy at all who will get cancer, much less tell you how to cure it with better-than-chance accuracy.</p>
<p>Little respect would naturally develop for such a profession, and members of the public would feel well qualified to add their own opinions and contributions, since they couldn&#8217;t possibly do much worse than the self-designated &#8220;professionals&#8221;. And indeed, that was exactly how medicine worked in premodern times, until doctors began to put forth testable predictions that actually accurately predicted future conditions and developed rigorous, repeatable experiments to test them. Economics has not yet achieved any measure of remotely reliable prediction. Economics is today a protoscience at best.</p>
<p>Athreya himself says, &#8220;For my part, seventeen years after my ﬁrst PhD coursework, I still feel ill at ease with my grasp of many issues, and I am fairly conﬁdent that this is not just a question of limited intellect.&#8221; (This false humility is ostentatious and self-serving; it was written to say, &#8220;hey, this is so hard that even us experts don&#8217;t know what&#8217;s going on, so you amateurs should just all be quiet.&#8221;)</p>
<p>Some amateurs, like Soros, have consistently done far, far better than the pros. The field is simply extremely immature and not capable of providing very good answers to anyone. &#8220;Experts&#8221; are not special in that regard. They&#8217;re barely more aware of what&#8217;s going on than anyone else, and often they develop emotional attachment to theories that they have invested professional capital in, resulting in tunnel vision. When they can consistently predict significant economic events before they happen, and consistently do so better than amateurs, then they can begin to merit the respect accorded to oncologists.</p>
<p>As <a href="http://www.nakedcapitalism.com/2007/10/nicholas-taleb-attacks-pseudo-science.html">Nicholas Taleb says</a>:</p>
<blockquote><p>
The environment in financial economics is reminiscent of medieval medicine, which refused to incorporate the observations and experiences of the ple­beian barbers and surgeons. Medicine used to kill more patients than it saved – just as financial economics endangers the system by creating, not reducing, risk. But how did financial economics take on the appearance of a science? Not by experiments (perhaps the only true scientist who got the prize was Daniel Kahneman, who happens to be a psychologist, not an economist). It did so by drowning us in mathematics with abstract “theorems”. Prof Merton’s book Continuous Time Finance contains 339 mentions of the word “theorem” (or equivalent). An average physics book of the same length has 25 such mentions. Yet while economic models, it has been shown, work hardly better than random guesses or the intuition of cab drivers, physics can predict a wide range of phenomena with a tenth decimal precision.
</p></blockquote>
</li>
<li><strong>Economic policy requires concerted action by all, and its results have vast consequences for everyone.</strong> A choice of several potential cancer treatments is between the patient and his doctor. If oncologists disagree about which treatment is best, concluding a decision as to which to go with requires convincing at most a small handful of people: the patient and his family and close friends. The consequences of that choice will also rarely radiate much farther than that.
<p>Economic policy, on the other hand, requires the concerted efforts of substantially all of the population, via government agencies and their use (or lack thereof) of tax money (at least in a democracy.)  Ordinary people don&#8217;t know or care about the abstruse details; they just want to know how it will affect <em>them</em>. Enter politicians and big businesses, who, needless to say, do not always have pure motives. Public opinion can be manipulated easily.</p>
<p>Given that the choice of which policies to implement is a political choice that ultimately rests with the entire population; given that self-interested politicians, investment banks, and other capital institutions are actively seeking to manipulate that opinion for their own benefit; and given the gravity of policy choice ramifications for each and every member of society, Athreya&#8217;s position of &#8220;just leave it all to us experts and don&#8217;t insult us by trying to think about it&#8221; begins to seem positively Orwellian in tone.</p>
<li><strong>Perverse incentives reward bland economic thinking by the professionals; the &#8220;cover your ass&#8221; syndrome.</strong>
<p>Working professional economists are not rewarded for making <em>accurate</em> predictions about the future of the economy; they are rewarded for making <em>safe</em> predictions about it. (Safe for them, not for the economy.) You can see this in action every time new economic indicators come out. Bloomberg and the other financial news media run stories with &#8220;consensus estimates&#8221; which do not usually deviate very much from each other. When there&#8217;s a surprise figure, there is rarely a pro willing to go on record and call it in advance.</p>
<p>Why? They have large career incentives to be safely mainstream and risk averse. The reward for correctly predicting an outlier economic data point is relatively small; maybe the financial press will perfunctorily laud you for half a day at most. The penalty for making an on-the-record inaccurate prediction of an outlier event is large in professional terms; other economists will suspect that you&#8217;re ignorant of the field&#8217;s basics. On the other hand, there is no penalty for making a safe prediction that is in line with the mainstream view. If the mainstream theory is right, all the better; naturally, everyone&#8217;s predictions will converge. If the mainstream theory is wrong and an outlier event occurs, no harm done; everyone else was wrong, too. How could anyone have known better?</p>
<p>The same general process plays out in academia. A graduate student will not get a PhD, and a new professor will not get tenure, for making earth-shattering predictions or proposing radical new theories. She gets the PhD and tenure for making very minor improvements to some existing body of theory, fleshing out a few small details here and there, and flattering the preconceptions of a committee who have all invested decades of their lives into some particular paradigm of economics.</p>
<li><strong>Cultural factors related to perceptions of formal credentials.</strong> Many cultures in the world adore fancy titles and formal credentials. America is not one of them.
<p>&#8220;All men are created equal,&#8221; reads our founding document, the Declaration of Independence. It was written by upstart bourgeois traders and lawyers who were, in part, greatly annoyed that their potential for social advancement was limited in British society due to lack of aristocratic birth and an Oxford diploma. They came to America to live somewhere where that did not matter much.</p>
<p>We are hardline egalitarians, proudly derisive of highfalutin institutional authority at every turn. The &#8220;experts&#8221; are a self-selected bunch who can often contribute something useful. Insofar as they can occasionally do so, great, we&#8217;ll keep them around. Just as often, they seek merely to guard their own status as elite members of an exclusive club, to defend their turf from outsiders. Not infrequently, they devolve into groupthink and dogmatism, eventually stifling progress if left unchecked. Mainstream society does not really care, because it pays little to no attention to them &mdash; though they are very often totally unaware of this and consider themselves important figures in society.</p>
<p>I think this anti-authoritarian attitude is in no small part exactly what has driven American successes in so many fields of endeavor over the centuries. Sure, there&#8217;s nothing <em>wrong</em> with having a PhD here, and you can gain wonderful amounts of knowledge by doing so, which is great. But as far as anyone outside the narrow specialized field is concerned, that doctor&#8217;s theories are judged on their own merits, not on reputation or fancy titles. Moreover, we in no way whatsoever feel the need to refrain from commenting on a matter simply because we are not &#8220;experts.&#8221; (This does not mean that the laymen are necessarily or even often right, of course, which is another matter.) We certainly don&#8217;t refrain from criticizing some &#8220;experts&#8221; just because they are highly placed at a respected institution and bear its seal of approval. </p>
<p>This is very much not the case in, say, Germany or China. Institutions there exist to imbue people with the right to have an opinion, and only after arduous study and prolonged ritualized vetting by the pre-existing high priests of the field. Everyone else simply shuts up and listen to them, because they know that they are not qualified to have an opinion on a complex matter without a PhD in hand.</p>
<p>Immigrants to America, and sometimes their children, naturally carry a cultural legacy from their home country with them. Those who bear fancy degrees and come from countries with high regard for institutionalized authority often have a hard time adapting to the fact that Americans just don&#8217;t care about fancy degrees and titles very much. They feel stilted and insulted. Often they don&#8217;t even notice the cultural correlation, or if they do they dismissively condemn it as merely an attitude for the ignorant and the stupid, those who are simply too unenlightened to realize the vast power of institutional blessing for one&#8217;s opinions.</p>
<p>I think this is the ultimate source of Athreya&#8217;s frustration. He&#8217;s annoyed that Americans are not exhibiting the proper deference to his institutionally sanctioned writ of authority to hold opinions about economics. His borderline-abusive derision of economics bloggers certainly supports this theory. How dare a &#8220;naif&#8221; layman hold a view that contradicts his, the great doctor, when he has spent so many years studying, and read so many books! He even goes to the trouble to be affectedly humble, disclaiming having a firm grasp of the subject himself so as to demonstrate just how tough it really is.</p>
<p>I am unaware of his exact cultural provenance, but <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Kartika_%28month%29">&#8220;Kartik&#8221; is the name of a month in Bengali</a>. Indian subcontinent cultures exhibit an extreme case of this appeal-to-authority automatic reverence for institutional knowledge approval. He is trying to impose Bengali cultural norms (or wherever he&#8217;s actually from) upon Americans, a curious case of &#8220;reverse cultural imperialism&#8221;. Perhaps he grew up here, considers himself an American, and doesn&#8217;t even realize this cultural dimension himself.
</li>
</ol>
<p>None of this should be construed as a rejection of the formal academic process. Having a PhD is fine, and many PhDs do useful work. There are even many knowledgeable, useful professional PhD-bearing economists! The problem comes when the PhD is not taken as a marker of knowledge but rather as a cudgel with which to bludgeon those lesser beings who somehow have the audacity to fail to obey the expert&#8217;s opinion. This becomes a farce when done in a field like economics where there is no certain knowledge at all, a long track record of totally failing to predict major and devastating events clearly declared to be within the field&#8217;s purview, and indeed relatively few predictions that can be construed as &#8220;scientific&#8221; in any sense.</p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=321&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/kartik-athreya-rebuttal/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/SjtK_AjmzSE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/kartik-athreya-rebuttal/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/kartik-athreya-rebuttal/</feedburner:origLink></item>
		<item>
		<title>Lazy-spy: Clojure logging/spy for lazy sequences</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/zzH3Gjhl6H0/</link>
		<comments>http://www.paullegato.com/blog/lazy-spy-clojure-logging-lazy-sequences/#comments</comments>
		<pubDate>Mon, 24 May 2010 02:27:16 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=315</guid>
		<description><![CDATA[Clojure.contrib's log/spy macro does not realize the contents of lazy sequences by default when logging, as they might be infinitely long. If you're sure that your lazy sequence is finite, you can use this lazy-spy macro to force it to be realized when it's logged, so that you can inspect the contents.]]></description>
			<content:encoded><![CDATA[<p>Clojure.contrib&#8217;s <a href="http://richhickey.github.com/clojure-contrib/logging-api.html#clojure.contrib.logging/spy"><code>logging/spy</code> macro</a> is really useful for quick investigation of bugs with unclear stack traces, and to check that intermediate values in a calculation are being returned and composed correctly. Lazy sequences don&#8217;t get logged correctly, however:</p>
<pre class="brush: clojure;">
&gt; (log/spy [1 2 3 4 5])
[1 2 3 4 5] ;;; prints &quot; [1 2 3 4 5] =&gt; [1 2 3 4 5]&quot; to the log
&gt; (log/spy (take 3 [1 2 3 4 5]))
(1 2 3) ;;; prints &quot;(take 3 [1 2 3 4 5]) =&gt; clojure.lang.LazySeq@8592&quot; to the log
</pre>
<p>The <code>spy</code> macro logs a string realization of the sequence per se, rather than its constituents. In the case of a concrete, fully realized sequence such as the literal vector in the first example, all values are known in advance, and the vector&#8217;s string realization in the log can helpfully be its actual contents. In the case of the lazy sequence returned by <code>take</code>, however, we get a less than helpful class name and some sort of instance identifier code rather than the actual contents of the sequence. A lazy sequence saves resources by merely promising to provide the values when asked. If they&#8217;re never asked for, they&#8217;re never computed. Since they haven&#8217;t been computed, they can&#8217;t be printed. A lazy sequence can also potentially be infinitely long, another good reason why they are not realized by default when converting the sequence to a string.</p>
<p>In our case, we don&#8217;t care about the resource usage, and we&#8217;re sure the sequence is finite. We want to force all values to be computed for manual inspection. (There are <a href="http://stackoverflow.com/questions/1641626/how-to-covert-a-lazy-sequence-to-a-non-lazy-in-clojure">several ways of going about this</a>.) The following modification of the <code>spy</code> macro converts the lazy sequence into a regular seq:</p>
<pre class="brush: clojure;">
(defmacro lazy-spy
  &quot;Evaluates expr and outputs the form and its result to the debug log.
   If the result is a lazy sequence, it is realized concretely in the log.
   Returns the result of expr.&quot;
  [expr]
  `(let [a# ~expr] (log/log :debug (str '~expr &quot; =&gt; &quot;
                                    (if (= clojure.lang.LazySeq (class a#))
                                      (seq a#)
                                       a#)))
        a#))
</pre>
<p>This gives us:</p>
<pre class="brush: clojure;">
&gt; (lazy-spy  (take 3 [1 2 3 4 5]))
(1 2 3) ;;; prints &quot;(take 3 [1 2 3 4 5]) =&gt; (1 2 3)&quot; to the log
</pre>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=315&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/lazy-spy-clojure-logging-lazy-sequences/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/zzH3Gjhl6H0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/lazy-spy-clojure-logging-lazy-sequences/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/lazy-spy-clojure-logging-lazy-sequences/</feedburner:origLink></item>
		<item>
		<title>Log4J and Clojure Configuration</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/jyBprd1hTeo/</link>
		<comments>http://www.paullegato.com/blog/log4j-clojure/#comments</comments>
		<pubDate>Sun, 16 May 2010 22:12:48 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=292</guid>
		<description><![CDATA[Clojure, Log4J, and clojure.contrib.logging can play nicely together. Here's a reasonable default configuration.]]></description>
			<content:encoded><![CDATA[<p>Clojure, Log4J, and <code>clojure.contrib.logging</code> can play nicely together. Here&#8217;s a reasonable default configuration.</p>
<ol>
<li>
<p>If using <a href="http://github.com/technomancy/leiningen">Leiningen</a>, add</p>
<pre class="brush: clojure;">
:dependencies [
                 [log4j &quot;1.2.15&quot; :exclusions [javax.mail/mail
                                              javax.jms/jms
                                              com.sun.jdmk/jmxtools
                                              com.sun.jmx/jmxri]]
]
</pre>
<p>to your <code>project.clj</code> file and rerun <code>lein deps</code> to auto-install the Log4J JAR.
</p>
<p>If not using Leiningen, <a href="http://logging.apache.org/log4j/1.2/download.html">acquire a Log4J JAR</a> and put it on your classpath.</p>
</li>
<li>Create a file called <code>log4j.properties</code> on your classpath and put the following into it:
<pre class="brush: plain;">
# Based on the example properties given at http://logging.apache.org/log4j/1.2/manual.html
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern= %-5p %c - %m%n
</pre>
</li>
</ol>
<p>That&#8217;s the short version. Read on for the gory details.<span id="more-292"></span></p>
<h2>Logging philosophy</h2>
<p>My logging requirements are simple at the moment. I want to write messages to the console, each tagged with a log level (&#8220;INFO&#8221;, &#8220;WARN&#8221;, &#8220;ERROR&#8221;, etc.) I want to be able to set a log level, and only see log messages of that severity or higher. That&#8217;s it. I take this to be the canonical base case of logging that covers 80% of needs. All other logging features (e.g. logging to a file, differentiating by class or namespace) are nice, but much less common, and ought to be handled via configurable deviations from this default case.</p>
<p><code>clojure.contrib.logging</code> does not presently make it easy to do any of this common base case out of the box. The Lispy façade quickly falls apart; you&#8217;re <a href="http://www.paullegato.com/blog/setting-clojure-log-level/">dumped into the deep end of the Java overengineering mire</a> without a life vest when you simply want to change the log level temporarily. </p>
<h3>What&#8217;s wrong with clojure.contrib.logging&#8217;s defaults?</h3>
<p><code>clojure.contrib.logging</code> with no special configuration done prefaces each and every logged line on my system with:</p>
<pre class="brush: plain;">
[null] May 16, 2010 1:08:48 PM clojure.contrib.logging$eval__2077$impl_write_BANG___2088 invoke
</pre>
<p>I have no idea why. This makes it very hard to read the log when logging any nontrivial amount of information.</p>
<p><a href="http://richhickey.github.com/clojure-contrib/logging-api.html">clojure.contrib.logging&#8217;s documentation</a> contains a rather cryptic offhanded remark, with no further explanation: <em>Note: your log configuration should display the name that was passed to the logging implementation, and not perform stack-inspection, otherwise you&#8217;ll see something like &#8220;fn__72$impl_write_BANG__39__auto____81&#8243; in your logs.</em></p>
<p>My log configuration? Stack inspection? Why do I need to have a log configuration to just dump strings to the console? Why is the default case to print a verbose and useless header for each line? Isn&#8217;t this Javaesque mess &mdash; <a href="http://wiki.apache.org/logging-log4j/Log4jXmlFormat">obscure 50 line XML configuration files just to get basic logging functionality working</a> &mdash; exactly what we&#8217;re trying to avoid?</p>
<h2>Log4J with <code>clojure.contrib.logging</code> configuration</h2>
<p>Ah, well, there&#8217;s nothing for it, I suppose.  Better just get a serious logging library and figure out how to configure it. The docs say that <code>clojure.contrib.logging</code> delegates to the first supported logging implementation that it finds. I am apparently using <a href="http://www.paullegato.com/blog/setting-clojure-log-level/">the builtin JDK logger</a> by default, and Apache Commons&#8217; logger is just another wrapper, so I added Log4J to Leiningen&#8217;s project.clj and it installed the jar for me.</p>
<p>Now, I get:</p>
<pre class="brush: plain;">
     [null] log4j:WARN No appenders could be found for logger (my-project-name).
     [null] log4j:WARN Please initialize the log4j system properly.
</pre>
<p>Followed by dead silence.</p>
<p>Hm.</p>
<p>I can only imagine that Log4j was never intended to be used without a custom configuration. Odd. Why people design software that comes without reasonable defaults pre-set to cover the common base case is beyond me. I fully understand that strange setups will require customized configuration, but &#8220;dumping strings to the console&#8221; does not seem like a bizarre edge case for a logging package. A default case of &#8220;send all log messages to the black hole unless configured to do otherwise&#8221; makes little sense.</p>
<p>So, how hard can it be to configure Log4J for this base case functionality? The &#8220;<a href="http://logging.apache.org/log4j/1.2/manual.html">short introduction to log4j</a>&#8221;  is 19 pages long. Sigh. (<a href="http://www.qos.ch/shop/products/log4jManual">The complete manual</a> is proudly described as &#8220;over 200 pages.&#8221; I sometimes wonder if they overengineer Java libraries on purpose just to drive book sales.) </p>
<p>I do not want to know what a Nested Diagnostic Context is, or the precise semantic distinction between &#8220;Loggers,&#8221; &#8220;Appenders,&#8221; and &#8220;Layouts.&#8221; I don&#8217;t care about &#8220;Appender Additivity&#8221; and &#8220;Named Hierarchies,&#8221; and I certainly don&#8217;t want to write an XML configuration file. I Just want to log tagged strings to the console, and have them print without a bizarre autogenerated header line. That&#8217;s it. I fully appreciate that those things will be useful for some people &mdash; maybe even for me, when my project grows to become more complex. I have nothing against their existence; but for the base case, one should not need to know of it.</p>
<p>On page 9 of the &#8220;short&#8221; manual, after a boatload of irrelevant information, we have an answer: there is a class called <code>BasicConfigurator</code> with a static method that does reasonable initialization for logging to the console. We can just do <code>(org.apache.log4j.BasicConfigurator/configure)</code> and get that.</p>
<p>However, we are still getting log messages like:</p>
<pre class="brush: plain;">
     [null] 3702 [8633270@qtp-3149669-2] INFO my.namespace - log message
</pre>
<p>We have to learn something about <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/EnhancedPatternLayout.html">Layouts</a> now. The thread names generated by Clojure are apparently not very useful, so we&#8217;re going to turn them off. And while interesting when profiling, the number of milliseconds since program start is just going to be visual clutter 98% of the time, so I&#8217;m going to turn that off, too, until I actually need it.</p>
<p>The result is the <code>log4j.properties</code> file listed above. Just copy and paste it into your classpath. If you want more or different information in your logs, take a look at the <a href="http://logging.apache.org/log4j/1.2/apidocs/index.html?org/apache/log4j/PatternLayout.html">PatternLayout API documentation</a> and alter the <code>ConversionPattern</code> line according to your preferences.</p>
<p>The result:</p>
<pre class="brush: plain;">
     [null] INFO  my.namespace - log message
</pre>
<p>I&#8217;m still not sure where the <code>[null]</code> comes from, but overall, it&#8217;s very readable.</p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=292&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/log4j-clojure/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/jyBprd1hTeo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/log4j-clojure/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/log4j-clojure/</feedburner:origLink></item>
		<item>
		<title>Why the EU is Screwed</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/SySE8mGFejU/</link>
		<comments>http://www.paullegato.com/blog/why-the-eu-is-screwed/#comments</comments>
		<pubDate>Tue, 11 May 2010 18:15:48 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Economics]]></category>
		<category><![CDATA[euro]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=287</guid>
		<description><![CDATA[Why the EU is screwed, from our friends at Der Spiegel: Print PDF]]></description>
			<content:encoded><![CDATA[<p>Why the EU is screwed, from our friends at Der Spiegel:<br />
<img src="http://www.spiegel.de/images/image-85576-galleryV9-gevl.jpg" alt="Why the EU is screwed" /></p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=287&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/why-the-eu-is-screwed/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/SySE8mGFejU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/why-the-eu-is-screwed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/why-the-eu-is-screwed/</feedburner:origLink></item>
		<item>
		<title>Flash BIOS Without a Floppy</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/hnUnqB8Ds2I/</link>
		<comments>http://www.paullegato.com/blog/flash-bios-without-floppy/#comments</comments>
		<pubDate>Sun, 09 May 2010 00:09:53 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=283</guid>
		<description><![CDATA[Flashing the BIOS without a floppy drive can be done with an Ultimate Boot CD (free!) and a USB memory stick. BIOS upgrades usually come in the form of an MS-DOS executable meant to be run from a bootable floppy, but modern computers don&#8217;t usually have floppy drives anymore, and who has a copy of [...]]]></description>
			<content:encoded><![CDATA[<p>Flashing the BIOS without a floppy drive can be done with an <a href="http://www.ultimatebootcd.com/download.html">Ultimate Boot CD</a> (free!) and a USB memory stick. BIOS upgrades usually come in the form of an MS-DOS executable meant to be run from a bootable floppy, but modern computers don&#8217;t usually have floppy drives anymore, and who has a copy of DOS lying around anyway?</p>
<ol>
<li>Download a copy of the free <a href="http://www.ultimatebootcd.com/download.html">Ultimate Boot CD</a> and burn it to disk. <a href="http://www.freedos.org/">FreeDOS</a> (and a lot of other useful stuff) is preinstalled on the CD. As the name implies, FreeDOS is a free, open source, binary-compatible replacement for MS-DOS.</lI>
<li>Download the replacement BIOS from your motherboard&#8217;s manufacturer. Unpack it onto a USB flash drive.</li>
<li>Plug your flash drive into the target computer and boot it with your Ultimate Boot CD. Select FreeDOS from the menu.</li>
<li>FreeDOS asks a number of configuration questions while booting. You can usually leave all at their default except for the ASPIUSB driver. ASPIUSB is <em>not</em> enabled by default (at the time of this writing), but is necessary for the use of a USB flash drive under DOS, so enable it when prompted.
<li>If you miss the prompt for the USB driver, don&#8217;t worry. Type &#8220;<code>menu</code>&#8221; at a command prompt and enable USB devices from the popup menu.</li>
</li>
<li>Change to your flash drive by typing e.g. <code>R:</code> and execute the BIOS flash utility as per the manufacturer&#8217;s instructions. (If you don&#8217;t know which drive letter to use, type &#8220;<code>menu</code>&#8221; and select the option to display active drive letters.)</li>
</ol>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=283&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/flash-bios-without-floppy/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/hnUnqB8Ds2I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/flash-bios-without-floppy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/flash-bios-without-floppy/</feedburner:origLink></item>
		<item>
		<title>XML DTD Validation in Clojure: Turning It Off, Parsing Malformed XML</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/SWi_RCgpd9U/</link>
		<comments>http://www.paullegato.com/blog/dtd-validation-malformed-xml-clojure/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 00:29:31 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[sax]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=262</guid>
		<description><![CDATA[I wanted to parse some externally-generated and malformed HTML, so naturally I went to the short and sweet clojure.xml/parse function. I got a nasty error: error: java.io.IOException: Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd It seems that the W3C blocked access to the DTDs two years ago, but Java still tries to load [...]]]></description>
			<content:encoded><![CDATA[<p>I wanted to parse some externally-generated and malformed HTML, so naturally I went to the short and sweet <a href="http://richhickey.github.com/clojure/clojure.xml-api.html"><code>clojure.xml/parse</code> function</a>. I got a nasty error:</p>
<blockquote><p>
<code>error: java.io.IOException: Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</code>
</p></blockquote>
<p>It seems that <a href="http://www.w3.org/blog/systeam/2008/02/08/w3c_s_excessive_dtd_traffic">the W3C blocked access to the DTDs</a> two years ago, but Java still tries to load them by default anyway. The following allows <code>clojure.xml</code> to run without checking external DTDs:</p>
<pre class="brush: clojure;">
(defn startparse-sax-non-validating [s ch]
  (.. (doto (. javax.xml.parsers.SAXParserFactory (newInstance))
       (.setValidating false)
       (.setFeature &quot;http://apache.org/xml/features/nonvalidating/load-dtd-grammar&quot; false)
       (.setFeature &quot;http://apache.org/xml/features/nonvalidating/load-external-dtd&quot; false)
       (.setFeature &quot;http://xml.org/sax/features/validation&quot; false)
       (.setFeature &quot;http://xml.org/sax/features/external-general-entities&quot; false)
       (.setFeature &quot;http://xml.org/sax/features/external-parameter-entities&quot; false))

       (newSAXParser) (parse s ch))))
</pre>
<p>Then you can simply <code>(xml/parse "sourcefile.xml" startparse-sax-non-validating)</code>. This is not the ideal solution &mdash; ideally, we want to use a locally cached DTD &mdash; but it works well enough for one-off code. Read on for further information.<span id="more-262"></span></p>
<h2>W3C&#8217;s malformed specification</h2>
<p>The W3C webserver was being DDoSed by the massive number of XML parsers trying to download the DTDs constantly, so they just blocked everyone. This is a direct result of the poorly considered technical specification for DTD identification and <a href="http://en.wikipedia.org/wiki/URI#Relationship_to_URL_and_URN">URIs themselves</a>, then exacerbated by the W3C&#8217;s institutional culture and philosophy.</p>
<h3>Technical commentary</h3>
<p>The root of the problem is, as they put it, that &#8220;these [DTD URIs] are <em>not hyperlinks</em>; these URIs are used for identification&#8221; (emphasis in original.) This is an abuse of the URL format. If it&#8217;s &#8220;for identification,&#8221; then it doesn&#8217;t need to specify a transport protocol! They are relying upon their particular interpretation of the old <a href="http://tools.ietf.org/html/rfc3305">URI/URL debate</a>, reducing the transport protocol element to a namespace identifier instead, and then assuming everyone will defer to their judgement and wisdom on the matter.</p>
<p>The W3C (and others who share their URL/URI interpretation) decided to conflate the semantic functions of <em>locating and transporting</em> a resource with the very distinct function of <em>identifying</em> a resource. &#8220;My name&#8221; is not the same thing as an instruction to &#8220;get in your car, drive to my street address, pick up someone with my name here, and then drive me back to your house,&#8221; even though there is indeed only one person with my name at this address. If you want to identify me, you would not give someone the latter instruction. Most likely, they didn&#8217;t think about this at all and just did it. Now everyone suffers for this poor design decision. They are being DDoSed and paying massive amounts of money to keep the servers going, and everyone&#8217;s XML parsers are broken because they&#8217;re now returing 503s for all the DTD URIs.</p>
<p>The W3C&#8217;s proposed solution is that everyone else should a) defer to their views on the URL/URI matter, and 2) rewrite their XML parsers to be massively more complex and build local caching DTD catalogs for every single one-off parse. In practice, most people will just turn DTD validation off, potentially breaking a lot of other things.</p>
<h3>Institutional commentary on the W3C itself</h3>
<p>The tone of naive incredulity in the W3C&#8217;s plea is most amazing of all. They seem genuinely baffled as to why anyone would ever choose to ignore their wisdom on the URL/URI matter, and even more confused as to how anyone could ignore any detail of a baroque and poorly communicated specification like those for XML and DTD cataloging. &#8220;We spent a long time writing that, and we have [the self-appointed] institutional authority to write specifications and make determinations like what a URI should be, so surely people would never just ignore us!&#8221;</p>
<p>For them, the only conceivable explanation for every detail of the specification not being implemented is sheer ignorance. They even gently chide the readers about their failure to use URIs properly and to build DTD caches into everything, much as a kindergarten teacher would a well-meaning but rather dumb child who continually ignores instructions about how to use his crayons. They think that they only have to patiently remind people enough times that there is indeed a right way to do it, that which is sanctioned by the appropriate institutional authorities (them, of course) &mdash; and finally everything will be fine once people get that message.</p>
<p>This is the sort of ingenuous attitude that can only develop in a pure research institute and among people who mostly have very high <a href="http://psychology.wikia.com/wiki/Power_distance">power distance index scores</a>. The high PDI explains their naive arrogation of global authority and utterly genuine assumption that everyone ought to just do as they say, simply because they&#8217;re the (self-)designated authority. The research institute setting means that they&#8217;re shut off from the economic real world. Since money is never a big issue, the worship of artificially created fancy titles and institutional authority can become rampant, and it&#8217;s perfectly fine to spend <a href="http://stackoverflow.com/questions/243728/how-to-disable-dtd-at-runtime-in-javas-xpath">extended amounts of time</a> parsing a 2 page XML document &#8220;the right way&#8221; rather than 15 minutes hacking it and moving on to more pressing problems so your company doesn&#8217;t go bankrupt in the interim.</p>
<p>Moreover, <em>they are still intransigently defending the original poor design choice</em> to use URIs with embedded transport protocols as unique identifiers, because they (as an institution) cannot admit the possibility that this was a poor choice. That would create a great deal of <a href="http://en.wikipedia.org/wiki/Cognitive_dissonance">cognitive dissonance</a> vis-à-vis their conception of the nature of an institution and its role in dictating what is correct and what is not in the world; their view that institutional authority must be right, because, well, otherwise it wouldn&#8217;t be an institution. After all, <a href="http://en.wikipedia.org/wiki/Argument_from_authority">everyone there does have more fancy titles</a> than most people who are not there.</p>
<p>These attitudes are pervasive throughout most W3C work, and are the main reason that real-world implementations ignore much of their work.</p>
<h2>Parsing malformed HTML</h2>
<p>So, in any case, I have another problem besides Java trying to load the unavailable DTD. The input HTML is malformed. Not just a little; it&#8217;s utterly broken. It&#8217;s both externally-generated and unreplaceable, so fixing it at the source is not an option. I&#8217;m stuck with it; it&#8217;s the only way to get the data I need. (That&#8217;s real-world programming as opposed to academia right there.)</p>
<h3>Disabling XML validation</h3>
<p>Disabling all XML validation is the obvious solution to both problems, but there is no readily apparent way to do that <code>clojure.xml</code>. Calling <code><a href="http://java.sun.com/javase/6/docs/api/javax/xml/parsers/SAXParserFactory.html#setValidating%28boolean%29">setValidating(false)</a></code> on the factory is insufficient. Thanks to <a href="http://stackoverflow.com/questions/243728/how-to-disable-dtd-at-runtime-in-javas-xpath">Stack Overflow</a>, I found that you must also use<br />
<code><a href="http://java.sun.com/javase/6/docs/api/javax/xml/parsers/SAXParserFactory.html#setFeature%28java.lang.String,%20boolean%29">setFeature()</a></code> with several obscure &#8220;<a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description">SAX2 Standard Feature Flags</a>&#8220;, as above.</p>
<h3>HTML Tidy to the rescue</h3>
<p>This still leaves the problem of the malformed HTML. There does not seem to be any easy way to make Sax ignore errors. (<code>(.setFeature "http://apache.org/xml/features/continue-after-fatal-error" true)</code> has no apparent effect; it still doesn&#8217;t continue after a fatal parse error.)</p>
<p>In the end, I just ran the malformed input HTML through <a href="http://tidy.sourceforge.net/">HTML Tidy</a> before attempting to parse it. HTML Tidy coerces the malformed input into valid XML, and Sax is finally happy.</p>
<p>(I now get &#8220;<code>Exception in thread "Swank REPL Thread" java.lang.RuntimeException: java.lang.IllegalMonitorStateException</code>&#8221; from SLIME when I try to actually <em>display</em> the parsed XML in Emacs, but that&#8217;s another matter&#8230;)</p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=262&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/dtd-validation-malformed-xml-clojure/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/SWi_RCgpd9U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/dtd-validation-malformed-xml-clojure/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/dtd-validation-malformed-xml-clojure/</feedburner:origLink></item>
		<item>
		<title>Goldman’s Blankfein before Congress</title>
		<link>http://feedproxy.google.com/~r/PaulLegato/~3/2xann7rtBtU/</link>
		<comments>http://www.paullegato.com/blog/goldman-blankfein-congress/#comments</comments>
		<pubDate>Tue, 27 Apr 2010 23:40:57 +0000</pubDate>
		<dc:creator>Paul Legato</dc:creator>
				<category><![CDATA[Economics]]></category>
		<category><![CDATA[Politics and International Relations]]></category>
		<category><![CDATA[goldman sachs]]></category>
		<category><![CDATA[politics]]></category>

		<guid isPermaLink="false">http://www.paullegato.com/?p=246</guid>
		<description><![CDATA[And it came to pass, that Goldman&#8217;s then-chief overlord was order&#8217;d to parade full 7 days and 7 nights through the streets of lower Manhattan, clad in naught save his drawers, bearing tether&#8217;d to heavy chains every SEC filing that Goldman hath wrought for 10 years previous; while the peasants of the borough were to [...]]]></description>
			<content:encoded><![CDATA[<div class="alignright"><img style="padding: 0 0.38em 0 0.62em;" class="size-large wp-image-247   " title="Blankfein before Congress" src="http://www.paullegato.com/wp-content/uploads/2010/04/Blankfein-Congress.jpg" alt="Goldman CEO Lloyd Blankfein testifying before Congress" width="511" height="250" />
</div>
<p><span style="font-variant: small-caps;">And  it came to pass</span>, that Goldman&#8217;s then-chief overlord was order&#8217;d to parade full 7 days and 7 nights through the streets of lower Manhattan, clad in naught save his drawers, bearing tether&#8217;d to heavy chains every SEC filing that Goldman hath wrought for 10 years previous; while the peasants of the borough were to gather round to hurl rotting vegetables thence, and cry, &#8220;Lo! How the mighty have fallen!&#8221;</p>
<p>And only then, once the indignity were suffer&#8217;d in full, might he retreat to his penthouse to recover, or to his yacht, or to the coffers of his chalet in southern France, or to his Bahamas estate countinghouse, or to any other sequester&#8217;d location whatsoever.</p>
<img src="http://www.paullegato.com/?ak_action=api_record_view&id=246&type=feed" alt="" /><div id="pfButton"><a href="http://www.paullegato.com/blog/goldman-blankfein-congress/?pfstyle=wp" title="Print an optimized version of this web page" style="text-decoration: none;"><img id="printfriendly" style="border:none; padding:0;" src="http://cdn.printfriendly.com/pf-print-icon.gif" alt="Print"/><span style="font-size: 12px; color: #55750c;"> Print <img src="http://cdn.printfriendly.com/pf-pdf-icon.gif" alt="Get a PDF version of this webpage" /> PDF </span></a></div><img src="http://feeds.feedburner.com/~r/PaulLegato/~4/2xann7rtBtU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.paullegato.com/blog/goldman-blankfein-congress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.paullegato.com/blog/goldman-blankfein-congress/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 0.924 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-09-06 10:34:06 -->
