Latest Publications

I want a mailing list & forum hybrid

There are some thoughts which are repeating in my head for years, and I’ve just decided its time that I write them down.

When it comes to non-instantly many-to-many communication, there are to big systems currently in use: forums and mailing lists. What annoys me that much about those is that both systems are actually exactly the same, except for the frontend they use.

Mailing lists send the messages to all users by mail, and allow them to answer again by mail. Additionally, they have a website (archive) where all messages can be checked, but this website is usually pretty awful and doesn’t allow answering to the messages.

Comparably, forums show all messages -and allow to answer to them- in a website which is excellent for this purpose, but the mail subscription option isn’t useful at all (often requiring that you open the website to see the content) and doesn’t allow to answer to the messages directly.

But, let’s look again at what their key function actually is. Delivering messages. It’s just, one simple purpose that both systems share. So my point is, why isn’t there a single solution adjusting to both (mail and web) workflows. Why are there only two exclusive options, which only provide one good interface and a broken attempt at the other one?

I want a system where I can visit a website and see all messages (also being able to answer to them), and then after five months decide that I don’t want to visit the website any more and subscribe to it by mail, still getting to read and answer the discussions in the same way but now from my mail client? (And while we are at it, having an option to link several email addresses to the same account, so that I can answer using any of those – like with Launchpad’s mailing lists).

In all the years I’ve been using the Internet, I haven’t seen a single solution like the one I’m describing. Sure, there are third-party websites which show discussions from mailing lists in a more readable way, and some even allow answering to them, but it isn’t quite the same. There is Google Groups, which is quite close at providing both interfaces, but the website isn’t really like a forum either and it just doesn’t feel right (also, it’s proprietary/centralized and not appropriate for usage by, for example, the Debian project).

Am I really asking for that much? I’ve considered, several times, writing such a system myself, but I just can’t believe that nobody has thought of it before (or, in case it already exists, that it isn’t in much more widespread use).

Joining the vrms meme…

Oh well, there’s another meme around and I can’t resist joining it…

[rainct, ~]$ vrms
bash: vrms: command not found

Whoops!

How to help with package screenshots

By now most of you should have noticed that nifty feature that Add/Remove applications and Synaptic got a few months ago – being able to fetch a screenshot for every package, as can be seen in the image below.

...

What maybe isn’t that well-known is, where do those images actually come from? Easy: they are all at screenshots.debian.net and applications interested in showing them fetch them from there.

Now, I’m not telling you this because I think it’s soooo interesting, but because I’m seeing lots of packages without screenshots and… you can help create those! So, go look for some of your favourite application missing a screenshot, take a meaningful screenshot of it (in English, using PNG format, etc.) and head over to screenshots.debian.net to upload it :).

The new software centre (which can be tested in Karmic) of course also shows those screenshots, and in a much nicer way (they fade in automatically).

The new software centre (which can be tested in Karmic) of course also shows those screenshots, and in a much nicer way (they fade in automatically).

Here is Zeitgeist 0.2.1!

One month after the first Zeitgeist release (0.2), here is Zeitgeist 0.2.1! This version, which is fully backwards compatible with the previous release, fixes a couple of issues, provides enhanced performance and removes the dependency on Storm and on a patches PyGTK+ version.

Here is the full changelog:

- Added compatibility with Python version 2.5.
- Removed the Storm dependency, obtaining general performance improvements.
- Removed the need for a patched PyGTK.
- Made the GtkRecentlyUser logger more robust (fixes an infinit loop on some
systems).
- Improved performance of DeleteItems and UpdateItems.
- Fixed a problem with the contents of the EventsChanged signal.
- Fixed InsertEvents to enforce "mimetype" as a required value.
- Fixed a bug where the sorting_asc=True in FindEvents would be ignored if used
together with mode="mostused" (LP: #404947).
- Highly improved caching.
- Added a "--quit" option to zeitgeist-daemon to stop any running daemon.
- General code improvements, new test cases and other minor fixes.

Additionally, it also adds the possibility to use a list of strings (instead of just a single string) as value for the “uri” and “name” filters; if used, the condition between the different values in the list is OR (so you can do, for example, "name": [u"%ubuntu%", u"%debian%"] to get all those items with either “ubuntu” or “debian” in their name).

Go get it here! (Note: Zeitgeist by itself doesn’t provide any user interface and shouldn’t be relevant to end users. However, a GTK+ interface depending on it should be available soon, followed by GNOME Shell and other products which will also use it.)

Introduction to Zeitgeist 0.2′s API

So now that Zeitgeist 0.2.0 is out I’ve thought I’d write down some examples of how to use it’s API to get information from it. Please keep in mind that this is a development version and the API isn’t guaranteed to be stable (and I can tell you now, many of them will change). If you’re going to develop something for Zeitgeist it’s a good idea to come by and explain us what you’re doing (so that we can keep your use cases in mind and notify you in case of any important changes). This said, here we go.

Installation

If you use Ubuntu you can grab packages from Zeitgeits’s PPA, else get the tarball and install it (# make; make install). Once installed, start “zeitgeist-daemon” and leave it running in the background (at first it may be busy for some time going through all of your Firefox history, but after that you shouldn’t notice it).

Zeitgeist comes with a public Python module providing some convenience functions. This module makes it very easy to play with Zeitgeist from an interactive Python instance, which is something I recommend you to do while reading this post. Thanks to it, you can get access to Zeitgeist’s D-Bus interface simply doing: from zeitgeist import dbusutils; iface = dbusutils.DBusInterface().

API Examples

For brevity, I’m only going to show some examples, but not explain what every parameter used in the call stands for. You’ll need to look at the DBus API documentation to completely understand them.

Also, I’m using Python for the examples, but the same works with very little modifications in any other language (as long as it has D-Bus bindings).

iface.GetItems([u'file:///home/rainct/todo'])
Returns a dictionary with basic information about the “todo” file in my home directory; uri, text (usually the filename), mimetype, tags, whether it’s bookmarked or not, etc. The values for some keys, like “timestamp”, are empty because they are only relevant for events, which are items put into a timeline (yes, this is a bit confusing, in future versions of Zeitgeist we will clearly differentiation between events and items).

iface.FindEvents(time.time() - 24*3600, time.time(), 5, False, 'event', [])
Returns the five last events (or less, if less than five events where logged within the last twenty-four hours). If you opened the same file twice, it will have two events; to avoid this change 'event' to 'item'.

iface.FindEvents(0, 0, 10, True, 'event', [])
Returns the ten first events ever registered with Zeitgeist which happened first (the sorting is always done by timestamp, not by insertion order).

iface.FindEvents(0, 0, 2, False, 'mostused', [])
Returns the last two events for to the items (URIs) which are used the most often.

iface.FindEvents(0, 0, 0, False, 'item', [{'tags': [u'zeitgeist'], 'bookmarked': True}])
Returns all events (when there are more than one with the same URI, only the most recent of them because of the 'item' parameter) which are bookmarked and have the tag “zeitgeist”.

iface.FindEvents(0, 0, 0, False, 'item', [{'tags': [u'zeitgeist']}, {'mimetypes': ['text/x-python'], 'bookmarked': True}])
Returns all events (when there are more than one with the same URI, only the most recent of them because of the 'item' parameter) which are bookmarked and have the tag “zeitgeist”.

iface.FindEvents(0, 0, 0, False, 'item', [{'tags': [u'zeitgeist', 'engine']}, {'mimetypes': ['text/x-python'], 'bookmarked': True}])
Returns all events (without duplicated URIs) which either have the tags “zeitgeist” and “engine” or, alternatively, are Python files (determined by their mimetype) and are bookmarked.

iface.CountEvents(0, 0, 'item', [{'tags': [u'zeitgeist', 'engine']}, {'mimetypes': ['text/x-python'], 'bookmarked': True}])
Same as above, but returning only the amount of results that the previous call would yield.

iface.FindApplications(time.time() - 3600*24*30, 0, [{'mimetypes': ['text/x-python']}])
Returns the path to the .desktop files of all applications which were used to manipulate Python files within the last 30 days (eg., in my case: [u'/usr/share/applications/geany.desktop', u'/usr/share/applications/gedit.desktop' ]).

iface.GetTags(0, 0, 5, u'a%')
Returns the five most used tags which start with “a” (case insensitive) in a list of tuples containing both the tag name and the amount of times it was used.

iface.GetLastInsertionDate(u'/usr/share/applications/gedit.desktop')
Returns the timestamp of the last event related to Gedit.

iface.connect('EventsChanged', callback_function); import gobject; gobject.MainLoop.run()
Calls callback_function every time a new event is inserted into the database or an existing one is modified. The callback function receives a list containing in the first place a string representing the type of change (“added”, “modified”, “deleted”) and in second place a list containing the affected events (or, in case of deletion, only a list with the deleted URIs).