<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7170092975132372391</id><updated>2010-08-30T21:12:27.600-07:00</updated><title type='text'>Woohoo</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-4631672378901480354</id><published>2010-08-30T20:53:00.000-07:00</published><updated>2010-08-30T20:55:35.901-07:00</updated><title type='text'>Moving</title><content type='html'>My blog has a new &lt;a href="http://blog.abandonedwig.info"&gt;URL&lt;/a&gt;. Please update your RSS subscriptions accordingly!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-4631672378901480354?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/4631672378901480354/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2010/08/moving-around.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/4631672378901480354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/4631672378901480354'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2010/08/moving-around.html' title='Moving'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-4852676561895066832</id><published>2010-08-30T18:26:00.001-07:00</published><updated>2010-08-30T21:12:27.614-07:00</updated><title type='text'>Node.js Knockout</title><content type='html'>I participated in the &lt;a href="http://nodeknockout.com/"&gt;Node.js Knockout&lt;/a&gt; this year, kindly hosted by &lt;a href="http://fortnightlabs.com/"&gt;Fortnight Labs&lt;/a&gt;. Our team became a bit smaller as we neared the competition, so we decided to make something dead simple. When you're making software, it's good to have a vision statement. Even if you don't finish the software, you'll at least have a well-constructed sentence, which is progress.  Frankly, I was too embarrassed to mention my vision statement to my teammate, Josh.&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Each tweet is a tiny burst of light illuminating a cold, dark world.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;My opinion is that if you're not inspired after reading that, you've probably lost the ability to feel actual human emotions such as hope, rage, and yellow.  We decided to make a Twitter visualization for people like you.&lt;br /&gt;&lt;br /&gt;I'd never written anything on &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; before this competition and it did nothing but impress me. Node.js is built from the ground up with asynchronicity in mind, so ideally you aren't bound by the overhead of creating one thread per connection. Think &lt;a href="http://twistedmatrix.com/trac/"&gt;Twisted&lt;/a&gt;. We also used &lt;a href="http://socket.io/"&gt;Socket.IO&lt;/a&gt;, which made WebSockets sinfully pleasant.&lt;br /&gt;&lt;br /&gt;My partner, Josh, handled the server-side part of the application and I generally worked on the client-side&lt;sup&gt;1&lt;/sup&gt;. My favorite challenge was calculating the &lt;a href="http://en.wikipedia.org/wiki/Robinson_projection"&gt;Robinson Projection&lt;/a&gt; for mapping latitude and longitude onto the map surface. It turns out that Robinson, unlike most projection progenitors, &lt;a href="http://findarticles.com/p/articles/mi_hb3006/is_2_31/ai_n29118548/"&gt;relied on lookup tables and interpolation&lt;/a&gt; rather than providing a set of formulas only. I was easily able to port some Robinson Projection code from &lt;a href="http://trac.osgeo.org/proj4j/"&gt;Java&lt;/a&gt; (which had itself been ported from &lt;a href="http://trac.osgeo.org/proj/"&gt;C&lt;/a&gt;). It was some time later that I realized I had to scale the resulting numbers by the limits of projection output. It all seemed so obvious later on.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://node-us.no.de/"&gt;In any case, I hope this amuses you for a couple seconds.&lt;/a&gt; The code will be on github after it's been cleaned up and licensed.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;I clumsily contributed a last minute cache optimization which had a negligible effect on the output.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-4852676561895066832?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/4852676561895066832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2010/08/nodejs-knockout.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/4852676561895066832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/4852676561895066832'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2010/08/nodejs-knockout.html' title='Node.js Knockout'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-8755760541013491568</id><published>2010-01-23T10:39:00.000-08:00</published><updated>2010-01-24T13:17:32.107-08:00</updated><title type='text'>Looking back at the WebKit GTK hackfest</title><content type='html'>In December, I attended the WebKit GTK hackfest which has been &lt;a href="http://blogs.gnome.org/xan/2009/12/21/webkitgtk-hackfest-day-g_maxint/"&gt;summed&lt;/a&gt; &lt;a href="http://arstechnica.com/open-source/news/2010/01/webkitgtk-hackfest-improves-html-renderer-for-gnome-apps.ars"&gt;up&lt;/a&gt; &lt;a href="http://danw.mysterion.org/2010/01/webkitgtk-hackfest/"&gt;nicely&lt;/a&gt; in &lt;a href="http://blog.kov.eti.br/?p=100"&gt;many&lt;/a&gt; &lt;a href="http://www.twotoasts.de/index.php?/archives/25-Back-from-the-WebKitGTK+-hackfest.html"&gt;other&lt;/a&gt; &lt;a href="http://base-art.net/Articles/112/"&gt;places&lt;/a&gt;. Some of the things I worked on (apart from getting my luggage):&lt;br /&gt;&lt;br /&gt;With the closing of &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=20736"&gt;20736&lt;/a&gt; WebKit GTK should now properly support windows with RGBA colormaps. This means that WebKit GTK can now be used to create nice desktop widgets or non-rectangular applications without worrying about BadMatch errors. Surprisingly non-rectangular windows is one of the most requested features for &lt;a href="http://www.appcelerator.com"&gt;Titanium&lt;/a&gt; and we now support it on OS X, Linux and Windows via the &lt;tt&gt;transparent-background&lt;/tt&gt; property in tiapp.xml.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://abandonedwig.info/blog/uploaded_images/rgba-colormaps-704760.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 331px; height: 400px;" src="http://abandonedwig.info/blog/uploaded_images/rgba-colormaps-704752.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The first big part of my &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=30623"&gt;clipboard / drag-and-drop reorganization&lt;/a&gt; also landed. Once I get the remaining patches together, DOM DataTransfer access to WebKit GTK clipboard and drag-and-drop data will work properly. With luck one day you'll be able to drop your photos and videos onto your web browser and have them upload seamlessly.&lt;br /&gt;&lt;br /&gt;The hackfest itself was in A Coru&amp;ntilde;a, a picturesque Galician city right on the coast of the Atlantic (which I managed to call the &lt;i&gt;Pacific&lt;/i&gt; once, against all odds). I also had a rather abrupt introduction to the bounty of European languages &amp;mdash; Spain has four recognized regional languages apart from Spanish (Castilian).&lt;br /&gt;&lt;br /&gt;&lt;div style="font-size:small;text-align:center"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/mariosp/4201554598/in/set-72157622899055111"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 375px;" src="http://farm3.static.flickr.com/2773/4201554598_3fea667df2.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.gnome.org/xan/"&gt;Xan&lt;/a&gt; and me, probably trying to convince him that drag-and-drop is the future.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;On a personal note, the hackfest solidified my love for open source software. I want to keep doing this, however possible. &lt;a href="http://neugierig.org/"&gt;Evan Martin&lt;/a&gt; made a really good point about open source at some point during the hackfest. He said that people sometimes think that being open source means that you can simply host an archive of your source code somewhere. There is more to it though, including having an open and active community and understanding and responding to your users. Some of this is just good software development practice, but being open source requires doing even more work to open the development process.&lt;br /&gt;&lt;br /&gt;One important aspect of this work is having community discussions and allowing the community to help make decisions. One look at the WebKit development mailing list shows this working. There are many interests tied up with WebKit and some of them are direct competitors, yet somehow they manage to coordinate development on a humongous project. LWN.net recently posted a &lt;a href="http://lwn.net/Articles/370157/"&gt;great article related to this topic&lt;/a&gt;, which I think exemplifies what not to do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-8755760541013491568?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/8755760541013491568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2010/01/looking-back-at-webkit-gtk-hackfest.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8755760541013491568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8755760541013491568'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2010/01/looking-back-at-webkit-gtk-hackfest.html' title='Looking back at the WebKit GTK hackfest'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-8888406959852037616</id><published>2009-10-06T20:51:00.000-07:00</published><updated>2009-10-06T21:59:56.706-07:00</updated><title type='text'>Managing the Python GIL via RAII</title><content type='html'>One of the killer features of C++ is &lt;a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization"&gt;&lt;acronym title="Resource Acquisition is Initialization"&gt;RAII&lt;/acronym&gt;&lt;/a&gt;. RAII means that the amount of special-case cleanup code in the case of exceptions or early exits is minimized. For more on exactly how this happens, I recommend the Wikipedia article linked above.&lt;br /&gt;&lt;br /&gt;This feature became useful to me when making our Python Kroll module work properly with the Python GIL. There were two usage patterns I was interested in for this work.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Letting Python code in other threads run&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;PyThreadState* threadState = PyEval_SaveThread();&lt;br /&gt;...do some expensive non-Python work here...&lt;br /&gt;PyEval_RestoreThread(threadState);&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Taking back the GIL to use the Python API&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;PyGILState gstate = PyGILState_Ensure();&lt;br /&gt;...use the Python API here...&lt;br /&gt;PyGILState_Release(gstate);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The problem with this approach is that if an uncaught exception escapes from anywhere between the ellipses, the cleanup code (&lt;tt&gt;PyEval_RestoreThread&lt;/tt&gt; or &lt;tt&gt;PyGILState_Release&lt;/tt&gt;) will not run, likely leaving the program in a bad state. It turns out that RAII has a very elegant solution to this problem.&lt;code&gt;&lt;pre&gt;&lt;br /&gt;    class PyLockGIL&lt;br /&gt;    {&lt;br /&gt;        PyLockGIL() : gstate(PyGILState_Ensure())&lt;br /&gt;        { }&lt;br /&gt;&lt;br /&gt;        ~PyLockGIL()&lt;br /&gt;        {&lt;br /&gt;            PyGILState_Release(gstate);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        PyGILState_STATE gstate;&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    class PyAllowThreads&lt;br /&gt;    {&lt;br /&gt;        PyAllowThreads() : threadState(PyEval_SaveThread())&lt;br /&gt;        { }&lt;br /&gt;&lt;br /&gt;        ~PyAllowThreads()&lt;br /&gt;        {&lt;br /&gt;            PyEval_RestoreThread(threadState);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        PyThreadState* threadState;&lt;br /&gt;    };&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The acquisition and release of the GIL is just wrapped in the constructors and destructors of objects that are allocated on the stack. Here is the previous example using these new objects:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;{&lt;br /&gt;    PyLockGIL lock&lt;br /&gt;    ...do some expensive non-Python work here...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;    PyAllowThreads allow;&lt;br /&gt;    ...use the Python API here...&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Notice that braces can be used to fine tune the amount of code with the desired GIL state. The destructor for these objects will be called as soon as they go out of scope.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-8888406959852037616?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/8888406959852037616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/10/managing-python-gil-via-raii.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8888406959852037616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8888406959852037616'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/10/managing-python-gil-via-raii.html' title='Managing the Python GIL via RAII'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-8658466682173965119</id><published>2009-04-23T11:16:00.000-07:00</published><updated>2009-04-23T11:47:05.113-07:00</updated><title type='text'>End-run around registration-free COM</title><content type='html'>With the introduction of registration-free COM, Windows now allows you to create COM objects without registering their DLLs in the registry. This means that you can include your COM DLLs with your application files and run the application without being an administrator and mucking with regsvr32. Instead you include (or embed in your executable/DLL) a manifest which specifies the location of the COM DLL relative to your application. &lt;br /&gt;&lt;br /&gt;This "new" (it was introduced with Windows XP, I believe) approach is not flexible enough for Titanium, which doesn't know until after run-time which WebKit DLL it will be using. Writing this manifest file into the application directory and restarting or copying the DLLs into the application directory is a less than ideal solution. While the copy may work in Vista because of the wonky UAC virtualization of write permissions (that's an entirely different rant), copying an entire DLL and it's dependencies at startup is expensive and defeats the purpose of DLLs.&lt;br /&gt;&lt;br /&gt;This situation bothered me until I stumbled upon &lt;a href="http://blogs.msdn.com/gpalem/archive/2007/03/26/avoid-registration-free-com-manifest-problems-with-activation-context-api.aspx"&gt;this blog post &lt;/a&gt;in the murky underbelly of the interblogs. It basically describes an approach using the somewhat thinly documented (perhaps intentionally) &lt;a href="http://msdn.microsoft.com/en-us/library/aa375134.aspx"&gt;activation context API&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This Windows nightmare has a happy ending in that we were able to simply point an activation context at the WebKit DLL's manifest path. Here's what it looks like (this is originally from Gopalakrishna's blog which I linked to above):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// This is a normal CoCreateInstance -- done as if the COM DLL&lt;br /&gt;// was actually registered with the system -- it will fail&lt;br /&gt;IMyComponent* pObj = NULL;&lt;br /&gt;HRESULT hr = CoCreateInstance(&lt;br /&gt;    CLSID_MyComponent, &lt;br /&gt;    NULL, &lt;br /&gt;    CLSCTX_INPROC_SERVER, &lt;br /&gt;    IID_IMyComponent,&lt;br /&gt;    (void**)&amp;pObj);&lt;br /&gt;&lt;br /&gt;ACTCTX actctx;&lt;br /&gt;ZeroMemory(&amp;actctx, sizeof(actctx));&lt;br /&gt;actctx.cbSize = sizeof(actctx);&lt;br /&gt;actctx.lpSource = "C:\Path\To\My\Manifest.manifest";&lt;br /&gt;HANDLE pActCtx = CreateActCtx(&amp;actctx);&lt;br /&gt;ULONG_PTR lpCookie;&lt;br /&gt;&lt;br /&gt;if(pActCtx != INVALID_HANDLE_VALUE)&lt;br /&gt;{&lt;br /&gt;    if (ActivateActCtx(pActCtx, &amp;lpCookie))&lt;br /&gt;    {&lt;br /&gt;       // CoCreateInstance should succeed now. &lt;br /&gt;       HRESULT hr = CoCreateInstance(&lt;br /&gt;           CLSID_MyComponent, &lt;br /&gt;           NULL, &lt;br /&gt;           CLSCTX_INPROC_SERVER, &lt;br /&gt;           IID_IMyComponent,&lt;br /&gt;           (void**)&amp;pObj);&lt;br /&gt;       DeactivateActCtx(0, lpCookie);&lt;br /&gt;    }&lt;br /&gt;    ReleaseActCtx(pActCtx);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-8658466682173965119?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/8658466682173965119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/04/end-run-around-registration-free-com.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8658466682173965119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8658466682173965119'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/04/end-run-around-registration-free-com.html' title='End-run around registration-free COM'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-6324368556226003660</id><published>2009-04-04T12:04:00.000-07:00</published><updated>2009-04-04T12:53:32.992-07:00</updated><title type='text'>Avoiding the Logging Performance Hit</title><content type='html'>Sometimes you have a function or a method which more often throws away its arguments than actually uses them. Quite possibly the most common example of this situation is logging. Often you'll see a snippet like this:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;log.Debug("Processing " + index + " of " + count);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;It's just the way things are that debug log statements are used more liberally than error statements. Even if log.debug(...) doesn't actually log it's argument, your program will still pay the penalty of doing the string concatenation continuously. As a result many programmers are forced to write code that looks like this:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;if (log.IsDebug()&lt;br /&gt;{&lt;br /&gt;    log.Debug("Processing " + index + " of " + count);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Now the internal state of the logger must be examined externally for every debug statement. D solves this issue through &lt;a href="http://www.digitalmars.com/d/2.0/lazy-evaluation.html"&gt;lazily evaluated functional arguments&lt;/a&gt;. In D you can change the signature of your function to look like this:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;void Debug(lazy char[] entry)&lt;br /&gt;{&lt;br /&gt;   if (debug)&lt;br /&gt;     fwritefln(logfile, entry());&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This is really just syntactic sugar around D's delegate parameters in which you can pass a function as an argument. The end result, though, is that the statement that composed the argument won't be evaluated until it is actually used.&lt;br /&gt;&lt;br /&gt;Titanium and Kroll are written in C++ though, which doesn't have the same kind of syntactic niceties that D does. Recently, when putting the first bits of the logging system into Kroll, I decided that I wasn't satisfied with the Java-style debugging which I wrote above. I wanted to fully encapsulate the behavior of the logger &lt;span style="font-style:italic;"&gt;and&lt;/span&gt; avoid paying the penalty of uneeded string processing. One common approach for C/C++ is to use macros, but as Walter Bright explains in his essay on lazy argument evaluation, this isn't the best solution.&lt;br /&gt;&lt;br /&gt;Luckily, C and C++ have variadic arguments which allow us to create both easy-to-read logging code and to avoid paying a penalty for those statements which should essentially be no-ops. I  harnessed the power of a seldom-used friend from the C library for this task: &lt;a href="http://www.opengroup.org/onlinepubs/9699919799/functions/vprintf.html"&gt;vsnprintf&lt;/a&gt;. vsnprintf operates much like snprintf, except that instead of taking a variable list of arguments it takes a va_list (basically a variadic list of arguments that can be passed forward to other functions). Here is the resulting code from Kroll:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  std::string Logger::Format(const char* format, va_list args)&lt;br /&gt;  {&lt;br /&gt;    // Protect the buffer&lt;br /&gt;    Poco::Mutex::ScopedLock lock(this-&gt;mutex);&lt;br /&gt; &lt;br /&gt;    vsnprintf(Logger::buffer, LOGGER_MAX_ENTRY_SIZE - 1, format, args);&lt;br /&gt;    Logger::buffer[LOGGER_MAX_ENTRY_SIZE - 1] = '\0';&lt;br /&gt;    std::string text = buffer;&lt;br /&gt;    return text;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void Logger::Log(Level level, const char* format, va_list args)&lt;br /&gt;  {&lt;br /&gt;    Poco::Logger&amp; loggerImpl = Poco::Logger::get(name);&lt;br /&gt; &lt;br /&gt;    // Don't do formatting when this logger filters the message.&lt;br /&gt;    // This prevents unecessary string manipulation.&lt;br /&gt;    if (level &gt;= (Level) loggerImpl.getLevel())&lt;br /&gt;    {&lt;br /&gt;      std::string messageText = Logger::Format(format, args);&lt;br /&gt;      this-&gt;Log(level, messageText);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void Logger::Debug(const char* format, ...)&lt;br /&gt;  {&lt;br /&gt;    va_list args;&lt;br /&gt;    va_start(args, format);&lt;br /&gt;    this-&gt;Log(LDEBUG, format, args);&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;A typical logging statement looks like this:&lt;pre&gt;&lt;code&gt;&lt;br /&gt;log.Debug("Processing %i of %i", index, count);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-6324368556226003660?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/6324368556226003660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/04/avoiding-logging-performance-hit.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/6324368556226003660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/6324368556226003660'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/04/avoiding-logging-performance-hit.html' title='Avoiding the Logging Performance Hit'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-8437085169912698735</id><published>2009-03-06T12:23:00.000-08:00</published><updated>2009-03-06T12:32:58.881-08:00</updated><title type='text'>DBus and Threads</title><content type='html'>Sometimes you'll be using Dbus with threads and notice intermittent segfaults with stack traces like this;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#0  0xb4d58d29 in _dbus_watch_invalidate (watch=0x0) at dbus-watch.c:147&lt;br /&gt;#1  0xb4d57066 in free_watches (transport=0x979c0d0) at dbus-transport-socket.c:82&lt;br /&gt;#2  0xb4d57e7e in socket_disconnect (transport=0x979c0d0) at dbus-transport-socket.c:908&lt;br /&gt;#3  0xb4d561e8 in _dbus_transport_disconnect (transport=0x979c0d0) at dbus-transport.c:494&lt;br /&gt;#4  0xb4d56c68 in _dbus_transport_queue_messages (transport=0x979c0d0) at dbus-transport.c:1137&lt;br /&gt;#5  0xb4d3dc24 in _dbus_connection_get_dispatch_status_unlocked (connection=0x979c4b0) at dbus-connection.c:3983&lt;br /&gt;#6  0xb4d3b695 in check_for_reply_and_update_dispatch_unlocked (connection=0x979c4b0, pending=0xb3c00550) at dbus-connection.c:2235&lt;br /&gt;#7  0xb4d3b883 in _dbus_connection_block_pending_call (pending=0xb3c00550) at dbus-connection.c:2337&lt;br /&gt;#8  0xb4d501c1 in dbus_pending_call_block (pending=0xb3c00550) at dbus-pending-call.c:707&lt;br /&gt;#9  0xb4d7aedf in dbus_g_proxy_end_call_internal (proxy=0x9776f90, call_id=30, error=0xb4d2d30c, first_arg_type=158972744, args=0xb4d2d2e4 "&amp;#65533;&amp;#65533;&amp;#1204;") at dbus-gproxy.c:2256&lt;br /&gt;#10 0xb4d7b90e in dbus_g_proxy_call (proxy=0x9776f90, method=0xb4dca4bb "Get", error=0xb4d2d30c, first_arg_type=64) at dbus-gproxy.c:2584&lt;br /&gt;&lt;/pre&gt;This is happening because DBus doesn't do locking by default. I presume this is for performance reasons. Luckily, the solution to this problem is very simple. Simply run &lt;tt&gt;&lt;a href="http://dbus.freedesktop.org/doc/api/html/group__DBusThreads.html#ge3f80916adb6d7fdfe613385e044f58a"&gt;dbus_thread_init_default()&lt;/a&gt;&lt;/tt&gt; before you try accessing DBus.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-8437085169912698735?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/8437085169912698735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/03/dbus-and-threads.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8437085169912698735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/8437085169912698735'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/03/dbus-and-threads.html' title='DBus and Threads'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-1861465589526017605</id><published>2009-01-18T10:16:00.000-08:00</published><updated>2009-01-18T12:35:38.139-08:00</updated><title type='text'>Compiling D Source is Easy</title><content type='html'>There are two compilers available for D. The original D compiler (the one written by Walter) is DMD. It has an open-source front-end (the part that generate the IL) and a proprietary, closed-source back-end (the part that converts the IL into machine code). Two other, fully open-source compilers exist, GDC and LDC, which use the &lt;a href="http://gcc.gnu.org/"&gt;GCC&lt;/a&gt; and &lt;a href="http://llvm.org/"&gt;LLVM&lt;/a&gt; back-ends respectively.&lt;br /&gt;&lt;br /&gt;I like using GDC, because it's open-source and has &lt;a href="http://www.digitalmars.com/d/archives/digitalmars/D/learn/How_to_create_a_shared_library_with_DMD_on_Linux_5740.html"&gt;better support&lt;/a&gt; for shared library linking on Unices. It's fairly easy to switch between GDC and DMD, as GDC includes a &lt;tt&gt;gdmd&lt;/tt&gt; command which emulates the command-line behavior of DMD. &lt;br /&gt;&lt;br /&gt;Previously I was using &lt;a href="http://www.dsource.org/projects/dsss"&gt;DSSS&lt;/a&gt; to build my D projects. While DSSS is very nice in many ways, it felt odd using a build tool that was really only popular in the D community. After we started using &lt;a href="http://www.scons.org/"&gt;SCons&lt;/a&gt; at &lt;a href="http://appcelerator.org/" title="More Tap, Less Foxtrot"&gt;work&lt;/a&gt;, I was positively pickled to find that it supported building D code. SCons works just as easily for D code as it does for building other things.&lt;br /&gt;&lt;br /&gt;Say you have a source file containing your ground-breaking implementation of the Smash Mouth Optimization (see Computational Football vol. 23), SmashMouth.d. To build this with SCons, simply create a SConstruct file that looks like this:&lt;br /&gt;&lt;pre&gt;BuildDir('build', 'src')&lt;br /&gt;e = Environment()&lt;br /&gt;e.Program('build/SmashMouth.d')&lt;/pre&gt;This assumes that you have your source in a folder called &lt;tt&gt;src&lt;/tt&gt; and you want to build into a folder called &lt;tt&gt;build&lt;/tt&gt; (I know, I know...this is a pretty brazen assumption). Running &lt;tt&gt;scons&lt;/tt&gt; should produce something like this:&lt;br /&gt;&lt;pre&gt;scons: Reading SConscript files ...&lt;br /&gt;scons: done reading SConscript files.&lt;br /&gt;scons: Building targets ...&lt;br /&gt;gcc -o build/Test build/Test.o -lgphobos -lpthread -lm -lgphobos -lgphobos -lgphobos&lt;br /&gt;scons: done building targets.&lt;/pre&gt;You can see here that scons decided to build using GDC and Phobos. The SCons D scanner is pretty smart about what compilers you have on your system. It's also configurable. Okay, here comes the magical wonderland part.&lt;br /&gt;&lt;br /&gt;What happens when you decide that you want SmashMouthOptimizer to be a shared library? You have some options here.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;You could simply look through all the man pages of the D compilers you are using, hunt for all the relevant linking options, and finally write conditional code in your Makefile to use them.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;On the other hand, you could just change your SConstruct to look like this:&lt;br /&gt;&lt;pre&gt;BuildDir('build', 'src')&lt;br /&gt;e = Environment()&lt;br /&gt;e.SharedLibrary('build/SmashMouth.d')&lt;/pre&gt;Then let &lt;tt&gt;scons&lt;/tt&gt; do this:&lt;br /&gt;&lt;pre&gt;scons: Reading SConscript files ...&lt;br /&gt;scons: done reading SConscript files.&lt;br /&gt;scons: Building targets ...&lt;br /&gt;gdmd -I. -c -ofbuild/SmashMouth.os build/SmashMouth.d&lt;br /&gt;gcc -o build/libSmashMouth.so -shared build/SmashMouth.os&lt;br /&gt;scons: done building targets.&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-1861465589526017605?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/1861465589526017605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/01/compiling-d-source-is-easy.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/1861465589526017605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/1861465589526017605'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/01/compiling-d-source-is-easy.html' title='Compiling D Source is Easy'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-1431535747791129326</id><published>2009-01-03T12:34:00.000-08:00</published><updated>2009-01-03T13:01:40.310-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='film'/><title type='text'>Different People</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Being_There_(film)"&gt;Being There&lt;/a&gt; warms my heart for several reasons. One of the most notable is that &lt;a href="http://en.wikipedia.org/wiki/Hal_Ashby"&gt;Hal Ashby&lt;/a&gt; managed to turn&lt;a href="http://en.wikipedia.org/wiki/Basketball_jones"&gt; a Cheech and Chong song&lt;/a&gt; into some kind of religious experience with umbrellas. There is also the unexpected vignette during the ending, which many people seem to hate. I have no idea why.&lt;br /&gt;&lt;br /&gt;One of the lesser known reasons though, is that it exposes you to some truly awesome music from somewhere you didn't expect. If I had to construct a rigid philosophical framework, I think this would be a major tenet. You might be asking, "What is that unexpected source, Martin?"&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Sesame_street"&gt;&lt;div style="margin: 0px auto; text-align:center;"&gt;&lt;img title="Sesame Street" alt="Sesame Street"  src="http://abandonedwig.info/blog/uploaded_images/sesame_street_logo-798824.gif" border="0" alt="" /&gt;&lt;/div&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here's the rundown: &lt;a href="http://en.wikipedia.org/wiki/Buffy_Sainte-Marie"&gt;Buffy Sainte-Marie&lt;/a&gt; is talking to Big Bird about some of their interpersonal problems. Big Bird, of course, is suffering unshakable angst, so Buffy is forced to crack it in typical Sesame Street fashion. The music starts at 2:05, by the way.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin: 0px auto; text-align:center;"&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/4oNHAl_d4Y4&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en&amp;feature=player_embedded&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/4oNHAl_d4Y4&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en&amp;feature=player_embedded&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-1431535747791129326?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/1431535747791129326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/01/calm-down.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/1431535747791129326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/1431535747791129326'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/01/calm-down.html' title='Different People'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7170092975132372391.post-4877769417176885026</id><published>2009-01-01T21:31:00.000-08:00</published><updated>2009-01-01T21:40:14.598-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GTK'/><category scheme='http://www.blogger.com/atom/ns#' term='D'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Embedding Python in D</title><content type='html'>&lt;div style="float:right; margin: 0pt 0pt 10px 10px; "&gt;&lt;img style="cursor: pointer; width: 200px; height: 200px;" src="http://abandonedwig.info/blog/uploaded_images/python-758704.png" alt="" border="0" /&gt;&lt;div style="font-size: small; width:100%; text-align:center;"&gt;Oooooooooh.&lt;br/&gt;It's some snakes.&lt;br/&gt;It's some snakes.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;A while back I began spending some time acquainting myself with D. For those who don't know, D is a relatively new &lt;a href="http://en.wikipedia.org/wiki/System_programming_language"&gt;system programming language&lt;/a&gt; with all kinds of interesting features like very flexible garbage collection, mixins and an easy-to-use yet powerful template system. D was created by &lt;a href="http://en.wikipedia.org/wiki/Walter_Bright"&gt;Walter Bright&lt;/a&gt;, who also created the first native C++ compiler and &lt;a href="http://en.wikipedia.org/wiki/Classic_Empire_%28computer_game%29"&gt;Empire&lt;/a&gt; (of all things).&lt;br /&gt;&lt;br /&gt;Anyhow, one of the things that I really like about D is that it is maintains link compatibility with C &lt;sup&gt;1&lt;/sup&gt;. This means that D code can make calls into libraries like those from GTK in the same way that C++ code can. This mitigates the need or the desire to rewrite useful tools. Many times simple binding layers can be written to expose C-style APIs in D-style ways.&lt;br /&gt;&lt;br /&gt;In my case, I'm writing an application which uses the GTK bindings for D, &lt;a href="http://www.dsource.org/projects/gtkd"&gt;GtkD&lt;/a&gt;, and embeds a Python interpreter. Creating the D header from Python.h turns out to be pretty easy with &lt;a href="http://www.dsource.org/projects/bcd/"&gt;bcd&lt;/a&gt;, a tool which tries to automate most of the process &lt;sup&gt;2&lt;/sup&gt;.&lt;br /&gt;&lt;br /&gt;The first step is to run bcd against the header you want to use. For me this looked like:&lt;br /&gt;&lt;pre&gt;./bcdgen /usr/include/python2.5/Python.h Python -C -A&lt;/pre&gt;In this case "-C" means "C-mode" (as opposed to C++-mode) and "-A" tells bcdgen to continue working on all includes recursively (since Python.h is really a meta-header). Unfortunately this gives me:&lt;br /&gt;&lt;pre&gt;In file included from /usr/include/stdio.h:906,&lt;br /&gt;              from /usr/include/python2.5/Python.h:32:&lt;br /&gt;/usr/include/bits/stdio2.h: In function 'int sprintf(char*, const char*, ...)':&lt;br /&gt;/usr/include/bits/stdio2.h:35: error: '__builtin_va_arg_pack' was not declared in this scope&lt;br /&gt;/usr/include/bits/stdio2.h: In function 'int snprintf(char*, size_t, const char*, ...)':&lt;br /&gt;...&lt;/pre&gt;This is a &lt;a href="https://bugs.launchpad.net/ubuntu/+source/gccxml/+bug/293807"&gt;bug&lt;/a&gt; with Intrepid Ibex's version of gccxml. Luckily there are &lt;a href="http://www.kloss-familie.de/moin/Root/PatchingGccXml"&gt;workarounds&lt;/a&gt;. Once bcdgen finishes it's work, it should create a bcd/Python/Python.d, which is where all the Python.h definitions landed. If you open it up and take a look, you can see bcdgen has converted them to D definitions. Way to go automated software development tools!&lt;br /&gt;&lt;br /&gt;Generally some work is required before the D compiler accepts this file and the bcd page lists some general guidelines for this task. I'm familiar with Python's C interface, but definitely not intimate. This is a secret code that I'm using which means I spent a bit of time fixing weird D compiler errors. It wasn't bad though and I was was able to resolve most of the compile errors without much trouble. I'm my next post I'll write a little bit about that.&lt;br /&gt;&lt;hr /&gt;&lt;div style="font-size: small;"&gt;&lt;ol&gt;&lt;li&gt;D does not have link compatibility with C++.  Many C++ projects have have external APIs which are C-compatible though. One example from recent memory is the KJS API from WebKit.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There is a really great project called &lt;a href="http://pyd.dsource.org/celerid.html"&gt;CeleriD&lt;/a&gt;, which has already done a lot of this work. CeleriD is really geared toward extending Python rather than embedding it though. I decided to strike out on my own as an educational gesture&lt;sup&gt;3&lt;/sup&gt; and to avoid depending on distutils for my build process.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;Gesture&lt;/i&gt; because it's hard to believe this is can be considered larnin'&lt;sup&gt;4&lt;/sup&gt;, which is coincidentally the way I feel about most professional software training programs.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The best thing about the &amp;lt;sup&amp;gt; tag is that it's a formatting markup  &lt;i&gt;and&lt;/i&gt; a greeting. 'Sup &amp;lt;sup&amp;gt;?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7170092975132372391-4877769417176885026?l=blog.abandonedwig.info' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.abandonedwig.info/feeds/4877769417176885026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.abandonedwig.info/2009/01/embedding-python-in-d.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/4877769417176885026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7170092975132372391/posts/default/4877769417176885026'/><link rel='alternate' type='text/html' href='http://blog.abandonedwig.info/2009/01/embedding-python-in-d.html' title='Embedding Python in D'/><author><name>Martin</name><uri>http://www.blogger.com/profile/18168329958413731738</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13073246243915021154'/></author><thr:total>0</thr:total></entry></feed>
