Xfce

Subdomains
 

Looking for a full time job in Open Source

  • August 29, 2011
  • Jannis Pohlmann

Two years ago I was really close to canceling my studies and looking for a job instead. In the end I continued studying, passed the final exams of my Diplom (the German old-school equivalent to a Master’s degree) with excellent results and started working on my graduate thesis. Today, I am 1 1/2 months away from the submission deadline and it is clear that I will make it.

So, this time I’m serious: I’m looking for a full time employment in Open Source software development, engineering or management starting November this year. Hiring me will get you an experienced and talented hacker with a natural intuition for software architecture and aesthetics as well as a scientific and painstaking approach to software planning and implementation.

Through my work at the university and within the Xfce and Lunar Linux projects, I have gained experience in/with

  • many programming languages (including C, C++, Ruby, Python, Vala, Lua, XSLT, TeX, Java, Bash and a couple of others),
  • many frameworks (the whole GTK+/GLib stack including D-Bus, a bit of Clutter, XLib and Qt/QML, SWT/JFace, the FOX toolkit as well as web frameworks like Sinatra and Rails; some knowledge about the Linux kernel, its facilities and kernel-userspace communication mechanisms included),
  • many developer tools (GNU compilers, Autotools, VIM, NetBeans, Eclipse and others),
  • many software versioning systems (Git, Subversion, CVS and Mercurial), and
  • various areas of computer science and software engineering (complexity theory, signal processing, graph drawing, micro-controller programming and sensor-based networking, software planning, testing etc.).

I feel equally at home developing for the desktop or for the web. Granted, my main area of expertise is user interface and middleware development on Linux, which my fellow Xfce hackers and I have successfully participated in, but I’ve always found web development with Ruby to be a refreshing change.

There are many other things related to open source that I love doing. Over the past years I’ve enjoyed being able to improve the transparency of the development and release management of Xfce. Streamlining the release process and providing tools for making release management fun was an initiative I am particularly proud of. The same goes for community efforts like the Xfce Foundation, which we’ve launched in early 2011 and which I am currently heading as president.

This post is not just about the past though, it’s also about what lies ahead. Things I am particularly interested in with regards to the future include

  • mobile platforms and applications (iOS and Android are not good enough, I think we need open alternatives),
  • multi-touch interfaces on Linux (yep, this is on the way, but there still is a lot of potential work to be done, I guess),
  • cloud-based applications (I know I can store files and data on the web, but where are the mind-blowing features that go beyond availability of personal data everywhere?), and
  • environmental and power saving applications (living responsibly will become important soon enough; how can we generate awareness and support environmental causes with the help of software?).

I am excited and curious what my role will be in all this. Anway, I guess this is enough information about me for now. After all, this is no biography but a job-search post. ;)

If you read this and you happen to be Microsoft or Apple, do not even bother to send a headhunter. I prefer to work in the open and I believe in Open Source for many reasons. This ecosystem that we’ve created over the past two decades provides a great way for people from all around the world to collaborate on projects they care about, in an honest and tolerant way. I think that’s an inspirational model from which our entire society can and hopefully will benefit. Why would we want to have it any other way?

If you are a member or leader of a company dedicated to Open Source software and are interested in hiring me, please let me know. Linked below are my resumé, software projects and email address. I’m looking forward to talking to you!

Download my resumé/CV — A list of references is included. Feel free to contact them; they are aware of being listed and I’m sure they will be happy to answer any of your questions.

My software projects — A list of open source software projects I am or have been working on.

Email address: jannis@xfce.org

Attending FOSDEM 2011

  • January 10, 2011
  • Jannis Pohlmann

I'm going to FOSDEM, the Free and Open
Source Software Developers' European Meeting

Today Nick and I booked hotel rooms for FOSDEM so now it’s official that the two of us will be there. I’m very much looking forward to it and I’m hoping to meet some of you at the FOSDEM Beer Event on Friday! Still need to think about a way to make ourselves recognizable as Xfce folks though.

If you are planning to attend and would like to meet any of the Xfce folks, please add your name in the wiki:

  http://wiki.xfce.org/events/2011/fosdem

We haven’t decided where and when to meet on Saturday and Sunday but I’m sure we will find something. Stay tuned for additional announcements on this weblog.

