<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">

<channel>
	<title>Planet IM</title>
	<link>http://planet-im.com/</link>
	<language>en</language>
	<description>Planet IM - http://planet-im.com/</description>

<item>
	<title>Artur Hefczyc: Migration on the new server completed</title>
	<guid>http://www.tigase.org/1435 at http://www.tigase.org</guid>
	<link>http://www.tigase.org/en/tigase-migration-completed</link>
	<description>&lt;p&gt;Tigase.org website, e-mail, SVN, XMPP and all other services have been successfully migrated to a new server at &lt;a href=&quot;http://www.flosoft.biz/&quot;&gt;the external service provider&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let &lt;a href=&quot;http://www.tigase.org/contact&quot;&gt;me know&lt;/a&gt; if you find any problems with the website or any other services.&lt;/p&gt;
&lt;p&gt;I hope this solves for good problems with availability and accessibility to the Tigase.org services.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.tigase.org/en/tigase-migration-completed&quot;&gt;read more&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 06 Aug 2008 10:26:06 +0000</pubDate>
</item>
<item>
	<title>Christian Hammond: Django Development with Djblets: Dynamic Site Configuration</title>
	<guid>http://www.chipx86.com/blog/?p=261</guid>
	<link>http://feeds.feedburner.com/~r/chipx86/chiplog/~3/356278421/</link>
	<description>&lt;div class=&quot;series_toc&quot;&gt;&lt;h3&gt;Table of contents for Django Development with Djblets&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=244&quot; title=&quot;Django Development with Djblets&quot;&gt;Django Development with Djblets&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=245&quot; title=&quot;Django Development with Djblets: Custom Tag Helpers&quot;&gt;Django Development with Djblets: Custom Tag Helpers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=253&quot; title=&quot;Django Development with Djblets: Unrooting your URLs&quot;&gt;Django Development with Djblets: Unrooting your URLs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=258&quot; title=&quot;Django Development with Djblets: Data Grids&quot;&gt;Django Development with Djblets: Data Grids&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Django Development with Djblets: Dynamic Site Configuration&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt; &lt;p&gt;Django&amp;#8217;s a powerful toolkit and offers many things to ease the creation of websites and web applications. Features such as the automatically built Administration UI are just awesome and save developers from having to reinvent the wheel on every project. It does fall short in a few areas, however, and one of them is site configuration.&lt;/p&gt;
&lt;p&gt;Now, Django&amp;#8217;s settings support isn&amp;#8217;t bad. You get a nice little &lt;tt&gt;settings.py&lt;/tt&gt; file to put settings in for your site/webapp, and since it&amp;#8217;s just a Python module, your settings can really hold whatever data you want and can be well documented with comments. That&amp;#8217;s all great, but when you want to actually change a setting, you must SSH in, edit the file, save it, and restart the server.&lt;/p&gt;
&lt;p&gt;This is fine for small websites with a few visitors, or sites with almost no custom settings, but for large sites it can be a problem. Bringing down the site however briefly could interrupt users, generate errors, causing worries during a checkout process or when editing a post on a site. Doing anything more complex and preventing downtime really means rolling your own thing.&lt;/p&gt;
&lt;p&gt;So we rolled our own thing. &lt;a href=&quot;http://www.review-board.org/&quot;&gt;Review Board&lt;/a&gt; has operated with the standard Django settings module since day 1, but it&amp;#8217;s become obvious over time that it wasn&amp;#8217;t good enough for us. So we wrote the dynamic Site Configuration app for Djblets.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;djblets.siteconfig&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;siteconfig is a relatively small Django app that stores setting data in the database, along with project versioning data in case you need it to handle migrations of some sort down the road. There&amp;#8217;s a lot of useful things in this app, so I&amp;#8217;ll summarize what it provides before I jump into details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
  &lt;b&gt;Saving/Retrieving settings.&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Setting values can be simple strings, integers, booleans, or something more complex like an array of dictionaries of key/value pairs.&lt;/p&gt;

&lt;li&gt;
  &lt;b&gt;Default values for settings.&lt;/b&gt;&lt;/li&gt;
&lt;p&gt;These default values could be provided by your application directory or could be based off the contents in your &lt;tt&gt;settings.py&lt;/tt&gt; file.&lt;/p&gt;

&lt;li&gt;
  &lt;b&gt;Syncing to/from &lt;tt&gt;settings.py&lt;/tt&gt;.&lt;/b&gt;&lt;/li&gt;
&lt;p&gt;Just because you&amp;#8217;re using &lt;tt&gt;djblets.siteconfig&lt;/tt&gt; doesn&amp;#8217;t mean you can&amp;#8217;t still support &lt;tt&gt;settings.py&lt;/tt&gt;. Settings can be pulled from your old settings and saved back there when modified.&lt;/p&gt;

&lt;li&gt;
  &lt;b&gt;Compatibility with standard Django settings.&lt;/b&gt;&lt;/li&gt;
&lt;p&gt;Django offers a lot of useful settings that you may want to customize. We do the hard work of mapping these and keeping them in sync so you can customize them dynamically.&lt;/p&gt;

&lt;li&gt;
  &lt;b&gt;Auto-generated settings pages.&lt;/b&gt;&lt;/li&gt;
&lt;p&gt;Much like the existing admin UI, we offer an easy way to provide settings pages for your application. Go ahead and stick these in the admin UI if you like.&lt;/p&gt;


&lt;p&gt;&lt;b&gt;Getting Started&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;To start out, you&amp;#8217;ll want to add some code in your app that creates a &lt;tt&gt;SiteConfiguration&lt;/tt&gt; model, perhaps as a &lt;tt&gt;post_syncdb&lt;/tt&gt; management hook. This is project-specific, since you&amp;#8217;ll be storing version information in here and linking it with your existing &lt;tt&gt;Site&lt;/tt&gt;. Here&amp;#8217;s one way to do it. We&amp;#8217;ll use this file as a template in later examples:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/siteconfig.py&lt;/span&gt;
&lt;span&gt;# NOTE: Import this file in your urls.py or some place before&lt;/span&gt;
&lt;span&gt;#       any code relying on settings is imported.&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django.&lt;span&gt;contrib&lt;/span&gt;.&lt;span&gt;sites&lt;/span&gt;.&lt;span&gt;models&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; Site
&amp;nbsp;
&lt;span&gt;from&lt;/span&gt; djblets.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;models&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; SiteConfiguration
&amp;nbsp;
&amp;nbsp;
&lt;span&gt;def&lt;/span&gt; load_site_config&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;Sets up the SiteConfiguration, provides defaults and syncs settings.&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span&gt;try&lt;/span&gt;:
        siteconfig = SiteConfiguration.&lt;span&gt;objects&lt;/span&gt;.&lt;span&gt;get_current&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    &lt;span&gt;except&lt;/span&gt; SiteConfiguration.&lt;span&gt;DoesNotExist&lt;/span&gt;:
        &lt;span&gt;# Either warn or just create the thing. Depends on your app&lt;/span&gt;
        siteconfig = SiteConfiguration&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;site&lt;/span&gt;=Site.&lt;span&gt;objects&lt;/span&gt;.&lt;span&gt;get_current&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;,
                                       version=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;# Code will go here for settings work in later examples.&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
load_site_config&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Saving/Retrieving Settings&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Settings exist in a &lt;tt&gt;SiteConfiguration&lt;/tt&gt; model inside a &lt;tt&gt;JSONField&lt;/tt&gt;. Anything that Django&amp;#8217;s native JSON serializer/deserializer code can handle, you can store. Usually you&amp;#8217;ll want to store primitive values (strings, booleans, integers, etc.), but you&amp;#8217;re free to do something more complex.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;from&lt;/span&gt; djblets.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;models&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; SiteConfiguration
&amp;nbsp;
&amp;nbsp;
siteconfig = SiteConfiguration.&lt;span&gt;objects&lt;/span&gt;.&lt;span&gt;get_current&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
siteconfig.&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;mystring&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;foobar&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
siteconfig.&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;mybool&amp;quot;&lt;/span&gt;, &lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
siteconfig.&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;myarray&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;, &lt;span&gt;2&lt;/span&gt;, &lt;span&gt;3&lt;/span&gt;, &lt;span&gt;4&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
mybool = siteconfig.&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;mybool&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It&amp;#8217;s pretty straightforward. The &lt;tt&gt;set&lt;/tt&gt;/&lt;tt&gt;get&lt;/tt&gt; functions are just simple accessors for the &lt;tt&gt;SiteConfiguration.settings&lt;/tt&gt; JSON field, but you&amp;#8217;ll want to use them because they&amp;#8217;ll handle the registered defaults for settings, which I will get to in a moment.&lt;/p&gt;
&lt;p&gt;Since this is just a Djblets JSONField, which is a glorified dictionary, you can do a lot of things, such as iterate through the keys and values:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;for&lt;/span&gt; key, value &lt;span&gt;in&lt;/span&gt; siteconfig.&lt;span&gt;settings&lt;/span&gt;:
    &lt;span&gt;print&lt;/span&gt; &lt;span&gt;&amp;quot;%s: %s&amp;quot;&lt;/span&gt; % &lt;span&gt;&amp;#40;&lt;/span&gt;key, value&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And so on. Let&amp;#8217;s go a step further.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Default Values&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Say you&amp;#8217;re starting fresh and just created your &lt;tt&gt;SiteConfiguration&lt;/tt&gt; instance, or you&amp;#8217;ve introduced a new setting into an existing site. The setting won&amp;#8217;t be in the saved settings, so what value is returned when you do a &lt;tt&gt;get&lt;/tt&gt; call? Well, that depends on your setup a bit.&lt;/p&gt;
&lt;p&gt;In the first case, with a fresh new setting:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span&gt;print&lt;/span&gt; siteconfig.&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;mynewsetting&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;None&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Any setting without a default value and not in the saved settings will return &lt;tt&gt;None&lt;/tt&gt;. Good ol&amp;#8217; reliable &lt;tt&gt;None.&lt;/tt&gt;. If you want to make sure you return something sane at this specific callpoint, you can specify a default value in the call to &lt;tt&gt;get&lt;/tt&gt;, like so:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span&gt;print&lt;/span&gt; siteconfig.&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;mynewsetting&amp;quot;&lt;/span&gt;, default=&lt;span&gt;123&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;123&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can be really useful at times, but it&amp;#8217;s a pain to have to do this in every call and keep the values in sync. So we provide a third option: Registered default values.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/siteconfig.py&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
defaults = &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;'mystring'&lt;/span&gt;:     &lt;span&gt;'Foobar'&lt;/span&gt;,
    &lt;span&gt;'mybool'&lt;/span&gt;:       &lt;span&gt;False&lt;/span&gt;,
    &lt;span&gt;'mynewsetting'&lt;/span&gt;: &lt;span&gt;123&lt;/span&gt;,
&lt;span&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span&gt;def&lt;/span&gt; load_site_config&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
&amp;nbsp;
    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; siteconfig.&lt;span&gt;get_defaults&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        siteconfig.&lt;span&gt;add_defaults&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;defaults&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That&amp;#8217;s all it takes. Now calling &lt;tt&gt;get&lt;/tt&gt; with just the setting name will return the default value, if the setting hasn&amp;#8217;t been saved in the database.&lt;/p&gt;
&lt;p&gt;Down the road we&amp;#8217;re going to have support for automatic querying of apps to grab their settings, giving third party apps an easier way to integrate into codebases using siteconfig.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Syncing Settings with &lt;tt&gt;settings.py&lt;/tt&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Django&amp;#8217;s &lt;tt&gt;settings.py&lt;/tt&gt; is and will continue to be an important place for some settings to go. If you&amp;#8217;re developing a reusable application for other projects, you may not want to fully ditch &lt;tt&gt;settings.py&lt;/tt&gt;. Or maybe you&amp;#8217;re using a third party application that uses &lt;tt&gt;settings.py&lt;/tt&gt; and want to make the settings dynamic.&lt;/p&gt;
&lt;p&gt;siteconfig was designed from the beginning to handle syncing settings in both places. Now, when I say syncing, I don&amp;#8217;t mean we write out to &lt;tt&gt;settings.py&lt;/tt&gt;, since that would require enforcing certain permissions on the file. What we do instead is to load in the values from &lt;tt&gt;settings.py&lt;/tt&gt; if not set in the siteconfig settings, and to write out to the &lt;tt&gt;settings&lt;/tt&gt; object, an in-memory version of &lt;tt&gt;settings.py&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s revisit our example above, but in this case we want to be able to dynamically control Django&amp;#8217;s &lt;tt&gt;EMAIL_HOST&lt;/tt&gt; setting.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/siteconfig.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django.&lt;span&gt;conf&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; settings
&amp;nbsp;
&lt;span&gt;from&lt;/span&gt; djblets.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;django_settings&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; apply_django_settings, \
                                               generate_defaults
&amp;nbsp;
&amp;nbsp;
settings_map = &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;# siteconfig key    settings.py key&lt;/span&gt;
    &lt;span&gt;'mail_host'&lt;/span&gt;:        &lt;span&gt;'EMAIL_HOST'&lt;/span&gt;,
&lt;span&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
defaults = &lt;span&gt;&amp;#123;&lt;/span&gt;
    ...
