<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc=" http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>briancarper.net (λ) (Tag: Web Design)</title><link>http://briancarper.net/tag/228/web-design</link><description>Some guy's blog about programming and Linux and cows.</description><item><title>Split page vertically in CSS (minus pixels)</title><link>http://briancarper.net/blog/589/split-page-vertically-in-css-minus-pixels</link><guid>http://briancarper.net/blog/589/split-page-vertically-in-css-minus-pixels</guid><pubDate>Mon, 23 Apr 2012 21:43:06 -0700</pubDate><description>&lt;p&gt;I was designing an online database application recently.  The layout I wanted was, I thought, fairly simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;N pixel header at the top&lt;/li&gt;
&lt;li&gt;The rest of the page split vertically into two panes&lt;/li&gt;
&lt;li&gt;Each pane should scroll independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Super easy to do in CSS, right?  Of course not!  You can't do this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: css&quot;&gt;#header {  height: 50px; }

#panels {  height: 100% - 50px; }

#top, #bottom { overflow: auto; }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is because (of course) you can't do simple arithmetic in CSS. &lt;/p&gt;

&lt;p&gt;I can't think of a reason why it's not supported.  My browser knows the height of the window at any given point in time.  The browser can surely subtract two numbers.  If someone knows of a solid reason why we can't do this in CSS, please clue me in.&lt;/p&gt;

&lt;p&gt;I can think of many reasons why I would want to do it though.  The above use case is just one of them.&lt;/p&gt;

&lt;p&gt;I really dislike resorting to this (which does work, as seen &lt;a href=&quot;/random/layout-good.html&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: css&quot;&gt;#header {  height: 50px; }

#panels {
    position: absolute;
    top: 50px;
    left: 0px;
    right: 0px;
    bottom: 0px;
}

#top, #bottom { overflow: auto; }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whenever I start using absolute positioning, I know something went off the rails somewhere.&lt;/p&gt;

&lt;p&gt;The worst part isn't that CSS doesn't support this, it's that even if CSS did suddenly support it, I couldn't use it until sometime in 2023 when all the major browsers implemented it and everyone using the old browsers switched or died of old age.&lt;/p&gt;</description></item><item><title>gaka 0.2.0</title><link>http://briancarper.net/blog/562/gaka-020</link><guid>http://briancarper.net/blog/562/gaka-020</guid><pubDate>Thu, 29 Jul 2010 13:59:22 -0700</pubDate><description>&lt;p&gt;Per &lt;a href=&quot;http://briancarper.net/blog/543/introducing-gaka&quot;&gt;many commenters' suggestions&lt;/a&gt; and thanks to code from &lt;a href=&quot;http://github.com/purcell/&quot;&gt;Steve Purcell&lt;/a&gt;, you can now use maps for CSS attributes in &lt;a href=&quot;http://github.com/briancarper/gaka&quot;&gt;gaka&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (println (gaka/css [:a {:color :red}]))
a {
  color: red;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This looks more like vanilla CSS thanks to the curlies, which is nice.   You just have to keep in mind that your key/value pairs could end up being printed in random order, and order is significant&lt;sup id=&quot;fnref:css&quot;&gt;&lt;a href=&quot;#fn:css&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; in CSS.&lt;/p&gt;

&lt;p&gt;It just so happens that maps are implemented in Clojure right now such that if they only have a few entries (16 key/value pairs), the order will be preserved, because you get a &lt;code&gt;PersistentArrayMap&lt;/code&gt; instead of a &lt;code&gt;PersistentHashMap&lt;/code&gt;.  But it's &lt;em&gt;highly dangerous&lt;/em&gt; to rely on such a thing.  It could change at any time in the future.&lt;/p&gt;

&lt;p&gt;In any case, you can also mix and match maps, lists and &quot;flat&quot; keyvals.  They'll all be flattened  That can help preserve attribute order in those cases where you need to.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (println (gaka/css [:a :color &quot;red&quot; {:padding 0} (list :margin 0)]))
a {
  color: red;
  padding: 0;
  margin: 0;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've also enhanced &quot;mixins&quot; a bit further.  You can now mixin entire tags as well as attributes.  Or a combination of both.  Say you want a mixin that means &quot;&lt;em&gt;Make my element have no padding, and make links within the element be red&lt;/em&gt;&quot;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;user&amp;gt; (println (gaka/css [:div.foo mixin :margin 0]
                         [:div.bar mixin]))
div.foo {
  padding: 0;
  margin: 0;}

  div.foo a {
    color: red;}