In addition to celebrating the 4.8 release of Xfce which is scheduled for next weekend, one of our goals for FOSDEM 2011 will be to sign the papers for registering the Xfce Foundation e.V. in Germany. The details of this still need to be worked out, however. I’ll keep you posted about this as well.

If you would like to talk to me about things other than Xfce, please drop me a mail and I’m sure we can arrange something.

Final exams, diplom thesis and thunar-volman

  • July 17, 2010
  • Jannis Pohlmann

I guess it’s time for an update.

This week I passed the last of four final exams in computer science and human-computer interaction at my university. Not only am I pleased that nine months of learning are over; I am also blessed with excellent grades. And while my understand of good grades is similar to that of money (nice to have it but nothing to focus on and/or brag with), I have to admit that this time I’m at least a little proud of myself. Five years at the university are slowly coming to an end, the first friends are leaving town and it will soon be time to take the next big step in life.

I cannot leave this city before writing another thesis, however. Thus, I am currently looking for a Diplom thesis at the university or at companies related to open source technologies. If you happen work for such a company with interesting thesis ideas or opportunities, please let me know. The thesis is supposed to take about 6 months, ideally starting early in September. After that it’s time to pack my stuff and look for an employer. I’m hoping for a position in open source software development. Areas I’m particularly interested in include Linux, mobile computing, desktop-related technologies as well as renewable energy, environment protection and open government. I’m here to make a difference.

On to something else. A few weeks ago I was offered sponsoring in order to work on thunar-volman for a few days. I accepted the offer, so for the entire next week from 2010-07-19 to 2010-07-26 (including the weekend) I’ll do some sponsored work on porting Thunar and thunar-volman to udev and GIO! The goal is to finish all major features (storage devices, cameras etc.).

Yesterday I did some warm-up hacking on tumbler to verify that if I’m still up to the task. The results: a new ffmpegthumbnailer-based video thumbnailer plugin (written by Lionel Le Folgoc), a new PDF/PostScript thumbnailer plugin based on poppler-glib and a new tumbler release (0.1.2). The master branch contains another commit adding arbitrary URI support to the PDF/PostScript thumbnailer but for that you’ll have to wait until the next release.

That’s it for now, I’ll be a lot more active next week. Take care everyone!

Xfce 4.8 Schedule Changes

  • January 26, 2010
  • Jannis Pohlmann

As the Xfce release manager, I’d prefer to be the bringer of good news. Unfortunately, we have to make some adjustments with regards to the Xfce 4.8 release schedule.

You may well remember last year’s chaos with the 4.6 release date. We’re trying our best not to repeat that and if it should happen again, we’ll at least keep you posted about the issues as good as we can.

So, what’s the deal with 4.8?

One thing that hasn’t changed much is that our development team is very small. A hobby project of this size requires a certain amount of time to be invested by each individual developer. Time not everyone has as much has he would like to dedicate to Xfce.

Today, Brian announced his absence for the coming months due to his new job, leaving 2-3 of our core components (xfdesktop, xfconf and xfce4-session) more or less unmaintained (aside from bugfixes). The good news is that Jérôme (who has recently started to improve xfce4-settings and port xfce4-session to libxfce4ui) and Daniel (the maintainer of the thunar-shares-plugin) have offered their help with xfdesktop and xfce4-session.

Brian is not the only one having little time at hand though. I’m preparing myself for my final university exams, so ideally I’d be sticking my nose into lecture notes all day long. I still have the time to write mails like this but there hasn’t been much activity around thunar and related projects lately.

Again, I’m really happy to see people volunteering to help because that’s what we need right now. There’s a lot left to do before we can release 4.8. Let me get to that now.

As some of might have heard, thunar was ported to GIO this summer. Through GVfs, GIO brings new features such as SMB, SFTP, FTP browsing which some people use one a daily basis already. Now, GVfs has turned out to be problematic for us for various reasons. At first it shipped a HAL-based volume monitor with a hard-coded dependency on gnome-mount. Today it ships a volume monitor based on gnome-disk-utility (uses DeviceKit-disks itself) which proves to be inconsistent and somewhat incompatible to the HAL mounting code in exo.