&lt;span&gt;&amp;#125;&lt;/span&gt;
defaults.&lt;span&gt;update&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;generate_defaults&lt;span&gt;&amp;#40;&lt;/span&gt;settings_map&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span&gt;def&lt;/span&gt; load_site_config&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
&amp;nbsp;
    &lt;span&gt;apply_django_settings&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;siteconfig, settings_map&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What we did here was to generate a mapping table of our custom settings to Django &lt;tt&gt;settings.py&lt;/tt&gt; settings. We can then generate a set of defaults using the &lt;tt&gt;generate_defaults&lt;/tt&gt; function. This goes through the Django settings keys, pulls out the values if set in &lt;tt&gt;settings.py&lt;/tt&gt;, and returns a dictionary similar to the one we wrote above. This guarantees that our default values will be what you have configured in &lt;tt&gt;settings.py&lt;/tt&gt;, handling the first part of our synchronization.&lt;/p&gt;
&lt;p&gt;The second part is handled through use of the &lt;tt&gt;apply_django_settings&lt;/tt&gt; function. This will take a siteconfig and a settings map and write out all values that have actually changed. So if &amp;#8220;&lt;tt&gt;mail_host&lt;/tt&gt;&amp;#8221; above is never modified, &lt;tt&gt;apply_django_settings&lt;/tt&gt; won&amp;#8217;t write it out to the database, allowing the default value to change without having to do anything too fancy.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Compatibility with Django&amp;#8217;s Settings&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The above example dealt with the &lt;tt&gt;settings.EMAIL_HOST&lt;/tt&gt; setting, but in reality we won&amp;#8217;t have to cover this at all. There&amp;#8217;s a few other goodies in the &lt;tt&gt;django_settings&lt;/tt&gt; module that handle all the Django settings for you.&lt;/p&gt;
&lt;p&gt;First off is &lt;tt&gt;get_django_settings_map&lt;/tt&gt;. You&amp;#8217;ll rarely need to call this directly, but it returns a settings map for all the Django settings sites are likely to want to change.&lt;/p&gt;
&lt;p&gt;Then there&amp;#8217;s &lt;tt&gt;get_django_defaults&lt;/tt&gt;, which you&amp;#8217;ll want to either merge into your existing &lt;tt&gt;defaults&lt;/tt&gt; table or add directly. We don&amp;#8217;t do it for you because you may very well not care about these settings.&lt;/p&gt;
&lt;p&gt;The third is one you just saw, &lt;tt&gt;apply_django_settings&lt;/tt&gt;. In the above example, we passed in our settings map, but if you don&amp;#8217;t specify one it will use &lt;tt&gt;get_django_settings_map&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s take a look at how this works.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/siteconfig.py&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;from&lt;/span&gt; djblets.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;django_settings&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; apply_django_settings, \
                                               get_django_defaults
&amp;nbsp;
&amp;nbsp;
&lt;span&gt;def&lt;/span&gt; load_site_config&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
&amp;nbsp;
    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; siteconfig.&lt;span&gt;get_defaults&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        siteconfig.&lt;span&gt;add_defaults&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;defaults&lt;span&gt;&amp;#41;&lt;/span&gt;
        siteconfig.&lt;span&gt;add_defaults&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;get_django_defaults&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    apply_django_settings&lt;span&gt;&amp;#40;&lt;/span&gt;siteconfig, settings_map&lt;span&gt;&amp;#41;&lt;/span&gt;
    apply_django_settings&lt;span&gt;&amp;#40;&lt;/span&gt;siteconfig&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is all it takes.&lt;/p&gt;
&lt;p&gt;If you take a look at &lt;a href=&quot;http://svn.navi.cx/misc/trunk/djblets/djblets/siteconfig/django_settings.py&quot;&gt;django_settings.py&lt;/a&gt;, you&amp;#8217;ll notice that we don&amp;#8217;t reuse the existing Django settings names and instead provide our own. This is an attempt to cleanly namespace the settings used. You&amp;#8217;ll also notice that there&amp;#8217;s several settings maps and defaults functions. This is so you can be more picky if you really want to.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Auto-generated Settings Pages&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Oh, this is where it gets fun.&lt;/p&gt;
&lt;p&gt;Dynamic settings are all well and good, but if you can&amp;#8217;t set them through your browser, why bother?&lt;/p&gt;
&lt;p&gt;We wanted to make sure that not only could these be modified through a browser, but that it was dead simple to put up pages for changing settings. All you have to do is add a URL mapping and one form per page.&lt;/p&gt;
&lt;p&gt;The form doesn&amp;#8217;t even need much more than fields.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s start out with some code. It should be pretty self-explanatory.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# urls.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; myapp.&lt;span&gt;forms&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; GeneralSettingsForm
&amp;nbsp;
urlpatterns = patterns&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;''&lt;/span&gt;,
    &lt;span&gt;&amp;#40;&lt;/span&gt;r&lt;span&gt;'^admin/settings/general/$'&lt;/span&gt;, &lt;span&gt;'djblets.siteconfig.views.site_settings'&lt;/span&gt;,
     &lt;span&gt;&amp;#123;&lt;/span&gt;&lt;span&gt;'form_class'&lt;/span&gt;: GeneralSettingsForm&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;,
    &lt;span&gt;&amp;#40;&lt;/span&gt;r&lt;span&gt;'^admin/(.*)'&lt;/span&gt;, admin.&lt;span&gt;site&lt;/span&gt;.&lt;span&gt;root&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;,
&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/forms.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django &lt;span&gt;import&lt;/span&gt; forms
&lt;span&gt;from&lt;/span&gt; djblets.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;forms&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; SiteSettingsForm
&amp;nbsp;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; GeneralSettingsForm&lt;span&gt;&amp;#40;&lt;/span&gt;SiteSettingsForm&lt;span&gt;&amp;#41;&lt;/span&gt;:
    mystring = forms.&lt;span&gt;CharField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;
        label=&lt;span&gt;&amp;quot;My String&amp;quot;&lt;/span&gt;,
        required=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    mybool = forms.&lt;span&gt;BooleanField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;
        label=&lt;span&gt;&amp;quot;My Boolean&amp;quot;&lt;/span&gt;,
        required=&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    mail_host = forms.&lt;span&gt;CharField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;
        label=&lt;span&gt;&amp;quot;Mail Server&amp;quot;&lt;/span&gt;,
        required=&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
    &lt;span&gt;class&lt;/span&gt; Meta:
        title = &lt;span&gt;&amp;quot;General Settings&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That&amp;#8217;s it. Now just go to &lt;tt&gt;/admin/settings/general/&lt;/tt&gt; and you&amp;#8217;ll see your brand new settings form. It will auto-load existing or default settings and save modified settings. Like any standard form, it will handle help text, field validation and error generation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.chipx86.com/blog/wp-content/uploads/2008/08/settings-page.png&quot; width=&quot;763&quot; height=&quot;273&quot; alt=&quot;Example Settings Page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Proxy Fields&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;For a lot of sites, this will be sufficient. For more complicated settings, we have a few more things we can do.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s take the array above. Django&amp;#8217;s forms doesn&amp;#8217;t have any concept of array values, but we can fake it with custom load and save methods and a proxy field.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/forms.py&lt;/span&gt;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;re&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; GeneralSettingsForm&lt;span&gt;&amp;#40;&lt;/span&gt;SiteSettingsForm&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
&amp;nbsp;
    &lt;span&gt;my_array&lt;/span&gt; = forms.&lt;span&gt;CharField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;
        label=&lt;span&gt;&amp;quot;My Array&amp;quot;&lt;/span&gt;,
        required=&lt;span&gt;False&lt;/span&gt;,
        help_text=&lt;span&gt;&amp;quot;A comma-separated list of anything!&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;def&lt;/span&gt; load&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;fields&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'my_array'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;.&lt;span&gt;initial&lt;/span&gt; = \
            &lt;span&gt;', '&lt;/span&gt;.&lt;span&gt;join&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'myarray'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;super&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;GeneralSettingsForm, &lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;load&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;def&lt;/span&gt; save&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;siteconfig&lt;/span&gt;.&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'myarray'&lt;/span&gt;,
            &lt;span&gt;re&lt;/span&gt;.&lt;span&gt;split&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;r&lt;span&gt;',&lt;span&gt;\s&lt;/span&gt;*'&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;cleaned_data&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'my_array'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;super&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;GeneralSettingsForm, &lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;save&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;class&lt;/span&gt; Meta:
        save_blacklist = &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'my_array'&lt;/span&gt;,&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What we&amp;#8217;re essentially doing here is to come up with a new field not in the settings database (notice &amp;#8220;my_array&amp;#8221; versus &amp;#8220;myarray&amp;#8221;) and to use this as a proxy for the real setting. We then handle the serialization/deserialization in the &lt;tt&gt;save&lt;/tt&gt; and &lt;tt&gt;load&lt;/tt&gt; methods.&lt;/p&gt;
