<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-8212254010436871241</atom:id><lastBuildDate>Mon, 09 Nov 2009 08:40:56 +0000</lastBuildDate><title>Mock It!</title><description>News from the testing underground</description><link>http://mockit.blogspot.com/</link><managingEditor>noreply@blogger.com (malthe)</managingEditor><generator>Blogger</generator><openSearch:totalResults>43</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/MockIt" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4433996884499631327</guid><pubDate>Thu, 05 Nov 2009 23:29:00 +0000</pubDate><atom:updated>2009-11-06T11:56:24.399+01:00</atom:updated><title>Emperor's new clothes</title><description>The &lt;a href="http://wiki.zope.org/zope3/ComponentArchitectureOverview"&gt;Zope Component Architecture&lt;/a&gt; is often touted for letting you override so-called components which have already been registered elsewhere (by a library, out of your immediate control).&lt;br /&gt;&lt;br /&gt;It's &lt;span style="font-style: italic;"&gt;wrong&lt;/span&gt; (edit: to clarify, using the overriding facility of the ZCA is wrong, and by extension, to use the ZCA &lt;span style="font-style: italic;"&gt;because&lt;/span&gt; you can override components, is wrong too; I do not mean to suggest that the use of ZCA is misguided in general).&lt;br /&gt;&lt;br /&gt;Shrink-wrap software is a circumstance. If you must change it from outside (instead of &lt;a href="http://mockit.blogspot.com/2009/08/singing-and-branching.html"&gt;branching&lt;/a&gt;, which is a fine approach in many cases), just go ahead and update the functions or classes in question using the &lt;a href="http://mail.python.org/pipermail/edu-sig/2007-February/007787.html"&gt;reload approach&lt;/a&gt; (object identity changes should be avoided at all costs).&lt;br /&gt;&lt;br /&gt;There's nothing wrong with ZCA; it's in my view a misunderstanding to employ it for web application development at large. Rather, it's applicable for deployments that require live software component introspection. I don't know that web applications need this in general. What happens is that frameworks like &lt;a href="http://docs.zope.org/zopetoolkit/"&gt;Zope Toolkit&lt;/a&gt; and &lt;a href="http://www.plone.org/"&gt;Plone&lt;/a&gt; use these introspection features to map requests to code. That's a bit like using &lt;a href="http://en.wikipedia.org/wiki/Radio-frequency_identification"&gt;RDIF&lt;/a&gt; tags for consumption tracking (hint: require credit card payment or identity-based rebate instead).&lt;br /&gt;&lt;br /&gt;Most software is misunderstood. How to use it, when to use it. Sometimes it's worth the while to retrace your steps to learn why you ended up using a particular software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4433996884499631327?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/11/emperors-new-clothes.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">19</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-5552613818582895226</guid><pubDate>Tue, 03 Nov 2009 21:11:00 +0000</pubDate><atom:updated>2009-11-04T00:39:58.723+01:00</atom:updated><title>New in school</title><description>I've written an HTTP publisher!&lt;br /&gt;&lt;br /&gt;The most common reaction is: &lt;span style="font-style: italic;"&gt;why write a new framework?&lt;/span&gt; Well, it's not a framework. It's a little device that sits between the server and your code. It does more than &lt;a href="http://bobo.digicool.com/"&gt;bobo&lt;/a&gt;, less than &lt;a href="http://bottle.paws.de/"&gt;bottle&lt;/a&gt;. What it does, it does better than both.&lt;br /&gt;&lt;br /&gt;The name is &lt;a href="http://www.ottohttp.org/"&gt;Otto&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There aren't many moving parts, but the design is flexible enough to handle most use-cases. The syntax is agreeable, terse and very clear. Most importantly, it gets you going without any mental effort. There is no inversion of control. It is obvious at every step what happens, from request to response.&lt;br /&gt;&lt;br /&gt;The design has evolved entirely through examples, setting the library requirements instead of the other way around. The documentation is tested continuously using the &lt;a href="http://pypi.python.org/pypi/manuel"&gt;manuel&lt;/a&gt; package which keeps everything in sync and makes it possible to write out and test complete self-contained examples right in the documentation.&lt;br /&gt;&lt;br /&gt;That said, there isn't a lot to it.&lt;br /&gt;&lt;br /&gt;You can use the publisher directly as the basis of a web application, or integrate it into an existing framework. Suggestions or other feedback are welcome as comments are on the repository &lt;a href="http://github.com/malthe/otto/issues"&gt;tracker&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The publisher will grow a few more features (e.g. support for virtual hosting, static file helper) before its first release, but an effort is made to keep scope narrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-5552613818582895226?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/11/new-in-school.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-9193927569565418042</guid><pubDate>Thu, 15 Oct 2009 22:53:00 +0000</pubDate><atom:updated>2009-10-16T01:16:00.885+02:00</atom:updated><title>The cure</title><description>A couple of years ago I wrote a small package called &lt;a href="http://pypi.python.org/pypi/z3c.jbot"&gt;z3c.jbot&lt;/a&gt; which made life as an integrator on Zope and Plone a lot easier. This is an advertisement for the latest version 0.5.&lt;br /&gt;&lt;br /&gt;New features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No performance hit&lt;/li&gt;&lt;li&gt;It works with Chameleon&lt;/li&gt;&lt;li&gt;Replace images,  stylesheets and javascripts too!&lt;/li&gt;&lt;/ul&gt;With this release you can actually fully customize an out-of-box Plone site without writing a single line of code; replace the site logo, customize content templates and portlets, or change the included stylesheets.&lt;br /&gt;&lt;br /&gt;More information on the &lt;a href="http://pypi.python.org/pypi/z3c.jbot"&gt;project page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-9193927569565418042?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/10/cure.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">7</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-6184959291017105446</guid><pubDate>Sat, 03 Oct 2009 10:24:00 +0000</pubDate><atom:updated>2009-10-03T13:39:31.146+02:00</atom:updated><title>Copying music left or right</title><description>I pirate music. Frequently. Most people do, too. It's not right in terms of &lt;a href="http://www.copyright.gov/"&gt;copyright&lt;/a&gt;; so let's talk about &lt;a href="http://www.gnu.org/copyleft/"&gt;copyleft&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When we talk about music piracy, we usually think of it as a &lt;span style="font-style: italic;"&gt;free lunch&lt;/span&gt;. But we've been told many times over that there's no such thing. Money don't grow on trees; there are no free lunches. Won't the world stop turning if we give up copyright?&lt;br /&gt;&lt;br /&gt;'Lo and behold free software.&lt;br /&gt;&lt;br /&gt;I write free software, made available &lt;span style="font-style: italic;"&gt;as is&lt;/span&gt;, under the BSD license. My only source of income is the hours I clock from clients. The clients are interested because I write free software.&lt;br /&gt;&lt;br /&gt;The answer to music piracy is free music, as in copyleft. Everybody can hum, sing, dance and play along to music. To copyright music and sell it under a non-free license is artificial. It's no different than software, books or thoughts. Need a source of income? Work. Perform your music, or other people's music, sell it to advertisers (god forbid), sell merchandise to teenagers looking for an identity.&lt;br /&gt;&lt;br /&gt;There's just one problem. Record labels aren't interested; they are afraid that free music will hurt their business model. The irony is that it probably won't. They can still issue compact discs and charge for them. We have recently seen that the LP has grown popular again. There is money to be made from selling free music goods. I think there is money to be made from printing and selling free books, too (in fact, many older books are free; they are still being printed and sold for a profit).&lt;br /&gt;&lt;br /&gt;I think my music habits will stay illegal for the better part of this century. Things won't change. But when people complain "but how can you make yourself do it, knowing that the artists are starving from lack of income" my answer is:&lt;br /&gt;&lt;br /&gt;I don't starve.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-6184959291017105446?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/10/copying-music-left-or-right.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">8</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4383679420107674654</guid><pubDate>Mon, 28 Sep 2009 15:54:00 +0000</pubDate><atom:updated>2009-09-28T19:18:09.321+02:00</atom:updated><title>Picking the right nose</title><description>Like or dislike, &lt;a href="http://docs.python.org/library/doctest.html#unittest-api"&gt;doctests&lt;/a&gt; formatted as restructured text (e.g. the venerable README.txt that resides in many packages) are a convenient way to document your software and make sure the documentation stays in sync with the actual codebase.&lt;br /&gt;&lt;br /&gt;It's surprisingly awkward to run these tests using &lt;a href="http://somethingaboutorange.com/mrl/projects/nose/0.11.1/"&gt;nose&lt;/a&gt;. After some debugging of the &lt;a href="http://docs.python.org/library/unittest.html"&gt;unittest&lt;/a&gt; module, the following is the workaround I've resorted to employ.&lt;br /&gt;&lt;pre&gt;import unittest&lt;br /&gt;import doctest&lt;br /&gt;&lt;br /&gt;class MyTestCase(unittest.TestCase):&lt;br /&gt;  def __new__(self, test):&lt;br /&gt;    return getattr(self, test)()&lt;br /&gt;&lt;br /&gt;  @classmethod&lt;br /&gt;  def test_readme(cls):&lt;br /&gt;    return doctest.DocFileSuite('README.txt')&lt;br /&gt;&lt;/pre&gt;The documentation for &lt;span style="font-style: italic;"&gt;nose&lt;/span&gt; suggests using the ``--doctest-extension`` command-line flag to use non-Python files as doctests, but it seems much more convenient to define them in the actual test module.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4383679420107674654?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/09/picking-right-nose.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-1597744852997108568</guid><pubDate>Sat, 26 Sep 2009 12:31:00 +0000</pubDate><atom:updated>2009-09-27T02:40:40.342+02:00</atom:updated><title>A new object database for Python</title><description>When Chris McDonough presents his &lt;a href="http://bfg.repoze.org/"&gt;BFG&lt;/a&gt; framework he uses the punchline "like Zope, but less". I'll take the liberty to reuse it about a new object database that I've written over the summer: "like ZODB, but less". It's called &lt;span style="font-style: italic;"&gt;dobbin&lt;/span&gt;, which is a reuse from another project, incidentally also an object database.&lt;br /&gt;&lt;br /&gt;Less code. About one twentieth. Of course, less features, too. And easier assumptions.&lt;br /&gt;&lt;br /&gt;I'll be the first to admit that I felt caught in the act when I first read the so-called &lt;a href="http://varnish.projects.linpro.no/wiki/ArchitectNotes"&gt;architect notes&lt;/a&gt; of the varnish proxy server. The author of that software claims most developers are still writing software like it was 1975. If you read that document and consider the memory management attempts of the ZODB, you might get the feeling that he's right.&lt;br /&gt;&lt;br /&gt;Dobbin is the logical consequence of that document. It doesn't try to manage its own memory.&lt;br /&gt;&lt;br /&gt;Less overhead. Persistent objects are read-only, until &lt;span style="font-style: italic;"&gt;checked out&lt;/span&gt;. Their state is shared between threads. This significantly reduces memory usage; in fact, memory usage has always been the Achilles' heel of the object database. This reduction comes with an inconvenience: objects must always be explicitly checked out before they can be changed.&lt;br /&gt;&lt;br /&gt;There's no inherent network support, but multiple processes can connect to the same database without configuration. There's no server process; the database is simply a file.&lt;br /&gt;&lt;br /&gt;Less complexity. Dobbin is written all in Python.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://pypi.python.org/pypi/dobbin"&gt;project page&lt;/a&gt; on PyPi has more information including a user's guide. It's not quite ready for serious usage yet. If you're interested in helping out, these are the next steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Packing (trimming away old versions from the transaction log)&lt;/li&gt;&lt;li&gt;Indexing (field-indexing and querying)&lt;/li&gt;&lt;li&gt;Persistent dictionaries and lists (buckets or similar)&lt;/li&gt;&lt;/ul&gt;To contribute code to the project you must sign the &lt;a href="http://repoze.org/contributor.pdf"&gt;contributor agreement&lt;/a&gt; for the repoze repository.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-1597744852997108568?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/09/new-object-database-for-python.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-860875679948050855</guid><pubDate>Wed, 16 Sep 2009 15:03:00 +0000</pubDate><atom:updated>2009-09-16T17:48:53.313+02:00</atom:updated><title>Where to eat in Porto</title><description>It's just &lt;a href="http://maps.google.com/maps?f=q&amp;amp;source=s_q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;q=central+dos+leoes,+loc:+Oporto,+Portugal&amp;amp;sll=41.147344,-8.614915&amp;amp;sspn=0.00942,0.018582&amp;amp;ie=UTF8&amp;amp;ll=41.148737,-8.614762&amp;amp;spn=0,359.981418&amp;amp;z=16&amp;amp;layer=c&amp;amp;cbll=41.147322,-8.61491&amp;amp;panoid=0jTY0bVLt7x3K6De3SXHLg&amp;amp;cbp=12,350.36,,0,16.44"&gt;around the corner&lt;/a&gt;; you sit where you like. The waiter (&lt;span style="font-style: italic;"&gt;empregado&lt;/span&gt;) will quickly bring bread, olive oil and vinegar, a tray of olives, mixed salad and two charcoal-grilled sausages (chouriço), then insist on a bottle of &lt;span style="font-style: italic;"&gt;vinho verde&lt;/span&gt;, green wine. He will then take the actual order. The people known as &lt;span style="font-style: italic;"&gt;os tripeiros&lt;/span&gt; are hedonists; this is at midday.&lt;br /&gt;&lt;br /&gt;I usually ask for the &lt;span style="font-style: italic;"&gt;picanha&lt;/span&gt;, which is an exquisite red meat cut from the loins. It's prepared on the grill and always served rare. Served with rice, black beans and cabbage (usually kale, prepared like the East-African &lt;span style="font-style: italic;"&gt;sukuma wiki&lt;/span&gt;, quite bitter), it's not exactly an incentive to get back to work. The wine doesn't help here.&lt;br /&gt;&lt;br /&gt;After the meal the waiter will bring the &lt;span style="font-style: italic;"&gt;sobremesa&lt;/span&gt;. It's impolite to refuse. Then coffee.&lt;br /&gt;&lt;br /&gt;The restaurant goes by the name of &lt;span style="font-style: italic;"&gt;central dos leões&lt;/span&gt;, which is only apt. You needn't actually try and find any other restaurant in Porto; it's the best there is and you'll find that they open before you even wake up and serve the last &lt;span style="font-style: italic;"&gt;picanha&lt;/span&gt; long after it's bedtime for Frances.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-860875679948050855?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/09/where-to-eat-in-porto.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8473239127853893601</guid><pubDate>Mon, 31 Aug 2009 19:19:00 +0000</pubDate><atom:updated>2009-08-31T21:20:34.551+02:00</atom:updated><title>Singing and branching</title><description>Let me try and say this in more than 140 characters.&lt;br /&gt;&lt;br /&gt;Inevitably with shrink-wrap software like Plone there's a need to customize behavior. With Plone one of the first things you'll want to change is the look and feel of the retail site. Different packages give different answers to how this is best done; some give several. There are inherent limitations.&lt;br /&gt;&lt;br /&gt;Here's one that'll work for any piece of software that is shrink-wrapped from a version control system: branch and change the software itself.&lt;br /&gt;&lt;br /&gt;I'll argue that it's as prudent or better than any of the official customization stories. Upgrades are straight-forward, just merge the desired changesets into your branch; if there are conflicts, chances are that the burden equals that of the official story. Besides, upgrades across major revisions are rare.&lt;br /&gt;&lt;br /&gt;Python is an interpreted language; you can actually change the source code, restart the process and see your changes take immediate effect. It's your project; think about what's right for you, not what's more clinical.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8473239127853893601?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/08/singing-and-branching.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-3147170414507843436</guid><pubDate>Mon, 27 Jul 2009 10:58:00 +0000</pubDate><atom:updated>2009-07-27T14:11:53.583+02:00</atom:updated><title>Hungry for memory</title><description>The ZODB object database is characteristically hungry for memory. You can almost always trade memory for performance and it's entirely unfair to say that ZODB went all-in.&lt;br /&gt;&lt;br /&gt;All objects are mutable at any time with changes persisted automatically at the end of the transaction. This holds for each thread to the effect that memory usage is often linear on the number of threads (data consistency during a transaction calls for strict separation of mutable data). It only adds to injury that Python has inherent difficulties with memory consumption over time.&lt;br /&gt;&lt;br /&gt;Must we be multi-threaded? Unless we're CPU bound then yes, it's the only way to increase capacity.&lt;br /&gt;&lt;br /&gt;If instead objects weren't mutable by default, threads could share them. When a program wanted to change an object, it would simply ask ZODB to provide a mutable instance. At the end of the transaction this instance would become the new shared object.&lt;br /&gt;&lt;br /&gt;This would not challenge the benefits of using an object database, nor do I expect it to cost much in terms of performance. For a database that's optimized for reading, the convenience of being able to change objects without preparation is a non-goal.&lt;br /&gt;&lt;br /&gt;To limit memory usage in general, we can configure the amount of objects ZODB keeps in memory (per thread). If this number of exceeded, ZODB automatically dereferences the objects least in use, an apparatus known as the &lt;span style="font-style: italic;"&gt;object cache&lt;/span&gt;. Poul-Henning Kamp calls this "1975 programming" in his &lt;a href="http://varnish.projects.linpro.no/wiki/ArchitectNotes"&gt;notes&lt;/a&gt; for the architecture of Varnish, the HTTP caching proxy. In his own words, this is how Varnish does it:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;Varnish allocate some virtual memory, it tells the operating system to back this memory with space from a disk file. When it needs to send the object to a client, it simply refers to that piece of virtual memory and leaves the rest to the kernel.&lt;/blockquote&gt;Should ZODB manage its own memory consumption? Kamp would argue that it should instead let the operating system swap out objects not in active use.&lt;br /&gt;&lt;br /&gt;The operation system must of course spend time paging where the ZODB simply dereferences objects, freeing them from memory. However, when objects need to be made available again, ZODB must unpickle them, arguably much more expensive than paging.&lt;br /&gt;&lt;br /&gt;That said, the operating system might not be in a position to swap out the objects least in use; Python has its own memory allocation system that operates on a program-level.&lt;br /&gt;&lt;br /&gt;Read-only objects and virtual memory–both, either or neither?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-3147170414507843436?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/07/hungry-for-memory.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-3930649052465386917</guid><pubDate>Thu, 23 Jul 2009 14:59:00 +0000</pubDate><atom:updated>2009-07-23T17:00:13.503+02:00</atom:updated><title>Relay chat</title><description>&amp;lt;hydra__&amp;gt; Ergo^: do you use decorator.decorator to write decorators?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-3930649052465386917?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/07/relay-chat.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-3554622672740749855</guid><pubDate>Wed, 22 Jul 2009 12:22:00 +0000</pubDate><atom:updated>2009-07-22T23:52:42.941+02:00</atom:updated><title>Fitter, happier and more productive</title><description>I'm usually unhappy working.&lt;br /&gt;&lt;br /&gt;Here's a short account of the remedies I've attempted; they are all peripherals that you can connect to your computer.&lt;br /&gt;&lt;br /&gt;The first peripheral I acquired was a USB telephone handset. It has no buttons and does not integrate with anything; instead it provides a microphone and speaker device. I am very happy with this device. You need to physically hold it with one hand when you talk, like you would a normal telephone.&lt;br /&gt;&lt;br /&gt;Then I bought a Kinesis Advantage keyboard. It was very difficult for me to learn how to use it; the first two weeks were awkward, progress–slow. Not unlike learning to play an instrument. Or wearing glasses. It has built-in key remapping with a memory of its own. It's a wonderful keyboard.&lt;br /&gt;&lt;br /&gt;Mouse: Logitech Nano. I'm not a serious mouse-user by any measure, but if you're going to take someone's word for a mouse, this is one good mouse.&lt;br /&gt;&lt;br /&gt;The next peripheral is my headphones, a pair of Grado SR 225. It's an open ear cup headphone which means that it doesn't try to silence out background noise. Good for sound reproduction quality, but you can't opt out of office chattering–open social, right? If you are in Europe, it's possible to buy them from a company called "The Sound Room" for the US-market price. Note that there is a new improved version available under the name SR 225i.&lt;br /&gt;&lt;br /&gt;I listen to music to rest my mind every now and then while working, but the paper mache sound of the built-in soundcard doesn't resonate well with me. My laptop has optical audio output and I connect it to a Tianyun Zero D/A converter which has built-in headphone amplification. It makes a world of a difference. The 2009 edition even has USB input. It sells on ebay for $118 (shipped from Hong Kong)–robbery at broad daylight.&lt;br /&gt;&lt;br /&gt;Not exactly a peripheral, but easily the most essential ingredient in my setup: emacs. I use it for shell work, notes, editing and internet relay chat, everything that involves typing. It took me some years before I understood how to use this editor and why. If you're on a mac, the carbon emacs package seems to be the better build. Dot emacs configuration on request.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-3554622672740749855?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/07/fitter-happier-and-more-productive.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-2942832258546994932</guid><pubDate>Wed, 15 Jul 2009 11:55:00 +0000</pubDate><atom:updated>2009-07-15T22:43:24.387+02:00</atom:updated><title>It's all wrong</title><description>It all started with an &lt;a href="http://osdir.com/ml/python.web/2005-01/msg00013.html"&gt;innocent post&lt;/a&gt; to the Python web development mailinglist: "Fun with WSGI - commenting middleware". It sounds harmless, but the idea had a viral potential. Middleware was to be the building blocks of web applications, much like LEGO. Not convinced? This was written in a &lt;a href="http://www.boduch.ca/2009/04/idea-for-loading-pylons-middleware.html"&gt;blog post&lt;/a&gt; only two months ago:&lt;br /&gt;&lt;blockquote&gt;"This way, Pylons middleware components could be discovered and loaded as they are installed on the system."&lt;/blockquote&gt;It's plug and play and it works out of the box. Want users to be able to rate content? Plug in the right middleware. Want it to share a database with the application? Use the &lt;a href="http://pypi.python.org/pypi/repoze.zodbconn"&gt;database sharing&lt;/a&gt; middleware.&lt;br /&gt;&lt;br /&gt;Now, some readers will say, "is it really that simple?" Yes. Is it good software design? No.&lt;br /&gt;&lt;br /&gt;That's a fairly strong statement, but I don't think I will regret it.&lt;br /&gt;&lt;br /&gt;WSGI middleware relies on a protocol in which you're given a request and an application object (which might itself be middleware) and in return, you're expected to provide a response. That's it–there's exactly nothing more to it.&lt;br /&gt;&lt;br /&gt;How is it possible to share a database across these middlewares (or with the application since we can't know which it is)? Well, it's Python, so you just might insert the database connection object into the HTTP environment (aptly termed &lt;span style="font-style: italic;"&gt;WSGI environment&lt;/span&gt; to keep up appearances). Another option is to keep it in a thread-local global–afterall, WSGI applications run in their own thread.&lt;br /&gt;&lt;br /&gt;Is it abuse? You tell me. But wait, there's more.&lt;br /&gt;&lt;br /&gt;Modular is good. You don't need much experience in software development to realize that. That's why it feels attractive to have the commenting apparatus in a separate module and plug it in "from the outside". Let's have a closer look at the fun commenting middleware:&lt;br /&gt;&lt;br /&gt;The user interface for viewing and posting comments is typically presented at the end of an article. It uses simple GET and POST requests, perhaps coupled with user authentication and/or &lt;span style="font-style: italic;"&gt;captcha&lt;/span&gt;. Disregarding Ajax-functionality, styling can be left to the host application. For storage we can connect to a SQL database.&lt;br /&gt;&lt;br /&gt;Fairly self-contained, but not really.&lt;br /&gt;&lt;br /&gt;Can we do any better? We could require that POST requests come from human beings with valiant intentions. Such users are commonly allowed to post a comment. A middleware sitting in front of the commenting apparatus could safeguard POST requests by looking at the &lt;span style="font-style: italic;"&gt;remote user&lt;/span&gt; header (a successful captcha challenge would put a system string here). This header could be set by an authentication middleware (configured with the right cipher to validate an authentication cookie).&lt;br /&gt;&lt;br /&gt;It would be difficult to get to such attributes as &lt;span style="font-style: italic;"&gt;full name&lt;/span&gt; (certainly some developers will be itching to  introduce a &lt;span style="font-style: italic;"&gt;remote user full name&lt;/span&gt; key into the WSGI environment to work around this) but software is compromise.&lt;br /&gt;&lt;br /&gt;To follow up on the authentication middleware story, it could in theory be responsible for setting the authentication cookie on &lt;span style="font-style: italic;"&gt;egress&lt;/span&gt;, if it found that a remote user header had been set in the environment by a downstream application. The signal to clear the cookie could be the non-existance of this header. Middleware is not wrong in general.&lt;br /&gt;&lt;br /&gt;What's wrong is the abuse of the WSGI specification to sneak around Python-objects because your middleware really isn't middleware–it's part of the application!&lt;br /&gt;&lt;br /&gt;Abuse is like a casino; the house always wins.&lt;br /&gt;&lt;br /&gt;The commenting middleware is wrong in a different way, too. It's a small application, but web applications share many of the same moving parts. Authentication, authorization, sessions, language negotiation, routing–these are just examples. You can't split them out to middleware because it violates the WSGI contract. The result is that every miniature application in the pipeline needs its own set of moving parts. Never mind that it's painful to merge HTML from two applications.&lt;br /&gt;&lt;br /&gt;The promise of the &lt;span style="font-style: italic;"&gt;semantic web&lt;/span&gt; might be the way out of this situation. Until it materializes  we need to embrace integration and find the right abstractions to make modular programming possible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-2942832258546994932?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/07/its-all-wrong.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-950490363732234663</guid><pubDate>Tue, 02 Jun 2009 04:32:00 +0000</pubDate><atom:updated>2009-06-02T07:03:43.424+02:00</atom:updated><title>The curry diet</title><description>&lt;span style="font-style: italic;"&gt;This might just work&lt;/span&gt;. That's really the best I can come up with to describe an odd little library that I've secretly been working on. It's called &lt;span style="font-weight: bold;"&gt;curry&lt;/span&gt;, because it's both &lt;span style="font-style: italic;"&gt;cooking&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;currying&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Also referred to as &lt;a href="http://en.wikipedia.org/wiki/Currying"&gt;partial application&lt;/a&gt;, currying is the transformation of a function of &lt;span style="font-style: italic;"&gt;n&lt;/span&gt; variables into a chain of &lt;span style="font-style: italic;"&gt;n&lt;/span&gt; functions of a single variable. That seemed a bit too mathematical for me to be of any practical use in Python, so my starting point is a bound method. The idea then is to apply partial application to this method to shift off the class instance pointer, partially evaluating the function body (recursively). This is actually a means of optimization and the motivation is to try and use it instead of code generation in libraries like &lt;a href="http://pypi.python.org/pypi/chameleon.core"&gt;chameleon&lt;/a&gt;. Rather than generating code, the idea is to reduce existing, working, tested code to obtain the exact same result.&lt;br /&gt;&lt;br /&gt;There are more technical details available on the &lt;a href="http://pypi.python.org/pypi/curry"&gt;project page&lt;/a&gt;, while &lt;a href="http://repoze.org/viewcvs/curry/trunk/src/curry/tests/examples.py?view=markup"&gt;examples&lt;/a&gt; are included in the test suite.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-950490363732234663?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/06/curry-diet.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8792306407420478581</guid><pubDate>Sat, 16 May 2009 15:02:00 +0000</pubDate><atom:updated>2009-05-16T17:11:22.604+02:00</atom:updated><title>Activist appears on a tortilla in mexico god</title><description>Yesterday, while attending a poetry slam session in a Nairobi suburb, it dawned upon me that a central theme in the Christian belief goes against my morality. I find it interesting, because non-believers are often lead to believe that their morals are inherited from Christian doctrine. Appearently, not so. I suppose it's a relief to me, which is why I feel like sharing. An apology for posting this here is due being wanton off-topic, but rest assured that the word "science" does appear. For the record, the title of this piece was inspired by a friend who said, "I honestly don't even think I believe in God more than like some levelling force of good in the universe, I don't believe in this activist appears on a tortilla in mexico god". I'm not personally seeing much of this levelling force and not very compelled to spirituality in general, but the rest of the remark does make for a good title.&lt;br /&gt;&lt;br /&gt;Spirituality is strong in Kenya and most of the poems recited in the session carried religious messages. I took note of one piece in particular, which had a female poet ask her would-be suitor if "He was your king, your leader" (he would then ask her the same). This lead me to think about the concept of judgment, e.g. the notion that after we pass away, divine judgment awaits (protecting the kingdom of heaven). Another poet introduced his piece by reminding the audience that "scientists should stick to formulas". While a fair proposition, I hope it does not exclude me from employing logic, because I will need it in the following.&lt;br /&gt;&lt;br /&gt;You'll recall that in Christian doctrine, Purgatory is the station just before Heaven and Hell (there's a notion of being in "limbo" as well, but that's irrelevant here). I've always thought that eternal damnation was an odd concept, but I've been lead to believe that it's a scarecrow idea that will never materialize (surely if it did, it would undermine the entire foundation of Christian morality, being such as cruel punishment). As such, we all go to Heaven eventually. What's important is that we don't know this while down here and so there's still this judgment awaiting us which could prove detrimental.&lt;br /&gt;&lt;br /&gt;I call this morality of Purgatory "The Carrot or the Chariot", inspired by Malcolm X's speech "The Ballot or The Bullet", which in 1964 warns the United States government that if African-Americans are not given full equality, armed struggle will ensue. Mine is a pun on the obvious flaw of using Heaven as a carrot, while Hell is the actual destination should anything go wrong. The opposite of a carrot must be neutral, else it's no carrot.&lt;br /&gt;&lt;br /&gt;We must believe in reform and morality while down here and we cannot instill this using fear for divine judgment. The carrot is the joy of living a moral life with all in which entails of honesty, modesty, humility, and so forth. With the morality of divine judgment comes reasoning that leads us to such cruelties as capital punishment (the secular counterpart to eternal damnation).&lt;br /&gt;&lt;br /&gt;Further, if Purgatory is merely a scarecrow institution, we must question whether Heaven is even possible. Can such a state of being truly be different from that which we experience here below? The same petty thiefs, thugs and defilers will dwell there, too, demanding justice.&lt;br /&gt;&lt;br /&gt;To observe this belief of happiness in living a life in morality and accepting happiness as a carrot is thus to reject the existance of Purgatory, Heaven and Hell, all of which are central to Christian morality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8792306407420478581?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/05/activist-appears-on-tortilla-in-mexico.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">11</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-9098907723119346089</guid><pubDate>Mon, 11 May 2009 16:16:00 +0000</pubDate><atom:updated>2009-05-11T19:14:52.724+02:00</atom:updated><title>Pesky operands</title><description>Unlike ZPT, Chameleon relies on the venerable expat parser. It's not forgiving in the slightest and won't parse a "&lt;" character that isn't part of a tag (as often used in an inline Javascript for-loop). Often times we can't make assumptions on the document mode, which rules out CDATA. We're not spoilt for choice.  Then I stumbled upon a &lt;a href="http://www.informit.com/articles/article.aspx?p=1193471&amp;amp;seqNum=9"&gt;clever&lt;/a&gt; workaround: Reverse the operands and invert the operator, then it &lt;span style="font-style: italic;"&gt;just works&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-9098907723119346089?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/05/pesky-operands.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-3017076329300041822</guid><pubDate>Thu, 07 May 2009 14:20:00 +0000</pubDate><atom:updated>2009-05-07T18:18:46.780+02:00</atom:updated><title>Forms that don't make you tense and nervous</title><description>Forms are tedious. I used to think that some five thousand lines of code was the remedy [1]. All the pesky details are abstracted away and in their stead is a very reasonable model based on schemas, widgets, converters, add forms, edit forms, display forms, page forms, subforms–rest assured, there's an option that fits &lt;span style="font-style: italic;"&gt;you&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Invariably, with any framework you'll need to adjust things a bit. As it happens, this is where it gets tedious with the framework that is supposed to remedy tediousness. Endless abstraction and delegation makes it difficult to plug in custom behavior, let alone come to terms with what needs to be plugged out and how to write the code to replace it.&lt;br /&gt;&lt;br /&gt;Typesetting documents in Latex is similar; you'll spend hours trying to align four graphs on a page, because "letting the system do it for you" doesn't get you where you want. The better you're acquainted with the system, headaches will come fewer and farther between–the learning curve pays off. Yet, arguably not all documents are best typeset in Latex.&lt;br /&gt;&lt;br /&gt;Where's the restructured text of forms? There's Ian Bicking's &lt;a href="http://formencode.org"&gt;FormEncode&lt;/a&gt;. It does some of the things I want and it does a lot of things I don't want. It also does the things I do want in a way I don't quite like.&lt;br /&gt;&lt;br /&gt;Sanctioned by the "scratch your own itch" approach to software development (if it works for you, chances are it'll work for others), Stefan Eletzhofer and I decided to write a minimalistic form library called &lt;a href="http://pypi.python.org/pypi/repoze.formapi"&gt;repoze.formapi&lt;/a&gt;. Part of the library was actually written with Ian present, while Jeroen Vloothuis wrote most of the error handling and validation logic. The result is a very usable library which intentionally does very little. It provides powerful field marshalling, flexible validation and a minimalistic form class framework. You write your &lt;span style="font-style: italic;"&gt;own&lt;/span&gt; HTML.&lt;br /&gt;&lt;br /&gt;Note: Narrative &lt;a href="http://docs.repoze.org/formapi/"&gt;documentation&lt;/a&gt; for the library is now available.&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://pypi.python.org/pypi/z3c.form"&gt;z3c.form&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-3017076329300041822?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/05/forms-that-dont-make-you-tense-and.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8573909334963929944</guid><pubDate>Wed, 15 Apr 2009 12:02:00 +0000</pubDate><atom:updated>2009-04-16T09:07:56.220+02:00</atom:updated><title>Book review: Practical Plone 3</title><description>Let me first make the observation that printed books are here to stay; I received an electronic copy of the &lt;a href="http://www.packtpub.com/practical-plone-3-beginners-guide-to-building-powerful-websites/book"&gt;latest Plone book&lt;/a&gt; from the &lt;a href="http://www.packtpub.com/"&gt;publisher&lt;/a&gt; asking for a review and it's been looking at me from its place on the desktop for about two months now. Today I received an e-mail from the publisher asking for the location of the review, so I'd better get on with it.&lt;br /&gt;&lt;br /&gt;I haven't bought or read a technical book for about five years. The last one was Philipp's book on developing Zope applications using the component architecture. I thought that was quite a good book and certainly one that I'll revisit from time to time (okay, less and less so, but it's had a very decent life span). Why is it a good book? I think the primary reason is that it knows its audience and stays with it throughout the book. There's a learning curve, but not an audience curve.&lt;br /&gt;&lt;br /&gt;I think the average reader will take one year to read this book (sic).&lt;br /&gt;&lt;br /&gt;When I read through the initial chapters, I got the odd feeling that it's got an audience curve instead of a learning curve. In the first few chapters we learn what Plone looks like and we're introduced to some new vocabulary like &lt;span style="font-style: italic;"&gt;breadcrumbs&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;colophon&lt;/span&gt;. That doesn't seem very &lt;span style="font-style: italic;"&gt;practical&lt;/span&gt;; it seems introductory. To spend some fifty pages going through the main user interface may not seem like an issue (you can easily skip them), but skipping pages is something you do on Google, not when reading. In other words, skip the extended introduction–it's too likely that it will be anyway.&lt;br /&gt;&lt;br /&gt;Parts 2 and 3 (starting on page 55) make up the rest of the book. Part 2 is essentially a user's guide (how to use Plone) while part 3 is an integrator's guide (how to extend and customize Plone). It's good writing and the material matches expectations. However, we can't get around the fact that this book addresses three different audience in three different parts. It'll take a year to read the book and by then we'll have Plone 4.&lt;br /&gt;&lt;br /&gt;Perhaps 500+ pages isn't always the right balance for a technical book; in the case of Plone, it seems that 50/250/250 would be better, distributed in three separate volumes, like a trilogy. Perhaps 50/250/500/500, where the missing part 4 would deal with how to develop enterprise Plone apps, but luckily, this is what Martin's book is all about.&lt;br /&gt;&lt;br /&gt;Is there a conclusion to these ramblings? I'm not sure, but knowing your audience, staying with them and appreciating the &lt;span style="font-style: italic;"&gt;quick read&lt;/span&gt; are valuable points I think. As for a recommendation, I'll say that this book belongs in any &lt;span style="font-style: italic;"&gt;office&lt;/span&gt; where Plone is being used, but perhaps not in every &lt;span style="font-style: italic;"&gt;home&lt;/span&gt;. I look forward to the revised second edition, coming out in three separate volumes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8573909334963929944?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/04/book-review-practical-plone-3.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-934816558785659263</guid><pubDate>Fri, 27 Mar 2009 11:28:00 +0000</pubDate><atom:updated>2009-03-27T12:46:34.770+01:00</atom:updated><title>Time-out in Africa</title><description>Yesterday, while listening to "White Car in Germany" by The Associates, I kept getting an error while running buildout:&lt;br /&gt;&lt;pre&gt;Error: MD5 validation failed for plone.app.locales-3.2.0.zip;&lt;/pre&gt;"What the hell", I thought and went step-debugging into the code. First an observation: I would not expect a ``check_md5`` method to actually go ahead and unlink the downloaded file if validation fails. That aside, the error persisted and it turns out that ``urllib2`` silently times out a request if the socket does not receive data within some period of time (this happens quite often here).&lt;br /&gt;&lt;br /&gt;The documentation suggests that it will raise an exception, but perhaps the clue is that if no time-out value has been set, it's really not a time-out (so why raise an exception). At least, setting it (at a reasonable location in the buildout-script) resolves the issue:&lt;br /&gt;&lt;pre&gt;import socket&lt;br /&gt;socket.setdefaulttimeout(3600)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-934816558785659263?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/03/time-out-in-africa.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8123270384175000869</guid><pubDate>Thu, 29 Jan 2009 14:49:00 +0000</pubDate><atom:updated>2009-01-29T13:55:52.734+01:00</atom:updated><title>Wire it up</title><description>While trying to wire up an interface for managing composited content on a page, it occurred to me that it's very similar to using something like Interface Builder (IB) on the Mac and pulling the wires with XCode. The wire problem is fundamentally difficult, but with JavaScript and HTML, it's plain awkward.&lt;br /&gt;&lt;br /&gt;Essentially there are two ways to go about creating user interfaces and this goes for both desktop applications and browser-based applications. It's either done programatically or graphically. Certain tasks can only be accomplished programatically, so there nothing's new under that sun.&lt;br /&gt;&lt;br /&gt;Both HTML and IB are essentially based on containment. Buttons inside panes inside dialog windows aren't much different than buttons inside divs inside a document body. However, IB is object-oriented and each object corresponds to a class in Objective-C. The linker is actually tying the knots of the wires at compile-time.&lt;br /&gt;&lt;br /&gt;It's hard to express abstract objects with HTML, because you're typically only afforded a class name, the exception being form elements and anchors, but even they carry only a minimal set of attributes. It's common to simply put binary decorators in elements in the form of multiple class names, e.g. "selected", "enabled", "current".&lt;br /&gt;&lt;br /&gt;An alternative wiring scheme is to use invisible anchors to signal some interaction using the "href", "rel" and "name" attributes to carry information. It's not a good solution, because there's no "value" attribute (which would facilitate an RDF-like structure) and none of these attributes are indexed, making queries slow.&lt;br /&gt;&lt;br /&gt;A third strategy is to use hidden definition lists. This can be coupled with containment to express attribute name/value pairs. The disadvantage is that it's an inappropriate container. Definition lists are part of the document content, while element attributes typically aren't. But the structure is near-perfect.&lt;br /&gt;&lt;br /&gt;Meanwhile, XML namespace attributes may qualify as a fourth option even though browser-support is still disappointing. There's fundamental support, but no high-level API. To change this situation, I decided to put together a&lt;a href="http://plugins.jquery.com/project/xmlattr"&gt; jQuery plugin&lt;/a&gt; which provides XML attribute access using James Clark's namespace notation "{ns}name" which will be familiar to most people who've been parsing XML.&lt;br /&gt;&lt;br /&gt;By combining the HTML attributes "id" and "class" (which all elements may carry) and XML attributes, we can model the state of a class instance. In a complex situation, one could use the prototyping features of JavaScript, but in many cases it will be good enough to simply use this as a data storage.&lt;br /&gt;&lt;br /&gt;Update: I've successfully tested the plugin in Safari, Firefox and IE7.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8123270384175000869?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/01/wire-it-up.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4539338562982930990</guid><pubDate>Fri, 28 Nov 2008 11:28:00 +0000</pubDate><atom:updated>2008-11-28T12:44:01.852+01:00</atom:updated><title>An lxml you can build on</title><description>Last week I &lt;a href="http://mockit.blogspot.com/2008/11/lxml-you-can-bank-on.html"&gt;wrote about&lt;/a&gt; Chris Perkins' &lt;a href="http://pypi.python.org/pypi/staticlxml"&gt;staticlxml&lt;/a&gt; package. While it did work for me in a virtualenv, it wasn't feasible for a &lt;a href="http://pypi.python.org/pypi/zc.buildout"&gt;buildout&lt;/a&gt; environment.&lt;br /&gt;&lt;br /&gt;However, &lt;a href="http://seletz.blogspot.com/"&gt;Stefan Eletzhofer&lt;/a&gt; has come to the aid with his &lt;a href="http://pypi.python.org/pypi/z3c.recipe.staticlxml"&gt;z3c.recipe.staticlxml&lt;/a&gt; package which really nails this dreadful issue.&lt;br /&gt;&lt;br /&gt;Configuration is slightly verbose, but straightforward:&lt;span style="font-family:onload;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;pre class="literal-block"&gt;  [lxml]&lt;br /&gt;  recipe = z3c.recipe.staticlxml&lt;br /&gt;  egg = lxml&lt;br /&gt;  force = false&lt;br /&gt;  build-libxml2 = true&lt;br /&gt;  build-libxslt = true&lt;br /&gt;  static-build = true&lt;br /&gt;&lt;/pre&gt;Put this part into your buildout configuration; note that it must come before any parts that would try to pull in an lxml egg over the wire, otherwise it won't work. Make sure to wipe any existing lxml eggs from your buildout cache before you start.&lt;br /&gt;&lt;br /&gt;To verify that everything's gone to plan, use the bindings tool:&lt;br /&gt;&lt;pre class="literal-block"&gt;   bash-3.2$ find . -name "*.so" -exec otool -L '{}' \;&lt;/pre&gt; We don't expect to see any references to libxml or libxslt here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4539338562982930990?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2008/11/lxml-you-can-build-on.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-3136577706601695197</guid><pubDate>Wed, 19 Nov 2008 14:03:00 +0000</pubDate><atom:updated>2008-11-29T10:39:26.463+01:00</atom:updated><title>Speedup</title><description>&lt;p&gt;You can now have your cake and eat it, too.&lt;/p&gt;&lt;img style="width: 400px; height: 195px;" src="http://www.testingunderground.com/%7Emborch/plone-benchmark.png" alt="Plone benchmark comparing Chameleon to ZPT" /&gt;&lt;br /&gt;&lt;br /&gt;Disclaimer: Don't try this at home! Or actually, do try it, but only on Plone trunk. Simply pull in the &lt;a href="http://pypi.python.org/pypi/five.pt"&gt;five.pt&lt;/a&gt; egg and load its configuration. It's a whole-sale drop-in replacement of Zope Page Templates.&lt;br /&gt;&lt;br /&gt;If you're interesting in sponsoring this on-going effort, there's an excellent sponsorship opportunity for the upcoming performance-sprint in Bristol. Please contact me by e-mail at &lt;a href="mailto:mborch@gmail.com"&gt;mborch@gmail.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Update: CMF-bindings have been split out to the &lt;a href="http://pypi.python.org/pypi/cmf.pt"&gt;cmf.pt&lt;/a&gt; package.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-3136577706601695197?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2008/11/speedup.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">14</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-7198901819644673321</guid><pubDate>Fri, 07 Nov 2008 15:19:00 +0000</pubDate><atom:updated>2008-11-07T16:53:23.177+01:00</atom:updated><title>An lxml you can bank on</title><description>&lt;a href="http://www.percious.com/blog/"&gt;Chris Perkins&lt;/a&gt; has saved the Mac's reputation as a development platform with his &lt;a href="http://pypi.python.org/pypi/staticlxml"&gt;&lt;tt&gt;staticxml&lt;/tt&gt;&lt;/a&gt; package (see the &lt;a href="http://groups.google.com/group/paver/browse_thread/thread/bf954914f69db0c5/62ad0f00efb6945e?lnk=gst&amp;amp;q=staticlxml&amp;amp;pli=1"&gt;discussion&lt;/a&gt; on the mailinglist for &lt;tt&gt;paver&lt;/tt&gt; for reference). It allows you to build &lt;tt&gt;lxml&lt;/tt&gt; as a statically linked egg with little effort. As most Mac-users looking to reap the benefits of &lt;tt&gt;lxml&lt;/tt&gt; will know, building this egg reliable using dynamic linking is difficult; or rather, building it is easy, getting it pick up the right libraries at run-time is a science.&lt;br /&gt;&lt;br /&gt;There's really not much more to say. Build that egg and sleep better at night, knowing that no-one can break that sacred bond between &lt;tt&gt;lxml&lt;/tt&gt; and its system library dependencies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-7198901819644673321?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2008/11/lxml-you-can-bank-on.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-312974943127839728</guid><pubDate>Mon, 06 Oct 2008 14:19:00 +0000</pubDate><atom:updated>2008-10-07T18:03:04.861+02:00</atom:updated><title>Bringing it all back home</title><description>In Zope 2, the application "skin" is comprised of a set of ordered layers, each containing a number of skin objects. These could be Python scripts (running in restricted mode), templates, form controller scripts and static files such as images.&lt;br /&gt;&lt;br /&gt;The upshot is that you get to dump files in there and have them immediately working with no additional configuration needed (the file extension is used to infer the type); the downside is that it's a global namespace, there's no restriction on adaptation (any object can be the context and every request type is valid) and there's no permission check.&lt;br /&gt;&lt;br /&gt;To contrast, in Zope 3, skin objects have been replaced with browser pages and resources, which are typically configured using the ZCML component configuration language. The Zope 3 way essentially boils down to configuration over convention, and a dose of "explicit is better than implicit".&lt;br /&gt;&lt;br /&gt;We can play around with these words and relate to even other ways; one of them is "implicit configuration", and this is partly where &lt;a href="http://grok.zope.org"&gt;Grok&lt;/a&gt; finds itself.&lt;br /&gt;&lt;br /&gt;In this little writeup, I'd like to introduce two packages that try to be "explicit and conventional", ``&lt;a href="http://pypi.python.org/pypi/repoze.bfg.skins"&gt;repoze.bfg.skins&lt;/a&gt;`` and ``&lt;a href="http://pypi.python.org/pypi/repoze.bfg.static"&gt;repoze.bfg.static&lt;/a&gt;``.&lt;br /&gt;&lt;br /&gt;Although they can very well be used on their own, it makes sense to combine them. The latter provides "configure once, use everywhere" static resource serving (we're in a WSGI Paste application here).&lt;br /&gt;&lt;br /&gt;Static resources are served from mount points that map a URL to a directory on the file-system. The mount points are just adapters registered as views, but they are also responsible for handing out a URL for a particular file-system path (if applicable).&lt;br /&gt;&lt;br /&gt;Assuming &lt;code&gt;skin_path&lt;/code&gt; is file-system path passed to the WSGI application constructor as a configuration option and &lt;code&gt;app&lt;/code&gt; is the Router-object, we can use a statement such as:&lt;br /&gt;&lt;pre&gt;  app.registry.registerAdapter(&lt;br /&gt;   repoze.bfg.static.static_view_factory(skin_path),&lt;br /&gt;   name='static')&lt;br /&gt;&lt;/pre&gt;Note that multiple static views are allowed; the library will go through the available views until it finds a mount point that's applicable to serve up a given static resource. We can now serve any static resources in or below the skin path using the ``repoze.bfg.static.get_url`` function.&lt;br /&gt;&lt;br /&gt;This integrates with the skins package, but a quick introduction is in order before we continue.&lt;br /&gt;&lt;br /&gt;The skins package provides a ZCML-directive to register a directory of "skin templates" (see the PyPi-page for a more thorough description).&lt;br /&gt;&lt;pre&gt;  &amp;lt;bfg:templates&lt;br /&gt;   for="..." request_type="..." permission="..."&lt;br /&gt;   directory="templates" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;Skin templates are registered individually as view components. From inside a skin template (which is essentially a page template that gets passed two special symbols),  it's easy to include other skin templates. And if the directory where the templates is located, lies within a mount point to serve static resources, we can link to resources local to the template like so:&lt;br /&gt;&lt;pre&gt;  &amp;lt;img src="${api.static.url('logo.png')}" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;This can also be used to link to stylesheets and javascript. This way, using just these two packages, one could create the frontend for a simple web application, complete with images.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-312974943127839728?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2008/10/bringing-it-all-back-home.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-2273509053004574136</guid><pubDate>Sat, 04 Oct 2008 21:29:00 +0000</pubDate><atom:updated>2008-10-05T00:14:25.783+02:00</atom:updated><title>Blitting and squeezing</title><description>When middleware actually sits in the middle and is not attached like a parasite to its host, it's makes for some very convenient software. After a few misguided attempts, we believe to have come up with two good middlewares.&lt;br /&gt;&lt;br /&gt;First there's ``&lt;a href="http://pypi.python.org/pypi/repoze.bitblt"&gt;repoze.bitblt&lt;/a&gt;``. It transforms images on the fly! Give it a width and a height, and it'll resize your image. Use it in conjunction with a caching proxy for optimum performance. Ideas for future enhancements include mimetype conversion and image scale presets.&lt;br /&gt;&lt;br /&gt;Then we have ``&lt;a href="http://pypi.python.org/pypi/repoze.squeeze"&gt;repoze.squeeze&lt;/a&gt;``. It literally squeezes your stylesheets and javascripts, all with zero configuration! How can it work?! It keeps a record of which resources appear together and keeps an internal cache of the resources as they are served; when it has enough information to determine which resources should be bundled (merged), it intercepts HTML documents and rewrites the resource links. Expiration dates and vary-headers are observed, too!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-2273509053004574136?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2008/10/blitting-and-squeezing.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4866803503160812040</guid><pubDate>Wed, 24 Sep 2008 21:24:00 +0000</pubDate><atom:updated>2008-09-24T23:28:13.328+02:00</atom:updated><title>Haiku</title><description>&lt;pre&gt;&gt;&gt;&gt; class WhatTheFuck(object):&lt;br /&gt;...     def __init__(self):&lt;br /&gt;...         self._WhatTheFuck__answer_to_everything = 42&lt;br /&gt;...         print self.__answer_to_everything&lt;br /&gt;&gt;&gt;&gt; metadata = WhatTheFuck()&lt;br /&gt;42&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4866803503160812040?l=mockit.blogspot.com'/&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2008/09/haiku.html</link><author>noreply@blogger.com (malthe)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total></item></channel></rss>