The result: thunar-volman (not part of the core but important for thunar nonetheless) and xfdesktop will have to be ported to udev (the mounting being done with GIO, ideally). I’ve started working on this but this is far from being finished.

Question to the other developers: Didn’t xfce4-session use HAL for logging out and stuff? We might have to look into replacing those portions of code with something based on ConsoleKit, I guess?

HAL/udev is not the only issue however. With Xfce 4.8 we’ll be replacing libxfcegui4 with a new library called libxfce4ui. Not all core applications (again, xfdesktop being one of them, I think) have been ported to it yet. In most cases, this is no big deal and probably could be resolved within a few days though.

Then we have garcon, the much improved menu library that is supposed to replace libxfce4menu. At the time of writing the only feature it is lacking that is crucial for 4.8 is file system monitoring. We’ll probably implement basic monitoring like we had in libxfce4menu. Work on this hasn’t started yet.

Also, xfdesktop needs to be ported not only from ThunarVFS/HAL to GIO/udev but also from libxfce4menu to garcon.

So, as you can see there is quite a lot of work ahead of us. Taking into account the little free time some of us have these days, we’ve decided to postpone the 4.8 release until June 12th instead of April 12th. The entire release phase in our schedule has been moved by two months in time, as you can see on the official schedule wiki page:

 http://wiki.xfce.org/releng/4.8/schedule

To be honest, I wouldn’t consider this new date fixed either. It all depends on how much we can do until the feature freeze on April 1st. I’m optimistic that meeting the deadlines is possible though.

For all of you who can’t wait until June, try out our development releases which are announced on http://identi.ca/xfce. I have at least something good to share: For a few weeks now I’ve been running Fedora 12 with a mixture of Xfce 4.6 packages and development package from the upcoming 4.8 series and the new components have proven to be very stable already.

I’m especially happy about the new panel which works almost flawlessly (except for a few dual head issues) and not only supports real transparency and more comfortable launcher creation based on garcon, but is also compatible to panel plugins written for Xfce 4.6. (Good work, Nick!)

So, I guess this is it. A mixture of good and bad. I hope nobody is too disappointed. As always, we’re doing the best we can.

Cheers!

News From Busyland

  • November 25, 2009
  • Jannis Pohlmann

This is just a short heads up concerning Tumbler. I just merged Philip’s last critical commit to complete support for specialized thumbnailer services into master. We’ll have to give this some testing but I’m quite optimistic that we’ll be able to release 0.1.0 this weekend or next week. A new release of Thunar will follow shortly after that in preparation for 1.2 (to be released along with Xfce 4.8), supporting virtual and remote file systems based on GIO.

I’ve been pretty occupied lately. Aside from learning for my final university exams I finished my short thesis on porting Thunar to GIO. I already got the very positive results back and I’m going to publish the official version of the thesis soon. Unfortunately, being busy has started to cause not-so-positive developments as well. I haven’t had much time to hack on anything lately and my attendence of FOSDEM 2010 is uncertain. I might still go but I failed to organize anything related to Xfce this year, leaving us without a devroom and talks. So it’d be more like a private meetup rather than an organized team trip with the goal to represent Xfce.

Another consequence of me being busy is that Xfce 4.8 might include less features than planned, at least with regards to the ones I had in mind. For now let’s just hope that I’ll find a little more time for hacking the next months. It doesn’t look too well right now but who knows…

Long Overdue Update

  • September 7, 2009
  • Jannis Pohlmann

I haven't posted anything in a while, but I'm not complaining. The last month I've been mostly busy pretending to be busy. Ok, to be honest, that's not entirely true. Over at Xfce, we have achieved a lot in August:

  • We've moved all Xfce repositories (including the goodies) over to Git. Kudos to Brian for doing most of the work.
  • All Xfce translation updates are now submitted via Transifex. Thanks to the Transifex developers for all the support and for being such a friendly bunch. It amazes me that Dimitris, the founder of Indifex, is also active on our translations mailing list to support people!
  • The migration of the Thunar core to GIO is complete and has been merged into the main development branch. The overall delta was 2.9MB, although admittedly, a big part of that is due to the removal of ThunarVFS, so I can only take credit for about 16,000 of the 24,335 insertions and 6,000 of the 41,356 deletions.
  • We've kicked off the Xfce 4.8 development cycle on August 16th. The schedule and all other details are available on the wiki. Xfce 4.8 is scheduled for April 12th, 2010. Expect development releases of the various core components soon!

