<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>xyzzy xyzzy...</title>
	<atom:link href="http://xyzzyxyzzy.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://xyzzyxyzzy.net</link>
	<description>...you are in a grid of twisty, little links, all alike. there's a teleport gate here.</description>
	<lastBuildDate>Fri, 01 Mar 2013 19:47:59 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>spamassassin: learning from inbox and junk folders</title>
		<link>http://xyzzyxyzzy.net/2012/09/15/spamassassin-learning-from-inbox-and-junk-folders/</link>
		<comments>http://xyzzyxyzzy.net/2012/09/15/spamassassin-learning-from-inbox-and-junk-folders/#comments</comments>
		<pubDate>Sat, 15 Sep 2012 06:28:35 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[void]]></category>
		<category><![CDATA[auto learn]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[spamassassin]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=843</guid>
		<description><![CDATA[while tweaking the spam filters on our mail server i finally took the step of adding a cron job to learn from the inbox and junk folders of each user. as we are using spamassassin as part of our spam defense this basically involves a couple of invocations of sa-learn to learn the &#8220;ham&#8221; from [...]]]></description>
				<content:encoded><![CDATA[<p>while tweaking the spam filters on our mail server i finally took the step of adding a cron job to learn from the inbox and junk folders of each user. as we are using <a href="http://spamassassin.apache.org/">spamassassin</a> as part of our spam defense this basically involves a couple of invocations of <code>sa-learn</code> to</p>

<ul>
<li>learn the &#8220;ham&#8221; from each users inbox folder</li>
<li>learn the &#8220;spam&#8221; from each users junk folder</li>
</ul>

<p>below is the shell script that gets invoked by cron once a day:</p>

<p></p><pre class="crayon-plain-tag">#!/bin/bash
echo &quot;updating spamassassin bayesian spam/ham filter&quot;
echo
for userDir in /home/*; do

    user=$(basename $userDir)
    ham=$userDir/Maildir/{cur,new}
    spam=$userDir/Maildir/.Junk/{cur,new}

    echo &quot;    learning from $user&quot;

    echo &quot;       spam: $spam&quot;
    /usr/bin/sa-learn --no-sync --spam $spam | while read line; do
	echo &quot;            $line&quot;
    done

    echo &quot;        ham: $ham&quot;
    /usr/bin/sa-learn --no-sync --ham $ham | while read line; do
	echo &quot;            $line&quot;
    done

    echo
done
echo &quot;syncing:&quot;
/usr/bin/sa-learn --sync | while read line; do
    echo &quot;    $line&quot;
done
echo
echo &quot;stats:&quot;
sa-learn --dump magic | while read line; do
    echo &quot;    $line&quot;
done</pre><p></p>

<p>the <code>while read line; do ... done</code> bits are there so that i can nicely indent the output of <code>sa-learn</code>.</p>

<p>works rather nicely.</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2012/09/15/spamassassin-learning-from-inbox-and-junk-folders/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ajax fun with jquery &amp; python</title>
		<link>http://xyzzyxyzzy.net/2012/07/01/ajax-fun-with-jquery-python/</link>
		<comments>http://xyzzyxyzzy.net/2012/07/01/ajax-fun-with-jquery-python/#comments</comments>
		<pubDate>Sun, 01 Jul 2012 14:47:18 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[REST]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=802</guid>
		<description><![CDATA[the other day i tried to come up with a minimalistic Ajax setup — minimalistic in the sense of minimal coding overhead. my ingredients of choice were jquery and JavaScript on the client side and python on the server side. the goal was to use both GET and POST REST calls for obtaining the dynamic [...]]]></description>
				<content:encoded><![CDATA[<p>the other day i tried to come up with a minimalistic Ajax setup — minimalistic in the sense of minimal coding overhead. my ingredients of choice were jquery and JavaScript on the client side and python on the server side. the goal was to use both GET and POST REST calls for obtaining the dynamic data and utilize JSON as the data format.</p>

<p>the python server code makes use of python&#8217;s <code>BaseHTTPServer.HTTPServer</code> and <code>BaseHTTPServer.BaseHTTPRequestHandler</code> classes:</p>

<p><a href="http://xyzzyxyzzy.net/wp-content/uploads/2012/06/ajaxserver-e1341086477961.png"><img class="aligncenter size-full wp-image-805" title="Ajax server python side" alt="" src="http://xyzzyxyzzy.net/wp-content/uploads/2012/06/ajaxserver-e1341086477961.png" width="600" height="456" /></a></p>

<p><span id="more-802"></span></p>

<p><code>AjaxServer</code> extends <code>BaseHTTPServer.HTTPServer</code> and supplies <code>Handler</code> which in turn extends <code>BaseHTTPServer.BaseHTTPRequestHandler</code>. the <code>Handler</code> class also implements the GET and POST REST interfaces.</p>

<p>the <em>server</em> supports</p>

<ul>
<li><code>text/html</code> GETs on file names from the document root, retrieving <code>index.html</code> for GETs on directories, and</li>
<li><code>application/json</code> GETs on</li>
<li><code>/ajax/time</code> returning the current time</li>
<li><code>/ajax/processcount</code> returning the number of currently running processes</li>
<li><code>application/json</code> POSTs on any URL returning the length of the posted content</li>
</ul>

<p>the <em>client</em> is a simple HTML5 page that uses jquery&#8217;s <code>ajax()</code> support to invoke the GET REST and POST REST calls on our python server.</p>

<h3>client code</h3>

<div>
<pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;title&gt;AJAX sandbox&lt;/title&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
&lt;meta name="description" content="not found document"&gt;
&lt;meta name="author" content="hud@zurich.ibm.com"&gt;
&lt;link href="css/bootstrap.css" rel="stylesheet"&gt;
&lt;style&gt;
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
&lt;/style&gt; 

&lt;!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --&gt;
&lt;!--[if lt IE 9]&gt;
&lt;script src="http://html5shim.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;
&lt;![endif]--&gt;
&lt;/head&gt;
&lt;body id="home"&gt;
&lt;div&gt;OK, let's go!&lt;/div&gt;

&lt;div&gt;current time: &lt;span id="ajax-datetime"&gt;waiting for time update...&lt;/span&gt;&lt;/div&gt;

&lt;div&gt;current process count: &lt;span id="ajax-processcount"&gt;waiting for process count update...&lt;/span&gt;&lt;/div&gt;

&lt;div&gt;&lt;input id="typehere" type="text" value="type here" /&gt;&lt;/div&gt;
&lt;div id="ajax-processedinput"&gt;waiting for result&lt;/div&gt;

&lt;!-- JavaScript at the bottom to speed up page loading --&gt;
&lt;script src="/js/jquery-1.7.2.min.js"&gt;&lt;/script&gt;
&lt;script src="/js/bootstrap.min.js"&gt;&lt;/script&gt;
&lt;script src="/js/ajax-datetime.js"&gt;&lt;/script&gt;
&lt;script src="/js/ajax-processcount.js"&gt;&lt;/script&gt;
&lt;script src="/js/ajax-processinput.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>

<p>the HTML5 code itself doesn&#8217;t really do anything. the magic happens in the <code>ajax-datetime.js</code>, <code>ajax-processcount.js</code>, <code>ajax-processinput.js</code> javascripts:</p>

<p><code>ajax-datetime.js</code> calls the <code>/ajax/time</code> GET REST method every 3 seconds and sets the content of the <code>#ajax-datetime</code> div element to the return value of the GET REST call:</p>

<div>&lt;pre lang=&#8221;javascript&#8221;&gt;
<pre class="crayon-plain-tag">$(document).ready(function() { 

function updateDateTime() {
$.ajax({
cache: false,
url: "/ajax/time",
type: "GET",
contentType: "application/json",
}).done(function(json) {
$("#ajax-datetime").html(json.time);
});
}

setInterval(updateDateTime, (3 * 1000));
});</pre>
</div>

<p>pretty much the same procedure is used for <code>ajax-processcount.js</code>:</p>

<div>
<pre class="crayon-plain-tag">$(document).ready(function() { 

function updateProcessCount() {
$.ajax({
cache: false,
url: "/ajax/processcount",
type: "GET",
contentType: "application/json",
}).done(function(json) {
$("#ajax-processcount").html(json.processcount);
}).error(function(json) {
$("#ajax-processcount").html("connection to server lost...");
});
}

setInterval(updateProcessCount, (5 * 1000));
});</pre>
</div>

<p>the only difference is that <code>ajax-processcount.js</code> invokes the <code>/ajax/processcount</code> GET REST method and does so every 5 seconds &#8212; demonstrating the asynchronous nature of AJAX rather nicely.</p>

<p>while the previous two javascripts used GET to retrieve information from our python server, the next, <code>ajax-processinput.js</code> attaches itself to the <code>#typehere</code> text input field and POSTs the content of the field to <code>/ajax/processinput</code>, returning the result of the POST REST call via the <code>#ajax-processedinput</code> div element:</p>

<div>
<pre class="crayon-plain-tag">(document).ready(function() { 

function processInput() {
$.ajax({
cache: false,
url: "/ajax/processinput",
type: "POST",
contentType: "application/json",
dataType: "json",
data: JSON.stringify({ "input": $("#typehere").val() })
}).done(function(json) {
$("#ajax-processedinput").html(json.processed);
}).error(function(json) {
$("#ajax-processedinput").html("connection to server lost...");
});
}

$("#typehere").change(function () {
processInput();
});
});</pre>
</div>

<p>unfortunately, even though i tell <code>ajax(...)</code> that i&#8217;m sending JSON &#8212; the <code>contentType: "application/json"</code> line &#8212; jquery will not convert the data i&#8217;m sending into JSON and i need to explicitly turn it into JSON myself:</p>

<div>
<pre class="crayon-plain-tag">...
data: JSON.stringify({ "input": $("#typehere").val() })
...</pre>
</div>

<h3>server code</h3>

<p>the server code consists of two modules: <code>ajaxserver</code> and <code>handler</code>.</p>

<p><code>handler</code> contains the <code>Handler</code> class which extends <code>BaseHTTPServer.BaseHTTPRequestHandler</code> and implements the GET and POST REST calls explained earlier:</p>

<div>
<pre class="crayon-plain-tag">#!/usr/bin/env python2.6
# -*- encoding: utf-8 -*- 

'''
handler.Handler is the HTTP handler for ajaxserver
'''

import BaseHTTPServer
import logging as log
import os
import subprocess

try:
import simplejson as json
except ImportError:
import json

from datetime import datetime

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

def logRequest(s):
log.debug("%s: %s/%s" %(s.client_address, s.command, s.path))

def do_GET(self):
self.logRequest()

path = self.path

if 'Content-type' in self.headers:
contentType = self.headers['Content-type']
else:
contentType = 'text/html'

log.debug("ajaxserver.GET: Path %s" % path)
log.debug("ajaxserver.GET: Content-type %s" % contentType)

if contentType.startswith('text/html'):
(respCode, respContent, respContentType) = self.do_GET_HTML()
elif contentType.startswith('application/json'):
(respCode, respContent, respContentType) = self.do_GET_JSON()

self.send_response(respCode, "thank you")
self.send_header('Content-type', respContentType)
self.send_header('Content-length', len(respContent))
self.end_headers()

self.wfile.write(respContent)

def do_POST(self):
self.logRequest()

path = self.path
contentType = self.headers['Content-type']

log.debug("ajaxserver.POST: Path %s" % path)
log.debug("ajaxserver.POST: Content-type %s" % contentType)

if not contentType.startswith('application/json'):
self.send_response(404, "oh, shiny!")
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({ "error": "only accepting application/json" }))
return

contentLength = int(self.headers['Content-length'])
content = self.rfile.read(contentLength)

log.debug("ajaxserver.POST: Content-length %d" % contentLength)
log.debug("ajaxserver.POST: Content: %s" % content)

data = json.loads(content)
if 'input' not in data:
log.debug("ajaxserver.POST: missing input parameter: %s" % content)
self.send_response(404, "oh, shiny!")
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({ "error": "missing input parameter" }))
return

self.send_response(200, "oh, shiny!")
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({ "processed": len(data['input'])}))

return

def do_GET_HTML(self):

docRoot = self.server.docRoot
docPath = "%s%s" % (docRoot, self.path)
errorPath = "%s/not-found.html" % docRoot

if self.path.startswith('../'):
log.debug('ajaxserver.GET(HTML): "%s" trying to escape from the sandbox' % self.path)
docFile = open(errorPath, 'r')
code = 404
elif docPath.endswith('/') and os.path.exists("%sindex.html" % docPath):
log.debug('ajaxserver.GET(HTML): serving %sindex.html for %s' % (docPath, self.path))
docFile = open("%sindex.html" % docPath, 'r')
code = 200
elif os.path.exists(docPath):
log.debug('ajaxserver.GET(HTML): serving %s for %s' % (docPath, self.path))
docFile = open(docPath, 'r')
code = 200
else:
log.debug('ajaxserver.GET(HTML): no document found for %s' % self.path)
docFile = open(errorPath, 'r')
code = 404

doc = docFile.read()
docFile.close()

return (code, doc, 'text/html')

def utilProcessCount(self):
psCmd = subprocess.Popen(["ps", "ax"], stdout=subprocess.PIPE)
wcCmd = subprocess.Popen(["wc", "-l"], stdin=psCmd.stdout, stdout=subprocess.PIPE)
count = wcCmd.communicate()[0]

return json.dumps({ 'processcount': int(count) - 1 })

def do_GET_JSON(self):

if self.path.startswith('/ajax/time'):
return (200, '{ "time": "%s" }' % datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'), 'application/json')

if self.path.startswith('/ajax/processcount'):
return (200, self.utilProcessCount(), 'application/json')

return (200, '{ "resp": "bark!" }', 'application/json')</pre>
</div>

<p><code>ajaxserver</code> contains the <code>AjaxServer</code> class which extends the <code>BaseHTTPServer.HTTPServer</code> class and is the driver of my simple python web server. it also contains the setup code to instantiate the server and start it:</p>

<div>
<pre class="crayon-plain-tag">#!/usr/bin/env python2.6
# -*- encoding: utf-8 -*- 

'''
ajaxServer is a simple proof-of-concept web server for serving AJAX pages and their contents.
'''

import BaseHTTPServer
import logging as log
import logging.handlers
import os
import re
import subprocess
import sys
import urllib2

import handler

from datetime import date

class AjaxServer(BaseHTTPServer.HTTPServer):

def __init__(self, serverAddress, requestHandlerClass, docRoot):
BaseHTTPServer.HTTPServer.__init__(self, serverAddress, requestHandlerClass)
self.docRoot = docRoot

# from python module doc
def run(server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler,
root='root',
ip='', port=8000):

server_address = (ip, port)

httpd = server_class(server_address, handler_class, root)
log.info("ajaxserver: waiting for requests")
httpd.serve_forever()

if __name__ == '__main__':

log.basicConfig(level = log.DEBUG,
format = '%(asctime)s %(levelname)-8s %(message)s',
datefmt = '%a, %d %b %Y %H:%M:%S')

ip = '127.0.0.1'
port = 8000
docRoot = '../root'

try:

# start the server
log.info("ajaxserver: starting HTTP server on %s:%d" %(ip, port))
run(server_class=AjaxServer, handler_class=handler.Handler, ip=ip, port=port, root=docRoot)
log.info("ajaxserver: terminating")

except KeyboardInterrupt, k:
print "\r&lt;&lt;terminated by user, good bye!&gt;&gt;"
log.info("aborted by user, terminating")</pre>
</div>

<h3>running it</h3>

<p>start the ajax server:
</p><pre class="crayon-plain-tag">&amp;gt; ./ajaxserver 
Sun, 01 Jul 2012 16:35:12 INFO     ajaxserver: starting HTTP server on 127.0.0.1:8000
Sun, 01 Jul 2012 16:35:12 INFO     ajaxserver: waiting for requests</pre><p>
then point your browser to http://localhost:8000/ &#8212; in your terminal
running <code>ajaxserver</code> you&#8217;ll see a bunch of log lines showing you the requests triggered by loading the <code>index.html</code> page.</p>

<p>the browser will initially show just the static text of <code>index.html</code> &#8212;</p>

<p><a href="http://xyzzyxyzzy.net/wp-content/uploads/2012/07/Screen-Shot-2012-07-01-at-16.40.10-.png"><img class="aligncenter size-full wp-image-830" title="Screen Shot 2012-07-01 at 16.40.10" alt="" src="http://xyzzyxyzzy.net/wp-content/uploads/2012/07/Screen-Shot-2012-07-01-at-16.40.10-.png" width="409" height="168" /></a></p>

<p>&#8212; after a couple of seconds the current date and time will be displayed and continuously updated, followed by the current process count of your machine. when you enter text into the text input field and tab out, the length of your input will be shown next to it.</p>

<p><a href="http://xyzzyxyzzy.net/wp-content/uploads/2012/07/Screen-Shot-2012-07-01-at-16.44.51-.png"><img class="aligncenter size-full wp-image-831" title="Screen Shot 2012-07-01 at 16.44.51" alt="" src="http://xyzzyxyzzy.net/wp-content/uploads/2012/07/Screen-Shot-2012-07-01-at-16.44.51-.png" width="277" height="118" /></a></p>

<p>all three activities are happening independently from one another, the page itself is never reloaded (as you can verify in the <code>ajaxserver</code> log output).</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2012/07/01/ajax-fun-with-jquery-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>emacs tip: getting lines numbered</title>
		<link>http://xyzzyxyzzy.net/2012/01/19/emacs-tip-getting-lines-numbered/</link>
		<comments>http://xyzzyxyzzy.net/2012/01/19/emacs-tip-getting-lines-numbered/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 10:09:08 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[emacs]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[region]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[trick]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=796</guid>
		<description><![CDATA[the other day i was coding a scala apply(array: Array[String}) method to instantiate an object from a CSV file. i ended up with something like this: [crayon-51c27632c1bb3/] there were about a 100 parameters to use. i wasn't really too excited about having to change the rewired(0) to use the proper index by hand. so, here's [...]]]></description>
				<content:encoded><![CDATA[<p>the other day i was coding a scala <code>apply(array: Array[String})</code> method to instantiate an object from a CSV file. i ended up with something like this:</p>

<p></p><pre class="crayon-plain-tag">apply(uuid = uuid,
source = source,
hostname = rewired(0),
type = rewired(0),
state = rewired(0),
category = rewired(0),
id = rewired(0),
lifecycle = rewired(0),
classification = rewired(0),
...
flag = rewired(0))</pre><p></p>

<p>there were about a 100 parameters to use. i wasn't really too excited about having to change the <code>rewired(0)</code> to use the proper index by <em>hand</em>. so, here's what i did:</p>

<ul>
<li>in emacs mark the region</li>
<li>then invoke <code>shell-command-on-region</code> and</li>
<li>use <code>perl -pi -e 's{rewired&#40;0&#41;}{sprintf("rewired(%d)", $. - 1)}e;'</code> as command to invoke</li>
</ul>

<p>emacs will then show you the result of the command in a temporary buffer, you can either copy and paste from there, or just repeat the <code>shell-command-on-region</code> and prefix it with ctrl-u --- emacs with then replace the region with the output of the command directly.</p>

<p>voila!</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2012/01/19/emacs-tip-getting-lines-numbered/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>sbt10, webplugin, jetty, run-in-place: once more&#8230;</title>
		<link>http://xyzzyxyzzy.net/2011/07/22/sbt10-webplugin-jetty-run-in-place-once-more/</link>
		<comments>http://xyzzyxyzzy.net/2011/07/22/sbt10-webplugin-jetty-run-in-place-once-more/#comments</comments>
		<pubDate>Fri, 22 Jul 2011 14:55:03 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[jetty]]></category>
		<category><![CDATA[sbt]]></category>
		<category><![CDATA[scala]]></category>
		<category><![CDATA[web-plugin]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=788</guid>
		<description><![CDATA[it turns out that the sbt/web-plugin configuration i described in my last post is not quite cutting it. what we observed is that while changes to the contents of the webapp subtree were indeed effective immediately1 sbt commands like prepare-webapp and jetty-reload would sometimes work and sometimes just ignore us. so, back to digging around [...]]]></description>
				<content:encoded><![CDATA[<p>it turns out that the sbt/web-plugin configuration i described in <a href="http://xyzzyxyzzy.net/2011/07/04/sbt10-webplugin-running-jetty-from-source-tree/">my last post</a> is not quite cutting it. what we observed is that while changes to the contents of the <code>webapp</code> subtree were indeed effective immediately<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> sbt commands like <code>prepare-webapp</code> and <code>jetty-reload</code> would sometimes work and sometimes just ignore us.</p>

<p>so, back to digging around in the <a href="https://github.com/siasia/xsbt-web-plugin">web-plugin sources</a> and this is what we are now using:</p>

<div>
[scala]
temporaryWarPath &lt;&lt;= (sourceDirectory in Runtime) / &quot;webapp&quot;,
// watch temporaryWarPath / WEB-INF / classes
jettyScanDirs &lt;&lt;= (temporaryWarPath) { (target) =&gt; Seq(target / &quot;WEB-INF&quot; / &quot;classes&quot;) },
[/scala]
</div>

<p>this sbt configuration tells <code>jetty</code> to run out of the <code>src/main/webapp</code> directory — any changes you do in there will become effective immediately and <code>prepare-webapp</code> and <code>jetty-reload</code> are working as expected. the drawback is that your generated <code>classes</code> and <code>lib</code> files get copied to <code>src/main/webapp/WEB-INF</code> <img src='http://xyzzyxyzzy.net/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />  i know, sucks, but still better than having to restart your webapp everytime you change a <code>{html,css,js}</code> file. if you are using <a href="http://en.wikipedia.org/wiki/Git_%28software%29">git</a> you might want to add</p>

<p></p><pre class="crayon-plain-tag">src/main/webapp/WEB-INF/lib/*
src/main/webapp/WEB-INF/classes/*</pre><p></p>

<p>to your top-level <code>.gitignore</code> file.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>on browser reload, that is.&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/07/22/sbt10-webplugin-jetty-run-in-place-once-more/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>sbt10, webplugin: running jetty from source tree</title>
		<link>http://xyzzyxyzzy.net/2011/07/04/sbt10-webplugin-running-jetty-from-source-tree/</link>
		<comments>http://xyzzyxyzzy.net/2011/07/04/sbt10-webplugin-running-jetty-from-source-tree/#comments</comments>
		<pubDate>Mon, 04 Jul 2011 14:39:38 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[continuous redeployment]]></category>
		<category><![CDATA[jetty]]></category>
		<category><![CDATA[sbt10]]></category>
		<category><![CDATA[scala]]></category>
		<category><![CDATA[simple build tool]]></category>
		<category><![CDATA[source]]></category>
		<category><![CDATA[webplugin]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=776</guid>
		<description><![CDATA[the solution described below turns out to have its flaws and is not really recommended — have a look at the recently posted update for a better solution! simple build tool 0.7.5 comprised the jetty and webapp functionality — version 0.10.0 (sbt10) no longer does so, instead you have to pull in the sbt webplugin. [...]]]></description>
				<content:encoded><![CDATA[<p><em>the solution described below turns out to have its flaws and is not really recommended — have a look at the <a href="http://xyzzyxyzzy.net/2011/07/22/sbt10-webplugin-jetty-run-in-place-once-more/">recently posted update</a> for a better solution!</em></p>

<p>simple build tool 0.7.5 comprised the jetty and webapp functionality — version 0.10.0 (sbt10) no longer does so, instead you have to pull in the <a href="https://github.com/siasia/xsbt-web-plugin">sbt webplugin</a>. one feature of sbt7.5&#8242;s webapp support that we used heavily was the ability to run jetty out of the source tree instead of the exploded temporary WAR file:</p>

<p>&gt; Another possibility is to directly run the web application out of the the source web application path:
&gt;
&gt; override def jettyWebappPath = webappPath
&gt; override def scanDirectories = mainCompilePath :: testCompilePath :: Nil
&gt;
&gt; <a href="http://code.google.com/p/simple-build-tool/wiki/WebApplications"><em>— sbt7.5, continuous redeployment</em></a></p>

<p>(we actually used to set <code>scanDirectories</code> to <code>Nil</code>)</p>

<p>achieving the same setup with sbt10 is not as simple or even obvious, the <a href="https://groups.google.com/d/topic/simple-build-tool/5rxFN2L73bA/discussion">solution reported in the simple build tool newgroups</a> does not really provide the same feature, as it still requires to have a <code>~ prepare-webapp</code> running in sbt. here&#8217;s what seems to work:</p>

<div>&lt;pre language=&#8221;scala&#8221;&gt;
// run jetty from source tree
jettyConfiguration &lt;&lt;= (sourceDirectory in Runtime, jettyConfiguration) map {
(sourceDir, jettyConf) =&gt; {
val conf = jettyConf.asInstanceOf[DefaultJettyConfiguration]
new DefaultJettyConfiguration {
def classpath = conf.classpath
def jettyClasspath = conf.jettyClasspath
def war = sourceDir / &#8220;webapp&#8221;
def contextPath = conf.contextPath
def classpathName = conf.classpathName
def parentLoader = conf.parentLoader
def scanDirectories = conf.scanDirectories
def scanInterval = conf.scanInterval
def port = conf.port
def log = conf.log
def jettyEnv = conf.jettyEnv
def webDefaultXml = conf.webDefaultXml
}
}
}</div>

<div>

&nbsp;

// set jetty scan dirs to empty list
jettyScanDirs := Nil
&lt;/pre&gt;

</div>

<p>changes in <code>src/main/webapp</code> are immediately effective for the running jetty instance. voila!</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/07/04/sbt10-webplugin-running-jetty-from-source-tree/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>scala, emacs, sbt 0.10.0, ensime</title>
		<link>http://xyzzyxyzzy.net/2011/06/28/scala-emacs-sbt-0-10-0-ensime/</link>
		<comments>http://xyzzyxyzzy.net/2011/06/28/scala-emacs-sbt-0-10-0-ensime/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 09:56:11 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[emacs]]></category>
		<category><![CDATA[ensime]]></category>
		<category><![CDATA[sbt10]]></category>
		<category><![CDATA[scala-2.9.0]]></category>
		<category><![CDATA[simple build tool]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=765</guid>
		<description><![CDATA[i&#8217;m an ardent emacs user. for our current project we chose the scala language as our programming language along with lift as the web application framework. initially we used maven but have switched over to the simple build tool — sbt in short — about half a year ago, as we found that to be [...]]]></description>
				<content:encoded><![CDATA[<p>i&#8217;m an ardent emacs user. for our current project we chose <a href="http://www.scala-lang.org/">the scala language</a> as our programming language along with <a href="http://liftweb.net/">lift</a> as the web application framework. initially we used maven but have switched over to the <a href="https://github.com/harrah/xsbt/wiki">simple build tool</a> — sbt in short — about half a year ago, as we found that to be faster than maven and also offering more features (such as test-only, test-quick, etc). to get scala support in emacs i&#8217;ve been using <a href="https://github.com/aemoncannon/ensime">ensime</a> which cooperated really well with sbt.</p>

<p>the sbt project recently made version 0.10.0 available — aka sbt10. switching from sbt7.5 to sbt10 is either very easy or a bit of a struggle. it&#8217;s easy if you are using a plain vanilla setup. it&#8217;s a struggle if you&#8217;ve created your own tasks — to paraphrase star trek: &#8220;it&#8217;s tasks, but not as we know it, jim&#8221;.</p>

<p>among the changes brought by sbt10 is that manged JARs are no longer copied into the <code>lib_managed</code> tree (instead the version in <code>$HOME/.ivy2/cache</code> is used, avoiding redundant copies) — that unfortunately <a href="https://groups.google.com/d/topic/simple-build-tool/qM9fsovylzQ/discussion">confuses the heck out of ensime</a>. florian hars, suffering from the same problem, wrote an <a href="https://github.com/fhars/sbt-ensime-plugin">sbt10 ensime plugin</a> that fixes the issue for the time being (until ensime has proper sbt10 support).</p>

<p>to install the sbt ensime plugin, follow the instructions in its <a href="https://github.com/fhars/sbt-ensime-plugin#readme">README</a>, then in restart <code>sbt</code> and invoke the <code>ensime</code> task. after a compile of your project, it will generate a new <code>.ensime</code> project file (save an eventually existing old one if you care about it). then it&#8217;s just a restart of emacs and the invocation of <code>ensime</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/06/28/scala-emacs-sbt-0-10-0-ensime/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>getting thunderbird to use yyyy-MM-dd HH:MM date format</title>
		<link>http://xyzzyxyzzy.net/2011/04/13/getting-thunderbird-to-use-yyyy-mm-dd-hhmm-date-format/</link>
		<comments>http://xyzzyxyzzy.net/2011/04/13/getting-thunderbird-to-use-yyyy-mm-dd-hhmm-date-format/#comments</comments>
		<pubDate>Wed, 13 Apr 2011 06:40:08 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[ISO date format]]></category>
		<category><![CDATA[locale]]></category>
		<category><![CDATA[thunderbird]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=573</guid>
		<description><![CDATA[thunderbird is a terrific mail application (&#8220;mail user agent&#8221; is the posh name, i believe). pretty much the only thing i don&#8217;t like about it though is its way of formatting the date and time and not providing a way of letting me configure the date format via preferences. it got bad enough that i [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://bit.ly/e1TJRb">thunderbird</a> is a terrific mail application (&#8220;mail user agent&#8221; is the posh name, i believe).</p>

<p>pretty much the only thing i don&#8217;t like about it though is its way of formatting the date and time and not providing a way of letting <em>me</em> configure the date format via preferences. it got bad enough that i recently spent a bit of time to figure out how get thunderbird to display date and time in yyyy-MM-dd HH:MM format — that is, 2011-04-13 20:34 instead of 04/13/2011 08:34pm or something similarly silly.</p>

<p>the solution was hiding in <a href="http://ubuntuforums.org/showthread.php?t=407421">a forum post on the ubuntu forum</a>: by switching the locale (well, at least parts of it) to <code>en_DK.utf8</code> thunderbird would use the yyyy-MM-dd HH:MM format (aka ISO date–time format).</p>

<p>here&#8217;s how i did that on ubuntu:</p>

<p>[sourcecode language="bash"]
     # first: create a diversion of the normal /usr/bin/thunderbird
     dpkg-divert &#8211;divert /usr/bin/thunderbird.ubuntu &#8211;rename &#8211;local &#8211;add /usr/bin/thunderbird 
     # next: create our locale setting wrapper
     cat &lt;&lt;HERE &gt;/usr/bin/thunderbird
     #!/bin/bash
     export LC_TIME=en_DK.utf8
     export LC_PAPER=en_DK.utf8
     export LC_MEASUREMENT=en_DK.utf8
     exec /usr/bin/thunderbird.ubuntu &quot;$@&quot;
     HERE
     chmod a+x /usr/bin/thunderbird
[/sourcecode]</p>

<p>that should do the trick.</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/04/13/getting-thunderbird-to-use-yyyy-mm-dd-hhmm-date-format/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>adding a USB monitor</title>
		<link>http://xyzzyxyzzy.net/2011/03/09/adding-a-usb-monitor/</link>
		<comments>http://xyzzyxyzzy.net/2011/03/09/adding-a-usb-monitor/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 13:30:18 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[directvnc]]></category>
		<category><![CDATA[displaylink]]></category>
		<category><![CDATA[third monitor]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vnc]]></category>
		<category><![CDATA[vnc2dl]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=540</guid>
		<description><![CDATA[i&#8217;ve long been using an external 22&#8243; monitor with my ubuntu linux powered X200 thinkpad. while ubuntu maverick (10.10) has some issues with attaching and detaching the second monitor and subsequent suspend–resume cycles (the second suspend after a detach would not resume, d&#8217;oh), ubuntu lucid (10.04.02) works just fine (as befitting a long-term-support release). for [...]]]></description>
				<content:encoded><![CDATA[<p>i&#8217;ve long been using an external 22&#8243; monitor with my ubuntu linux powered X200 thinkpad. while ubuntu maverick (10.10) has some issues with attaching and detaching the second monitor and subsequent suspend–resume cycles (the second suspend after a detach would not resume, d&#8217;oh), ubuntu lucid (10.04.02) works just fine (as befitting a long-term-support release).</p>

<p>for quite a while i&#8217;ve had the old 20&#8243; monitor which i had been using previously sitting on my desktop along with an <a href="http://en.wikipedia.org/wiki/DisplayLink">USB DisplayLink</a> adapter — the idea being to hook the old monitor up as well as a third monitor<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>. the displaylink driver provided by ubuntu lucid seemed to work properly — the monitor&#8217;s screen would turn green on connecting it and a framebuffer device (<code>/dev/fb1</code>) and so i tried various recipes floating around on ubuntu forums and elsewhere — all promising to achieve a grand unified desktop comprising all three monitors — and they either didn&#8217;t work or if they achieved the <em>grand unified desktop</em> it was unusable.</p>

<p>so, after another prolonged period during which the monitor and the displaylink adapter gathered even more dust, i tried a different approach: give up on the grand unified desktop goal and instead just try to make use of the monitor. the idea this time was to start up a <a href="http://en.wikipedia.org/wiki/Virtual_Network_Computing">VNC</a> server, then use a VNC client to directly render the server into the framebuffer device (<code>/dev/fb1</code>) provided by linux&#8217;s displaylink driver. the vncserver bit is actually quite easy:</p>

<p>[sourcecode language="bash"]
vncserver -name hidden -geometry 1600&#215;1200 -depth 16 :42
[/sourcecode]</p>

<p>which starts a VNC server for the <code>:42</code> display.</p>

<p>the VNC client bit turned out to be a bit more difficult. ubuntu lucid does have <code>directvnc</code> client which is &#8220;a vnc client for the linux framebuffer device&#8221;<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>. that client does seem to require keyboard and mouse access and in some configurations did not work at all or locked up my keyboard (not the mouse, though, funnily enough) or crashed the running X session, so no points on that one. further research luckily turned up <a href="https://github.com/quentinsf/vnc2dl">vnc2dl</a> by none other than quentin stafford-fraser one of the <a href="http://en.wikipedia.org/wiki/Virtual_Network_Computing#History">original VNC developers</a> (and also the <a href="http://en.wikipedia.org/wiki/Quentin_Stafford-Fraser">inventor of the webcam</a> it seems). <code>vnc2dl</code> seemed a bit more promising and — after slightly modifying<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup> <code>dldevice.c</code> — did do the job:</p>

<p>[sourcecode language="bash"]
sudo vnc2dl :42
[/sourcecode]</p>

<p>next up was fusing display :42 to my main display :0 on a keyboard and mouse level so that i could just move the mouse pointer over to the left and end up on display :42 — here <code>x2x</code> (in the equally named ubuntu package) came into play:</p>

<p>[sourcecode language="bash"]
x2x -west -to :42 &gt;/dev/null 2&gt;&amp;1 &amp;
[/sourcecode]</p>

<p>and, hey, presto!, both displays are linked mouse and keyboard wise.</p>

<p>only thing still bothering me was that cut and paste was not working. to fix that required adding</p>

<p>[sourcecode language="bash"]
vncconfig -nowin &amp;
[/sourcecode]</p>

<p>to my <code>.vnc/xstartup</code> file.</p>

<p>to have firefox run on display :42 required creation of a new firefox profile — i added that to <code>.vnc/xstartup</code> as well.<sup id="fnref:4"><a href="#fn:4" rel="footnote">4</a></sup></p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:1">
<p>yep, even more screen real estate; can&#8217;t have enough of that:  the ur-IDE emacs in one screen, instant messaging app pidgin on the other (for communicating with the team), the third screen would be really useful to host a firefox window with the API docs and so forth.&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:2">
<p>see <code>man directvnc</code> for more information about that one.&#160;<a href="#fnref:2" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:3">
<p><code>vnc2dl</code> in the version on <a href="https://github.com/quentinsf/vnc2dl">quentin&#8217;s github</a> is hard-wired to 1280&#215;1040/24bpp which my old monitor doesn&#8217;t quite grok, changing the wiring to 1600&#215;1200/16bpp made it more grokkable for my setup.&#160;<a href="#fnref:3" rev="footnote">&#8617;</a></p>
</li>

<li id="fn:4">
<p>to get the new profile synchronized with the default profile i used firefox&#8217;s recently added <em>Firefox Sync</em> add-on.&#160;<a href="#fnref:4" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/03/09/adding-a-usb-monitor/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>protecting an emacs buffer window from being split or replaced&#8230;</title>
		<link>http://xyzzyxyzzy.net/2011/03/03/protecting-an-emacs-buffer-window-from-being-split-or-replaced/</link>
		<comments>http://xyzzyxyzzy.net/2011/03/03/protecting-an-emacs-buffer-window-from-being-split-or-replaced/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 10:00:04 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[buffer]]></category>
		<category><![CDATA[dedicated window]]></category>
		<category><![CDATA[emacs]]></category>
		<category><![CDATA[irc]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=528</guid>
		<description><![CDATA[i&#8217;m a big fan of IRC and we use it in our distributed team to stay in touch and also coordinate testing and upgrades. as i&#8217;m also a big fan of the ur-IDE emacs i&#8217;m using emacs&#8217;s rcirc mode for my IRC needs. typically i have a small buffer window at the bottom of my [...]]]></description>
				<content:encoded><![CDATA[<p>i&#8217;m a big fan of <a href="http://en.wikipedia.org/wiki/IRC">IRC</a> and we use it in our distributed team to stay in touch and also coordinate testing and upgrades. as i&#8217;m also a big fan of the ur-IDE <a href="http://en.wikipedia.org/?title=Emacs">emacs</a> i&#8217;m using emacs&#8217;s <a href="http://www.emacswiki.org/emacs/rcirc">rcirc mode</a> for my IRC needs. typically i have a small buffer window at the bottom of my emacs frame dedicated to IRC. quite nice&#8230;</p>

<p>&#8230;until you start <a href="http://code.google.com/p/simple-build-tool/">sbt</a> or do some git work in <a href="https://github.com/byplayer/egg">egg</a> as then those modes try to acquire some screen real-estate and without scruples either &#8220;recycle&#8221; my IRC buffer for their content <img src='http://xyzzyxyzzy.net/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />  or split it into two <img src='http://xyzzyxyzzy.net/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> </p>

<p>this being emacs there had to be a way to get that IRC buffer window protected. and there is <img src='http://xyzzyxyzzy.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  digging into the emacs info docs and looking at the underlying emacs lisp files this is what i came up with:</p>

<pre><code> [sourcecode language="text"]
 (defun rcirc-toggle-current-window-dedication ()
   (interactive)
   (let* ((window (selected-window))
          (dedicated (window-dedicated-p window)))
     (set-window-dedicated-p window (not dedicated))
     (setq window-size-fixed (not window-size-fixed))
     (message &amp;quot;Window %sdedicated to %s&amp;quot;
              (if dedicated &amp;quot;no longer &amp;quot; &amp;quot;&amp;quot;)
              (buffer-name))))

 (global-set-key (kbd &amp;quot;&amp;lt;Scroll_Lock&amp;gt;&amp;quot;) 'rcirc-toggle-current-window-dedication)
 [/sourcecode]
</code></pre>

<p>this will toggle the <code>window-dedicated-p</code> and <code>window-size-fixed</code> bits of the window in which you press the scroll-lock key &#8212; and, hey, presto! &#8212; no more pirating of the IRC buffer window.</p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/03/03/protecting-an-emacs-buffer-window-from-being-split-or-replaced/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSS selector transforms&#8230;</title>
		<link>http://xyzzyxyzzy.net/2011/02/18/css-selector-transforms/</link>
		<comments>http://xyzzyxyzzy.net/2011/02/18/css-selector-transforms/#comments</comments>
		<pubDate>Fri, 18 Feb 2011 16:05:46 +0000</pubDate>
		<dc:creator>Dr. Dirk Husemann</dc:creator>
				<category><![CDATA[hacking]]></category>
		<category><![CDATA[CSS transform]]></category>
		<category><![CDATA[lift]]></category>
		<category><![CDATA[pimp]]></category>
		<category><![CDATA[scala]]></category>

		<guid isPermaLink="false">http://xyzzyxyzzy.net/?p=515</guid>
		<description><![CDATA[we have been using scala and the lift framework for our project for over a year now. as we are starting on a new subcomponent of it, i thought i&#8217;d take a crack at using lift&#8217;s new CSS selector transforms. CSS transforms provide an alternative to the traditional lift templating mechanism: [sourcecode language="xml"] &#60;lift:FooBar&#62; &#60;foobar:dosomething [...]]]></description>
				<content:encoded><![CDATA[<p>we have been using scala and the lift framework for our project for over a year now. as we are starting on a new subcomponent of it, i thought i&#8217;d take a crack at using lift&#8217;s new <a href="http://www.assembla.com/wiki/show/liftweb/Binding_via_CSS_Selectors">CSS selector transforms</a>.</p>

<p>CSS transforms provide an alternative to the traditional lift templating mechanism:</p>

<p>[sourcecode language="xml"]
    &lt;lift:FooBar&gt;
        &lt;foobar:dosomething /&gt;
    &lt;lift:FooBar&gt;
[/sourcecode]</p>

<p>which requires the following scala code:</p>

<p>[sourcecode language="scala"]
class FooBar { 
    def render(in: NodeSeq): NodeSeq =
        bind(&quot;foobar&quot;, in,
             &quot;dosomething&quot; -&gt; &lt;span&gt;dog&lt;/span&gt;)
}
[/sourcecode]</p>

<p>and would result in</p>

<p>[sourcecode language="xml"]
    &lt;span&gt;dog&lt;/span&gt;
[/sourcecode]</p>

<p>with the new CSS transforms we get rid of the <code><lift:FooBar></code> tags and instead use plain HTML:</p>

<p>[sourcecode language="xml"]
    &lt;div class=&quot;lift:Foobar&quot;&gt;
        &lt;span id=&quot;animal&quot;&gt;XXX&lt;/span&gt;
    &lt;/div&gt;
[/sourcecode]</p>

<p>and then change the binding to:</p>

<p>[sourcecode language="scala"]
class FooBar { 
    def render = &quot;#animal *&quot; &quot;dog&quot;
}
[/sourcecode]</p>

<p>and end up, again, with</p>

<p>[sourcecode language="xml"]
    &lt;span id=&quot;animal&quot;&gt;dog&lt;/span&gt;
[/sourcecode]</p>

<p>— just with much less code! and once you start looking into expanding lists, it really becomes obvious that CSS transforms are a huge step forward. add to that that you can now design your web apps using normal HTML design tools (which in my case is <a href="http://www.emacswiki.org/">emacs</a>, <a href="http://ourcomments.org/Emacs/nXhtml/doc/nxhtml.html">nxhtml mode</a>, and <a href="https://github.com/bard/mozrepl/wiki/">moz-repl</a>) and life has just become a lot easier and more productive&#8230;</p>

<p>&#8230;except for one thing <img src='http://xyzzyxyzzy.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  you see, we are using <a href="http://en.wikipedia.org/wiki/Comet_%28programming%29">comets</a> and lift&#8217;s rather cool <code>partialUpdate(SetHtml("dog", Text(wuff! wuff!)))</code> construct to dynamically update the &#8220;dog&#8221; span. for that we were — in the pre-CSS transform age — using calls to <code>chooseTemplate</code> to fetch XML snippets and re-render them. how to do this with CSS transforms?</p>

<p>let&#8217;s assume our HTML snippet is a bit more complex and includes an image:</p>

<p>[sourcecode language="xml"]
    &lt;div class=&quot;lift:Foobar&quot;&gt;
        &lt;div&gt;&lt;span id=&quot;animal&quot;&gt;&lt;img src=&quot;XXX&quot; /&gt;&lt;/span&gt;&lt;/div&gt;
    &lt;/div&gt;
[/sourcecode]</p>

<p>the <a href="http://www.assembla.com/wiki/show/liftweb/Binding_via_CSS_Selectors">CSS selector transforms</a> page lists the following construct:</p>

<p>[sourcecode language="scala"]
&quot;animal ^^&quot; #&gt; &quot;ignore&quot;
[/sourcecode]</p>

<p>this will select the element with the id &#8220;animal&#8221;. so far, so good. what&#8217;s not so good is that the intuitively next idea</p>

<p>[sourcecode language="scala"]
&quot;animal ^^&quot; #&gt; &quot;ignore&quot; &amp; &quot;img [src]&quot; #&gt; &quot;dog.png&quot;
[/sourcecode]</p>

<p>doesn&#8217;t work (CSS transforms are actually functions, so we can invoke them on <code>NodeSeq</code> in <a href="http://code.google.com/p/simple-build-tool/wiki/RunningSbt#Build_Actions">sbt&#8217;s console</a>):</p>

<pre><code>scala&gt; val in = &lt;div&gt;&lt;span id="animal"&gt;&lt;img src="XXX" /&gt;&lt;/span&gt;&lt;/div&gt;
in: scala.xml.Elem = &lt;div&gt;&lt;span id="animal"&gt;&lt;img src="XXX"&gt;&lt;/img&gt;&lt;/span&gt;&lt;/div&gt;

scala&gt; ("#animal ^^" #&gt; "ignore")(in)
res0: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="XXX"&gt;&lt;/img&gt;&lt;/span&gt;)

scala&gt; ("#animal ^^" #&gt; "ignore" &amp; "img [src]" #&gt; "dog.png")(in) 
res1: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="XXX"&gt;&lt;/img&gt;&lt;/span&gt;)
</code></pre>

<p>what does work is the following code:</p>

<p>[sourcecode language="scala"]
val template = (&quot;#animal ^^&quot; #&gt; &quot;ignore&quot;)(in)
(&quot;img [src]&quot; #&gt; &quot;dog.png&quot;)(template)
[/sourcecode]</p>

<p>if we try this in console we get:</p>

<pre><code>scala&gt; val template = ("#animal ^^" #&gt; "ignore")(in)
template: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="XXX"&gt;&lt;/img&gt;&lt;/span&gt;)

scala&gt; ("img [src]" #&gt; "dog.png")(template)
res2: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="dog.png"&gt;&lt;/img&gt;&lt;/span&gt;)
</code></pre>

<p>which is what we expect. just a bit cumbersome to write and the contraction</p>

<p>[sourcecode language="scala"]
(&quot;img [src]&quot; #&gt; &quot;dog.png&quot;)((&quot;#animal ^^&quot; #&gt; &quot;ignore&quot;)(in))
[/sourcecode]</p>

<p>while producing the same result, is a bit hard to understand.</p>

<p>ideally, we could write it as:</p>

<p>[sourcecode language="scala"]
&quot;#animal ^^&quot; #&gt; &quot;ignore&quot; ~&gt; &quot;img [src]&quot; #&gt; &quot;dog.png&quot;
[/sourcecode]</p>

<p>as in: first select the template, then apply the following transform. well, we are in scala land, where (almost) everything is possible! so, why not create that operator? how hard can it be?</p>

<p>&#8220;not very&#8221; is the answer. first step is to figure out what it is that we want: <code>CssBindFunc</code> <a href="http://stable.simply.liftweb.net/#toc-Section-7.10">can be viewed</a> as <code>(NodeSeq) => NodeSeq</code> functions. so, we really want to concatenate one <code>(NodeSeq) => NodeSeq</code> with another one. writing this as a function that translates into:</p>

<p>[sourcecode language="scala"]
def andThenInto(first: (NodeSeq) =&gt; NodeSeq, second: (NodeSeq) =&gt; NodeSeq): (NodeSeq) =&gt; NodeSeq =
    (ns: NodeSeq) =&gt; second(first(ns))
[/sourcecode]</p>

<p>throwing that into the sbt console yields:</p>

<pre><code>scala&gt; def andThenInto(first: (NodeSeq) =&gt; NodeSeq, second: (NodeSeq) =&gt; NodeSeq): (NodeSeq) =&gt; NodeSeq =
    (ns: NodeSeq) =&gt; second(first(ns))
andThenInto: (first: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq,second: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq)(scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq

scala&gt; andThenInto("#animal ^^" #&gt; "ignore", "img [src]" #&gt; "dog.png")
res4: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq = &lt;function1&gt;

scala&gt; res4(in)
res4(in)
res5: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="dog.png"&gt;&lt;/img&gt;&lt;/span&gt;)

scala&gt; 
</code></pre>

<p>which is exactly what we are after — well, almost. <code>andThenInto</code> is a bit long, we wanted to use <code>~></code>. so, let&#8217;s try that:</p>

<pre><code>def ~&gt;(first: (NodeSeq) =&gt; NodeSeq, second: (NodeSeq) =&gt; NodeSeq): (NodeSeq) =&gt; NodeSeq =
    (ns: NodeSeq) =&gt; second(first(ns))
$tilde$greater: (first: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq,second: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq)(scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq
</code></pre>

<p>doesn&#8217;t look too bad. let&#8217;s give it a spin:</p>

<pre><code>~&gt;("#animal ^^" #&gt; "ignore", "img [src]" #&gt; "dog.png")
res6: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq = &lt;function1&gt;

scala&gt; res6(in)
res6(in)
res7: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="dog.png"&gt;&lt;/img&gt;&lt;/span&gt;)
</code></pre>

<p>looking good. next, let&#8217;s pimp <code>CssBindFunc</code> with that:</p>

<p>[sourcecode language="scala"]
implicit def pimpCssBindFuncWithAndThenInto(first: (NodeSeq) =&gt; NodeSeq) = new { 
    def ~&gt;(second: (NodeSeq) =&gt; NodeSeq): (NodeSeq) =&gt; NodeSeq =
        (ns: NodeSeq) =&gt; second(first(ns))
}
[/sourcecode]</p>

<p>and give it a go:</p>

<pre><code>scala&gt; "#animal ^^" #&gt; "ignore" ~&gt; "img [src]" #&gt; "dog.png"
&lt;console&gt;:14: error: type mismatch;
 found   : java.lang.String("img [src]")
 required: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq
       "#animal ^^" #&gt; "ignore" ~&gt; "img [src]" #&gt; "dog.png"
</code></pre>

<p>ooops. what happened? the compiler seems to be doing the grouping in a different way then we expected. &#8220;operator precedence&#8221; was jumping up and down in my mind in the back row desparate to get called on: looking up that topic in the <a href="http://programming-scala.labs.oreilly.com/ch03.html">&#8220;scala bible&#8221;</a> turned up the explanation: the <code>~</code> character is in the highest precedence category together with <code>#</code>. to avoid having to use parenthesis we changed our &#8220;andThenInto&#8221; operator to <code>&amp;~></code>:</p>

<p>[sourcecode language="scala"]
implicit def pimpCssBindFuncWithAndThenInto(first: (NodeSeq) =&gt; NodeSeq) = new { 
    def &amp;~&gt;(second: (NodeSeq) =&gt; NodeSeq): (NodeSeq) =&gt; NodeSeq =
        (ns: NodeSeq) =&gt; second(first(ns))
}
[/sourcecode]</p>

<p>which then yields the desired result:</p>

<pre><code>"#animal ^^" #&gt; "ignore" &amp;~&gt; "img [src]" #&gt; "dog.png"
res10: (scala.xml.NodeSeq) =&gt; scala.xml.NodeSeq = &lt;function1&gt;

scala&gt; res10(in)
res10(in)
res11: scala.xml.NodeSeq = NodeSeq(&lt;span id="animal"&gt;&lt;img src="dog.png"&gt;&lt;/img&gt;&lt;/span&gt;)

scala&gt; 
</code></pre>

<p> <img src='http://xyzzyxyzzy.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://xyzzyxyzzy.net/2011/02/18/css-selector-transforms/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