&lt;p&gt;When doing this, it&amp;#8217;s very important to add the proxy field to the &lt;tt&gt;save_blacklist&lt;/tt&gt; tuple in the &lt;tt&gt;Meta&lt;/tt&gt; class so that the form doesn&amp;#8217;t save your proxy field in the database!&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Fieldsets&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Much like Django&amp;#8217;s own administration UI, the &lt;tt&gt;SiteSettingsForm&lt;/tt&gt; allows for placing fields into custom fieldsets, allowing settings to be grouped together under a title and optional description. This is done by filling out the &lt;tt&gt;fieldsets&lt;/tt&gt; variable in the &lt;tt&gt;Meta&lt;/tt&gt; class, like so:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;class&lt;/span&gt; GeneralSettingsForm&lt;span&gt;&amp;#40;&lt;/span&gt;SiteSettingsForm&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;class&lt;/span&gt; Meta:
        fieldsets = &lt;span&gt;&amp;#40;&lt;/span&gt;
            &lt;span&gt;&amp;#123;&lt;/span&gt;
                &lt;span&gt;'title'&lt;/span&gt;:   &lt;span&gt;&amp;quot;General&amp;quot;&lt;/span&gt;,
                &lt;span&gt;'classes'&lt;/span&gt;: &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'wide'&lt;/span&gt;,&lt;span&gt;&amp;#41;&lt;/span&gt;,
                &lt;span&gt;'fields'&lt;/span&gt;:  &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'mystring'&lt;/span&gt;, &lt;span&gt;'mybool'&lt;/span&gt;, &lt;span&gt;'my_array'&lt;/span&gt;,&lt;span&gt;&amp;#41;&lt;/span&gt;,
            &lt;span&gt;&amp;#125;&lt;/span&gt;,
            &lt;span&gt;&amp;#123;&lt;/span&gt;
                &lt;span&gt;'title'&lt;/span&gt;:       &lt;span&gt;&amp;quot;E-Mail&amp;quot;&lt;/span&gt;,
                &lt;span&gt;'description'&lt;/span&gt;: &lt;span&gt;&amp;quot;Some description of e-mail settings.&amp;quot;&lt;/span&gt;,
                &lt;span&gt;'classes'&lt;/span&gt;:     &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'wide'&lt;/span&gt;,&lt;span&gt;&amp;#41;&lt;/span&gt;,
                &lt;span&gt;'fields'&lt;/span&gt;:      &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'mail_host'&lt;/span&gt;,&lt;span&gt;&amp;#41;&lt;/span&gt;,
            &lt;span&gt;&amp;#125;&lt;/span&gt;,
        &lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will result in two groups of settings, each with a title, and one with a description. The description can span multiple paragraphs by inserting newlines (&amp;#8221;&lt;tt&gt;\n&lt;/tt&gt;&amp;#8220;). All fields in the dictionary except for &lt;tt&gt;&amp;#8216;fields&amp;#8217;&lt;/tt&gt; are optional.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Re-applying Django settings&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;When you modify a field that corresponds to a setting in &lt;tt&gt;settings.py&lt;/tt&gt;, you want to make sure you re-apply the setting or you could break something. This is pretty simple. Again override &lt;tt&gt;save&lt;/tt&gt; as follows:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;from&lt;/span&gt; myapp.&lt;span&gt;siteconfig&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; load_site_config
&amp;nbsp;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; GeneralSettingsForm&lt;span&gt;&amp;#40;&lt;/span&gt;SiteSettingsForm&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;def&lt;/span&gt; save&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;super&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;GeneralSettingsForm, &lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;save&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        load_site_config&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will re-synchronize the settings, making sure everything is correct. Note that down the road, this will likely be automatic.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s one last thing to show you&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Disabled Fields&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Sometimes it&amp;#8217;s handy to disable fields. Maybe a particular setting requires a third party module that isn&amp;#8217;t installed. The &lt;tt&gt;SiteSettingsForm&lt;/tt&gt; has two special dictionaries, &lt;tt&gt;disabled_fields&lt;/tt&gt; and &lt;tt&gt;disabled_reasons&lt;/tt&gt;, that handle this. Just override your &lt;tt&gt;load&lt;/tt&gt; function again.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;class&lt;/span&gt; GeneralSettingsForm&lt;span&gt;&amp;#40;&lt;/span&gt;SiteSettingsForm&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;def&lt;/span&gt; load&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;if&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; myarray_supported&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;disabled_fields&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'my_array'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt; = &lt;span&gt;True&lt;/span&gt;
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;disabled_reasons&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'my_array'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt; = \
                &lt;span&gt;&amp;quot;This cannot be modified because we don't support arrays today.&amp;quot;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;super&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;GeneralSettingsForm, &lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;load&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The resulting fields in the HTML will be disabled, and the error message will be displayed below the field.&lt;/p&gt;
&lt;p&gt;Depending on whether or not you have a custom administration UI, you may want to tweak the CSS file or completely override it. Note that this all assumes that the &lt;tt&gt;djblets/media/&lt;/tt&gt; directory exists in your &lt;tt&gt;MEDIA_URL&lt;/tt&gt; as the &amp;#8220;&lt;tt&gt;djblets&lt;/tt&gt;&amp;#8221; directory. If you have something custom, you can always override &lt;tt&gt;siteconfig/settings.html&lt;/tt&gt; and pass the new template to the view along with your settings form.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;More Coming Soon!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s some new stuff in the works for the siteconfig app. Auto-detection of defaults and settings maps is the big one. I also have a few more useful tricks for doing advanced things with settings pages that I&amp;#8217;ll demonstrate.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re a user of Djblets, let us know, and feel free to blog about it! I&amp;#8217;ll link periodically to other blogs talking about Djblets and projects using Djblets.&lt;/p&gt;
&lt;p&gt;And as always, suggestions, constructive criticism and &lt;a href=&quot;http://reviews.review-board.org/&quot;&gt;patches&lt;/a&gt; are always welcome :)&lt;/p&gt;
 &lt;div class=&quot;series_links&quot;&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=258&quot; title=&quot;Django Development with Djblets: Data Grids&quot;&gt;Previous in series&lt;/a&gt; &lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/chipx86/chiplog/~4/356278421&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Tue, 05 Aug 2008 11:50:36 +0000</pubDate>
</item>
<item>
	<title>Ross Burton: Sound Juicer "We're Singing In Tune But Now It's Over" 2.23.1</title>
	<guid>http://www.burtonini.com/blog/computers/sound-juicer/sj-2.23.1</guid>
	<link>http://www.burtonini.com/blog/computers/sound-juicer/sj-2.23.1</link>
	<description>&lt;p&gt;
  Sound Juicer &quot;We're Singing In Tune But Now It's Over&quot; 2.23.1 has been released.  Tarballs
  are available &lt;a href=&quot;http://www.burtonini.com/computing/sound-juicer-2.23.1.tar.bz2&quot;&gt;on
    &lt;tt&gt;burtonini.com&lt;/tt&gt;&lt;/a&gt;, or from
  the &lt;a href=&quot;ftp://ftp.gnome.org/pub/gnome/sources/sound-juicer/2.23/&quot;&gt;GNOME
  FTP servers&lt;/a&gt;.  Nothing that amazing here, sorry:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Fix play+pause+play (#523182, thanks Matthew Martin)&lt;/li&gt;
  &lt;li&gt;Add %ay, album year (#522909, Juan F. Giménez Silva)&lt;/li&gt;
&lt;/ul&gt;</description>
	<pubDate>Mon, 04 Aug 2008 19:33:17 +0000</pubDate>
</item>
<item>
	<title>Jabber Filaments Blog: XMPP and (not versus) REST</title>
	<guid>http://blog.jabber.com/filaments/2008/08/01/xmpp-and-not-versus-rest/</guid>
	<link>http://blog.jabber.com/filaments/2008/08/01/xmpp-and-not-versus-rest/</link>
	<description>&lt;p&gt;If you&amp;#8217;ve been on vacation or haven&amp;#8217;t yet added the feeds at &lt;a title=&quot;RedMonk&quot; target=&quot;_blank&quot; href=&quot;http://redmonk.com/&quot;&gt;Redmonk&lt;/a&gt; to your reader, you may have missed an &lt;a title=&quot;Beyond Rest? or Beyond XMPP?&quot; target=&quot;_blank&quot; href=&quot;http://redmonk.com/sogrady/2008/07/30/xmpp_rest/&quot;&gt;interesting discussion&lt;/a&gt; about the OSCON presentation &lt;a title=&quot;Building Data Services with XMPP&quot; target=&quot;_blank&quot; href=&quot;http://en.oreilly.com/oscon2008/public/schedule/detail/4359&quot;&gt;Beyond REST? Building Data Services with XMPP&lt;/a&gt;. As is often the case with discussions about software architecture, there is controversy swirling around the presentation, bringing some relief to the midsummer torpor.&lt;/p&gt;
&lt;p&gt;Jabber, Inc.&amp;#8217;s CTO, Joe Hildebrand (who rarely minces words) writes:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Many people are coming to the conclusion that HTTP polling doesn’t work. It doesn’t scale, and it can’t deal with high-flow feeds without missing data that scrolls off the end of your feed during the interval between polls. &lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;These are bold words, but are supported by more than a little experience around the Jabber, Inc. software shop.&lt;/p&gt;
&lt;p&gt;This discussion is not about dumping on HTTP based development, it is a discussion about using the right tools for the job. As Stephen O&amp;#8217;Grady writes:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;But also because we’re generally different-tools-for-different-jobs kind of folks. And XMPP is most certainly a different tool, as Kellan and Rabble’s presentation &lt;a href=&quot;http://www.slideshare.net/kellan/beyond-rest&quot;&gt;reminds us&lt;/a&gt;. Consider &lt;a href=&quot;http://patricklogan.blogspot.com/2007/09/amqp-xmpp.html&quot;&gt;the proposition&lt;/a&gt;, for instance, of AMQP internally to AtomPub/XMPP externally. &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;No, my interest in XMPP is not a binary, mutually exlusive REST and/or, but rather a recognition that the technology that is more than instant messaging might be poised for a role in more than just instant messaging. &lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Part of the discussion is about how to make it easier to work with XMPP, in which Joe Hildebrand points out the value of XMPP client libraries for simplifying and accelerating application development. Jabber, Inc. has new &lt;a title=&quot;JabberWerx Libraries&quot; target=&quot;_blank&quot; href=&quot;http://www.jabber.com/CE/JabberWerxLibraries&quot;&gt;JabberWerx Libraries&lt;/a&gt; that are designed with these goals in mind.&lt;/p&gt;
&lt;p&gt;If you have interest, experience or opinions about this topic, have a look and consider joining the &lt;a target=&quot;_blank&quot; title=&quot;Beyond Rest? or Beyond XMPP?&quot; href=&quot;http://redmonk.com/sogrady/2008/07/30/xmpp_rest/&quot;&gt;thread&lt;/a&gt;.
&lt;/p&gt;</description>
	<pubDate>Fri, 01 Aug 2008 19:30:36 +0000</pubDate>
</item>
<item>
	<title>Christopher Zorn: Palmetto Open Source Software Conference</title>
	<guid>urn:lj:livejournal.com:atom1:thetofu:72085</guid>
	<link>http://thetofu.livejournal.com/72085.html</link>
	<description>As some of you know I live in Charleston, SC. Likewise, you may know that South Carolina is not necessarily known as a technical state. The amount of software/engineering jobs are not the same as other states. Similar with technical students and people. That said, I went to the &lt;a href=&quot;http://posscon.org/&quot;&gt;Palmetto Open Source Software Conference&lt;/a&gt; on Weds July 30th 2008. It was a one day conference at the University of South Carolina and I was pleasantly surprised.&lt;br /&gt;&lt;br /&gt;    The conference was well done, and apparently the concept and idea came about 3 months ago. So, with 3 months planning and a first year conference, it was very well done! The turn out was better than I imagined too. Being a developer/contributor of open source projects, I was in the minority, but there were plenty of people excited about open source and using it. All of the speakers were great and presented well. You can get a list at the website. &lt;a href=&quot;http://posscon.org/&quot;&gt;http://posscon.org/&lt;/a&gt; This post is not about the specifics of the conference but the themes that seemed to be throughout each of the presentations and informal discussions. &lt;br /&gt;&lt;br /&gt;    One theme in the conference seemed to be pragmatic approaches to solving problems, be it business problems or just software problems.  People wanted to use and used open source because it solved their problem and solved it well. &lt;br /&gt;   &lt;br /&gt;    Another theme was &quot;openness&quot;, being open in the way you do business, working with businesses and the open source community, and &quot;open&quot;, in giving your employees the ability to improve your business, and the way they do work, by encouraging them to be curious and contribute or use open source. &lt;br /&gt;&lt;br /&gt;    And last, how does South Carolina find these kinds of employees. Ones that can solve problems, have a curiosity and can do most anything you ask of them (jack of all trades). The last theme or topic that was discussed brought questions on how to help students and others in South Carolina to be curious and excited about technology, solving technical problems, and using open source, to enrich and encourage that. &lt;br /&gt;&lt;br /&gt;    These are all old topics and nothing new, but pragmatic and open technical solutions are definitely the way to go, and seeing companies and programmers start to think this way is very very encouraging for South Carolina! I just wish more of them knew what &lt;a href=&quot;http://xmpp.org&quot;&gt;XMPP&lt;/a&gt; was. :) &lt;br /&gt;&lt;br /&gt;Thanks to everyone involved and for starting this important topic of conversation in South Carolina! &lt;br /&gt;&lt;br /&gt;I definitely recommend everyone in South Carolina and the surrounding areas to go back next year!</description>
	<pubDate>Fri, 01 Aug 2008 16:23:13 +0000</pubDate>
</item>
<item>
	<title>Artur Hefczyc: Public accounts in tigase.org domain</title>
	<guid>http://www.tigase.org/1433 at http://www.tigase.org</guid>
	<link>http://www.tigase.org/en/public-account-removal</link>
	<description>&lt;p&gt;Registering new accounts on the website has been disabled. Also all existing public accounts will be removed when the service is moved onto the new server.&lt;/p&gt;
&lt;p&gt;If you have an account on the Tigase.org website which you use as your XMPP/Jabber account please move to any public service available as in about week all those accounts will be removed.&lt;/p&gt;
&lt;p&gt;Tigase.org will only keep accounts for people involved in Tigase projects. Creating a new account will be possible by the administrator only.&lt;/p&gt;
&lt;p&gt;If you use an account on the Tigase website for interoperability testing or any other tests please &lt;a href=&quot;http://www.tigase.org/contact&quot;&gt;contact&lt;/a&gt; me to preserve your account.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.tigase.org/en/public-account-removal&quot;&gt;read more&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Fri, 01 Aug 2008 08:26:48 +0000</pubDate>
</item>
<item>
	<title>Artur Hefczyc: Back from holiday</title>
	<guid>http://www.tigase.org/1432 at http://www.tigase.org</guid>
	<link>http://www.tigase.org/en/back-from-holiday</link>
	<description>&lt;p&gt;I am back from holiday and all Tigase services are back too.&lt;/p&gt;
&lt;p&gt;It's been a long holiday, maybe too long but very enjoyable and interesting. Part of the trip was participation in the XMPP Summit in Portland.&lt;/p&gt;
&lt;p&gt;Unfortunately during the trip our main server which has been working fine for last 6 months has stopped accepting network connections for unknown reason. There is no apparent trace in log files so I am uncertain whether this is a hardware problem or misconfiguration. After kicking the power button restarting the machine everything came back to normal.&lt;/p&gt;
&lt;p&gt;To avoid such a problem in the future I am now in process of moving all Tigase services to the external service provider - &lt;a href=&quot;http://www.flosoft.biz/&quot;&gt;Flosoft.biz&lt;/a&gt; on to dedicated &lt;a href=&quot;http://www.flosoft.biz/products/dedicated/eco/&quot;&gt;Eco08 XXL&lt;/a&gt; machine. This should solve for good problem with the hardware as well as with accessing the machine while I am away.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.tigase.org/en/back-from-holiday&quot;&gt;read more&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Fri, 01 Aug 2008 07:15:19 +0000</pubDate>
</item>
<item>
	<title>John Bailey: The Holy War of Tool Choice</title>
	<guid>tag:blogger.com,1999:blog-2576186912722433445.post-7510099207624435076</guid>
	<link>http://theflamingbanker.blogspot.com/2008/07/holy-war-of-tool-choice.html</link>
	<description>Tools are vital to any open-source project.  Because of that, tool choice is critical.  You really don't want to be switching tools frequently, because doing so is more work than you'll ever be able to put into the project.  By that same token, you don't want to pick tools no one in the project wants to use.  This leads to the problem--tool choice is often a &quot;Holy War&quot;, so to speak, because everyone has their pet tool and thinks everything else to be inferior.&lt;br /&gt;&lt;br /&gt;Let's use Pidgin as a practical example.  Prior to our most recent legal problems (which prompted our rename), we had been evaluating new version control software for some time.  At that time, we were using CVS.  Almost everyone who has developed on a project as large as Pidgin will agree that CVS sucks.  You can't rename files unless you rename them in the repository itself, branching and merging are a pain, etc.  I wasn't involved with the project at this point in time, but I do know that every distributed VCS in existence at the time was evaluated.  After the evaluation, &lt;a href=&quot;http://monotone.ca/&quot;&gt;Monotone&lt;/a&gt; was the preferred choice.  Keep in mind that this was over two years ago, more likely closer to three.&lt;br /&gt;&lt;br /&gt;We continued to use CVS, and later made an ill-advised switch to Subversion.  Sticking with these tools was mainly due to our complete reliance on &lt;a href=&quot;http://sourceforge.net/&quot;&gt;SourceForge&lt;/a&gt;, who offered only CVS and SVN.  Finally, when it came time to rename our project to Pidgin, we had a donated virtual server on which we could run (essentially) whatever we wanted.  Ethan Blanton used tailor to convert our SVN repository into a monotone database.&lt;br /&gt;&lt;br /&gt;We also set up &lt;a href=&quot;http://trac.edgewall.org/&quot;&gt;Trac&lt;/a&gt; for bug, patch, and feature request tracking.  The built-in wiki was a bonus.  We ended up installing a number of plugins for Trac to customize it and provide some additional features, such as restricting some ticket fields from those who we feel should not be able to modify them.&lt;br /&gt;&lt;br /&gt;All was well initially.  We had a few complaints because we chose to use monotone instead of sticking with SVN, but these were users who had no intention of contributing patches, so we were (mostly) happy to see them angrily go back to using our &quot;blessed&quot; releases.  We did, however, have a lot of confusion initially about what monotone was and how it related to Pidgin.  A few hundred explanations later and those questions faded too.&lt;br /&gt;&lt;br /&gt;Trac proved to have some scalability and performance issues for us on numerous occasions.  Eventually we were able to narrow the biggest issues down to their causes and implement fixes.  Some of this involved a LOT of poking and prodding, as well as some assistance from Trac developers, who we thank profusely for their time in resolving the issues.  I am quite surprised, overall, that we haven't had any real complaints about Trac.  For a while it was frequently completely unusable, and of course we saw a number of complaints related to that, but since the issues have been resolved we've seen no real complaints.&lt;br /&gt;&lt;br /&gt;As for monotone, fast-forward a year from the announcement of the rename.  We consistently get complaints about having to download a &quot;huge&quot; database just to get the latest development source for Pidgin.  We do also get a few complaints that it's hard to use, but almost all of these are solved simply by pointing people at the &lt;a href=&quot;http://developer.pidgin.im/wiki/UsingPidginMonotone&quot;&gt;UsingPidginMonotone&lt;/a&gt; wiki page.  As for the huge database, we do acknowledge that it is inconvenient for some people, but &quot;shallow-pull&quot; support is coming to monotone.  A shallow pull would be similar to an svn checkout.&lt;br /&gt;&lt;br /&gt;I don't mind the database, myself.  I have 11 working copies (checkouts) from my single pidgin database (8 distinct branches, plus duplicates of the last three branches I worked on or tested with).  Each clean checkout (that is, a checkout prior to running autogen.sh and building) is approximately 61 MB.  If this were SVN, each working copy would be approximately 122 MB due to svn keeping a pristine copy of every file to facilitate 'svn diff' and 'svn revert' without needing to contact the server the working copy was pulled from.  Now, let's add that up.  For SVN, I would have 11 times 122 MB, or 1342 MB, just in working copies.  For monotone, I have 11 times 61 MB for the working copies (671 MB), plus 229 MB for the database, for a grand total of 900 MB.  For me, this is an excellent bargain, as I save 442 MB of disk space thanks to the monotone model.  For another compelling comparison that's sure to ruffle a few feathers, let's compare to &lt;a href=&quot;http://git.or.cz/&quot;&gt;git&lt;/a&gt;.  If I clone the &lt;a href=&quot;http://github.com/felipec/pidgin-clone&quot;&gt;git mirror&lt;/a&gt; of our monotone repository, I find a checkout size of 148 MB after git-repack--running git-gc also increased the size by 2 MB, but I'll stick with the initial checkout size for fairness.  If I multiply this by my 11 checkouts, I will have 1628 MB.  This is even more compelling for me, as I now save 728 MB of disk space with monotone.&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Richard Laager also took the time to point out an interesting, but as yet unexploited feature of monotone--the use of certs allow us to do a number of useful things while being backed by the cryptographic signing of certs.  For one, we could implement something similar to the kernel's Signed-Off-By markers.  We could also have an automated test suite run compiles of each revision and add a cert indicating whether or not the test succeeded.  We could also include a test suite using check (we do already have some tests) and use more certs to indicate success or failure.  The extensibility of monotone using lua and the certificates is truly mind-boggling.&lt;br /&gt;&lt;br /&gt;I think I've picked on version control enough here, but before I move on, I'd like to say that I don't specifically hate any one version control system.  Ok, maybe I hate CVS and Subversion, but I'm certainly not alone in that.  I don't, however, hate git, &lt;a href=&quot;http://bazaar-vcs.org/&quot;&gt;bzr&lt;/a&gt;, &lt;a href=&quot;http://www.selenic.com/mercurial/wiki/&quot;&gt;hg&lt;/a&gt;, etc.  In fact, I think hg looks quite promising--the &lt;a href=&quot;http://www.adiumx.com/&quot;&gt;Adium&lt;/a&gt; folks have decided to switch to it, and are currently in the process of trying to convert from SVN.  However, given that for us monotone was the best choice when we made our decision, and given the extensibility of monotone, I think it would be foolish of us to choose another tool at this point.  Perhaps in a few more years when all the DVCSes have had time to mature further it will make sense to revisit this decision.&lt;br /&gt;&lt;br /&gt;Another tool choice involves communication between developers and users.  Specifically, forums.  We have elected not to have forums for Pidgin, although as a legacy of our continued involvement with Sourceforge for download hosting we are stuck with the forums they provided us.  We are quite frequently belittled for our choice to forego widely visible forums.  At least four of us that I am aware of have a strong distaste for forums.  I find them to be worse than the ticket system  for attracting duplicated questions which most users won't search beforehand.  All the useless extra features, such as emoticons, formatting, etc., are a waste, as well.&lt;br /&gt;&lt;br /&gt;It's also been my experience with forums that one or two people will start answering others' questions with misinformation that will sound legitimate to those receiving the bad answers.  I've seen this numerous times, but it comes to mind so quickly as I've seen it quite recently on Ubuntu's Launchpad &quot;Questions&quot; forum or tracker or whatever you call it for Pidgin.&lt;br /&gt;&lt;br /&gt;Instead of forums, we have chosen to use &lt;a href=&quot;http://pidgin.im/listinfo.html&quot;&gt;mailing lists&lt;/a&gt;.  We receive complaints about this too.  These complaints run the gamut from &quot;mailing lists are hard to use&quot; to &quot;but you can't search the mailing list!&quot;  In reality, the mailing lists are searchable--Google indexes our mailing lists, as do a number of other search engines.  Perhaps we could provide a nice search box or something that does the necessary google magic (make the search query &quot;terms site:pidgin.im&quot;) to make it a bit friendlier, but searchability exists.  Not that it matters much in my experience, but hey, I'm just a developer; what do I know?&lt;br /&gt;&lt;br /&gt;I'd also argue that mailing lists are easier to use than forums, as all you have to do is, y'know, send an e-mail.  With a forum, you have to register, log in, find the right forum if there is more than one, then post your question, and check back for answers.  With the mailing list, those genuinely interested in providing assistance will helpfully use the &quot;Reply All&quot; feature of their mail client to provide the answer both to the user requesting help and the mailing list's archive, thus providing an answer that is both helpful and searchable.&lt;br /&gt;&lt;br /&gt;Even so, all the choices made during the evolution of a project will result in people trying to start a crusade, holy war, revolt, ..., over the chosen tool.  Unfortunately, it's a fact of life.  The best we can do is take it in stride, justify our choices, and move on.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Note: It's come to my attention that I had missed the ability to share a git database across multiple working copies.  In &lt;/span&gt;that&lt;span&gt; scenario, the total size of the database and 11 working copies is slightly under 750 MB, and thus a space savings in the neighborhood of 150 MB over monotone.  It had been my understanding that I needed a copy of the database per working copy.  I stand corrected.  I don't use git on a daily basis, as the projects I work with currently use CVS, SVN, or monotone, so I am bound to miss finer details of git here and there.  There are other reasons I prefer to stick with monotone, but I won't get into them here, as they're not important to the point of this post.&lt;/span&gt;</description>
	<pubDate>Fri, 01 Aug 2008 04:14:40 +0000</pubDate>
</item>
<item>
	<title>Hal Rottenberg: Growing Popularity for the Psi Jabber Client</title>
	<guid>http://halr9000.com/article/579</guid>
	<link>http://halr9000.com/article/579</link>
	<description>&lt;a href=&quot;http://halr9000.com/article/category/software/instant-messaging/jabber&quot; title=&quot;Jabber&quot;&gt;&lt;img src=&quot;http://halr9000.com/wp-content/icons/topic_jabber.png&quot; align=&quot;right&quot; width=&quot;64&quot; height=&quot;87&quot; alt=&quot;Jabber&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://halr9000.com/article/category/software/instant-messaging/psi&quot; title=&quot;Psi&quot;&gt;&lt;img src=&quot;http://halr9000.com/wp-content/icons/topic_psi.png&quot; align=&quot;right&quot; width=&quot;64&quot; height=&quot;64&quot; alt=&quot;Psi&quot; /&gt;&lt;/a&gt;
&lt;p&gt;I had an email in my mailbox this morning which I’d not seen before:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The domain psi-im.org (psi) is about to exceed their bandwidth limit&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Now bear in mind this limit is somewhat artificial as I host the website myself and the quota was just a random number I pulled out of my hat.  But it was a pretty big number.  A year ago, we would usually run through about 30-35 GB of bandwidth in a month.  (Bear in mind, this does &lt;strong&gt;not&lt;/strong&gt; include actual software downloads—those are hosted on &lt;a href=&quot;http://sf.net/projects/psi&quot; target=&quot;_blank&quot;&gt;Sourceforge&lt;/a&gt;.  I’ll get to that.)&lt;/p&gt;
&lt;p&gt;We used over &lt;span&gt;one-hundred-and-nineteen gigabytes&lt;/span&gt; of bandwidth in the month of July, 2008.  And that’s just for the website itself!  We do not host a single tarball, zip archive or Mac disk image on the site.&lt;/p&gt;
&lt;p&gt;For the benefit of those on the Psi groupchat this morning (available at &lt;a href=&quot;mailto:psi@conference.psi-im.org&quot;&gt;psi@conference.psi-im.org&lt;/a&gt;), I broke the stats down a bit, and I was asked to share them here as well.&lt;/p&gt;
&lt;h3&gt;Traffic by sub-domain:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;blog.psi-im.org 5.91MB / planet.psi-im.org 1.68GB (both point to the same place)&lt;/li&gt;
&lt;li&gt;flyspray.psi-im.org 8.75GB (our bug tracker)&lt;/li&gt;
&lt;li&gt;forum.psi-im.org 34.21GB (not too surprising, given our strong community)&lt;/li&gt;
&lt;li&gt;psi-im.org 74.97GB&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Daily average number of unique visitors:&lt;/h3&gt;
&lt;p&gt;July 2008: 4102&lt;/p&gt;
&lt;h3&gt;Top Countries (by number of hits):&lt;/h3&gt;
&lt;p&gt;(Top-level domains .net and .com excluded.)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Russia&lt;/li&gt;
&lt;li&gt;Poland&lt;/li&gt;
&lt;li&gt;Czech Republic&lt;/li&gt;
&lt;li&gt;Germany&lt;/li&gt;
&lt;li&gt;Brazil&lt;/li&gt;
&lt;li&gt;Ukraine&lt;/li&gt;
&lt;li&gt;Slovakia&lt;/li&gt;
&lt;li&gt;Italy&lt;/li&gt;
&lt;li&gt;Australia&lt;/li&gt;
&lt;li&gt;France&lt;/li&gt;
&lt;li&gt;Bulgaria&lt;/li&gt;
&lt;li&gt;Netherlands&lt;/li&gt;
&lt;li&gt;United Kingdom&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And last but not least…&lt;/p&gt;
&lt;h3&gt;Download Statistics&lt;/h3&gt;
&lt;p&gt;Unfortunately, I can’t get very specific on these as Sourceforge’s stats engine is down for upgrades right now (has been for a few weeks…grr).  What I can say is we generally average around 1,500 downloads of Psi—every single day.  That was as of a month ago or so but is very typical.&lt;/p&gt;
&lt;p&gt;There is one number that I &lt;span&gt;can&lt;/span&gt; get specific about.&lt;/p&gt;
&lt;h3&gt;Total Downloads&lt;/h3&gt;
&lt;p&gt;Now this number is actually low because it doesn’t include the release candidates and it may not include downloads in the last few weeks because of the stats overhaul.  (SF claims they are keeping track.).  But anyway, here goes.&lt;/p&gt;
&lt;p&gt;Total downloads of Psi official releases (going all the way back to 0.86, released in 2002), only including the Windows zip archive and executable installer, the source tarball, and the Mac disk image.  Not including any of our unofficial contributed builds or the Linux distribution packages……drum roll please…&lt;/p&gt;
&lt;h4&gt;1,997,919&lt;/h4&gt;
&lt;p&gt;Wow.  All I can say is thanks to the loyal users of Psi!&lt;/p&gt;
&lt;h3&gt;Source Code Statistics&lt;/h3&gt;
&lt;p&gt;And by request, source code stats.&lt;br /&gt;
&lt;/p&gt;</description>
	<pubDate>Thu, 31 Jul 2008 13:00:22 +0000</pubDate>
</item>
<item>
	<title>Ralph Meijer: XMPP and Social Networks, part 2: Nodes</title>
	<guid>http://ralphm.net/blog/2008/07/30/xmpp_social_networks_2</guid>
	<link>http://ralphm.net/blog/2008/07/30/xmpp_social_networks_2</link>
	<description>&lt;p&gt;In &lt;a href=&quot;http://ralphm.net/&quot;&gt;part 1&lt;/a&gt; I wrote about what you can
        subscribe to and how a social network service will send out
        notifications. I often used &lt;em&gt;node&lt;/em&gt; as the thing
        you subscribe to, a term comes directly from the &lt;a href=&quot;http://www.xmpp.org/extensions/xep-0060.html&quot;&gt;XMPP Publish
          Subscribe&lt;/a&gt; specification. In other publish-subscribe
        implementations this is often referred to as
        &lt;em&gt;topic&lt;/em&gt;. Nodes are kept by a publish-subscribe
        service, and, among other things, this service is responsible for
        keeping the list of subscribers and sending out notifications.&lt;/p&gt;

      &lt;p&gt;Publish-subscribe services currently come in two forms: dedicated
        publish-subscribe services with their own domain (e.g.
        &lt;code class=&quot;literal&quot;&gt;pubsub.ik.nu&lt;/code&gt;) and publish-subscribe services tied
        to a user account (often mentioned in combination with the &lt;a href=&quot;http://www.xmpp.org/extensions/xep-0163.html&quot;&gt;Personal Eventing
          Protocol&lt;/a&gt;, also known as PEP). In the latter case, nodes are
        kept at the bare JID of a user's account (e.g.
        &lt;code class=&quot;literal&quot;&gt;ralphm@ik.nu&lt;/code&gt;. Personal pubsub-nodes have nice
        properties, like the ability to directly associate a particular node
        with a person, and the possibility of doing access control on the
        user's contact list (roster).&lt;/p&gt;

      &lt;h4&gt;Node organization&lt;/h4&gt;
        

        &lt;p&gt;In the context of federating social networks, a service needs to
          decide where to put the nodes it wants to allow other entities to
          subscribe to and send out notifications from. In some cases it makes
          sense to keep nodes at user accounts, though in some other cases it
          is better to provide the nodes at the domain of the service itself.
          This depends on the nature of the social objects and the
          subscribable unit you provide. Let's explore some use cases.
        &lt;/p&gt;

        &lt;h5&gt;Jaiku&lt;/h5&gt;
          

          &lt;p&gt;In &lt;a href=&quot;http://jaiku.com/&quot;&gt;Jaiku&lt;/a&gt;, social
            objects (microblog posts and aggregated items like photos,
            bookmarks, etc), are organized in streams. Streams are tied to
            either a user, or a channel, and don't change ownership. The
            social objects themselves are static, once created, they cannot be
            edited. They can have comments associated with them, but those
            also cannot be edited. The only thing that can happen to streams,
            stream items, and comments is deletion.&lt;/p&gt;

          &lt;p&gt;Here, it makes sense to have a node for each stream, and
            possibly a stream for the comments to each stream item. Those can
            be tied to the owner's JID (e.g.
            &lt;code class=&quot;literal&quot;&gt;ralphm@jaiku.com&lt;/code&gt; or
            &lt;code class=&quot;literal&quot;&gt;#jabber@jaiku.com&lt;/code&gt;). Another possible node could
            be: all comments by a person. Another node an entity might want to
            subscribe to is: all public microblog posts. Such a node would be
            associated with the domain of the service rather than any
            particular user's JID.&lt;/p&gt;

        

        &lt;h5&gt;anyMeta&lt;/h5&gt;
          

          &lt;p&gt;The company I work for, &lt;a href=&quot;http://www.mediamatic.nl/&quot;&gt;Mediamatic Lab&lt;/a&gt; has a
            (proprietary) CMS called &lt;a href=&quot;http://www.anymeta.net/&quot;&gt;anyMeta&lt;/a&gt;. Instead of
            'content', the C in CMS here stands for Community, to highlight
            the social network properties it provides. anyMeta is a highly
            semantic system that deals in &lt;em&gt;thing&lt;/em&gt;s (a
            person, an article, an event, a blog), and
            &lt;em&gt;edge&lt;/em&gt;s (the relations between things, each
            with a predicate like friend-of, author-of, etc). I mainly work on
            federating instances of anyMeta.&lt;/p&gt;

          &lt;p&gt;Things in anyMeta are usually editable, so it makes sense to
            want to keep informed about changes. For example, an article can
            have a large number of edits, and a person might move, change
            employers or have other changes to his profile. Thus, we chose to
          at least provide each thing as a subscribable unit. Upon creating a
          thing, a new node is created, and a representation of the thing is
          published to the node. Editing a thing, results in subsequent
          publishes. Subscribers will receive notifications as the node gets
          published to.&lt;/p&gt;

          &lt;p&gt;We organized the nodes in a flat namespace, tied to a domain,
            rather than a user. One reason is that the owner of any particular
            thing might change. Tying a node to the first owner, and then
            needing to move it when the owner changes, is cumbersome.&lt;/p&gt;

        

      

      &lt;h4&gt;Node naming&lt;/h4&gt;
        

        &lt;p&gt;Each node has an identifier that is unique within the
          publish-subscribe service holding them. So you could have two nodes
          named &lt;code class=&quot;literal&quot;&gt;updates&lt;/code&gt; tied to two different users. Node
          identifiers are opaque; one should not derive meaning from how the
          node identifier looks. Embedded slashes might suggest some
          hierarchy, for example, but an application should not assume that
          such a hierarchy actually exists.&lt;/p&gt;

        &lt;p&gt;That said, it makes perfect sense to use logical, human readable
          identifiers for nodes. They might even be very similar to the URI
          layout of the service's web site. Let's check what one could do for
          the examples given above.&lt;/p&gt;


        &lt;h5&gt;Jaiku&lt;/h5&gt;
          

          &lt;p&gt;It makes sense to have the node identifier for the regular
            posts (called presence) be &lt;code class=&quot;literal&quot;&gt;presence&lt;/code&gt; and the
            nodes for the individual posts (with comments)
            &lt;code class=&quot;literal&quot;&gt;presence/123456&lt;/code&gt;, where the number is the same
            as used in the web page for that post. Those two examples could be
            tied to a JID representing me at Jaiku:
            &lt;code class=&quot;literal&quot;&gt;ralphm@jaiku.com&lt;/code&gt;.&lt;/p&gt;

          &lt;p&gt;The node for all public posts could be called
            &lt;code class=&quot;literal&quot;&gt;explore&lt;/code&gt; and located at the JID of the whole
            service: &lt;code class=&quot;literal&quot;&gt;jaiku.com&lt;/code&gt;. This would be similar to
            the web site, where all public posts can be viewed at &lt;a href=&quot;http://jaiku.com/explore&quot;&gt;http://jaiku.com/explore&lt;/a&gt;.&lt;/p&gt;

          &lt;p&gt;It might also make sense to have a dedicated node for a user's
            profile information, that can be retrieved and presented at a
            service or application that consumes the social object updates. At
            least a (full) name and some icon or headshot would be nice to
            have there. Obviously, subscribing to such a node would mean that
            future profile changes will also propagate to the consuming
            entities. An example identifier would be
            &lt;code class=&quot;literal&quot;&gt;profile&lt;/code&gt;, to be kept at the user's JID.&lt;/p&gt;

        

        &lt;h5&gt;anyMeta&lt;/h5&gt;
          

          &lt;p&gt;In anyMeta, each thing has an identifier, that could be used
            for the node identifier as well. However, in the current
            implementation, all nodes are held by a loosely coupled, generic
            publish-subscribe service that caters multiple anyMeta instances.
            We chose to use unique identifiers as generated by the
            publish-subscribe service, which don't have any relation with the
            thing identifier.&lt;/p&gt;

          &lt;p&gt;As you might have guessed, some of the stuff being discussed
            here has already been implemented in anyMeta. The
            publish-subscribe service used is &lt;a href=&quot;http://idavoll.ik.nu/&quot;&gt;Idavoll&lt;/a&gt;. It has grown an
            &lt;a href=&quot;http://idavoll.ik.nu/wiki/HTTP_Interface&quot;&gt;HTTP
              interface&lt;/a&gt; that is used (internally) to create new nodes,
            publish items that represent things, and subscribe to, and receive
            notifications from, remote publish-subscribe nodes. The thing that
            holds &lt;a href=&quot;http://www.mediamatic.net/person/24879&quot;&gt;my
              Mediamatic profile&lt;/a&gt; is represented by the node
            &lt;code class=&quot;literal&quot;&gt;generic/4efe2253-2242-4e01-bfdf-957cc2a9481d&lt;/code&gt; at
            &lt;code class=&quot;literal&quot;&gt;pubsub.mediamatic.nl&lt;/code&gt;. All things in this site,
            but also the &lt;a href=&quot;http://www.picnicnetwork.org/&quot;&gt;PICNIC
              site&lt;/a&gt;, have nodes like this. In a future post I will
            explore what we do with these nodes.&lt;/p&gt;

        
        
      

      &lt;p&gt;In this part, we explored how one could organize the nodes that
        entities can subscribe to to get updates. Some might be tied to the
        (virtual) JID of the user's account, or associated with the JID of the
        service itself. Node identifiers might be human guessable, and like
        the web URIs, or could be seemingly random opaque strings.
        Implementations that consume subscribe to, and consume notifications
        from, the nodes at social networking services, should not assume
        anything about the organization and naming of the providing service.
        This presents a challenge for the next episode: how does one know
        which nodes are there and what they are called? So, up next:
        discovery. Homework assignment: look carefully at the HTML of my
        Mediamatic profile page.&lt;/p&gt;</description>
	<pubDate>Wed, 30 Jul 2008 15:25:02 +0000</pubDate>
</item>
<item>
	<title>Ross Burton: GUADEC</title>
	<guid>http://www.burtonini.com/blog/computers/guadec-2008-07-29-21-40</guid>
	<link>http://www.burtonini.com/blog/computers/guadec-2008-07-29-21-40</link>
	<description>&lt;p&gt;
  Hmm, so I never did blog a GUADEC roundup.  In two words: it rocked.
  Congratulations to Baris and everyone else who organised it!
&lt;/p&gt;
&lt;p&gt;
  In other late GUADEC news I finally reviewed the rest of my GUADEC photos and
  &lt;a href=&quot;http://www.flickr.com/photos/rossburton/sets/72157606166808992/&quot;&gt;uploaded
  them to Flickr&lt;/a&gt;.  I'll try and not take a month to upload next time,
  honest!
&lt;/p&gt;</description>
	<pubDate>Tue, 29 Jul 2008 20:40:00 +0000</pubDate>
</item>
<item>
	<title>Ralph Meijer: XMPP and Social Networks, part 1: Notifications</title>
	<guid>http://ralphm.net/blog/2008/07/26/xmpp_social_networks_1</guid>
	<link>http://ralphm.net/blog/2008/07/26/xmpp_social_networks_1</link>
	<description>&lt;p&gt;The use of XMPP publish-subscribe in federation and third-party
				applications deviates a bit from the standard use-case. Usually
				publishing, subscribing and receiving notifications happen through
				the same protocol on specific (leaf) nodes. Entities subscribe to a
				node that represents a particular thing they are interested in
				getting updates for, and when an item is published to that node,
				these subscribers will receive a notification for that item.&lt;/p&gt;

			&lt;p&gt;For federating social networks, the focus is on the exchange of
				updates on social objects or comments between services. For
				third-party applications, the most important thing is getting
				updates, preferably as soon as possible. So, for both of those use
				cases, receiving notifications through XMPP gives it an edge over
				HTTP: no polling, lower latency, less connections.&lt;/p&gt;

			&lt;p&gt;How these items are published, does not really matter that
				much. What you will typically see is that services somehow have a
				new item available (submission via the web, SMS, e-mail or a
				web-based API) and want to expose that through XMPP. Posting a new
				update through XMPP from a third-party client usually does not
				provide an advantage over existing web-based APIs.&lt;/p&gt;

			&lt;p&gt;For a service like Jaiku, Twitter or Identi.ca to provide XMPP
				publish-subscribe support, it is important to define the
				&lt;em&gt;subscribable unit&lt;/em&gt; and provide that as a
				node. Such a node will usually not be published to directly, but is
				more of an aggregate node. Examples would be: all updates by a
				particular user, all updates in particular channel, all updates by
				a user and his contacts, all public updates. An other example could
				be: all comments on a particular social object.&lt;/p&gt;

			&lt;p&gt;Conceptually, all such aggregate nodes are internally
				subscribed to a particular subset of new and updated social objects
				and comments. You might even implement it exactly like that. Think
				of a prospective search that is captured by a node: every time a
				new item comes into the service, it is determined which of the
				provided nodes would be a match for this item, based on author,
				contact lists and permissions. Subsequently, for all of those
				nodes, a notification will be sent out to its subscribers. Telling
				items apart in this scenario is then likely not done using the
				service JID, node identifier of item identifier, but using some
				identifier in the payload, like Atom's &lt;code class=&quot;literal&quot;&gt;id&lt;/code&gt;
				element, although those other identifiers might provide a
				context.&lt;/p&gt;

			&lt;p&gt;For those familiar with the concept of XMPP publish-subscribe
				collection nodes: those would be a special form of aggregate nodes
				that make it explicit what their relationship to the nodes they
				aggregate items for is.&lt;/p&gt;</description>
	<pubDate>Sat, 26 Jul 2008 14:12:11 +0000</pubDate>
</item>
<item>
	<title>Ralph Meijer: XMPP Summit #5: XMPP and Social Networks</title>
	<guid>http://ralphm.net/blog/2008/07/26/xmpp_summit_5</guid>
	<link>http://ralphm.net/blog/2008/07/26/xmpp_summit_5</link>
	<description>&lt;p&gt;The major topics on the 5th XMPP Summit were Jingle, and XMPP
				as a complementary protocol next to HTTP for building social
				networking services, as &lt;a href=&quot;http://stpeter.im/&quot;&gt;stpeter&lt;/a&gt; briefly &lt;a href=&quot;https://stpeter.im/?p=2227&quot;&gt;mentioned&lt;/a&gt;. While I think
				that the &lt;a href=&quot;https://stpeter.im/?p=2228&quot;&gt;consensus on OAuth
					over XMPP&lt;/a&gt;, was very important, I think we also settled on
				a good set of best practices for federating social networks using
				&lt;a href=&quot;http://www.xmpp.org/extensions/xep-0060.html&quot;&gt;XMPP
					Publish Subscribe&lt;/a&gt;.&lt;/p&gt;

			&lt;p&gt;This particular topic has had my full attention over the last
				year or so, and it is about time that I start writing about that,
				explaining the afore mentioned best practices in their context. As
				this covers a lot of ground, I'd like to make a series out of it,
				each detailing a particular aspect.&lt;/p&gt;

			&lt;p&gt;Topics that will come by include: the &lt;em&gt;subscribable
					unit&lt;/em&gt; and how notifications are generated, payload
				formats, discovery, local representation and implementation
				strategies.&lt;/p&gt;</description>
	<pubDate>Sat, 26 Jul 2008 14:12:05 +0000</pubDate>
</item>
<item>
	<title>Augie Fackler: Best iTunes Message Ever</title>
	<guid>tag:blogger.com,1999:blog-20139289.post-549597334818518047</guid>
	<link>http://durin42.blogspot.com/2008/07/best-itunes-message-ever.html</link>
	<description>&amp;quot;Purchasing updateAllSoftwareButton&amp;quot; just made me chuckle. Couldn't they have at least named the button something like &amp;quot;All Software Updates&amp;quot; so that a purchase would result in seeing &amp;quot;Purchasing All Software Updates&amp;quot; or something else sane?&lt;a href=&quot;http://bp1.blogger.com/_MNGKAmINUSU/SIqdDDwFn7I/AAAAAAAAABg/pIDJjtfRsYY/s1600-h/Picture+1.png&quot;&gt;&lt;img src=&quot;http://bp1.blogger.com/_MNGKAmINUSU/SIqdDDwFn7I/AAAAAAAAABg/pIDJjtfRsYY/s320/Picture+1.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5227162993389051826&quot; /&gt;&lt;/a&gt;</description>
	<pubDate>Sat, 26 Jul 2008 00:45:01 +0000</pubDate>
</item>
<item>
	<title>Christian Hammond: Django Development with Djblets: Data Grids</title>
	<guid>http://www.chipx86.com/blog/?p=258</guid>
	<link>http://feeds.feedburner.com/~r/chipx86/chiplog/~3/345606151/</link>
	<description>&lt;div class=&quot;series_toc&quot;&gt;&lt;h3&gt;Table of contents for Django Development with Djblets&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=244&quot; title=&quot;Django Development with Djblets&quot;&gt;Django Development with Djblets&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=245&quot; title=&quot;Django Development with Djblets: Custom Tag Helpers&quot;&gt;Django Development with Djblets: Custom Tag Helpers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=253&quot; title=&quot;Django Development with Djblets: Unrooting your URLs&quot;&gt;Django Development with Djblets: Unrooting your URLs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Django Development with Djblets: Data Grids&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=261&quot; title=&quot;Django Development with Djblets: Dynamic Site Configuration&quot;&gt;Django Development with Djblets: Dynamic Site Configuration&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt; &lt;p&gt;It&amp;#8217;s been a while since my last post in this series, but this one&amp;#8217;s a good one.&lt;/p&gt;
&lt;p&gt;A common task in many web applications is to display a grid of data, such as rows from a database. Think the Inbox from &lt;a href=&quot;http://www.gmail.com/&quot;&gt;GMail&lt;/a&gt;, the model lists from the Django administration interface, or the Dashboard from &lt;a href=&quot;http://www.review-board.org/&quot;&gt;Review Board&lt;/a&gt;. It&amp;#8217;s not too hard to write something that displays a grid by doing something like:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;html4strict&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lt;table&amp;gt;&lt;/span&gt;&lt;/span&gt;
 &lt;span&gt;&lt;span&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;th&amp;gt;&lt;/span&gt;&lt;/span&gt;Username&lt;span&gt;&lt;span&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;th&amp;gt;&lt;/span&gt;&lt;/span&gt;First Name&lt;span&gt;&lt;span&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;th&amp;gt;&lt;/span&gt;&lt;/span&gt;Last Name&lt;span&gt;&lt;span&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;/span&gt;
 &lt;span&gt;&lt;span&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;/span&gt;
{% for user in users %}
 &lt;span&gt;&lt;span&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;/span&gt;{{user.username}}&lt;span&gt;&lt;span&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;/span&gt;{{user.first_name}}&lt;span&gt;&lt;span&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;/span&gt;{{user.last_name}}&lt;span&gt;&lt;span&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;/span&gt;
 &lt;span&gt;&lt;span&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;/span&gt;
{% endfor %}
&lt;span&gt;&lt;span&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works fine, so long as you don&amp;#8217;t want anything fancy, like sortable columns, reorderable columns, or the ability to let users specify which columns they want to see. This requires something a bit more complex.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;djblets.datagrids&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We wrote a nifty little set of classes for making data grids easy. Let&amp;#8217;s take the above example and convert it over.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/datagrids.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django.&lt;span&gt;contrib&lt;/span&gt;.&lt;span&gt;auth&lt;/span&gt;.&lt;span&gt;models&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; User
&lt;span&gt;from&lt;/span&gt; djblets.&lt;span&gt;datagrid&lt;/span&gt;.&lt;span&gt;grids&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; Column, DataGrid
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;DataGrid&lt;span&gt;&amp;#41;&lt;/span&gt;:
    username = Column&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;Username&amp;quot;&lt;/span&gt;, sortable=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    first_name = Column&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;First Name&amp;quot;&lt;/span&gt;, sortable=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    last_name = Column&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;Last Name&amp;quot;&lt;/span&gt;, sortable=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, request&lt;span&gt;&amp;#41;&lt;/span&gt;:
        DataGrid.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, request, User.&lt;span&gt;objects&lt;/span&gt;.&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;is_active=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Users&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;default_sort&lt;/span&gt; = &lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'username'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;default_columns&lt;/span&gt; = &lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'username'&lt;/span&gt;, &lt;span&gt;'first_name'&lt;/span&gt;, &lt;span&gt;'last_name'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/views.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; myapp.&lt;span&gt;datagrids&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; UserDataGrid
&amp;nbsp;
&lt;span&gt;def&lt;/span&gt; user_list&lt;span&gt;&amp;#40;&lt;/span&gt;request, template_name=&lt;span&gt;'myapp/datagrid.html'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;return&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;request&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;render_to_response&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;template_name&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now while this may look a bit more verbose, it offers many benefits in return. First off, users will be able to reorder the columns how they like and choose which columns to see. You could extend the above DataGrid to add some new column but leave it out of &lt;tt&gt;default_columns&lt;/tt&gt; so that only users who really care about it would see it.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Custom columns&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s take this a step further. Say we want our users datagrid to optionally show staff members with a special badge. This might be useful to some users, but not all, so we&amp;#8217;ll leave it out by default. We can implement this by creating a custom column with image data:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;class&lt;/span&gt; StaffBadgeColumn&lt;span&gt;&amp;#40;&lt;/span&gt;Column&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, *args, **kwargs&lt;span&gt;&amp;#41;&lt;/span&gt;:
        Column.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, *args, **kwargs&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# These define what will appear in the column list menu.&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_url&lt;/span&gt; = settings.&lt;span&gt;MEDIA_URL&lt;/span&gt; + &lt;span&gt;&amp;quot;images/staff_badge.png&amp;quot;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_width&lt;/span&gt; = &lt;span&gt;16&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_height&lt;/span&gt; = &lt;span&gt;16&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_alt&lt;/span&gt; = &lt;span&gt;&amp;quot;Staff&amp;quot;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# Give the entry in the columns list menu a name.&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;detailed_label&lt;/span&gt; = &lt;span&gt;&amp;quot;Staff&amp;quot;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# Take up as little space as possible.&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;shrink&lt;/span&gt; = &lt;span&gt;True&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;def&lt;/span&gt; render_data&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;user&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;if&lt;/span&gt; &lt;span&gt;user&lt;/span&gt;.&lt;span&gt;is_staff&lt;/span&gt;:
            &lt;span&gt;return&lt;/span&gt; &lt;span&gt;'&amp;lt;img src=&amp;quot;%s&amp;quot; width=&amp;quot;%s&amp;quot; height=&amp;quot;%s&amp;quot; alt=&amp;quot;%s&amp;quot; /&amp;gt;'&lt;/span&gt; % \
                &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_url&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_width&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_height&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;image_alt&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;DataGrid&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
    &lt;span&gt;staff_badge&lt;/span&gt; = StaffBadgeColumn&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    ...&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will add a new entry to the datagrid&amp;#8217;s column customization menu showing the staff badge with a label saying &amp;#8220;Staff.&amp;#8221; If users enable this column, their datagrid will update to show an staff icon for any users who are marked as staff.&lt;/p&gt;
&lt;p&gt;Custom columns can render data in a couple of different ways.&lt;/p&gt;
&lt;p&gt;The first is to bind the column to a field in the model. By default, a &lt;tt&gt;Column&lt;/tt&gt; instance added to a DataGrid will use its own name (such as &amp;#8220;first_name&amp;#8221; above) as a lookup in the object. If you want to use a custom field, set the &lt;tt&gt;db_field&lt;/tt&gt; attribute on the column. This field can span relationships as well. For example:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;class&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;DataGrid&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
    &lt;span&gt;# Uses the field name as the lookup.&lt;/span&gt;
    username = Column&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;Username&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;# Spans relationships, looking up the age in the profile.&lt;/span&gt;
    age = Column&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;profile__age&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second is the way shown above, by overriding the &lt;tt&gt;render_data&lt;/tt&gt; function. This takes an object, which is the object the datagrid represents, and outputs HTML. The logic in this can be quite complicated, depending on what&amp;#8217;s needed.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Linking to objects&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A datagrid is pretty worthless if you can&amp;#8217;t link entries for the object to a URL. We have a couple of ways to do this.&lt;/p&gt;
&lt;p&gt;To link a column on a datagrid to a URL, set the &lt;tt&gt;link&lt;/tt&gt; parameter on the DataGrid to &lt;tt&gt;True&lt;/tt&gt;. By default, the URL used will be the result of calling &lt;tt&gt;get_absolute_url()&lt;/tt&gt; on the object represented by the datagrid, but you can override this:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/datagrids.py&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;DataGrid&lt;span&gt;&amp;#41;&lt;/span&gt;:
    username = Column&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;Username&amp;quot;&lt;/span&gt;, sortable=&lt;span&gt;True&lt;/span&gt;, link=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    ...
    @&lt;span&gt;staticmethod&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; link_to_object&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;, value&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;&amp;quot;/users/%s/&amp;quot;&lt;/span&gt; % &lt;span&gt;user&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then&lt;/p&gt;
&lt;p&gt;&lt;tt&gt;link_to_object&lt;/tt&gt; takes an object and a value. The object is the object being represented by the datagrid, and the value is the rendered data in the cell. The result is a valid path or URL. In the above example, we&amp;#8217;re explicitly defining a path, but we could use Django&amp;#8217;s &lt;tt&gt;reverse&lt;/tt&gt; function.&lt;/p&gt;
&lt;p&gt;Usually the value is ignored, but it can be useful. Imagine that your Column represents a field that is a &lt;tt&gt;ForeignKey&lt;/tt&gt; of an object. The contents of the cell is the string version of that object (implemented by the &lt;tt&gt;__str__&lt;/tt&gt; or &lt;tt&gt;__unicode__&lt;/tt&gt; function), but it&amp;#8217;s just an object and you want to link to it. This is where value comes in handy, as instead of being HTML output, it&amp;#8217;s actually an object you can link to.&lt;/p&gt;
&lt;p&gt;If you intend to link a particular column to &lt;tt&gt;value.get_absolute_url()&lt;/tt&gt;, we provide a handy utility function called &lt;tt&gt;link_to_value&lt;/tt&gt; which exists as a static method on the DataGrid. You can pass it (or any function) to the Column&amp;#8217;s constructor using the &lt;tt&gt;link_func&lt;/tt&gt; parameter.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;class&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;DataGrid&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
    &lt;span&gt;myobj&lt;/span&gt; = Column&lt;span&gt;&amp;#40;&lt;/span&gt;link=&lt;span&gt;True&lt;/span&gt;, link_func=link_to_value&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Custom columns can hard-code their own link function by explicitly setting these values in the constructor.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Saving column settings&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;If a user customizes his column settings by adding/removing columns or rearranging them, he probably expects to see his customizations the next time he visits the page. DataGrids can automatically save these settings in the user&amp;#8217;s profile, if the application supports it. Handling this is as simple as adding some fields to the app&amp;#8217;s Profile model and setting a couple options in the DataGrid. For example:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/models.py&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; Profile&lt;span&gt;&amp;#40;&lt;/span&gt;models.&lt;span&gt;Model&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;user&lt;/span&gt; = models.&lt;span&gt;ForeignKey&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;User, unique=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;# Sort settings. One per datagrid type.&lt;/span&gt;
    sort_user_columns = models.&lt;span&gt;CharField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;max_length=&lt;span&gt;256&lt;/span&gt;, blank=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;# Column settings. One per datagrid type.&lt;/span&gt;
    user_columns = models.&lt;span&gt;CharField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;max_length=&lt;span&gt;256&lt;/span&gt;, blank=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/datagrids.py&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; UserDataGrid&lt;span&gt;&amp;#40;&lt;/span&gt;DataGrid&lt;span&gt;&amp;#41;&lt;/span&gt;:
    ...
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, request&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;profile_sort_field&lt;/span&gt; = &lt;span&gt;&amp;quot;sort_user_columns&amp;quot;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;profile_columns_field&lt;/span&gt; = &lt;span&gt;&amp;quot;user_columns&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The DataGrid code will handle all the loading and saving of customizations in the Profile. Easy, isn&amp;#8217;t it?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Requirements and compatibility&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Right now, datagrids require both the &lt;a href=&quot;http://developer.yahoo.com/yui/&quot;&gt;Yahoo! UI Library&lt;/a&gt; and either yui-ext (which is hard to find now) or its replacement, &lt;a href=&quot;http://www.extjs.com/&quot;&gt;ExtJS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.review-board.org/&quot;&gt;Review Board&lt;/a&gt;, which Djblets was mainly developed for, still relies on yui-ext instead of ExtJS, so datagrids today by default are built with that in mind. However, the JavaScript portion of datagrids should work with ExtJS today. The default template for rendering the datagrids (located in &lt;tt&gt;djblets/datagrids/templates/datagrids/&lt;/tt&gt;) assumes both YUI and yui-ext are present in the media path, but sites using datagrids are encouraged to provide their own template to reflect the actual locations and libraries used.&lt;/p&gt;
&lt;p&gt;We would like to work with more JavaScript libraries, so if anyone wants to provide an implementation for their favorite library or help to dumb down our implementation to work with any and all, we&amp;#8217;d welcome patches.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;See it in action&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We make extensive use of datagrids on Review Board. You can get a sense of it and play around by looking at the &lt;a href=&quot;http://reviews.review-board.org/users/&quot;&gt;users list&lt;/a&gt; and the &lt;a href=&quot;http://reviews.review-board.org/dashboard/&quot;&gt;dashboard&lt;/a&gt; (which requires an account).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;That&amp;#8217;s it for now!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s more to datagrids than what I&amp;#8217;ve covered here, but this should give you a good understanding of how they work. Later on I&amp;#8217;d like to do a more in-depth article on how datagrids work and some more advanced use cases for them.&lt;/p&gt;
&lt;p&gt;For now, take a look at the &lt;a href=&quot;http://svn.navi.cx/misc/trunk/djblets/djblets/datagrid/&quot;&gt;source code&lt;/a&gt; and &lt;a href=&quot;http://code.google.com/p/reviewboard/source/browse/trunk/reviewboard/reviews/datagrids.py&quot;&gt;Review Board&amp;#8217;s datagrids&lt;/a&gt; for some real-world examples.&lt;/p&gt;
 &lt;div class=&quot;series_links&quot;&gt;&lt;a href=&quot;http://www.chipx86.com/blog/?p=253&quot; title=&quot;Django Development with Djblets: Unrooting your URLs&quot;&gt;Previous in series&lt;/a&gt; &lt;a href=&quot;http://www.chipx86.com/blog/?p=261&quot; title=&quot;Django Development with Djblets: Dynamic Site Configuration&quot;&gt;Next in series&lt;/a&gt;&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/chipx86/chiplog/~4/345606151&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Fri, 25 Jul 2008 12:16:59 +0000</pubDate>
</item>
<item>
	<title>Christian Hammond: Django Tips: PIL, ImageField and Unit Tests</title>
	<guid>http://www.chipx86.com/blog/?p=260</guid>
	<link>http://feeds.feedburner.com/~r/chipx86/chiplog/~3/345530219/</link>
	<description>&lt;div class=&quot;series_toc&quot;&gt;&lt;h3&gt;Table of contents for Django Tips&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;Django Tips: PIL, ImageField and Unit Tests&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt; &lt;p&gt;I recently spent a few days trying to track down a bug in &lt;a href=&quot;http://www.review-board.org/&quot;&gt;Review Board&lt;/a&gt; with our unit tests. Basically, unit tests involving uploading a file to a models.ImageField would fail with a validation error specifying that the file wasn&amp;#8217;t an image. This worked fine when actually using the application, just not during unit tests.&lt;/p&gt;
&lt;p&gt;The following code would cause this problem. (Note that this isn&amp;#8217;t actual code, just a demonstration.)&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/models.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django.&lt;span&gt;db&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; models
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; MyModel&lt;span&gt;&amp;#40;&lt;/span&gt;models.&lt;span&gt;Model&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    image = models.&lt;span&gt;ImageField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/forms.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django &lt;span&gt;import&lt;/span&gt; forms
&lt;span&gt;from&lt;/span&gt; myapp.&lt;span&gt;models&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; MyModel
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; UploadImageForm&lt;span&gt;&amp;#40;&lt;/span&gt;forms.&lt;span&gt;Form&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    image_path = forms.&lt;span&gt;ImageField&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;required=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;def&lt;/span&gt; create&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;file&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        mymodel = MyModel&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        mymodel.&lt;span&gt;save_image_file&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;.&lt;span&gt;name&lt;/span&gt;, &lt;span&gt;file&lt;/span&gt;, save=&lt;span&gt;True&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;return&lt;/span&gt; mymodel&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/views.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; myapp.&lt;span&gt;forms&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; UploadImageForm
&amp;nbsp;
&lt;span&gt;def&lt;/span&gt; upload&lt;span&gt;&amp;#40;&lt;/span&gt;request&lt;span&gt;&amp;#41;&lt;/span&gt;:
    form = UploadImageForm&lt;span&gt;&amp;#40;&lt;/span&gt;request.&lt;span&gt;POST&lt;/span&gt;, request.&lt;span&gt;FILES&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; form.&lt;span&gt;is_valid&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;# Return some error&lt;/span&gt;
        &lt;span&gt;pass&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;# Return success&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;


&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# myapp/tests.py&lt;/span&gt;
&lt;span&gt;from&lt;/span&gt; django.&lt;span&gt;test&lt;/span&gt; &lt;span&gt;import&lt;/span&gt; TestCase
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; MyTests&lt;span&gt;&amp;#40;&lt;/span&gt;TestCase&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;def&lt;/span&gt; testImageUpload&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        f = &lt;span&gt;open&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;testdata/image.png&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        resp = &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;client&lt;/span&gt;.&lt;span&gt;post&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;/upload/&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;#123;&lt;/span&gt;
            &lt;span&gt;'image_path'&lt;/span&gt;: f,
        &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        f.&lt;span&gt;close&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After a good many hours going through the Django code, expecting there to be a problem with file handles becoming invalidated or the read position not being reset to the beginning of the file, I finally decided to look at PIL, the Python Imaging Library. It turns out that at this point, due to some weirdness with unit tests, PIL hadn&amp;#8217;t populated its known list of file formats. All it knew was BMP, and so my perfectly fine PNG file didn&amp;#8217;t work.&lt;/p&gt;
&lt;p&gt;The solution? Be sure to import PIL and call &lt;tt&gt;init()&lt;/tt&gt; before the unit tests begin. If you have a &lt;a href=&quot;http://www.djangoproject.com/documentation/testing/#defining-a-test-runner&quot;&gt;custom runner&lt;/a&gt; (as we do), then putting it in here is appropriate. Just add the following:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;from&lt;/span&gt; PIL &lt;span&gt;import&lt;/span&gt; Image
Image.&lt;span&gt;init&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hopefully this helps someone else with the problems I&amp;#8217;ve dealt with the past few days.&lt;/p&gt;
 &lt;div class=&quot;series_links&quot;&gt; &lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/chipx86/chiplog/~4/345530219&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Fri, 25 Jul 2008 10:25:40 +0000</pubDate>
</item>
<item>
	<title>Mark Doliner: Poor Planning</title>
	<guid>http://thekingant.livejournal.com/82101.html</guid>
	<link>http://thekingant.livejournal.com/82101.html</link>
	<description>Why do ssh, scp and sftp all have different ways of specifying the port number?  I run ssh on my home computer on a non-standard port, and it's a pain in the calf to remember which one to use when.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;gt; ssh -p 1234 example.com&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;gt; scp -P 1234 example.com&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;gt; sftp -oPort=24 example.com&lt;/code&gt; (I thought this one was a joke at first)</description>
	<pubDate>Wed, 23 Jul 2008 16:41:40 +0000</pubDate>
</item>
<item>
	<title>Mark Doliner: Error Handling</title>
	<guid>http://thekingant.livejournal.com/81891.html</guid>
	<link>http://thekingant.livejournal.com/81891.html</link>
	<description>&quot;The general rule of thumb is that it takes $10 to fix the bug during development; $100 to fix the bug in QA; a $1,000 to fix the bug during beta testing; and $10,000 or more to fix the bug post-deployment.&quot;&lt;br /&gt;&lt;br /&gt;I pretty much agree with that.  Not to those specific numbers, just to the fact that it's a pain to fix stuff after the fact.  So when developing you should take your time and double-check your code when you're finished.  Then have a peer review it and make sure it's perfect.&lt;br /&gt;&lt;br /&gt;But there's no way you're going to catch all the bugs.  So to make debugging easier you should always have really good error handling and error logging.  Check for and log every error possible.  That means looking at the return value for every system call.  If an error &lt;i&gt;can&lt;/i&gt; happen then assume it &lt;i&gt;will&lt;/i&gt; happen.</description>
	<pubDate>Wed, 23 Jul 2008 16:35:41 +0000</pubDate>
</item>
<item>
	<title>Kevin Smith: I’m not at the XMPP Summit</title>
	<guid>http://www.kismith.co.uk/wordpress/?p=91</guid>
	<link>http://www.kismith.co.uk/wordpress/index.php/2008/07/21/im-not-at-the-xmpp-summit/</link>
	<description>I&amp;#8217;m not at the XMPP Summit, sadly, but I&amp;#8217;m being my usual nuisance self remotely, thanks to the summit MUC, and the live feed (thanks bear) at http://www.ustream.tv/channel/xmpp-summit&amp;#8211;5.
I&amp;#8217;m sure someone who&amp;#8217;s there can write a summary later, but at least this means those of us not fortunate enough to make it out there can enjoy [...]</description>
	<pubDate>Mon, 21 Jul 2008 20:16:29 +0000</pubDate>
</item>
<item>
	<title>Matt Rogers: Sunday - 07/20/2008</title>
	<guid>http://mattr.info:8080/blog/2008/07/20/sunday-07202008/</guid>
	<link>http://mattr.info:8080/blog/2008/07/20/sunday-07202008/</link>
	<description>&lt;ul&gt;
&lt;li&gt;Went to see Hancock today. Enjoyable movie. The Dark Knight is up next. Tons of people waiting in line for the next showing (1.5 hours from when we got to the theater). Completely crazy. I want to see it, but I&amp;#8217;ll wait until the theaters are a bit more empty. &lt;img src=&quot;http://mattr.info:8080/blog/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/li&gt;
&lt;li&gt;Completely skipped out on the Kopete bugday today. I figured I was going to have to miss one of them, and it was just too busy today for me to make it.&lt;/li&gt;
&lt;li&gt;Started setting up development stuff on the OS X side of the laptop today. Fink has gotten pretty nice since the last time i tried it.&lt;/li&gt;
&lt;li&gt;GTD reboot is the reason for going back to the OS X side of things. A few nice applications there that I need that there aren&amp;#8217;t open source (or even Linux-based) replacements for. If I can stay better organized and contribute to KDE more by using OS X rather than Linux, then that&amp;#8217;s what I&amp;#8217;m doing. &lt;/li&gt;
&lt;/ul&gt;</description>
	<pubDate>Mon, 21 Jul 2008 04:04:41 +0000</pubDate>
</item>
<item>
	<title>Johann Prieur: People in GNOME</title>
	<guid>http://jprieur.wordpress.com/?p=59</guid>
	<link>http://jprieur.wordpress.com/2008/07/20/where-people-fits-in-gnome/</link>
	<description>&lt;div class=&quot;snap_preview&quot;&gt;&lt;br /&gt;&lt;p&gt;Right after our GUADEC presentation, &lt;a href=&quot;http://asabil.wordpress.com&quot; target=&quot;_blank&quot;&gt;Ali Sabil&lt;/a&gt; and I met with &lt;a href=&quot;http://blog.fishsoup.net/&quot;&gt;Owen Taylor&lt;/a&gt;, &lt;a href=&quot;http://mugshot.org/person?who=Y4TMqGmjl4Jqkp&quot;&gt;Marina Zhurakhinskaya&lt;/a&gt; (both from Red Hat&amp;#8217;s Online Desktop project), &lt;a href=&quot;http://www.robot101.net/&quot;&gt;Robert McQueen&lt;/a&gt; (Telepathy) and &lt;a href=&quot;http://treitter.livejournal.com/&quot;&gt;Travis Reitter&lt;/a&gt; (Soylent). The goal of that quick meeting was to define how to integrate all those pieces of technologies together. Even if People aims to define a data model and a D-Bus API to be used on all the free desktops, we are also part of the GNOME community, thus particularly eager to see People integration with GNOME technologies happening.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s been always difficult to make people understand what People is. Moreover, our project is quite unknown. We are not present on GNOME&amp;#8217;s main communication channel (Planet GNOME) and that&amp;#8217;s something you feel also at GUADEC when the conference room isn&amp;#8217;t very populated. In that blog post, I&amp;#8217;ll try to explain what is People and what it will be for GNOME.&lt;/p&gt;
&lt;p&gt;The best explanation I can give to begin with is maybe that People is actually like &amp;#8220;libsoylent&amp;#8221;, which has been announced few time ago. The main goal is the same: provide first-class people objects to applications. Our approach is different: we designed People from the backend to application level, which allows us to consider whatever contact source, while libsoylent, based on what is done in Soylent, only uses Evolution Data Server and Telepathy as sources (for now). I think that our development is more advanced and our solution wider, hence even Soylent should use People.&lt;/p&gt;
&lt;p&gt;On the next diagram, you can find several components that are part of the GNOME ecosystem. It is based on the &lt;a href=&quot;http://asabil.files.wordpress.com/2008/07/people-blackboard.jpg&quot; target=&quot;_blank&quot;&gt;GUADEC after-talk meeting result&lt;/a&gt; and is not meant to be exhaustive.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Green boxes are what we call &lt;strong&gt;contact sources&lt;/strong&gt;. Any application, service or data source handling and exposing objects referred as contacts, friends, persons, people is a potential contact source. Those contact sources are plugged into the People framework through a &lt;strong&gt;backend&lt;/strong&gt; system. That interaction is represented as dashed arrows on the diagram. Each contact source provides partial information about some contacts to People.&lt;/li&gt;
&lt;li&gt;The blue box is the framework. It contains the &lt;strong&gt;backend system&lt;/strong&gt;, a mechanism to gather partial contact informations into high level contact object (often called meta-contacts) and a &lt;strong&gt;D-Bus daemon&lt;/strong&gt; to expose those high level contacts to applications. At some point, we&amp;#8217;d also like to expose backend directly to allow synchronization solutions to use them.&lt;/li&gt;
&lt;li&gt;Yellow boxes are a few possible applications that could use the framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&quot;attachment_60&quot; class=&quot;wp-caption aligncenter&quot;&gt;&lt;a href=&quot;http://jprieur.files.wordpress.com/2008/07/01.png&quot;&gt;&lt;img class=&quot;size-full wp-image-60&quot; src=&quot;http://jprieur.files.wordpress.com/2008/07/01.png?w=510&amp;amp;h=347&quot; alt=&quot;People in GNOME&quot; width=&quot;510&quot; height=&quot;347&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;People in GNOME&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Concerning Empathy, the current contact list could be turned into a people list, where each item wouldn&amp;#8217;t be an instant messaging contact anymore but just a known person, that you may reach using instant messaging. That list would contain some friends you have in Facebook and you could actually subscribe to them on Jabber directly from Empathy, as People would provide to Empathy the information saying that your friend has a jabber account.&lt;/p&gt;
&lt;p&gt;This is what People does, it provides contact information to application, and then applications should know how to use that information. People won&amp;#8217;t tell you to launch Evolution to write an e-mail, it&amp;#8217;ll just tell you that you can reach a certain contact through e-mail. We then need sort of an &amp;#8220;activity launcher&amp;#8221; and I think that&amp;#8217;s what Soylent should be. Using the people list provided by the Empathy widget set, Soylent should allow you to start activities with the people you know. At some point, maybe Empathy&amp;#8217;s client and Soylent are meant to be the same application.&lt;/p&gt;
&lt;p&gt;Our demonstration at GUADEC was an application containing a list of high level contacts built from local (sqlite database) and distant sources (lastfm and friendfeed web services). The list exposed contact information such as the full name of the contact, a picture, an e-mail address, a phone number, an icon per social network he&amp;#8217;s susbscribed to, all those information being provided by People. At some point, Ali brought his mobile phone next to the laptop and his phone&amp;#8217;s addressbook automatically became a contact source (over bluetooth) for the application, adding contacts from the phone in the list. This was supposed to show how flexible the backend system is and how cool are the things that People enables :).&lt;/p&gt;
&lt;p&gt;Yesterday we set up &lt;a href=&quot;http://www.people-project.org&quot; target=&quot;_blank&quot;&gt;www.people-project.org&lt;/a&gt; which is currently a wiki that will be useful to collaborate on stuff that are not code. We are also releasing &lt;a href=&quot;https://launchpad.net/people-project/0.0/0.0.5&quot; target=&quot;_blank&quot;&gt;0.0.5 &amp;#8220;Smelly hotel lobby&amp;#8221;&lt;/a&gt; (tribute to our hotel in Istanbul, where people still smoke in public places and People don&amp;#8217;t) today, as dictated by our sprint schedule. We are currently developing more backends (Online Desktop, Telepathy, EDS, &amp;#8230;) and trying to improve what we have for now. The backlog is huge but considering all the possible cool applications, will is around.&lt;/p&gt;
&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/categories/jprieur.wordpress.com/59/&quot; /&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/tags/jprieur.wordpress.com/59/&quot; /&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gocomments/jprieur.wordpress.com/59/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/jprieur.wordpress.com/59/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godelicious/jprieur.wordpress.com/59/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/jprieur.wordpress.com/59/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gostumble/jprieur.wordpress.com/59/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/jprieur.wordpress.com/59/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godigg/jprieur.wordpress.com/59/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/jprieur.wordpress.com/59/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/goreddit/jprieur.wordpress.com/59/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/jprieur.wordpress.com/59/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://stats.wordpress.com/b.gif?host=jprieur.wordpress.com&amp;amp;blog=784691&amp;amp;post=59&amp;amp;subd=jprieur&amp;amp;ref=&amp;amp;feed=1&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Sun, 20 Jul 2008 15:20:44 +0000</pubDate>
</item>
<item>
	<title>Johann Prieur: jprieur</title>
	<guid>http://jprieur.wordpress.com/?p=51</guid>
	<link>http://jprieur.wordpress.com/2008/07/18/entre-autres/</link>
	<description>&lt;div class=&quot;snap_preview&quot;&gt;&lt;br /&gt;&lt;p&gt;I finished my internship at Nokia around mid-June. I got to learn a lot of stuff over there, mainly corporate world related and it helped me a lot to define my professional expectations better. A lot.&lt;/p&gt;
&lt;p&gt;I graduated at the end of June and I&amp;#8217;m now an engineer, for real. A bit sad to leave university and friends but hey, what&amp;#8217;s next seems to be shiny as well.&lt;/p&gt;
&lt;p&gt;Last week, Ali and I presented the People framework at GUADEC in Istanbul. Few attendees but it seems we managed to reach the right persons and I have the hope that we&amp;#8217;ll be able to add value to the desktop with that project. More on that later.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m now back home for some time, trying to not get bored.&lt;/p&gt;
&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/categories/jprieur.wordpress.com/51/&quot; /&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/tags/jprieur.wordpress.com/51/&quot; /&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gocomments/jprieur.wordpress.com/51/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/jprieur.wordpress.com/51/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godelicious/jprieur.wordpress.com/51/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/jprieur.wordpress.com/51/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gostumble/jprieur.wordpress.com/51/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/jprieur.wordpress.com/51/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godigg/jprieur.wordpress.com/51/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/jprieur.wordpress.com/51/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/goreddit/jprieur.wordpress.com/51/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/jprieur.wordpress.com/51/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://stats.wordpress.com/b.gif?host=jprieur.wordpress.com&amp;amp;blog=784691&amp;amp;post=51&amp;amp;subd=jprieur&amp;amp;ref=&amp;amp;feed=1&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Fri, 18 Jul 2008 21:42:37 +0000</pubDate>
</item>
<item>
	<title>Process One: ProcessOne at XMPP summit</title>
	<guid>tag:process-one.net,2008:en/blogs/3.277</guid>
	<link>http://www.process-one.net/en/blogs/article/processone_at_xmpp_summit/</link>
	<description>ProcessOne will be at the &lt;a href=&quot;http://www.xmpp.org/summit/summit5.shtml&quot;&gt;XMPP summit&lt;/a&gt; from 20th to 22th of july 2008. &lt;p&gt;We are eager to meet XMPP servers and clients developers, but also our users around Portland.&lt;/p&gt;

&lt;p&gt;If you would like us to meet and will not be at the XMPP summit itself, please drop me a mail &lt;img class=&quot;inline&quot; src=&quot;http://www.process-one.net/images/smileys/smile.gif&quot; width=&quot;19&quot; height=&quot;19&quot; alt=&quot;smile&quot; /&gt;&lt;/p&gt;</description>
	<pubDate>Fri, 18 Jul 2008 08:50:23 +0000</pubDate>
</item>
<item>
	<title>Process One: Usage estimation of public XMPP servers per domain</title>
	<guid>tag:process-one.net,2008:en/imtrends/26.276</guid>
	<link>http://www.process-one.net/en/imtrends/article/usage_estimation_of_public_xmpp_servers_per_domain/</link>
	<description>Based on data gathered by our IMtrends search engine, here is our very first &quot;market shares&quot; estimation on XMPP servers, for domains known by IMtrends. &lt;p&gt;Please, first note that study relies on a panel of 7292 XMPP domains as discovered by the IMtrends engine. This should be still only a partial analysis of the existing XMPP servers: we cannot take into account totally private servers. However, we have received feedback that a lot of the known XMPP public deployments are already gathered in the IMtrends database. You can check by yourself on our search engine and add more public servers in the database that we could be missing: See &lt;a href=&quot;http://www.process-one.net/en/imtrends/&quot;&gt;IMtrends&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please, also note that those statistics do not take into account the size of the domains (the number of total users and simultaneous users peak).&lt;/p&gt;

&lt;p&gt;Now, let's get to the data. Here is a breakdown on server usage per type on the 18 july 2008:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://www.process-one.net/images/uploads/chart_20080718.png&quot; /&gt;&lt;/p&gt;

        &lt;table&gt;
            &lt;thead&gt;
            &lt;tr&gt;
                &lt;th&gt;Software Family&lt;/th&gt;
                &lt;th&gt;Market Share &lt;/th&gt;
            &lt;/tr&gt;
            &lt;tbody&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;ejabberd&lt;/td&gt;
                    &lt;td&gt;37.0%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;jabberd14&lt;/td&gt;
                    &lt;td&gt;22.4%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;openfire&lt;/td&gt;
                    &lt;td&gt;18.4%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;jabberd2&lt;/td&gt;
                    &lt;td&gt;11.3%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;Google XMPP&lt;/td&gt;
                    &lt;td&gt;6.2%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;wpjabber&lt;/td&gt;
                    &lt;td&gt;0.9%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;XCP&lt;/td&gt;
                    &lt;td&gt;0.2%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;djabberd&lt;/td&gt;
                    &lt;td&gt;0.1%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;SoapBox&lt;/td&gt;
                    &lt;td&gt;0.1%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;psyc&lt;/td&gt;
                    &lt;td&gt;0.1%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;Isode M-Link&lt;/td&gt;
                    &lt;td&gt;0.1%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;tigase&lt;/td&gt;
                    &lt;td&gt;0.1%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;timp&lt;/td&gt;
                    &lt;td&gt;0.1%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;JCS&lt;/td&gt;
                    &lt;td&gt;0.0%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt;MOO-XMPP&lt;/td&gt;
                    &lt;td&gt;0.0%&lt;/td&gt;
                &lt;/tr&gt;
                
                &lt;tr&gt;
                    &lt;td&gt; Unknown* &lt;/td&gt;
                    &lt;td&gt;3.0%&lt;/td&gt;
                &lt;/tr&gt;
                
            &lt;/tbody&gt;
        &lt;/thead&gt;&lt;/table&gt;

&lt;p&gt;We will publish more statistics analysis in the coming months, so stay tuned.&lt;/p&gt;

&lt;br /&gt;&lt;br /&gt;</description>
	<pubDate>Fri, 18 Jul 2008 08:40:45 +0000</pubDate>
</item>
<item>
	<title>Kevin Smith: Thanks, Psi</title>
	<guid>http://www.kismith.co.uk/wordpress/?p=90</guid>
	<link>http://www.kismith.co.uk/wordpress/index.php/2008/07/17/thanks-psi/</link>
	<description>I&amp;#8217;ve been meaning to make this post for an age&amp;#8230;
A decent number of people thank the Psi project, and that&amp;#8217;s great; I get thanked more than most, I think, because I&amp;#8217;m the one who gets to make the release announcements, and it looks like I do all the work because of this. These days, I [...]</description>
	<pubDate>Thu, 17 Jul 2008 21:09:05 +0000</pubDate>
</item>

</channel>
</rss>