Other things I've been planning to blog about but didn't have the time to:

  • Samuel is still busy setting up Buildbot. With less time than he had hoped for at hands this might still take a while.
  • I was provided with a free Linutop 2 in June. I'd like to thank the Linutop company again for this gift! So far, I've only found the time to give it a few test boots but I'm planning to set it up as a Xfce test machine soon. Its limited hardware makes it much better platform than my rather powerful laptop and/or virtual machines for testing the speed and memory demand of Xfce.
  • My thesis is progressing slowly. I think I have at least 3/4 finished now. I'll keep you posted about the result. I'm hoping to kick off the six month learning phase for my final exams before October because a friend of mine is already waiting for me. ;)

News Update

  • June 4, 2009
  • Jannis Pohlmann

A lot of things are going on lately and it turns out I'm way to busy to update my weblog on a regular basis. So, this is just a short post to keep you all updated.

Last two weeks

  • I took a new student job at the university, at the Institute of Theoretical Computer Science, which I love most. I'll be working on haplotyping algorithms.
  • I went to Barcelona and had a great time at the Ubuntu Developer Summit overall. Stephan and I were very productive. One evening during dinner we discussed our development and release process and later started writing it down. The result is a beautiful document that still needs a bit of polishing. I hope it'll serve as a good foundation for the development and release process of Xfce in the future. Several others commented on it and it looks like we'll give the proposed concept a shot after we've switched to git and all that.
  • Even though the week in Barcelona was great for Xfce, I was disappointed with how it went with regards to the cooperation between Xubuntu and Xfce. I talked it through with Stephan and after I got back, I resigned from my position as the Xubuntu Xfce4 Liaison.

At the moment

  • I've started to implement the so-called thumbnail management D-Bus specification. My implementation is called Tumbler and it will hopefully start serving thumbnails for other apps soon. I'm planning to use it in Thunar, Stephan has expressed interest in using it in Ristretto and when discussing the specification and the existing hildon-thumbnail implementation, Philip van Hoof told me that Hildon/Nokia might be interested in dropping hildon-thumbnail in favor of Tumbler if it's flexible enough. I'm working on it as much as I can and I'm hoping to do a release within the next few weeks.
  • I'm still working on the Transifex installation for Xfce. It's already running but I still need to import all the projects, releases and of course create accounts for maintainers automatically.
  • The migration of Xfce to Git is still work in progress. Brian has most of the repository issues sorted out and is now waiting for me to finish the commit mail script. I have two or three possible implementations lying around but I need to have a look at that again.
  • Jim needs the documentation repository next week, so I'm about to set it up.
  • Our Buildbot server has arrived in Sweden. Today I set up the firewall. Samual is taking care of setting up the Buildbot host VM and other things. We're considering to move a lot of the services not related to development (like the Xfce websites) into separate VMs on that server too, in order to make the current server a development-only machine.

Besides that I'm trying to catch up with the work and personal stuff that piled up while I was away last week. And I really should go and sleep.

Writing Your Own GIO Jobs

  • April 7, 2009
  • Jannis Pohlmann

After having moved into a new apartment I'm now back at working on my thesis about Thunar. There are a few things which are solved very differently in GIO than in ThunarVFS. One of them is the way jobs are handled. A job basically is a task which may take a while to run and thus is executed in a separate thread (so it doesn't block the GUI).

ThunarVFS has a framework called ThunarVfsJob. It lets you create different kinds of jobs e.g. for changing file permissions recursively or for computing the total number of files and the total size of a directory. These jobs report back to the GUI thread using signals such as "new-files" (when new files are added and need to picked up by the GUI) or "progress".

GIO has something similar ... but it's not so obvious how it works. When I tried to figure out how to migrate ThunarVfsJob to GIO I thought: hey, GIO must have something like this already! It contains several job-like functions such as g_file_copy_async() after all.

So here's what I found out after spending some time on reading gfile.c and glocalfile.c: there is a job framework in GIO ... but it's hidden behind easy-to-use asynchronous functions. It's based on GCancellable, GAsyncResult and a bunch of callback types. It uses GIOScheduler internally to glue everything together to something that is actually pretty convenient (but still kinda tricky).