div.bar {
  padding: 0;}

  div.bar a {
    color: red;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can get gaka from &lt;a href=&quot;http://github.com/briancarper/gaka&quot;&gt;github&lt;/a&gt; or &lt;a href=&quot;http://clojars.org/gaka&quot;&gt;Clojars&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:css&quot;&gt;&lt;p&gt;Order is only significant in cases where you're doing things like &lt;code&gt;padding: 0; padding-left: 1px&lt;/code&gt;.  This is arguably bad CSS style, but it's valid, and it's also possible you'll have this kind of thing if you're generating CSS procedurally.  But most of the time, order is not significant.  e.g. it doesn't matter if you set text color first and background color second, or vice versa.  So maybe this isn't so much of a problem in practice. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:css&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Footnotes</title><link>http://briancarper.net/blog/560/footnotes</link><guid>http://briancarper.net/blog/560/footnotes</guid><pubDate>Tue, 27 Jul 2010 12:30:57 -0700</pubDate><description>&lt;p&gt;Did you ever notice how footnotes make your writing seem more important&lt;sup id=&quot;fnref:important&quot;&gt;&lt;a href=&quot;#fn:important&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; somehow?&lt;/p&gt;

&lt;p&gt;Maybe one reason is that &quot;real&quot; books use footnotes.  At a glance, it looks like I have references&lt;sup id=&quot;fnref:refs&quot;&gt;&lt;a href=&quot;#fn:refs&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; backing up everything I say.  In reality, I don't, but the connotation carries through somehow&lt;sup id=&quot;fnref:telepathy&quot;&gt;&lt;a href=&quot;#fn:telepathy&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.  Now my blog seems scholarly and authoritative.&lt;/p&gt;

&lt;p&gt;And if you're like me, you can't resist clicking footnotes to see what they refer to&lt;sup id=&quot;fnref:clickme&quot;&gt;&lt;a href=&quot;#fn:clickme&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.  According to my estimates, by utilizing footnotes, in one fell swoop I have decreased my readers' average reading efficiency by 73%.&lt;/p&gt;

&lt;p&gt;In any case, I've added experimental, rudimentary support for footnotes to &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;cow-blog&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;I'm loosely copying the syntax from &lt;a href=&quot;http://michelf.com/projects/php-markdown/extra/&quot;&gt;Markdown Extra&lt;/a&gt; for this.  Markdown is great, except when it isn't.  The standard doesn't have support for some useful extensions.  I use &lt;a href=&quot;http://attacklab.net/showdown/&quot;&gt;Showdown&lt;/a&gt; for Markdown support, and I'm probably going to work on adding more features of Markdown Extra to Showdown in the near future.&lt;/p&gt;

&lt;p&gt;I just dread actually doing it.  Showdown (like Markdown itself) is implemented as a series of hackish regex transformations of blobs of text.  It's not a proper grammar.  Implementing more of Markdown Extra means more regex blobbing.  It's brittle and fragile and even getting incomplete support for footnotes was less than enjoyable.  But at the same time I find myself wanting to do things that Markdown can't so, so I may have to bite the bullet.&lt;/p&gt;

&lt;p&gt;(If there's a Showdown Extra out there already, drop me a URL.  It'd be most appreciated.  But I couldn't find one.)&lt;/p&gt;&lt;div class=&quot;footnotes&quot;&gt;&lt;ol&gt;&lt;li id=&quot;fn:important&quot;&gt;&lt;p&gt;In reality nothing I say is important. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:important&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:refs&quot;&gt;&lt;p&gt;Does my inner dialog count as a reference? &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:refs&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:telepathy&quot;&gt;&lt;p&gt;Via telepathy. &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:telepathy&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id=&quot;fn:clickme&quot;&gt;&lt;p&gt;See? &lt;a rev=&quot;footnote&quot; href=&quot;#fnref:clickme&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description></item><item><title>Clojure syntax highlighting via SyntaxHighlighter</title><link>http://briancarper.net/blog/556/clojure-syntax-highlighting-via-syntaxhighlighter</link><guid>http://briancarper.net/blog/556/clojure-syntax-highlighting-via-syntaxhighlighter</guid><pubDate>Wed, 21 Jul 2010 15:17:42 -0700</pubDate><description>&lt;p&gt;How do you syntax-highlight Clojure code for display on a website?   The best way I can find is &lt;a href=&quot;http://alexgorbatchev.com/SyntaxHighlighter/&quot;&gt;SyntaxHighlighter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Daniel Gómez wrote a &lt;a href=&quot;http://www.deepbluelambda.org/programs/sh-clojure/new-clojure-brush-for-syntaxhighlighter&quot;&gt;brush&lt;/a&gt; to give SyntaxHighlighter Clojure support.  I &lt;a href=&quot;http://github.com/briancarper/cow-blog/blob/master/public/js/brushes/shBrushClojure.js&quot;&gt;tweaked it&lt;/a&gt; a bit myself and integrated it into cow-blog.  I also converted my &lt;a href=&quot;http://github.com/briancarper/dotfiles/blob/master/.vim/colors/gentooish.vim&quot;&gt;favorite color scheme&lt;/a&gt; to a &lt;a href=&quot;http://github.com/briancarper/cow-blog/blob/master/public/css/shThemeCow.css&quot;&gt;SyntaxHighlighter theme&lt;/a&gt;.  So when I write this code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;brush: clojure&quot;&gt;(defn- ip
  &quot;Given a request, return the IP.  Looks for an x-forwarded-for
  header, falls back to :remote-addr on the request.&quot;
  [request]
  (or (get-in request [:headers &quot;x-forwarded-for&quot;])
      (request :remote-addr)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/clojure/syntax-highlight.png&quot; alt=&quot;Syntax highlighting example&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;...unless you're reading this via RSS, or in a browser without Javascript enabled, in which case you'll see plain, depressing black and white.  But that's one nice thing about SyntaxHighlighter.  It degrades nicely.&lt;/p&gt;

&lt;p&gt;One bad thing about SyntaxHighlighter is that it doesn't play nicely with Markdown.  Or rather, Markdown isn't powerful enough to let you specify the class of any markdown-generated HTML tags.  If you want the &lt;code&gt;&amp;lt;pre class=&quot;brush: clojure&quot;&amp;gt;&lt;/code&gt; that SyntaxHighlighter requires, you have to write out the HTML by hand.  But I hacked Showdown a bit to let me specify classes more easily, so I can avoid having to do that.&lt;/p&gt;

&lt;p&gt;The code for all of this is &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;on github&lt;/a&gt; with the rest of my blog.&lt;/p&gt;</description></item><item><title>In which border-radius is abused</title><link>http://briancarper.net/blog/548/in-which-border-radius-is-abused</link><guid>http://briancarper.net/blog/548/in-which-border-radius-is-abused</guid><pubDate>Mon, 05 Jul 2010 15:54:24 -0700</pubDate><description>&lt;p&gt;I threw together a new blog layout today.  I scaled back the level of cows a bit (just a bit, don't worry!) Criticism / feedback welcome.  (IE-related feedback should be dropped off in the circular file by my desk.)&lt;/p&gt;

&lt;p&gt;In what is surely a prelude to the future of the internets, I'm abusing &lt;code&gt;border-radius&lt;/code&gt; pretty heavily in this layout.  &lt;code&gt;border-radius&lt;/code&gt; is likely to become the new &lt;code&gt;marquee&lt;/code&gt; HTML tag or &lt;code&gt;text-shadow&lt;/code&gt; CSS attribute: Maybe an OK idea at first, but then everyone uses it so much it makes your eyes bleed.&lt;/p&gt;

&lt;p&gt;So I figured I'd best get my border-radiusing in early while it's still cool.  IE8 users, you still get pointy corners. Sucks to be you.&lt;/p&gt;

&lt;p&gt;Also, if you have any ideas for features I should implement for &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;cow-blog&lt;/a&gt;, please let me know.  I've been crawling the internet looking at blogs for ideas of things to implement and features to steal, but I'm running out of ideas.  It does everything I want now, but I'm not a reader.&lt;/p&gt;</description></item><item><title>Goodbye Tokyo Cabinet, hello PostgreSQL?</title><link>http://briancarper.net/blog/545/goodbye-tokyo-cabinet-hello-postgresql</link><guid>http://briancarper.net/blog/545/goodbye-tokyo-cabinet-hello-postgresql</guid><pubDate>Tue, 29 Jun 2010 11:32:58 -0700</pubDate><description>&lt;p&gt;The first version of this blog used MySQL; then I switched to Tokyo Cabinet.  But now I've switched back to PostgreSQL.  Here's why.&lt;/p&gt;

&lt;!--more Read on.--&gt;

&lt;h1&gt;Why did I switch to TC to begin with?&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;There weren't any good ORM-type libraries for Clojure at the time (over a year ago).  So there was a bit of an impedance mismatch trying to query and work with my data.  In the DB I have separate tables for posts, comments, tags, categories.  But 90% of the time I want to fetch a post and end up in Clojure with all related tags, comments etc.  (A JOIN won't work here without a lot of work to un-mangle the results; you usually need multiple queries.)  &lt;/p&gt;

&lt;p&gt;With TC I could store anything in the DB, so I just dumped a post into the DB as serialized hash-maps with all the comments, tags, and categories as sub-keys.  So querying was easy.  (Or was it?  More below.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MySQL was really slow. This is largely because my queries were terrible, as I tried to solve the problem from #1 via brute force.  TC on the other hand is fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I tried to solve #2 by using a Clojure ref as a cache.  But tying the STM to a database's transaction system is as far as I know difficult or impossible right now (per many threads on the mailing list).  I had a lot of potential race conditions, which (as far as I know) never bit me, but probably would've eventually.  I had to deal with keeping the cache up-to-date as comments were posted and posts were added and deleted and renamed.  Remember:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;&quot;There are only two hard problems in Computer Science: cache invalidation and naming things.&quot; --Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;So why did I stop using TC?&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I have no idea how to use a key/value store database properly.  TC will take anything you dump into it, which is both a strength and a weakness.&lt;/p&gt;

&lt;p&gt;There's a lot of crap you have to do by hand that a proper database does for you.  Consider checking for null values, for example; I ended up with a lot of &lt;code&gt;nil&lt;/code&gt;s in my data because my validations weren't 100% foolproof, or because I imported data via code that didn't run the validations and I never noticed..  Or enforcing uniqueness of values; I had tag objects in the database with the same key but different values (due to capitalization differences), which screwed up a lot of stuff.&lt;/p&gt;

&lt;p&gt;On the other hand, there's a lot of information about how to use RDBMS properly, and I have a lot of experience with it already.  Constraints are easy to set up.  Columns have types, which is nice.  (Strange that I gravitate toward statically-type databases while I gravitate toward dynamically-typed programming languages.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have to compile and install Tokyo Cabinet by hand on my Linux distro.  It's probably not worth distro maintainers to maintain a package that so few people use.  MySQL and PostgreSQL have lots of people working on keeping them running OK on most Linux distros.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some kinds of queries were still awkward in TC.  &quot;Give me post X&quot; was great: I'd also get all the tags, categories etc. for free.  But then how do you query to get all tags across all posts?  Or all comments?  Fetch all the posts and iterate over them, collecting their tags, then uniquify the resulting list?  Not so pretty, and not so fast.  So I was back to caching again, which still gave me nightmares about race conditions and dirty data.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;So now why am I using an RDBMS again?&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;An RDBMS is exactly what I really need, if I could just query the thing concisely and get it to run fast.  Thankfully there are some ORM-like libraries for Clojure in the works nowadays, already usable for a hobby project like this blog.  There are &lt;a href=&quot;http://github.com/duelinmarkers/clj-record&quot;&gt;clj-record&lt;/a&gt;, &lt;a href=&quot;http://github.com/brentonashworth/carte&quot;&gt;Carte&lt;/a&gt;, &lt;a href=&quot;http://gitorious.org/clojureql/&quot;&gt;ClojureQL&lt;/a&gt;, and my own &lt;a href=&quot;http://github.com/briancarper/oyako&quot;&gt;Oyako&lt;/a&gt;, and possibly others in the works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For my tiny blog's database, Oyako gives me slightly slower performance than TC, but along the same order of magnitude, which is good enough.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Via Oyako I can (fairly concisely) fetch posts and get the associated tags, comments etc.  But I can also easily fetch all tags, or all comments, since they're in their own tables.  The &quot;relational&quot; part of RDBMS does come in handy sometimes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;Summary version&lt;/h1&gt;

&lt;p&gt;I switched to TC to begin with because I was using SQL wrong, and it was too slow and clumsy.  Once I figured out how to use SQL correctly, it was a no-brainer to go back.&lt;/p&gt;</description></item><item><title>Introducing Gaka</title><link>http://briancarper.net/blog/543/introducing-gaka</link><guid>http://briancarper.net/blog/543/introducing-gaka</guid><pubDate>Mon, 28 Jun 2010 17:59:26 -0700</pubDate><description>&lt;p&gt;The CSS for &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;my blog&lt;/a&gt; is now being generated via &lt;a href=&quot;http://github.com/briancarper/gaka&quot;&gt;gaka&lt;/a&gt;, a CSS-generating library I wrote this afternoon.  It's extremely simple, but it got the job done for me.  I turned around 600 lines of CSS into around 250 lines of Clojure without much effort.  It looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (require '(gaka [core :as gaka]))
nil
user&amp;gt; (def rules [:div#foo
                  :margin &quot;0px&quot;
                  [:span.bar
                   :color &quot;black&quot;
                   :font-weight &quot;bold&quot;
                   [:a:hover
                    :text-decoration &quot;none&quot;]]])
#'user/rules
user&amp;gt; (println (gaka/css rules))
div#foo {
  margin: 0px;}

  div#foo span.bar {
    color: black;
    font-weight: bold;}

    div#foo span.bar a:hover {
      text-decoration: none;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gaka is partly inspired by &lt;a href=&quot;http://sass-lang.com/&quot;&gt;Sass&lt;/a&gt;, which I found very pleasant to work with recently.  And it's partly inspired by &lt;a href=&quot;http://github.com/weavejester/hiccup&quot;&gt;Hiccup&lt;/a&gt;, which is a delicious way to generate HTML in Clojure.  &lt;/p&gt;

&lt;p&gt;There's more info and more examples on &lt;a href=&quot;http://github.com/briancarper/gaka&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>New blog engine up and running</title><link>http://briancarper.net/blog/542/new-blog-engine-up-and-running</link><guid>http://briancarper.net/blog/542/new-blog-engine-up-and-running</guid><pubDate>Wed, 23 Jun 2010 15:48:24 -0700</pubDate><description>&lt;p&gt;Well, my new blog is up and running.  Sorry for the temporary lack of cows in my layout.  I'm dogfood-testing the blog engine in a fairly vanilla state until I work out some of the bugs.  This layout is based upon &lt;a href=&quot;http://shaheeilyas.com/archives/barecity/&quot;&gt;barecity&lt;/a&gt;, a minimalist Wordpress theme that I adapted easily enough to my blog.&lt;/p&gt;

&lt;p&gt;As a bonus, I applied a dirty hack to my RSS feed that I think should help avoid screwing up people's RSS readers with duplicate entries.&lt;/p&gt;

&lt;p&gt;I'll write again soon with some info about the blog engine and some things I learned writing it.&lt;/p&gt;

&lt;p&gt;(As mentioned previously, &lt;a href=&quot;http://github.com/briancarper/cow-blog/tree/0.2.0&quot;&gt;here's the code&lt;/a&gt;.)&lt;/p&gt;</description></item><item><title>Breaking links is easy to do</title><link>http://briancarper.net/blog/breaking-links-is-easy-to-do</link><guid>http://briancarper.net/blog/breaking-links-is-easy-to-do</guid><pubDate>Tue, 22 Jun 2010 23:23:27 -0700</pubDate><description>&lt;p&gt;I apologize in advance to everyone who subscribes to my blog's RSS feed, but this week your RSS reader is probably going to suddenly find 25 &quot;new&quot; posts from me.&lt;/p&gt;

&lt;p&gt;My blog currently uses &lt;code&gt;/blog/title&lt;/code&gt; as the URL scheme, with similar URLs for categories and tags etc.  Soon, I'm probably going to change it to &lt;code&gt;/blog/123/title&lt;/code&gt;, as part of the impending release of version 0.2 of my blog engine.  (The code-in-progress is in a &lt;a href=&quot;http://github.com/briancarper/cow-blog/tree/0.2.0&quot;&gt;branch on github&lt;/a&gt;, for the daring and foolish among you.)&lt;/p&gt;

&lt;p&gt;This way, I can change the title of a post without breaking everything.  I have heretofore lacked this ability.  It's easy to code, you just tell Compojure to ignore everything after the number in a route.  Something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defroutes foo
  (GET [&quot;/blog/:id:etc&quot; :id #&quot;\d+&quot; :etc #&quot;(/[^/]*)?&quot;] [id]
    (pages/post-page id)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's only a few lines of code to change, but the ramifications are widespread.  It'll instantly break every link to my blog, for example.  At least it's pretty easy to set up a bunch of redirects in Compojure to avoid that.  I think this'll work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(require (blog [db :as db]
               [link :as link])
         (oyako [core :as oyako])
         (ring.util [response :as response]))

(defn redirect-post [name]
  (when-let [post (oyako/fetch-one db/posts :url name)]
    (response/redirect (link/url post))))

(defroutes redirect-routes
  (GET [&quot;/blog/:name&quot; :name #&quot;[^/]+$&quot;] [name]
    (redirect-post name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(&lt;a href=&quot;http://github.com/briancarper/oyako&quot;&gt;Oyako&lt;/a&gt; here is the experimental ORM-like library I'm using to interface with PostgreSQL nowadays, having ditched Tokyo Cabinet.)&lt;/p&gt;

&lt;p&gt;Changing my URL scheme is also going to mess up RSS though, because I (foolishly) used post URLs as the GUIDs in my RSS feed up to this point.  This problem I don't know how to avoid.  I might reduce the number of posts included in my feed temporarily, to limit the damage.&lt;/p&gt;</description></item><item><title>Getting list of referers out of Apache logs</title><link>http://briancarper.net/blog/getting-list-of-referers-out-of-apache-logs</link><guid>http://briancarper.net/blog/getting-list-of-referers-out-of-apache-logs</guid><pubDate>Sun, 21 Feb 2010 12:46:34 -0800</pubDate><description>&lt;p&gt;I use Google Analytics, but it has a noticeable lag in updating its information.  When my site is being hammered, I'd like to see where all the traffic is coming from.  It'd also be nice to see how many hits my RSS feed is getting, and how many images and static files are being direct-linked, which Google Analytics currently isn't tracking for me at all.  &lt;/p&gt;

&lt;p&gt;So this script will look in my Apache logs and print referers for some URL, thanks to &lt;a href=&quot;http://www.simonecarletti.com/blog/2009/02/apache-log-regex-a-lightweight-ruby-apache-log-parser/&quot;&gt;ApacheLogRegex&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/ruby

require 'apachelogregex'

raise &quot;USAGE: #{$0} log_filename desired_url&quot; unless ARGV[0] and ARGV[1]

format = '%v:%p %h %l %u %t \&quot;%r\&quot; %&amp;gt;s %b \&quot;%{Referer}i\&quot; \&quot;%{User-Agent}i\&quot;'
parser = ApacheLogRegex.new(format)
pat = Regexp.new(ARGV[1])
refs = {}

File.readlines(ARGV[0]).each do |line|
  x = parser.parse(line)
  if pat.match(x[&quot;%r&quot;])
    r = x[&quot;%{Referer}i&quot;]
    refs[r] = (refs[r] || 0) + 1
  end
end
refs.sort_by{|k,v| -v}.each do |ref,count|
  puts &quot;%s: %s&quot; % [count,ref]
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I used to use awstats for this, but it was too heavyweight and a hassle to set up and keep running.  Google Analytics is a no-brainer to use, even though the accuracy isn't as good as parsing Apache logs.  At least I get an idea of which of my blatherings people are most interested in.&lt;/p&gt;</description></item><item><title>Out of memory... ouch</title><link>http://briancarper.net/blog/out-of-memory-ouch</link><guid>http://briancarper.net/blog/out-of-memory-ouch</guid><pubDate>Wed, 20 Jan 2010 12:12:05 -0800</pubDate><description>&lt;p&gt;I've written before about how I'm running four Clojure-driven websites out of a single JVM on my VPS.  No problems for many months, but today I tried to make a blog post and got all kinds of out-of-memory errors.  Hopefully I didn't lose any / many user comments on this blog in the past couple days, but it's possible.&lt;/p&gt;

&lt;p&gt;I restarted the JVM and gave it a bit more RAM to play with, I imagine this will fix things.  But we'll see.  It occurs to me now that there may be such a thing as too much caching.&lt;/p&gt;</description></item><item><title>Deploying Clojure websites</title><link>http://briancarper.net/blog/deploying-clojure-websites</link><guid>http://briancarper.net/blog/deploying-clojure-websites</guid><pubDate>Mon, 04 Jan 2010 20:42:17 -0800</pubDate><description>&lt;p&gt;On my server I'm running one Java process, which handles four of my websites on four different domains.  These are all running on Clojure + Compojure.  Some people asked for details of how to do this, so here's a rough outline.  For the sake of brevity I'm only going to talk about two domains here, though it scales up to however many you want pretty easily.&lt;/p&gt;

&lt;p&gt;This is surely not the only way to do this, and probably not the best way, but it's what I've arrived at after a year of goofing off.&lt;/p&gt;

&lt;p&gt;Summary: Emacs + SLIME + Clojure running in GNU Screen; all requests are handled by Apache and &lt;code&gt;mod_proxy&lt;/code&gt; sends them to the appropriate Jetty instance / servlet.&lt;/p&gt;

&lt;!--more Lots of fun details follow --&gt;

&lt;h1&gt;Directory structure&lt;/h1&gt;

&lt;p&gt;First you have to decide on a directory structure.  There's a sort of Clojure convention to have a &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;deps&lt;/code&gt; directory, though Clojure is so young that this convention may or may not stick.  Behold my ASCII line-art directory tree:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/public_html/base/
|
|----src/
|    |
|    |----common/
|    |
|    |----net/
|         |
|         |----briancarper/
|         |    |
|         |    |----&amp;lt;lots of .clj files&amp;gt;
|         |
|         |----ffclassic/
|              |
|              |----&amp;lt;lots of .clj files&amp;gt;
|
|----deps/
|    |
|    |----&amp;lt;lots of .jar files&amp;gt;
|
|----briancarper.net/
|    |
|    |----public/
|    |
|    |----db/
|    |
|    |----apache/
|
|----ffclassic.net/
|    |
|    |----public/
|    |
|    |----apache/
|
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;src&lt;/code&gt; holds the Clojure source code for all of my sites.  Java (therefore Clojure) forces your directory structure to match your namespaces, and traditionally people use domain names in reverse order for both.  Whether you like or dislike this convention, you must admit that if you're writing code that's actually going to be used to host websites on domains, the convention probably makes sense.  There are some utility libraries I wrote that I like to share between sites, so I put those in some &lt;code&gt;common&lt;/code&gt; namespace in their own directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;deps&lt;/code&gt; holds a bunch of &lt;code&gt;.jar&lt;/code&gt; files.  This includes &lt;code&gt;clojure.jar&lt;/code&gt;, &lt;code&gt;clojure-contrib.jar&lt;/code&gt;, &lt;code&gt;compojure.jar&lt;/code&gt;, &lt;code&gt;swank-clojure.jar&lt;/code&gt; (for SLIME), and all the Java libraries I use, like Jetty, a bunch of Apache Commons libraries, Tokyo Cabinet, Rhino and so on.  This means that all of my sites are sharing libraries, and therefore must be running the same version of Clojure and all other libraries.  So when I upgrade a library that one site is using, I must upgrade all the other sites.  This is sometimes a hassle, but it forces me not to be lazy.&lt;/p&gt;

&lt;p&gt;Then I have one more directory for each of my domains, for static files and such.  These directories have different subdirectories depending on how I'm running them.  For the sites that use Tokyo Cabinet, I have a &lt;code&gt;db&lt;/code&gt; directory to hold the database files.  On some sites I want to run a PHP or CGI script, so I have a directory for Apache to use.  All of them have a &lt;code&gt;public&lt;/code&gt; folder, from which Clojure serves images, JS and CSS files etc.&lt;/p&gt;

&lt;p&gt;Phil Hagelberg's recent &lt;a href=&quot;http://github.com/technomancy/leiningen&quot;&gt;Leiningen project&lt;/a&gt; can possibly help with some of this.  I don't use Lein but I may switch someday.&lt;/p&gt;

&lt;h1&gt;Emacs + SLIME + CLASSPATH setup&lt;/h1&gt;

&lt;p&gt;Building or installing Clojure and Emacs and SLIME and friends is beyond the scope of this blog post.  &lt;a href=&quot;http://github.com/technomancy/swank-clojure&quot;&gt;swank-clojure&lt;/a&gt; has come a long way in being auto-installable via ELPA nowadays, if you like.&lt;/p&gt;

&lt;p&gt;The most important thing is to set up &lt;code&gt;CLASSPATH&lt;/code&gt; correctly.  &lt;code&gt;src&lt;/code&gt; should be on the &lt;code&gt;CLASSPATH&lt;/code&gt;, as well as every &lt;code&gt;.jar&lt;/code&gt; file in &lt;code&gt;deps&lt;/code&gt;.  My &lt;code&gt;.emacs&lt;/code&gt; contains this, among other things:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(setq swank-clojure-classpath (list &quot;.&quot; &quot;./src&quot; &quot;./deps/*&quot;))
(setq swank-clojure-library-paths (list &quot;/usr/local/lib&quot;))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Java will take a glob and expand it to include every jar file in a directory, thankfully.  But this seems to happen right when you start Java, so to add a new &lt;code&gt;.jar&lt;/code&gt; to your &lt;code&gt;CLASSPATH&lt;/code&gt; you generally need to restart the JVM.  This is annoying, but oh well.&lt;/p&gt;

&lt;p&gt;If you AOT-compile your Clojure code you might also have a &lt;code&gt;classes&lt;/code&gt; folder on your classpath, but I don't bother.  You could also compile your whole site into its own &lt;code&gt;.jar&lt;/code&gt; file and use that.  I don't do this because I want to be able to edit my Clojure source files on the server if I need to. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;swank-clojure-library-paths&lt;/code&gt; is necessary for me because Tokyo Cabinet uses some C libraries.  You might not need it.&lt;/p&gt;

&lt;p&gt;Then when I start Emacs, I &lt;code&gt;M-x cd&lt;/code&gt; to the base folder and start SLIME there.  It'll find Clojure in &lt;code&gt;deps&lt;/code&gt; and give me a REPL.  If you can get this working, you're well on your way.&lt;/p&gt;

&lt;h1&gt;Clojure code&lt;/h1&gt;

&lt;p&gt;I have a file &lt;code&gt;server.clj&lt;/code&gt; for each domain, which are in charge of setting up and starting / stopping the servlets.  So in &lt;code&gt;src/net/briancarper/server.clj&lt;/code&gt; I have something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ns net.briancarper.server
  (:use (compojure.http request servlet session routes)
        (compojure.server jetty)
        (compojure control)
        (net.briancarper ...)))  ;; lots of files containing the guts of the site

(defroutes some-routes ...)
(defroutes other-routes ...)

(defroutes all-routes
  some-routes
  other-routes)

(defserver blog-server
  {:port 8080 :host &quot;localhost&quot;}
  &quot;/*&quot; (servlet all-routes))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;src/net/ffclassic/server.clj&lt;/code&gt; is similar, except with different routes (obviously) and a different port for the servlet.  Note that we bind to &lt;code&gt;localhost&lt;/code&gt; here, so that people can't connect directly to port 8080 and bypass Apache.&lt;/p&gt;

&lt;p&gt;One of the routes should be set up to point to the proper &lt;code&gt;public&lt;/code&gt; folder.  Generally some catch-all route near the end of your list of routes, like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(GET &quot;/*&quot; (static-file (params :*)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where this &lt;code&gt;static-file&lt;/code&gt; knows to serve files from &lt;code&gt;briancarper.net/public&lt;/code&gt;, and the other &lt;code&gt;server.clj&lt;/code&gt; for the other domains point to different directories.&lt;/p&gt;

&lt;p&gt;Compojure has the &lt;code&gt;compojure.http.helpers/serve-file&lt;/code&gt; function you can use to serve static files too.  I use my own function for various reasons.  Note that Compojure generally doesn't set any HTTP headers on your responses.  You should probably set some kind of cache control headers unless you want your users to re-download all of your image files and stylesheets every time they hit a new page.  You might also have to fiddle with &lt;code&gt;Content-Type&lt;/code&gt; sometimes, though Compojure is usually pretty good about guessing them.&lt;/p&gt;

&lt;p&gt;Note that Compojure's hands-off approach has its upsides too.  For example, I have a bunch of CSS files for my blog.  In Clojure, I read and concatenate all of those CSS files into one blob of text and have Clojure serve that as &lt;a href=&quot;http://briancarper.net/combined.css&quot;&gt;http://briancarper.net/combined.css&lt;/a&gt;.  &lt;code&gt;combined.css&lt;/code&gt; doesn't actually exist.  I do the same for JS.  This speeds up user requests quite a bit, without having to merge all the files on the filesystem.  I could further compactify them if I cared.&lt;/p&gt;

&lt;p&gt;If your Clojure app is handling arbitrary request URIs, you should be careful you aren't serving up &lt;code&gt;../../../../etc/passwd&lt;/code&gt; or something.  Pretty sure Apache protects you against this by default, but Compojure uses &lt;code&gt;compojure.http.helpers/safe-path?&lt;/code&gt; to test for it too if you use the built-in &lt;code&gt;serve-file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, for convenience, in the base directory I have a file called &lt;code&gt;server.clj&lt;/code&gt; which contains this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(ns server
  (:require [net.briancarper server]
            [net.ffclassic server]))

(defn go []
  (.start net.briancarper.server/blog-server)
  (.start net.ffclassic.server/ffclassic-server))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, to start everything, from a REPL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (require 'server)
2010-01-04 18:10:50.046::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
net.briancarper.server.proxy$javax.servlet.http.HttpServlet$0
net.ffclassic.server.proxy$javax.servlet.http.HttpServlet$0
nil
user&amp;gt; (server/go)
2010-01-04 18:11:02.260::INFO:  jetty-6.1.15
2010-01-04 18:11:02.358::INFO:  Started SocketConnector@localhost:8080
2010-01-04 18:11:02.707::INFO:  jetty-6.1.15
2010-01-04 18:11:02.789::INFO:  Started SocketConnector@localhost:8087
nil
user&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;On the server (Apache)&lt;/h1&gt;

&lt;p&gt;To deploy this to my server I just &lt;code&gt;rsync&lt;/code&gt; it all over SSH.  On the server, I have Emacs and Java installed, as well as Apache and GNU Screen.&lt;/p&gt;

&lt;p&gt;Why Apache?  In case I want to run something that isn't Clojure, like webmail or some CGI script.  Plus it's easy to run Clojure as a non-priviledged user on a non-priviledged port, and have Apache forward requests to the proper servlet based on the domain in the request.  Apache is also nice for doing HTTPS.&lt;/p&gt;

&lt;p&gt;My Apache setup is a pretty standard Debian-ish setup.  You need &lt;code&gt;mod_proxy&lt;/code&gt; installed.  My Apache config for one domain looks a bit like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
        ServerName ffclassic.net
        ServerAlias www.ffclassic.net

        &amp;lt;Directory /home/user/clj/ffclassic.net/apache/&amp;gt;
           AllowOverride All
           Order Allow,Deny
           Allow from all
        &amp;lt;/Directory&amp;gt;

        DocumentRoot /home/user/clj/ffclassic.net/apache/

        ProxyPass /foo !
        ProxyPass / http://localhost:8087/
        ProxyPassReverse / http://localhost:8087/
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yeah, that's about it.  By default, every request will be passed to Clojure.  The ports specified here should obviously match the ports you specify in your Clojure code for your servlets.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ProxyPass /foo !&lt;/code&gt; tells Apache to handle requests to &lt;code&gt;http://ffclassic.net/foo&lt;/code&gt; itself rather than pass them to Clojure.  I override URIs on a case-by-case basis like this, to tell Apache to run whatever CGI or PHP scripts I need.&lt;/p&gt;

&lt;p&gt;One oddity of running a setup like this is that thanks to &lt;code&gt;mod_proxy&lt;/code&gt;, the &quot;remote address&quot; for every request is always going to be &lt;code&gt;127.0.0.1&lt;/code&gt; by the time they get to Clojure.  So if you want to see the IP address of your users, you have to do something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn- ip [request]
  (or ((:headers request) &quot;x-forwarded-for&quot;)
      (:remote-addr request)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Another oddity is that sometimes if Apache is running, and then I start Clojure, I have to restart Apache before it &quot;finds&quot; Clojure and starts forwarding traffic.  No big deal though.&lt;/p&gt;

&lt;p&gt;This is otherwise transparent from the Clojure end.&lt;/p&gt;

&lt;h1&gt;Starting it up&lt;/h1&gt;

&lt;p&gt;You probably want to SSH to your server, start a REPL, start your code running, and then log off the server.  There are various ways you can run keep Emacs running in the background.  You could run Emacs in server mode and attach to it with emacsclient.  I use GNU Screen because it's easy and I have other things running in Screen instances that I like to switch between.  So I start Screen, start Emacs, start SLIME, and start my site from there.  Then detach from Screen when I'm done.  It's easier than it sounds.&lt;/p&gt;

&lt;p&gt;Why SLIME and not a normal commandline REPL?  Because in Emacs I can patch the code easily on a function-by-function basis, among other things.  You can do this from a commandline REPL but not nearly as easily.  Emacs is a much nicer place to type than any command line.  When I need to make an update to the site or fix a bug, my workflow is typically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix it locally on my test machine, make sure it works&lt;/li&gt;
&lt;li&gt;rsync the changed files to the server&lt;/li&gt;
&lt;li&gt;SSH to the server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;screen -r&lt;/code&gt; to bring up Emacs&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;.clj&lt;/code&gt; file(s) I changed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-c C-c&lt;/code&gt; to recompile and reload the individual function(s) I changed, or &lt;code&gt;C-c C-k&lt;/code&gt; to recompile and load a whole &lt;code&gt;.clj&lt;/code&gt; file, or whatever.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-a d&lt;/code&gt; to detach from Screen&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I can do any database inspecting or fiddling I need to do from the REPL.  I can also do some live testing of the site or whatever else I want.  It's good for debugging.&lt;/p&gt;

&lt;p&gt;I've had Emacs running for months this way without having to restart it, it seems to work OK.&lt;/p&gt;

&lt;h1&gt;That's it&lt;/h1&gt;

&lt;p&gt;It's not that hard.  It's clearly more steps than dumping some PHP files into a directory and having them work.  But with Clojure, you get the benefit of a persistently running environment with a nice REPL interface, all in a nice fast multi-threaded JVM.  Plus you get to write all your code in Clojure instead of PHP.  In terms of fun and long-term maintenance costs, Clojure comes out way ahead in the end, for me anyways.&lt;/p&gt;</description></item><item><title>Clojure and Compojure to the rescue, again</title><link>http://briancarper.net/blog/clojure-and-compojure-to-the-rescue-again</link><guid>http://briancarper.net/blog/clojure-and-compojure-to-the-rescue-again</guid><pubDate>Sun, 03 Jan 2010 15:57:52 -0800</pubDate><description>&lt;p&gt;I haven't posted here much recently because I've been hacking on another recently-sort-of-completed website.  One of my favorite hobbies is old 8-bit video games.  The first thing I ever programmed was a &lt;a href=&quot;http://ffclassic.net&quot;&gt;website about Final Fantasy for the old NES&lt;/a&gt;, and I've fiddled with it for the past 10 years or so.&lt;/p&gt;

&lt;p&gt;A while back I decided to rewrite the whole thing using Clojure + Compojure with data in mysql.  This went really well.  I know lines of code isn't that great a metric, but it can give a rough estimate: this whole website is done in 3,400 lines of Clojure, which includes all of the HTML &quot;templates&quot; and the DB layer I had to write.  And it's &lt;del&gt;turtles&lt;/del&gt; Clojure all the way down.  The only thing not written in Clojure are a couple bits of Javascript here and there and the stylesheet.&lt;/p&gt;

&lt;p&gt;I suspect the target audience of this blog and the target audience of that website don't overlap that much, but I figured someone might be interested in some of the detail of how it's implemented.  A few things I learned...&lt;/p&gt;

&lt;!--more Read on --&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I didn't write a single line of HTML by hand.  I can't overemphasize how wonderful this is.  Compojure's HTML library lets you write HTML as Clojure data structures, with vectors being tags, keywords being tag names, hash-maps being attribute-value pairs etc.&lt;/p&gt;

&lt;p&gt;Not only is this easier to write, it's easy to generate and manipulate.  I have a ton of functions where given a list of hash-maps of data, it spits out a nicely formatted chart of that data.  Here's an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(chart &quot;Armor&quot; (armor game)
       [&quot;&quot; #(name-with-image %)
        &quot;Locations&quot; (comp ulist location-links :locations)
        &quot;Buy&quot; (comp g :buy)
        &quot;Sell&quot; (comp g :sell)
        &quot;Absorb&quot; :abs
        &quot;Evade%&quot; (comp percent :ev)
        &quot;Element&quot; (comp ulist #(map :name %) :elements)
        &quot;Casts&quot; #(-&amp;gt; % :magic :name)
        &quot;Usable by&quot; (comp (partial equipable-by game ps) :pcs)])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;chart&lt;/code&gt; is a function taking a chart title, some data, and then a vector of column-header names and functions for the data in each column.  Anonymous functions are a great way to format each column differently depending on the kind of data it contains.  &lt;code&gt;chart&lt;/code&gt; also does some other stuff like standardizing the text of the chart title, alternating the background color of rows of data, re-inserting the header every so often, and formatting the first column specially (expecting it to be a title) and so on.&lt;/p&gt;

&lt;p&gt;Sample output of this function is &lt;a href=&quot;http://ffclassic.net/nes/armor&quot;&gt;here&lt;/a&gt;.  A screenshot for the lazy (click for bigger version):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/random/ffclassic-armor.png&quot;&gt;&lt;img src=&quot;/random/thumbs/ffclassic-armor.png&quot; alt=&quot;Armor Page&quot; title=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Who needs an ORM?  &lt;a href=&quot;http://briancarper.net/blog/clojure-orm-ish-stuff&quot;&gt;I wrote about this previously&lt;/a&gt;, but for my needs, an ORM is overkill.  The vast majority of my interaction with a DB is reading data.  All you need for that is an easy way to write SQL queries and get the results into a hash-map.  I wrote a bunch of macros for this, and there's &lt;a href=&quot;http://gitorious.org/clojureql&quot;&gt;ClojureQL&lt;/a&gt; and &lt;code&gt;clojure.contrib.sql&lt;/code&gt; and friends to help.  For example I run some polls that users can vote on, and here's the entirety of the code that fetches it out of the DB.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn polls []
  (with-tables [polls poll_options poll_votes]
    (map (fn [p] (assoc p
                   :total (count (:votes p))))
         (-&amp;gt; polls
             (one-to-many :options poll_options (key= :id :poll_id))
             (one-to-many :votes poll_votes (key= :id :poll_id))))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;with-tables&lt;/code&gt; is a simple macro I wrote that fetches data from the DB for some table (possibly putting a &lt;code&gt;WHERE&lt;/code&gt; clause on the query if specified, unspecified here).  It takes care to run the minimal number of queries necessary, generally one query per table of data.  Then I use other functions like &lt;code&gt;one-to-many&lt;/code&gt; to join the data together.  The result is a list of hash-maps, with the value of some keys (here &lt;code&gt;:options&lt;/code&gt;, &lt;code&gt;:votes&lt;/code&gt;) being sub-lists of hash-maps, for data that &quot;belongs&quot; to the toplevel hash-map.&lt;/p&gt;

&lt;p&gt;Doing it this way helps me avoid the infamous &quot;N+1 queries&quot; which plagues naive use of Rails (where each of N objects would query the DB again to get its sub-lists of objects).  I think Rails uses an &lt;code&gt;:include&lt;/code&gt; option in its &lt;code&gt;find&lt;/code&gt; functions to do that same kind of thing.&lt;/p&gt;

&lt;p&gt;This is dirt-simple, but it gives me a lot of control.  I can easily &lt;code&gt;map&lt;/code&gt; or &lt;code&gt;filter&lt;/code&gt; over any of these intermediary table lists before or after putting the results together.  I can add keys with values that are calculated from other values, so it looks like the records have fields that don't really exist in the DB.  I can do a &lt;code&gt;sort-by&lt;/code&gt; on some key.  I can take a &lt;code&gt;user&lt;/code&gt; parameter and return different results based on whether that user is an admin or not.  I can put metadata on the hash-maps, e.g. to indicate which table the data was fetched from.  And so on.  &lt;/p&gt;

&lt;p&gt;Thanks to &lt;code&gt;memoize&lt;/code&gt; (see below) this is really fast too.  The most complicated query I have is for my walkthrough.  After priming the cache:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;net.ffclassic.db.charts&amp;gt; (time (dorun (walkthrough-chapters :nes)))
&quot;Elapsed time: 0.074587 msecs&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speaking of metadata: I like metadata.&lt;/p&gt;

&lt;p&gt;For example I have a multimethod called &lt;code&gt;link&lt;/code&gt;, which dispatches on the &lt;code&gt;:table&lt;/code&gt; metadata key set from my SQL macros above, and outputs an appropriate link for something based on what it is.  So &lt;code&gt;(link some-user)&lt;/code&gt; links to a user's profile on the site, using the user's username as the anchor text, and styles it differently if it's an admin user or normal user.  &lt;code&gt;(link some-forum-post)&lt;/code&gt; links to the forum thread which contains the post.  &lt;code&gt;(link some-poll)&lt;/code&gt; links to a poll using the poll's title as the anchor.&lt;/p&gt;

&lt;p&gt;Each of these spits out a vector that looks like &lt;code&gt;[:a {:href &quot;/user/view-profile/1&quot;} &quot;Brian&quot;]&lt;/code&gt;.  And that's changed into HTML eventually via Compojure's delicious HTML library.&lt;/p&gt;

&lt;p&gt;This makes it really easy to link to things in a standard way with standard-looking anchor text.  It also makes it easy to standardize on a URL scheme.  If I want to change the URLs used to access my polls, I only need to change it in one place.&lt;/p&gt;

&lt;p&gt;This is kind of like OOP, but not really, since I can have different metadata tags and use different ones depending on what I'm doing.  And I can completely ignore the metadata whenever I don't need to use it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speaking of multimethods: multimethods are handy.&lt;/p&gt;

&lt;p&gt;I have five &quot;categories&quot; of pages of data on my site, with pages in each category that are usually identical across categories.  But sometimes a page in one category should look slightly different from the same page in other categories.  Sometimes a page only belongs in one category and should 404 for the other categories.  What I needed was some way to say &quot;Display this page identically for each category by default, but page Y on category X is an exception&quot;.  &lt;/p&gt;

&lt;p&gt;Multimethods are great for this.  Compojure's &quot;routes&quot; take a request URI and dispatch based on a regex pattern matched against it.  I dispatch most requests to a series of multimethods.  Given a request URI, I split the URI into category + everything else.  Then, I first try a multimethod for category-specific pages, dispatching on a vector of &lt;code&gt;[category rest-of-uri]&lt;/code&gt;.  If there is no method for this, it falls through (returning &lt;code&gt;:next&lt;/code&gt;) and Compojure tries the next route.  The next route tries a multimethod for pages that look the same category-wide, dispatching only on &lt;code&gt;rest-of-uri&lt;/code&gt; this time.  If there's no method for that, it falls through again with &lt;code&gt;:next&lt;/code&gt; and a list of &quot;static&quot; routes are tried (oddball pages that don't belong to any category).  If those all fail, you get a 404.&lt;/p&gt;

&lt;p&gt;This is an easy way to split your site into namespaces based on the uri.  You can also add new pages without editing your Compojure routes.  Just add a new method to the multimethod.&lt;/p&gt;

&lt;p&gt;The code looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*code edited 2010-01-04 to fix a crapload of typos, thanks Shawn&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmulti category-specific-page (fn [cat page] [(keyword cat) (keyword page)]))
(defmethod category-specific-page :default [&amp;amp; _] :next)
(defmethod category-specific-page [:cat1 :some-page] [cat page]
  (...))


(defmulti cross-category-page (fn [cat page] (keyword page)))
(defmethod cross-category-page :default [&amp;amp; _] :next)
(defmethod cross-category-page :some-page [cat page]
  (...))


(defroutes some-routes
  (GET #&quot;/(cat1|cat2|cat3)/([^/+])/*$&quot; (apply category-specific-page (:route-params request)))
  (GET #&quot;/(cat1|cat2|cat3)/([^/+])/*$&quot; (apply cross-category-page (:route-params request)))
  (GET &quot;/&quot; (default-index-page))
  (ANY &quot;/*&quot; (error-404))) 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This was a nightmare to do properly in Rails.  Rails wants to dispatch to controllers, which are classes. To make this work in Rails I had to mangle this concept to fit into the idea of a hierarchy of classes and subclasses.  There might have been an elegant way to do it, but I couldn't think of one.  I suspect someone will leave me a &lt;del&gt;flame&lt;/del&gt; comment telling me how to do it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;memoize&lt;/code&gt; is great as a poor-man's web cache.  I have a bunch of pages of data that never change.  So the first request fetches it from the DB, and subsequent requests are cached in RAM and are therefore nearly instantaneous.  The data is cached in the form of huge lists of hash-maps (many of which have sublists of more hash-maps, sometimes many levels deep).  I was concerned at first that this might take a lot of RAM, but I went with it, and it turned out not to.    &lt;code&gt;top&lt;/code&gt; tells me:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
17   0  257m 127m  12m S    0 23.6  48:18.91 java 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'm actually running four websites in the same instance of the JVM there, so it's not that much RAM usage at all.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;memoize&lt;/code&gt; doesn't work for everything, obviously.  There's no easy way to invalidate or refresh the cache with the built-in &lt;code&gt;memoize&lt;/code&gt;, so it's not good for data that is updated frequently.  If you do need to invalidate some data, you have to re-compile the function.  But it works well for static data.  The great thing is that it's very fine-grained.  Change a single &lt;code&gt;defn&lt;/code&gt; to &lt;code&gt;defn-memo&lt;/code&gt; (in &lt;code&gt;clojure.contrib.def&lt;/code&gt;) and you're done.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compojure's &quot;decorators&quot; are really quite nice.  For example I use them to implement a kind of templating / layout system.  I have a &lt;code&gt;with-layout&lt;/code&gt; function which, given a response, wraps the HTML for that response in a standard layout (header, sidebar, footer).  I group a bunch of routes together and decorate all of those routes with &lt;code&gt;with-layout&lt;/code&gt;, and then it's done.  This &quot;layout&quot; code is completely separate from the code the generates the HTML for the pages, and lets me change it easily (add a new layout for some specific pages, or whatever).  A bunch of other routes, like those that handle POST requests and such, don't get a layout; I just group those routes separately and don't decorate them.&lt;/p&gt;

&lt;p&gt;All of this is done with plain old Clojure functions.  There's no separate &quot;template library&quot;.  There's no ERB or Smarty to wrestle with, though you could use something like &lt;a href=&quot;http://www.stringtemplate.org/&quot;&gt;StringTemplate&lt;/a&gt; if you wanted to.&lt;/p&gt;

&lt;p&gt;Another example: certain pages are admin-only.  So I group all of those pages together into one group of routes, and do the admin check first-thing, immediately failing if someone isn't logged in or if the current user isn't an admin.  This thankfully lets me not have to worry about doing permissions checks all over the place.  The code looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn admin-only [handler]
  (fn [request]
    (when (:admin (:session request))
      (handler request))))


(defroutes admin-routes
  (GET &quot;/some-admin-only-page&quot; (admin-page))
  (GET &quot;/another-admin-only-page&quot; (other-admin-page)))


(defroutes admin-form-routes
  (POST &quot;/some-admin-only-page&quot; (mangle-database)))


(decorate admin-routes with-layout admin-only with-session)
(decorate admin-form-routes admin-only with-session)


(defroutes all-routes
  admin-routes
  admin-form-routes
  other-routes
  etc.)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm overall pretty pleased with the site.  There are still some rough edges and much more work to be done, but it's a joy to code compared to the Rails version.&lt;/p&gt;</description></item><item><title>Comments work again</title><link>http://briancarper.net/blog/comments-work-again</link><guid>http://briancarper.net/blog/comments-work-again</guid><pubDate>Thu, 24 Dec 2009 12:20:06 -0800</pubDate><description>&lt;p&gt;I broke the ability to leave comments a couple days ago.  Thanks to everyone who let me know.  It's fixed now.&lt;/p&gt;

&lt;p&gt;I broke it while uploading yet another website I finished a couple days ago.  It's yet another Compojure/Clojure site, this time a bit more ambitious than my humble blog.  I plan to write about that whole experience once I have a bit of time.&lt;/p&gt;</description></item><item><title>Lame comment spam management that works</title><link>http://briancarper.net/blog/lame-comment-spam-management-that-works</link><guid>http://briancarper.net/blog/lame-comment-spam-management-that-works</guid><pubDate>Sun, 06 Dec 2009 02:34:08 -0800</pubDate><description>&lt;p&gt;It's been nine months since I ditched Wordpress and moved to a blog system I wrote from scratch (in Clojure).  This was a great move in so many ways.  One of those ways is comment spam.  My site is as popular now (or maybe slightly more popular now) as it was when I was running Wordpress, so I think comparing before and after is valid.&lt;/p&gt;

&lt;p&gt;With Wordpress, every morning I'd do the ritual of deleting overnight spambot droppings.  Typically I got between 1 and 5 every night.  I had a default Wordpress install and all I used for spam filtering was Askimet.  Askimet did a surprisingly good job, catching literally if not thousands of spams every week which otherwise would've been ruining my site.  But inevitably some would still get through.  And what's worse, there were a lot more false positives than I could tolerate.&lt;/p&gt;

&lt;p&gt;Since I started counting with my new system, which is around 6 months, to the best of my knowledge I've gotten &lt;strong&gt;zero&lt;/strong&gt; spambot-produced comments that made it through my filters.  This is pleasant, to say the least.&lt;/p&gt;

&lt;p&gt;The system I'm using is stupid.  None of it is stuff I thought of myself, I got ideas from other lots of other blogs or articles I read, but the implementation is mine and it's not sophisticated.  It would take a bot author a few seconds to work around it.  But no one has bothered.  Why bother writing a bot for my one-man blog, when you can write a bot for Wordpress and have it work on tens of thousands of blogs?  And I can change my system to defeat the bots with a few lines of code just as easily as they can work around it.&lt;/p&gt;

&lt;p&gt;So here's why I think it's working.&lt;/p&gt;

&lt;!--more Spam prevention measures below.--&gt; 

&lt;h1&gt;1. It's not Wordpress&lt;/h1&gt;

&lt;p&gt;Just by using something slightly different from Wordpress, I'm think I'm already ahead.  For example if you have a blog where a form posts comments to &lt;code&gt;/wp-comments-post.php&lt;/code&gt;, a bot doesn't even need to look at your site to spam you.  They can blast your server with POST data at that URL in a format they already know Wordpress will accept.  My site is all custom code, so everything is different enough that default bot attempts fail immediately.&lt;/p&gt;

&lt;p&gt;I think this is the reason that only &lt;strong&gt;1853&lt;/strong&gt; spam comments have even been POSTed at me in the last six months.  That's an improvement of one or two orders of magnitude already.&lt;/p&gt;

&lt;h1&gt;2. Honeypot text field&lt;/h1&gt;

&lt;p&gt;So what about the comments that are actually POSTed?  They are presumably the result of bots that parse sites' HTML looking for comment forms and try to POST data that satisfies the form.&lt;/p&gt;

&lt;p&gt;So in my comment form I have a field called &lt;code&gt;referer&lt;/code&gt;.  A &quot;How did you find my site?&quot; kind of thing.  In fact I don't care how you found this site, this field is a honeypot.  The div containing this field is hidden via CSS.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;div#referer-row {
    display: none;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So you shouldn't ever see it if you're a human using a browser.  But bots parsing the HTML see this field, unless they also bother to parse my CSS and see that it's hidden, which would be expensive and apparently they don't do it.&lt;/p&gt;

&lt;p&gt;If you put anything in this &lt;code&gt;referer&lt;/code&gt; field, your comment will be rejected as spam.  Simple enough.   &lt;/p&gt;

&lt;p&gt;Many blogs require you to fill in every field or else the comment is rejected, so it seems reasonable to expect most bots to fill in all of your form fields.  (My blog actually requires you to fill in nothing but the comment text; author will be set to &lt;code&gt;Anonymous Cow&lt;/code&gt; if you don't fill it in.)&lt;/p&gt;

&lt;p&gt;In fact this seems to be the case; of 1853 spam comments since March, &lt;strong&gt;1810&lt;/strong&gt; put something into this field.  Most of the time it's a random string of letters.  Not even a URL.  Sometimes it's a couple words like &quot;insurance quotes&quot; or something about drugs or casinos.&lt;/p&gt;

&lt;p&gt;The downside of this is if you're a human using a browser that doesn't understand CSS, you will see this field.  Then if you type something into it and try to comment, it'll end up as spam.  So Lynx users and time travelers from 1987 trying to leave me comments might be confused at first.  &lt;/p&gt;

&lt;p&gt;However as far as I can tell, no intelligible data has ever been entered into this field by a human, so I don't think it's a concern.  Six times, the word &quot;None&quot; was entered, but I don't think this is a human because that's nonsense answer to &quot;How did you find this site?&quot;.  But you never know.&lt;/p&gt;

&lt;h1&gt;3. Lame static CAPTCHA&lt;/h1&gt;

&lt;p&gt;That leaves 43 spam comments that made it this far.  My other anti-spam measure is a word you have to type.  But it's always the same word, and the word is &lt;strong&gt;COWS&lt;/strong&gt;.  This CAPTCHA caught the remaining 43.  It looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/random/captcha.png&quot; alt=&quot;CAPTCHA&quot; title=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There's a normal text field with a default value of &lt;code&gt;&amp;lt;= Type this word&lt;/code&gt; specified right in the HTML.  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; value=&quot;&amp;lt;= Type this word&quot; name=&quot;test&quot; id=&quot;test&quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are no other instructions besides &quot;Type this word&quot;.  I'm assuming either that commenters are familiar enough with CAPTCHAs to know what I want, or can figure it out using common sense.  Given that my target audience is computer geeks and programmers, this should be a safe assumption.  In fact I've had less than a dozen false positives in the past six months via people failing this; see below for details.&lt;/p&gt;

&lt;p&gt;To post a comment, the value of this field must contain the word &quot;COWS&quot; somewhere in it, case-insensitively.  Otherwise it's spam.  Easy enough to implement.&lt;/p&gt;

&lt;p&gt;If you have Javacsript enabled, clicking on this field will clear out the default value.  If you unfocus the field without typing anything, Javascript will put the default value back in.  This is only for convenience.  If you don't have Javascript enabled, you have to highlight and backspace over the default text.  I don't think this is a huge burden.&lt;/p&gt;

&lt;p&gt;Of 1853 spam comments, here's the breakdown for what values end up in this field.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1131: &quot;&amp;amp;lt;= Type this word&quot;
691:  &quot;&amp;lt;= Type this word&quot;
21:   Random letters and numbers
6:    empty
2:    A bunch of URLs
2:    Human beings making typos, e.g. &quot;COW&quot; or &quot;COS&quot;.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So most bots are too stupid even to remove the default value from the field, and none of them entered the correct value.  691 times the bot was somehow smart enough to un-escape &lt;code&gt;&amp;amp;lt;&lt;/code&gt; into &lt;code&gt;&amp;lt;&lt;/code&gt;, which is interesting, but didn't help it defeat the filter.  A lot of the random words look like they were made by Markov chains, e.g. 'fridwolfur' and 'lyndonvolk' and 'calbertdom'.  If I need to write a childerns' poem I'll know where to look for ideas.  One time a bot or spammer managed to type &quot;vows&quot; somehow, but this might or might not be coincidence.&lt;/p&gt;

&lt;p&gt;I think this is better than a normal CAPTCHA because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It's always the word &quot;COWS&quot; in a normal font, so it requires no thought or eye strain to figure out.&lt;/li&gt;
&lt;li&gt;It's black and white, so hopefully people with minor vision problems and color blindness can see it.&lt;/li&gt;
&lt;li&gt;It fits thematically with my blog layout (it's COWS and it has cow spots).&lt;/li&gt;
&lt;li&gt;It's kind of silly, so hopefully people chuckle rather than become ticked off.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's worse than a real CAPTCHA because it requires no effort to break. So it wouldn't work for Wordpress or VBulletin or something with a million users.  But I wonder if every Wordpress had a single static word as a CAPTCHA, but a different word for every blog (generated at install-time maybe), would it work better or worse than the random mangled multi-color CAPTCHAs no one can read?  Real randomly-generated CAPTCHAs don't work anyways; bots can already beat them via OCR or other means.  A simple word would be less annoying for a human, to be sure.&lt;/p&gt;

&lt;p&gt;The other downside is that this is not very accessible to the blind or other people using screen readers, or browsers without image support.  This is unfortunate and I'm still trying to figure out how to get around this.  Right now the ALT text for the CAPTCHA image is &lt;code&gt;This says 'COWS'&lt;/code&gt;; I don't know if this is enough help for people in those situations.&lt;/p&gt;

&lt;p&gt;Of course I'll never know how many people see my CAPTCHA and storm away in a rage without even trying to post a comment.  But I've never heard a complaint.  If this level of CAPTCHA ticks you off personally, please swallow your anger and leave me a comment here saying so, if you feel obliged; I'd love to hear it.&lt;/p&gt;

&lt;h1&gt;False positives&lt;/h1&gt;

&lt;p&gt;As best I can tell, there are no false positives from people filling in the honeypot field.  But even as simple as it is, some people don't succeed at the CAPTCHA image.  Either they typo it or they ignore it entirely.&lt;/p&gt;

&lt;p&gt;I just checked and I counted around 6 comments by real humans where the CAPTCHA was ignored and the default &lt;code&gt;&amp;lt;= Type this word&lt;/code&gt; ended up in the spam DB.  4 of those people re-posted their comment successfully immediately afterwards by filling in the CAPTCHA.  I'm not sure I'm ever going to get much better than that.&lt;/p&gt;

&lt;h1&gt;Spam that makes it through&lt;/h1&gt;

&lt;p&gt;I &lt;em&gt;have&lt;/em&gt; still gotten spam.  Maybe a dozen or so in the past six months.  It's all been in the form of a human typing a normal-looking and relevant comment, about open source software or BASH for example, but with a spammy URL buried in it, e.g. a link to a really dodgy-looking blog trying to sell something, or some scummy SEO site.  It's either a human or a very sophisticated (or lucky) bot; the comment text in these is indistinguishable from a real comment other than the spam URLs.  I have to delete these by hand.&lt;/p&gt;

&lt;p&gt;But I was getting these with Wordpress too.  No automted anti-spam system is going to defeat a human being, so I don't worry about it.&lt;/p&gt;

&lt;h1&gt;That's it&lt;/h1&gt;

&lt;p&gt;The moral of this story is that it doesn't take much to protect yourself from comment spam if you write the code yourself.  As long as it's unique, you'll probably be fine.&lt;/p&gt;

&lt;p&gt;The other moral is that you don't have to annoy the hell out of your users to filter spam effectively.  I'm making the assumption here that my COWS method is not that annoying; tell me if I'm wrong.&lt;/p&gt;

&lt;p&gt;I don't know how well this scales.  Probably not so well.  My blog isn't that highly trafficked.  If my site were more popular it might be worse for me.  But the improvement over Wordpress is unquestionable.&lt;/p&gt;

&lt;p&gt;I've seen all kinds of complicated measures suggested elsewhere, like trying to predict if it's a bot by how many milliseconds it takes between page load and comment posting, or measuring keypress speed, or escaping the HTML of your forms and un-escaping it at loadtime it via Javascript, or setting and retrieving cookies and such.  But a lot of this stuff seems fragile and if your browser doesn't suppoort Javascript or cookies (or your users block them), you're screwed.  I block these things myself, so I expect visitors to do the same.&lt;/p&gt;

&lt;p&gt;If everyone wrote their own blog engines, the world would be a slightly less spammy place.  Or else we'd have much smarter bots.&lt;/p&gt;</description></item><item><title>Godaddy sucks</title><link>http://briancarper.net/blog/godaddy-sucks</link><guid>http://briancarper.net/blog/godaddy-sucks</guid><pubDate>Sun, 22 Nov 2009 12:56:57 -0800</pubDate><description>&lt;p&gt;I'm in the process of moving all my domains the heck off of Godaddy.  I'm trying &lt;a href=&quot;http://www.namecheap.com&quot;&gt;Namecheap&lt;/a&gt; which seems slightly less evil, if the sheer amount of ad banners and upselling bullcrap is any indication.  But probably only slightly less evil.&lt;/p&gt;

&lt;p&gt;Honestly Godaddy has so many ads I can't even find the button to renew my domains.  The process of buying anything takes you through 6 or 7 pages of the most garish, fanatical sleaze-peddling that you are likely to encounter on a website.&lt;/p&gt;

&lt;p&gt;Domain registrars are the used car salesmen of the internet.&lt;/p&gt;</description></item><item><title>Blog source code updated</title><link>http://briancarper.net/blog/blog-source-code-updated</link><guid>http://briancarper.net/blog/blog-source-code-updated</guid><pubDate>Thu, 22 Oct 2009 23:59:25 -0700</pubDate><description>&lt;p&gt;I updated the source code of my blog &lt;a href=&quot;http://github.com/briancarper/cow-blog&quot;&gt;on github&lt;/a&gt;.  I'm too tired to write much about it at the moment.&lt;/p&gt;

&lt;p&gt;Suffice it to say I rewrote it all from scratch for the purpose of sharing, because lots of people were asking for it.  It uses Tokyo Cabinet instead of mysql now, which is nice.  I gutted the codebase so it's about 700 lines now (down from 1500, not bad).  I plan to write up some posts later exploring various parts of it, for those who are interested.&lt;/p&gt;

&lt;p&gt;Hope someone gets something out of it.  Use at your own risk.&lt;/p&gt;</description></item><item><title>Moved to Linode</title><link>http://briancarper.net/blog/moved-to-linode</link><guid>http://briancarper.net/blog/moved-to-linode</guid><pubDate>Sat, 15 Aug 2009 23:03:33 -0700</pubDate><description>&lt;p&gt;My web host for a good long while was &lt;a href=&quot;http://www.futurehosting.com/&quot;&gt;Futurehosting&lt;/a&gt;.  My OS was Debian 4.0 (Etch).  Strike one: as of now there's still no option to upgrade to a newer version of Debian.  Debian lags so much to begin with, it's really painful ify ou want to use anything released in the past two years.&lt;/p&gt;

&lt;p&gt;I had an unmanaged VPS.  I ran a bunch of funky non-standard stuff on there and it ran mostly OK.  I had to upgrade to get more RAM just so SBCL would run on it, which sucked but I don't know that another host would've been any better.&lt;/p&gt;

&lt;p&gt;The good thing about Futurehosting was that they responded very fast to tickets.  The bad thing was the fact that I had ample opportunity to know this.  The server would go down randomly once every month or two.  I'd open a ticket saying &quot;Hi my server is down&quot;, then things would be working again in a half hour, but why did this happen so often?  I don't know.  An awful lot of &quot;failed switches&quot;.  I wonder how often this happened without my knowing about it, given how often it happened in the middle of my using the server for something.&lt;/p&gt;

&lt;p&gt;With all the hardware they were burning through I would've expected upgrades or price reductions over time, given that I was a steady customer for so long and that disk space and memory keeps becoming cheaper and cheaper in the world.  But the prices always stayed the same, which was another strike.&lt;/p&gt;

&lt;p&gt;Being hosted there was annoying but never annoying enough to switch. And migrating all of my sites and data to another server seemed like a huge pain.  Momentum: the worst enemy of progress.&lt;/p&gt;

&lt;p&gt;I moved to a new host on a whim recently: &lt;a href=&quot;http://linode.com&quot;&gt;Linode&lt;/a&gt;.  It was far less painful than I expected.  Thanks to Linux and plaintext config files, it was mostly a SCP-it-all-over and tweak process.  It took me one evening and a bit of time the next morning.  Linode offers a lot of OSes which is also nice.&lt;/p&gt;

&lt;p&gt;I pay less for Linode than I did at FH (and I get fewer resources at Linode, but I don't need much).   Thus far I'm astonished how much faster things are running on the server.  Even goofing off at a terminal, the shell is more responsive.  My email loads instantly in kmail instead of lagging for a second.  I never knew what I was missing.  Linode's DNS control panel is also pretty braindead simple to use.&lt;/p&gt;

&lt;p&gt;Futurehosting gets a C+ from me.  It worked and my website existed, but it didn't knock my socks off.  Hopefully Linode is better.&lt;/p&gt;</description></item><item><title>Adventures in blogging</title><link>http://briancarper.net/blog/adventures-in-blogging</link><guid>http://briancarper.net/blog/adventures-in-blogging</guid><pubDate>Tue, 04 Aug 2009 00:24:23 -0700</pubDate><description>&lt;p&gt;So my newest site is &lt;a href=&quot;http://stuffthatlookslikejesus.com/&quot;&gt;about pareidolia&lt;/a&gt; which I think is an interesting subject.  It's still in its early stages, using a data import from yet another of my old sites that I ran with a friend of mine.  This makes three websites I'm running out of the same JVM on my server now.  It'll be interesting to see how many more I can cram in there before my VPS explodes.  CPU and RAM utilization are still supposedly minimal.  I actually plan to redo my old faltering &lt;a href=&quot;http://ffclassic.net/&quot;&gt;FF1 site&lt;/a&gt; entirely in Clojure too, which is probably the largest Clojure project I plan to undertake in the foreseeable future.&lt;/p&gt;

&lt;p&gt;I'm still trying to come up with some kind of &quot;how to make a blog in Clojure&quot; tutorial once I nail down a good way to do it.  The code for my blog has &quot;grown organically&quot; (i.e. become a mess) beyond the point where I'd inflict it upon the world without substantial cleanup.  Probably easier to start over from scratch with something that's more demonstrative.  &lt;/p&gt;

&lt;p&gt;I'm also not too savvy on many of the &quot;right ways&quot; to do things in Compojure, as per &lt;a href=&quot;http://groups.google.com/group/compojure/browse_thread/thread/82ea788b2e0717e&quot;&gt;this discussion&lt;/a&gt;.  That's the good and bad thing about using a Lisp.  You can pull off almost anything.  There is no underlying structure to the code other than structure you impose.  It's easy to write a mess.&lt;/p&gt;</description></item><item><title>Who needs a DB?</title><link>http://briancarper.net/blog/who-needs-a-db</link><guid>http://briancarper.net/blog/who-needs-a-db</guid><pubDate>Wed, 20 May 2009 22:53:03 -0700</pubDate><description>&lt;p&gt;My blog is still working, in spite of my best efforts to crash it.  So that's good.  But lately I've been thinking that an SQL database is a lot of overkill just to run a little blog like this.&lt;/p&gt;

&lt;p&gt;My blog only has around 450 posts total (over the course of many years), and about an equal number of user comments (thanks to all commenters!).  Why do I need a full-blown database for that?  All of my posts plus comments plus all meta-data is only 2 MB as a flat text file, 700k gzipped.&lt;/p&gt;

&lt;p&gt;By far the most complicated part of my blog engine is the part that stuffs data into the database and gets it back out again in a sane manner (translating Clojure data to SQL values, and back again; splitting up my Clojure data structures into rows for different tables, and then re-combining values joined from multiple tables into one data structure).  Eliminating that mess would be nice.  &lt;/p&gt;

&lt;p&gt;Inevitably I ended up with some logic in the database too: enforcing uniqueness of primary keys, marking some fields as NOT NULL, giving default values and so on.  But a lot of other logic was in my Clojure code, e.g. higher-level semantic checking, and some things I wanted to set as default values were impossible to implement in SQL.  &lt;/p&gt;

&lt;p&gt;Wouldn't it be nice for all the logic to be in Clojure?  And the data store on disk to be a simple dump of a Clojure data structure?  I can (and did) write a few macros to give me SQL-like field declaration and data validation, for uniqueness of IDs and data types etc.  For my limited needs it works OK.  &lt;/p&gt;

&lt;p&gt;The next question is what format to use for dumping to disk.  Happily Clojure is Lisp, so dumping it as a huge s-exp via &lt;code&gt;pr-str&lt;/code&gt; works fine, and reading it back in later via &lt;code&gt;read-string&lt;/code&gt; is trivial.&lt;/p&gt;

&lt;p&gt;Some Java data types can't be printed readably by default, for example &lt;code&gt;java.util.Date&lt;/code&gt;s, which print like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#&amp;lt;Date Wed May 20 22:39:00 PDT 2009&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;#&amp;lt;&amp;gt;&lt;/code&gt; reader macro deliberately throws an error if you try to read that back in, because the reader isn't smart enough to craft Date objects from strings by default.  But Clojure is extensible; you can specify a readable-print method for any data type like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defmethod clojure.core/print-method java.util.Date [o w]
  (.write w (str &quot;#=&quot; `(java.util.Date. ~(.getTime o)))))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now dates print as &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#=(java.util.Date. 1242884415044)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and if you try to read that via &lt;code&gt;read-string&lt;/code&gt;, it'll create a Date object like you'd expect.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (def x (read-string &quot;#=(java.util.Date. 1242884415044)&quot;))
#'user/x
user&amp;gt; (class x)
java.util.Date
user&amp;gt; (str x)
&quot;Wed May 20 22:40:15 PDT 2009&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Storing data in a plain file has another benefit of letting me grep my data from a command line, or even edit the data in a text editor and re-load it into the blog (God help me if that's ever necessary).&lt;/p&gt;

&lt;p&gt;Having multiple threads banging on a single file on disk is a horrible idea, but Clojure refs and agents and transactions handle that easily.  But I do have to work out how not to lose all my data in case the server crashes in the middle of a file update.  (I've lost data (in a recoverable way) due to a server crash in the middle of a MySQL update too, so this is a problem for everyone.)  Perhaps I'll keep a running history of my data, each update being a new timestamped file, so old files can't possibly be corrupted.  Or use the old write-to-tmp-file-and-rename-to-real-file routine.  Or heck, I could keep my data in Git and use Git commands from Clojure.  It'd be nice to have a history of edits.&lt;/p&gt;

&lt;p&gt;If this idea works out I'll upload code for everything to github, as usual.&lt;/p&gt;</description></item><item><title>Blog and CRUD</title><link>http://briancarper.net/blog/blog-and-crud</link><guid>http://briancarper.net/blog/blog-and-crud</guid><pubDate>Sun, 12 Apr 2009 20:01:35 -0700</pubDate><description>&lt;p&gt;I updated my &lt;a href=&quot;http://github.com/briancarper/cow-blog/tree/master&quot;&gt;blog source code on github&lt;/a&gt;.  I also split my CRUD library out into its own &lt;a href=&quot;http://github.com/briancarper/clj-crud/tree/master&quot;&gt;clj-crud&lt;/a&gt; repo.  It is cruddy, so the name is apt.&lt;/p&gt;

&lt;p&gt;This code still isn't polished enough for someone to drop it on a server and fire it up, but maybe it'll give someone some ideas.  I think the new code is cleaner and it'll be easier for me to add features now.&lt;/p&gt;

&lt;p&gt;Beware bugs, I'm positive I introduced some.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt;: A word about the CRUD library... persisting data to disk is hard when the data may be mutated by many threads at once and the destination for your data is an SQL database that may or may not even be running.  I have more respect for people who've written libraries that actually do this kind of thing and work right.  Granted I only spent 3 days on mine but still, it's tricky.&lt;/p&gt;

&lt;p&gt;I gave up for a while and tried &lt;a href=&quot;http://github.com/duelinmarkers/clj-record/tree/master&quot;&gt;clj-record&lt;/a&gt;, but it was prohibitively slow.  It has the old N+1 queries problem when trying to select an object which has N sub-objects.  In real life you'd write SQL joins to avoid such things.  Ruby on Rails on the other hand gets around this via some nasty &lt;code&gt;find&lt;/code&gt; syntax.  &lt;/p&gt;

&lt;p&gt;I get around it by having all my data in a Clojure ref in RAM already so it doesn't matter.  And by using hooks so each object keeps a list of its sub-objects and the list is always up-to-date (updates of sub-objects propagate to their parents).  But the crap I have to do to get this to just barely work is pretty painful.&lt;/p&gt;</description></item><item><title>Blog source code released</title><link>http://briancarper.net/blog/blog-source-code-released</link><guid>http://briancarper.net/blog/blog-source-code-released</guid><pubDate>Fri, 27 Mar 2009 02:14:53 -0700</pubDate><description>&lt;p&gt;By popular demand, I've released the source code for my blog.  Hope someone finds it useful.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/briancarper/cow-blog/tree/master&quot;&gt;http://github.com/briancarper/cow-blog/tree/master&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback and bug reports welcome, email me or post them somewhere on my blog and I'll find them.&lt;/p&gt;</description></item><item><title>Anti-spam field still holding</title><link>http://briancarper.net/blog/anti-spam-field-still-holding</link><guid>http://briancarper.net/blog/anti-spam-field-still-holding</guid><pubDate>Mon, 23 Mar 2009 19:38:27 -0700</pubDate><description>&lt;p&gt;So far my silly anti-spam measures are working.  Since last week I've had 1861 spam comment attempts, of which 0 were successful.  1857 of them didn't even alter the text my the captcha text field at all.  Four of them inexplicably HTML-escaped the &lt;code&gt;&amp;lt;&lt;/code&gt; into a &lt;code&gt;&amp;amp;lt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One feature I didn't implement from Wordpress is subscribing to comments via email.  Sending an email from Java is possible but a little bit painful to implement.  The Javamail API is a monster.&lt;/p&gt;

&lt;p&gt;I do think it's useful to be able to know when someone responds to comment you left, but is spamming your inbox really the best way?  I have to think there's a better way.&lt;/p&gt;

&lt;p&gt;I did implement an RSS feed for each individual post's comments.  And separate RSS feeds for all the tags on my blog, and all the categories.  When RSS feeds are generated dynamically, why not?  This is all of the code for the tag feeds:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(defn tag-rss [tagname]
  (if-let [tag (get-tag tagname)]
    (rss
        (str &quot;briancarper.net Tag: &quot; (:name tag))
        (str &quot;http://briancarper.net/&quot; (:url tag))
        &quot;briancarper.net&quot;
        (map rss-item (take 25 (all-posts-with-tag tag))))
    (error-404 )))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Plus the routing code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(GET &quot;/feed/tag/:name&quot; (tag-rss (route :name)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But I haven't uploaded the comment-feed feature because I don't know if it's overkill.  Personally I am liberal with my RSS feeds, I just pop them into my Akregator and off I go.  But I don't know if other people take their feeds more seriously, or what.  RSS feeds can be a bit heavyweight.  Maybe I should make a feed for all of my comments across all posts.&lt;/p&gt;</description></item><item><title>Blog is still going strong</title><link>http://briancarper.net/blog/blog-is-still-going-strong</link><guid>http://briancarper.net/blog/blog-is-still-going-strong</guid><pubDate>Wed, 18 Mar 2009 22:01:11 -0700</pubDate><description>&lt;p&gt;After I implemented that silly CAPTCHA yesterday, the spam was stopped.  There's also a honeypot form field (it's hidden via CSS so humans don't know it's there, and if any bot POSTs text for that field, the data is rejected automatically).  It's silly and easily defeated, yet it stopped all 262 spam attempts since yesterday.  It looks like all the spam is for one site, but it's coming from a huge range of IPs.  So it's probably a botnet.  Thanks, MS Windows!&lt;/p&gt;

&lt;p&gt;I rewrote my whole CRUD layer so that I could use it for more than one database at once, and then rewrote my gallery code to take advantage, and now two hours later I have my &lt;a href=&quot;http://origamigallery.net&quot;&gt;origami gallery&lt;/a&gt; back up and running.  Both sites are running from the same JVM.  I wonder how many sites I can have going at once before the server melts into a puddle of Java-inflicted goo.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  PID PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
11338 16   0  512m 128m  12m S    0  0.3   0:28.33 java
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Good thing I have plenty of RAM on the server.  From looking at before and after shots of the memory usage, 66 MB is the JVM itself, and 40MB more is Jetty and Compojure and my code and all the dependencies.  Then the last ~20 MB or so is my database slurped into RAM.  So I can probably fit another few tens of thousands of posts and comments in here before I have to worry much.  The real test will be letting this thing run for a couple weeks and see how hard it leaks.&lt;/p&gt;</description></item><item><title>Fun with HTTP headers</title><link>http://briancarper.net/blog/fun-with-http-headers</link><guid>http://briancarper.net/blog/fun-with-http-headers</guid><pubDate>Tue, 17 Mar 2009 22:14:10 -0700</pubDate><description>&lt;p&gt;One fun thing about playing with Compojure is that it doesn't do much with HTTP headers for you, which is a good learning opportunity.  &lt;a href=&quot;http://tools.ietf.org/html/rfc2616&quot;&gt;RFC 2616&lt;/a&gt; is rather helpful here.&lt;/p&gt;

&lt;p&gt;For example I learned that if you don't set a &lt;code&gt;Cache-Control&lt;/code&gt; or &lt;code&gt;Expires&lt;/code&gt; header, your browser will happily re-fetch files over and over, which is a bit of performance hit.  Static files that don't change often like images etc. can be set with a higher &lt;code&gt;Expires&lt;/code&gt; value so they're cached.&lt;/p&gt;

&lt;p&gt;Another thing to keep in mind (note to self) is that using &lt;a href=&quot;http://httpd.apache.org/docs/2.0/mod/mod_proxy.html&quot;&gt;mod_proxy&lt;/a&gt; to forward traffic to a local Jetty server means that the &quot;remote IP&quot; you get from &lt;code&gt;(.getRemoteAddr request)&lt;/code&gt; will always be &lt;code&gt;127.0.0.1&lt;/code&gt;.  If you want the user's real remote IP, you have to look in the &lt;code&gt;X-Forwarded-For&lt;/code&gt; header (easily accessed as &lt;code&gt;(:x-forwarded-for headers)&lt;/code&gt; in Compojure.  Given that &lt;a href=&quot;http://en.wikipedia.org/wiki/Identicon&quot;&gt;Identicons&lt;/a&gt; are generated from a hash of an IP address, this has resulted in some screwed up (wrongly identical) avatars for a bunch of people in posts for the past couple days.  Oops.  Not much I can do to fix that now.&lt;/p&gt;

&lt;p&gt;In other non-news, I just the spam logging for the blog so I can see the kinds of things bots are doing to get around my feeble anti-spam measures.  Sadly the spam seems to have stopped entirely, right after I set this up.  How annoying.&lt;/p&gt;</description></item></channel></rss>