So, what do you need in orderto write your own jobs in the GIO style?

First of all, you need an example task. I picked counting files and computing the total size of a directory to understand how it works. What we want is an asynchronous function which does exactly that and uses a callback to report the progress back to the GUI thread ... just like g_file_copy_async() does.

First of all, you define the callback type and two functions for starting the job (sync and async version):

The Public API

typedef void (*GFileCountProgressCallback) (goffset  current_num_files,
                                            goffset  current_num_bytes,
                                            gpointer user_data);

static gboolean 
g_file_deep_count (GFile                     *file,
                   GCancellable              *cancellable,
                   GFileCountProgressCallback progress_callback,
                   gpointer                   progress_callback_data,
                   GError                   **error);

 static void
 g_file_deep_count_async (GFile                     *file,
                          int                        io_priority,
                          GCancellable              *cancellable,
                          GFileCountProgressCallback progress_callback,
                          gpointer                   progress_callback_data,
                          GAsyncReadyCallback        callback,
                          gpointer                   callback_data);

The Implementation

All the function g_file_deep_count_async() will do is to create a GSimpleAsyncResult, put the callback information into it and then tell the GIOScheduler to run the job. Here's how that looks like:

static void 
g_file_deep_count_async (GFile                     *file,
                         int                        io_priority,
                         GCancellable              *cancellable,
                         GFileCountProgressCallback progress_callback,
                         gpointer                   progress_callback_data,
                         GAsyncReadyCallback        callback,
                         gpointer                   callback_data)
{
  GSimpleAsyncResult *result;
  DeepCountAsyncData *data;

  g_return_if_fail (G_IS_FILE (file));

  data = g_new0 (DeepCountAsyncData, 1);
  data->file = g_object_ref (file);
  data->progress_cb = progress_callback;
  data->progress_cb_data = progress_callback_data;

  result = g_simple_async_result_new (G_OBJECT (file), 
                                      callback,
                                      callback_data, 
                                      g_file_deep_count_async);
  g_simple_async_result_set_op_res_gpointer (result, 
                                             data, 
                                             (GDestroyNotify) deep_count_async_data_free); 

  g_io_scheduler_push_job (deep_count_async_thread,
                           result, 
                           g_object_unref, 
                           io_priority, 
                           cancellable);
}

DeepCountAsyncData is a simple struct which needs no further explanation, I think. First data with callback and user data information is added to the GSimpleAsyncResult and then the job is added to the GIOScheduler. As you can see, there is another function involved: deep_count_async_thread. This is the function which runs in a separate thread and does most of the work (well, not quite ... but almost). Here's how it looks like:

static gboolean
deep_count_async_thread (GIOSchedulerJob *job,
                         GCancellable    *cancellable,
                         gpointer         user_data)
{
  GSimpleAsyncResult *res;
  DeepCountAsyncData *data;
  gboolean            result;
  GError             *error = NULL;

  res = user_data;
  data = g_simple_async_result_get_op_res_gpointer (res);

  data->job = job;
  result = g_file_deep_count (data->file, 
                              cancellable, 
                              data->progress_cb != NULL ? deep_count_async_progress_callback : NULL, 
                              data, 
                              &error);

  if (data->progress_cb != NULL)
    g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc) gtk_false, NULL, NULL);

  if (!result && error != NULL)
    {
      g_simple_async_result_set_from_error (res, error);
      g_error_free (error);
    }

  g_simple_async_result_complete_in_idle (res);

  return FALSE;
}

As you can see it runs the synchronous function g_file_deep_count() and makes sure the progress callback is called at least once. It does one more thing though: it defines it's own progress callback: deep_count_async_progress_callback. This is required for the real progress callback to be called inside the GUI thread. This is the code for the internal callback:

static gboolean
deep_count_async_progress_in_main (gpointer user_data)
{
  ProgressData       *progress = user_data;
  DeepCountAsyncData *data = progress->data;

  data->progress_cb (progress->current_num_files, 
                     progress->current_num_bytes, 
                     data->progress_cb_data);

  return FALSE;
}

static void
deep_count_async_progress_callback (goffset  current_num_files,
                                    goffset  current_num_bytes,
                                    gpointer user_data)
{
  DeepCountAsyncData *data = user_data;
  ProgressData       *progress;

  progress = g_new (ProgressData, 1);
  progress->data = data;
  progress->current_num_files = current_num_files;
  progress->current_num_bytes = current_num_bytes;

  g_io_scheduler_job_send_to_mainloop_async (data->job, 
                                             deep_count_async_progress_in_main, 
                                             progress, 
                                             g_free);
}

deep_count_async_progress_callback() is called from within the job thread. It then tells the scheduler to call deep_count_async_progress_in_main from the GUI thread. And finally deep_count_async_progress_in_main calls the real progress callback e.g. to update the GUI.

Now you still haven't seen any code related to counting files and computing the total file size of a directory ... let's get to that now. Here's the synchronous deep count function which is called from within the job thread:

static gboolean  
g_file_deep_count (GFile                     *file,
                   GCancellable              *cancellable,
                   GFileCountProgressCallback progress_callback,
                   gpointer                   progress_callback_data,
                   GError                   **error)
{
  ProgressData data = {
    .data = NULL,
    .current_num_files = 0,
    .current_num_bytes = 0,
  };

  g_return_val_if_fail (G_IS_FILE (file), FALSE); 

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  return g_file_real_deep_count (file, 
                                 cancellable, 
                                 progress_callback, 
                                 progress_callback_data, 
                                 &data, 
                                 error);
}

Damn ... it still doesn't do any real work! Ok, but this time there's no big rat-tail of nested function calls anymore, I promise. There's just one function left: g_file_real_deep_count(). Before we can call it, however, g_file_deep_count() has to initialize the progress data. After that we can call g_file_real_deep_count() recursively and do something useful. Here we go:

static gboolean
g_file_real_deep_count (GFile                     *file,
                        GCancellable              *cancellable,
                        GFileCountProgressCallback progress_callback,
                        gpointer                   progress_callback_data,
                        ProgressData              *progress_data,
                        GError                   **error)
{
  GFileEnumerator *enumerator;
  GFileInfo       *info;
  GFileInfo       *child_info;
  GFile           *child;
  gboolean         success = TRUE;
  
  g_return_val_if_fail (G_IS_FILE (file), FALSE);
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  info = g_file_query_info (file, 
                            "standard::*", 
                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 
                            cancellable, 
                            error);

  if (g_cancellable_is_cancelled (cancellable))
    return FALSE;

  if (info == NULL)
    return FALSE;

  progress_data->current_num_files += 1;
  progress_data->current_num_bytes += g_file_info_get_size (info);

  if (progress_callback != NULL)
    {
      /* Here we call the internal callback */
      progress_callback (progress_data->current_num_files, 
                         progress_data->current_num_bytes, 
                         progress_callback_data);
    }

  if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
    {
      enumerator = g_file_enumerate_children (file, 
                                              "standard::*", 
                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 
                                              cancellable, 
                                              error);
    
      if (!g_cancellable_is_cancelled (cancellable))
        {
          if (enumerator != NULL)
            {
              while (!g_cancellable_is_cancelled (cancellable) && success)
                {
                  child_info = g_file_enumerator_next_file (enumerator, 
                                                            cancellable, 
                                                            error);

                  if (g_cancellable_is_cancelled (cancellable))
                    break;

                  if (child_info == NULL)
                    {
                      if (*error != NULL)
                        success = FALSE;
                      break;
                    }

                  child = g_file_resolve_relative_path (file, g_file_info_get_name (child_info));
                  success = success && g_file_real_deep_count (child, 
                                                               cancellable, 
                                                               progress_callback, 
                                                               progress_callback_data, 
                                                               progress_data, 
                                                               error);
                  g_object_unref (child);
                  g_object_unref (child_info);
                }

              g_object_unref (enumerator);
            }
        }
    }

  g_object_unref (info);

  return !g_cancellable_is_cancelled (cancellable) && success;
}

And that's it. We can now compute the number of files and the total size of a directory recursively using a GCancellable and one or two callbacks. All of this is done using threads, so you don't have to worry about blocking your GUI main loop.

If you want to see this in action, visit the job framework page in my thesis wiki and download deepcount.c and the Makefile.