<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="http://julien.danjou.info">
  <title>
    jd:/dev/blog  </title>
    <link href="http://julien.danjou.info/blog/index.xml" rel="self" />
  
    <link href="http://julien.danjou.info/blog/"/>
  
    
  <updated>2013-05-22T14:45:01Z</updated>

  <id>http://julien.danjou.info/blog/index.xml</id>

    <entry>
    <title type="html">Rant about Github pull-request workflow implementation</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/rant-about-github-pull-request-workflow-implementation"/>
    <updated>2013-05-10T17:55:00Z</updated>
    <published>2013-05-10T17:55:00Z</published>
    <id>/blog/2013/rant-about-github-pull-request-workflow-implementation</id>
        <category   scheme="/blog/tags"
                term="github"
                label="Github" />
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="gerrit"
                label="Gerrit" />
    
    <content type="html">
            &lt;p&gt;One of my recent innocent tweet about &lt;em&gt;Gerrit vs Github&lt;/em&gt; triggered much more
reponses and debate that I expected it to. I realize that it might be worth
explaining a bit what I meant, in a text longer than 140 characters.&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet illustration&#34;&gt;
&lt;p&gt;
I&#39;m having a hard time now contributing to projects not using Gerrit. Github
isn&#39;t that good.&lt;/p&gt;&amp;mdash; Julien Danjou (@juldanjou)
&lt;a href=&#34;https://twitter.com/juldanjou/status/332076595521146881&#34;&gt;May 8, 2013&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&#34;//platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;h1&gt;The problems with Github pull-requests&lt;/h1&gt;
&lt;p&gt;&lt;img class=&#34;illustration pull-right&#34; width=&#34;150&#34; src=&#34;/media/images/github.svg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I always looked at Github from a distant eye, mainly because I always
disliked their pull-request handling, and saw no value in the social hype it
brings. Why?&lt;/p&gt;
&lt;h2&gt;One click away isn&#39;t one click effort&lt;/h2&gt;
&lt;p&gt;The pull-request system looks like an incredible easy way to contribute to
any project hosted on Github. You&#39;re a click away to send your contribution
to any software. But the problem is that any worthy contribution isn&#39;t an
effort of a single click.&lt;/p&gt;
&lt;p&gt;Doing any proper and useful contribution to a software is never done right
the first time. There&#39;s a dance you will have to play. A slowly rhythmed
back and forth between you and the software maintainer or team. You&#39;ll have
to dance it until your contribution is correct and can be merged.&lt;/p&gt;
&lt;p&gt;But as a software maintainer, not everybody is going to follow you on this
choregraphy, and you&#39;ll end up with pull-request you&#39;ll never get finished
unless you wrap things up yourself. So the gain in pull-requests here, isn&#39;t
really bigger than a good bug report in most cases.&lt;/p&gt;
&lt;p&gt;This is where the social argument of Github isn&#39;t anymore. As soon as you&#39;re
talking about projects bigger than a color theme for your favorite text
editor, this feature is overrated.&lt;/p&gt;
&lt;h2&gt;Contribution rework&lt;/h2&gt;
&lt;p&gt;If you&#39;re lucky enough, your contributor will play along and follow you on
this pull-request review process. You&#39;ll make suggestions, he will listen
and will modify his pull-request to follow your advice.&lt;/p&gt;
&lt;p&gt;At this point, there&#39;s two technics he can use to please you.&lt;/p&gt;
&lt;h3&gt;Technic #1: the Topping&lt;/h3&gt;
&lt;p&gt;Github&#39;s pull-requests invite you to send an entire branch, eclipsing the
fact that it is composed of several commits. The problem is that a lot of
one-click-away contributors do not masterize Git and/or do not make efforts
to build a logical patchset, and nothing warns them that their branch
history is wrong. So they tend to change stuff around, commit, make a
mistake, commit, fix this mistake, commit, etc. This kind of branch is
composed of the whole brain&#39;s construction process of your contributor, and
is a real pain to review. To the point I quite often give up.&lt;/p&gt;
&lt;figure&gt;
&lt;img class=&#34;illustration&#34;
src=&#34;/media/images/blog/2013/github-pull-request-iterative.png&#34;&gt;
&lt;figcaption&gt;
A typical case: 3 commits to build a 4 lines long file.
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Without Github, the old method that all software used, and that many
software still use (e.g. Linux), is to send a patch set over e-mail (or any
other medium like Gerrit). This method has one positive effect, that it
forces the contributor to acknowledge the list of commits he is going to
publish. So, if the contributor he has fixup commits in his history, they
are going to be seen as first class citizen. And nobody is going to want to
see that, neither your contributor, nor the software maintainers. Therefore,
such a system tend to push contributors to write atomic, logical and
self-contained patchset that can be more easily reviewed.&lt;/p&gt;
&lt;h3&gt;Technic #2: the History Rewriter&lt;/h3&gt;
&lt;p&gt;This is actually the good way to build a working and logical patchset using
Git. Rewriting history and amending problematic patches using the famous
&lt;em&gt;git rebase --interactive&lt;/em&gt; trick.&lt;/p&gt;
&lt;p&gt;The problem is that if your contributor does this and then repush the branch
composing your pull-request to Github, you will both lose the previous
review done, each time. There&#39;s no history on the different versions of the
branch that has been pushed.&lt;/p&gt;
&lt;p&gt;In the old alternative system like e-mail, no information is lost when
reworked patches are resent, obviously. This is far better because it eases
the following of the iterative discussions that the patch triggered.&lt;/p&gt;
&lt;p&gt;Of course, it would be possible for Github to enhance this and fix it, but
currently it doesn&#39;t handle this use case correctly..&lt;/p&gt;
&lt;figure&gt;
&lt;a href=&#34;https://github.com/hylang/hy/pull/157&#34;&gt;
&lt;img class=&#34;illusration&#34;
src=&#34;/media/images/blog/2013/hylang-pull-request-157.png&#34;&gt;
&lt;/a&gt;
&lt;figcaption&gt;
Exercise for the doubtful readers: good luck finding all revisions of my
patch in the pull-request #157 of Hy.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h1&gt;A quick look at OpenStack workflow&lt;/h1&gt;
&lt;p&gt;&lt;img class=&#34;illustration pull-right&#34; width=&#34;150&#34; src=&#34;/media/images/projects/openstack.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s not a secret for anyone that I&#39;ve been contributing to OpenStack as a
daily routine for the last 18 months. The more I contribute, the more I like
the contribution workflow and process. It&#39;s already
&lt;a href=&#34;https://wiki.openstack.org/wiki/Gerrit_Workflow&#34;&gt;well and longly described on the wiki&lt;/a&gt;,
so I&#39;ll summarize here my view and what I like about it.&lt;/p&gt;
&lt;h2&gt;Gerrit&lt;/h2&gt;
&lt;p&gt;To send a contribution to any OpenStack project, you need to pass via
Gerrit. This is way simpler than doing a pull-request on Github actually,
all you have to do is do your commit(s), and type
&lt;a href=&#34;https://pypi.python.org/pypi/git-review&#34;&gt;&lt;em&gt;git review&lt;/em&gt;&lt;/a&gt;. That&#39;s it. Your
patch will be pushed to Gerrit and available for review.&lt;/p&gt;
&lt;p&gt;Gerrit allows other developers to review your patch, add comments anywhere
on it, and score your patch up or down. You can build any rule you want for
the score needed for a patch to be merged; OpenStack requires one positive
scoring from two core developers before the patch is merged.&lt;/p&gt;
&lt;p&gt;Until a patch is validated, it can be reworked and amended locally using
Git, and then resent using
&lt;em&gt;git review&lt;/em&gt; again. That simple.
The historic and the different version of the patches are available, with
the whole comments. Gerrit doesn&#39;t lose any historic information on your
workflow.&lt;/p&gt;
&lt;p&gt;Finally, you&#39;ll notice that this is actually the same kind of workflow
projects use when they work by patch sent over e-mail. Gerrit just build a
single place to regroup and keep track of patchsets, which is really handy.
It&#39;s also much easier for people to actually send patch using a command line
tool than their MUA or &lt;em&gt;git send-email&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Gate testing&lt;/h2&gt;
&lt;p&gt;Testing is mandatory for any patch sent to OpenStack. Unit tests and
functionnals test are run for &lt;em&gt;each version of each patch of the patchset&lt;/em&gt;
sent. And until your patch passes all tests, it will be &lt;em&gt;impossible&lt;/em&gt; to
merge it.
Yes, this implies that all patches in a patchset must be working commits and
can be merged on their own, without the entire patchset going in! With such
a restricution, it&#39;s impossible to have &#34;fixup commits&#34; merged in your
project and pollute the history and the testability of the project.&lt;/p&gt;
&lt;p&gt;Once your patch is validated by core developers, the system checks that
there is not any merge conflicts. If there&#39;s not, tests are re-run, since
the branch you are pushing to might have changed, and if everything&#39;s fine,
the patch is merged.&lt;/p&gt;
&lt;p&gt;This is an uncredible force for the quality of the project. This implies
that no broken patchset can ever sneak in, and that the project pass always
all tests.&lt;/p&gt;
&lt;h1&gt;Conclusion: accessibility vs code review&lt;/h1&gt;
&lt;p&gt;In the end, I think that one of the key of any development process, which is
code review, is not well covered by Github pull-request system. It is, along
with history integrity, damaged by the goal of making contributions easier.&lt;/p&gt;
&lt;p&gt;Choosing between these features is probably a trade-off that each project
should do carefully, considering what are its core goals and the quality of
code it want to reach.&lt;/p&gt;
&lt;p&gt;I tend to find that OpenStack found one of the best trade-off available
using Gerrit and plugging testing automation via Jenkins on it, and I would
probably recommend it for any project taking seriously code reviews and
testing.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OpenStack Design Summit Havana, from a Ceilometer point of view</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/openstack-summit-havana-ceilometer"/>
    <updated>2013-04-25T14:49:45Z</updated>
    <published>2013-04-25T14:49:45Z</published>
    <id>/blog/2013/openstack-summit-havana-ceilometer</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;p&gt;Last week was the
&lt;a href=&#34;https://www.openstack.org/summit/portland-2013/&#34;&gt;OpenStack Design Summit&lt;/a&gt;
in Portland, OR where we, developers, discussed and designed the new
OpenStack release (Havana) coming up.&lt;/p&gt;
&lt;p&gt;&lt;img class=&#34;illustration&#34; src=&#34;/media/images/blog/2013/ods_havana_banner.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The summit has been wonderful. It was my first OpenStack design summit --
even more as a PTL -- and bumping into various people I&#39;ve never met so far
and worked with online only was a real pleasure!&lt;/p&gt;
&lt;figure&gt;
&lt;img width=&#34;500&#34; class=&#34;illustration shadow&#34; src=&#34;/media/images/blog/2013/ods_havana_ceilometer_nijaba_jd_talk.jpg&#34;&gt;
&lt;figcaption&gt;Me and Nick ready to talk about Ceilometer new features.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&#34;http://nicolas.barcet.com/&#34;&gt;Nick Barcet&lt;/a&gt; from
&lt;a href=&#34;http://www.enovance.com&#34;&gt;eNovance&lt;/a&gt;, our dear previous Ceilometer PTL, and
myself, talked about Ceilometer and presented the work that bas been done
for Grizzly, with some previews of what we&#39;ll like to see done for its
Havana release. You can take a look at
&lt;a href=&#34;http://julien.danjou.info/media/Ceilometer%20presentation%20ODS%20Havana.pdf&#34;&gt;the slides&lt;/a&gt;
if you&#39;re curious.&lt;/p&gt;
&lt;h1&gt;Design sessions&lt;/h1&gt;
&lt;p&gt;Ceilometer had his design sessions during the last days of the summit. We
noted a lot of things and commented during the sessions in our
&lt;a href=&#34;https://wiki.openstack.org/wiki/Summit/Havana/Etherpads#Ceilometer&#34;&gt;Etherpads instances&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first session was a description of Ceilometer core architecture for
interested people, and was a wonderful success considering that the room was
packed. Our &lt;a href=&#34;http://doughellmann.com/&#34;&gt;Doug Hellmann&lt;/a&gt; did a wonderful job
introducing people to Ceilometer and answering question.&lt;/p&gt;
&lt;figure&gt;
&lt;img width=&#34;500&#34; class=&#34;illustration shadow&#34; src=&#34;/media/images/blog/2013/ods_havana_ceilometer_dhellmann.jpg&#34;&gt;
&lt;figcaption&gt;Doug explaining Ceilometer architecture.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The next session was about getting feedbacks from our users. We had a lot of
surprise to discover wonderful real use-cases and deployments, like the CERN
using Ceilometer and generating 2 GB of data per day!&lt;/p&gt;
&lt;p&gt;The following sessions ran on Thursday and were much more about new features
discussion. A lot ot already existing blueprints were discussed and quickly
validated during the first morning session. Then,
&lt;a href=&#34;http://www.sandywalsh.com/&#34;&gt;Sandy Walsh&lt;/a&gt; introduced the architecture they
use inside &lt;a href=&#34;https://github.com/rackerlabs/stacktach&#34;&gt;StackTach&lt;/a&gt;, so we can
start thinking about getting things from it into Ceilometer.&lt;/p&gt;
&lt;p&gt;API improvements were discussed without surprises and with a good consensus
on what needs to be done. The four following sessions that occupied a lot of
the days were related to alarming. All were lead by Eoghan Glynn, from
&lt;a href=&#34;http://redhat.com&#34;&gt;RedHat&lt;/a&gt;, who did an amazing job presenting the possible
architectures with theirs pros and cons. Actually, all we had to do was to
nod to his designs and acknowledge the plan on how to build this.&lt;/p&gt;
&lt;p&gt;That last two sessions were about discussing advanced models for billing
where we got some interesting feedback from Daniel Dyer from HP, and then
were a quick follow-up of the StackTach presentation from the morning
session.&lt;/p&gt;
&lt;h1&gt;Havana roadmap&lt;/h1&gt;
&lt;p&gt;The
&lt;a href=&#34;https://blueprints.launchpad.net/ceilometer/havana&#34;&gt;list of blueprints targetting Havana is available&lt;/a&gt;
and should be finished by next week. If you want to propose blueprints,
you&#39;re free to do so and inform us about it so we can validate it. The same
applies if you wish to implement one of them!&lt;/p&gt;
&lt;h2&gt;API extension&lt;/h2&gt;
&lt;p&gt;I do think the API version 2 is going to be heavily extended during this
release cycle. We need more feature, like the
&lt;a href=&#34;https://blueprints.launchpad.net/ceilometer/+spec/api-group-by&#34;&gt;group-by&lt;/a&gt;
functionnality.&lt;/p&gt;
&lt;h2&gt;Healthnmon&lt;/h2&gt;
&lt;p&gt;In parallel of the design sessions, discussions took place in the
unconference room with the Healthnmon developers to figure out a plan in
order to merge some of their efforts into Ceilometer. They should provide a
component to help Ceilometer supports more hypervisors than it currently
does.&lt;/p&gt;
&lt;h2&gt;Alarming&lt;/h2&gt;
&lt;p&gt;Alarming is definitely going to be the next big project for Ceilometer.
Today, Eoghan and I started building blueprints on alarming,
&lt;a href=&#34;https://blueprints.launchpad.net/ceilometer/+spec/alarming&#34;&gt;centralized in a general blueprint&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We know this is going to happen for real and very soon, thanks to the
engagements of &lt;a href=&#34;http://enovance.com&#34;&gt;eNovance&lt;/a&gt; and
&lt;a href=&#34;http://redhat.com&#34;&gt;RedHat&lt;/a&gt; who are commiting resources to this amazing
project!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Hy, Lisp in Python</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/lisp-python-hy"/>
    <updated>2013-04-03T22:01:20Z</updated>
    <published>2013-04-03T22:01:20Z</published>
    <id>/blog/2013/lisp-python-hy</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="hy"
                label="Hy" />
        <category   scheme="/blog/tags"
                term="lisp"
                label="Lisp" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve meant to look at &lt;a href=&#34;http://github.com/paultag/hy&#34;&gt;Hy&lt;/a&gt; since
&lt;a href=&#34;http://http://blog.pault.ag/&#34;&gt;Paul Tagliamonte&lt;/a&gt; started to talk to me about
it, but never took a chance until now.
Yesterday, Paul indicated it was a good time for me to start looking at it,
so I spent a few hours playing.&lt;/p&gt;
&lt;h1&gt;But what&#39;s Hy?&lt;/h1&gt;
&lt;p&gt;Python is very nice: it has a great community and a wide range of useful
libraries. But let&#39;s face it, it misses a great language.&lt;/p&gt;
&lt;p&gt;Hy is an implementation of a
&lt;a href=&#34;http://en.wikipedia.org/wiki/Lisp_(programming_language)&#34;&gt;Lisp&lt;/a&gt; on top of
Python.&lt;/p&gt;
&lt;p&gt;Technically, Hy is built directly with a custom made parser (for now) which
then translates expressions using the
&lt;a href=&#34;http://docs.python.org/2/library/ast.html&#34;&gt;Python AST&lt;/a&gt; module to generate
code, which is then run by Python. Therefore, it shares the same properties
as Python, and is a Lisp-1 (i.e. with a single namespace for symbols and
functions).&lt;/p&gt;
&lt;p&gt;If you&#39;re interested to listen Paul talking about Hy during last PyCon US, I
recommend watching his lightning talk. As the name implies, it&#39;s only a few
minutes long.&lt;/p&gt;
&lt;iframe width=&#34;500&#34; height=&#34;374&#34; class=&#34;shadow&#34;
src=&#34;http://www.youtube.com/embed/1vui-LupKJI?wmode=transparent&amp;autohide=1&amp;egm=0&amp;hd=1&amp;iv_load_policy=3&amp;modestbranding=1&amp;rel=0&amp;showinfo=0&amp;showsearch=0#t=16m14s&#34;
frameborder=&#34;0&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;h1&gt;Does it work?&lt;/h1&gt;
&lt;p&gt;I&#39;ve been cloning the code and played around a bit with Hy. And to my
greatest surprise and pleasure, it works quite well. You can imagine writing
Python from there easily. Part of the syntax smells like
&lt;a href=&#34;http://clojure.org&#34;&gt;Clojure&lt;/a&gt;&#39;s, which looks like a good thing since they&#39;re
playing in the same area.&lt;/p&gt;
&lt;p&gt;You can try a &lt;a href=&#34;http://hy.pault.ag/&#34;&gt;Hy REPL&lt;/a&gt; in your Web browser if you
want.&lt;/p&gt;
&lt;p&gt;Here&#39;s what some code look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;requests&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;setv&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;requests.get&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://hy.pault.ag&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;req.status_code&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;for &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;kv&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;.iteritems&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;req.headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;print &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;kv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Wrong status code&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This code would ouput:&lt;/p&gt;
&lt;pre&gt;
(&#39;date&#39;, &#39;Wed, 03 Apr 2013 12:09:23 GMT&#39;)
(&#39;connection&#39;, &#39;keep-alive&#39;)
(&#39;content-encoding&#39;, &#39;gzip&#39;)
(&#39;transfer-encoding&#39;, &#39;chunked&#39;)
(&#39;content-type&#39;, &#39;text/html; charset=utf-8&#39;)
(&#39;server&#39;, &#39;nginx/1.2.6&#39;)
&lt;/pre&gt;

&lt;p&gt;As you can see, it&#39;s really simple to write Lispy code that really uses
Python idioms.&lt;/p&gt;
&lt;p&gt;There&#39;s obviously still a lots of missing features in Hy. The language if
far from complete and many parts are moving, but it&#39;s really promising, and
Paul&#39;s doing a great job implementing every idea.&lt;/p&gt;
&lt;p&gt;&lt;img class=&#34;illustration shadow rounded&#34; src=&#34;/media/images/hy-photo.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I actually started to hack a bit on Hy, and will try to continue to do so,
since I&#39;m really eager to learn a bit more about both Lisp and Python
internals in the process. I&#39;ve already send a few patches on small bugs I&#39;ve
encountered, and proposed a few ideas. It&#39;s really exciting to be able to
influence early a language design that I&#39;ll love to use! Being a recent fan
of Common Lisp, I tend to grab the good stuff from it to add them into Hy.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Announcing Climate, the OpenStack capacity leasing project</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/openstack-climate-capacity-leasing"/>
    <updated>2013-03-25T17:49:23Z</updated>
    <published>2013-03-25T17:49:23Z</published>
    <id>/blog/2013/openstack-climate-capacity-leasing</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="climate"
                label="Climate" />
    
    <content type="html">
            &lt;p&gt;While working on the &lt;a href=&#34;http://xlcloud.org/bin/view/Main/&#34;&gt;XLcloud project&lt;/a&gt;
(HPC on cloud) it appeared clear to us that OpenStack was missing a critical
component towards resource reservations.&lt;/p&gt;
&lt;div class=&#34;pull-left&#34;&gt;
    &lt;img width=&#34;120&#34; src=&#34;/media/images/calendar-reservation.jpg&#34;&gt;
&lt;/div&gt;

&lt;p&gt;A capacity leasing service is something really needed by service providers,
especially in the context of cloud platforms dedicated to HPC style
workload. Instead of building something really specific, the decision has
been made to build a new standalone OpenStack components aiming to provide
this kind of functionnality to OpenStack. In the spirit of others OpenStack
components, it will be extensible to fullfil a large panel of needs around
this problematic.&lt;/p&gt;
&lt;div class=&#34;pull-right&#34;&gt;
    &lt;img width=&#34;80&#34; src=&#34;/media/images/projects/openstack.png&#34;&gt;
&lt;/div&gt;

&lt;p&gt;The project is named &lt;a href=&#34;http://launchpad.net/climate&#34;&gt;Climate&lt;/a&gt;, and is hosted
on &lt;a href=&#34;http://ci.openstack.org/stackforge.html&#34;&gt;StackForge&lt;/a&gt;. It will follow the
standard OpenStack development modal. This service will be able to handle a
calendar of reservations for various resources, based on various criteria.&lt;/p&gt;
&lt;p&gt;The project is still at its early design stage, and we plan to have a
unconference session during
&lt;a href=&#34;http://www.openstack.org/summit/portland-2013/&#34;&gt;the next OpenStack summit in Portland&lt;/a&gt;
to present our plans and ideas for the future!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Ceilometer bug squash day &amp;#35;2</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/ceilometer-bug-squash-day-2"/>
    <updated>2013-03-04T11:55:00Z</updated>
    <published>2013-03-04T11:55:00Z</published>
    <id>/blog/2013/ceilometer-bug-squash-day-2</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;p&gt;The Ceilometer team is pleased &lt;a href=&#34;http://lists.openstack.org/pipermail/openstack-dev/2013-March/006188.html&#34;&gt;to
announce&lt;/a&gt;
that tomorrow &lt;a href=&#34;http://wiki.openstack.org/Ceilometer/BugSquashingDay/20130304&#34;&gt;Tuesday 5th March 2013 will be the second bug squash day for
Ceilometer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We wrote an extensive page about &lt;a href=&#34;http://wiki.openstack.org/Ceilometer/Contributing&#34;&gt;how you can contribute to
Ceilometer&lt;/a&gt;, from
updating the documentation, to fixing bugs. There&#39;s a lot you can do. We&#39;ve
good support for Ceilometer built into &lt;a href=&#34;http://devstack.org&#34;&gt;Devstack&lt;/a&gt;, so
installing a development platform is really easy.&lt;/p&gt;
&lt;p&gt;The main goal for this bug day will be to put Ceilometer in the best
possible shape before the &lt;em&gt;grizzly-rc1&lt;/em&gt; release arrives (14th March 2013).
This version of Ceilometer &lt;em&gt;should&lt;/em&gt; be the last one before the final Grizzly
release, so it&#39;s a pretty important one.&lt;/p&gt;
&lt;p&gt;We&#39;ll be hanging out on the &lt;em&gt;#openstack-metering&lt;/em&gt; IRC channel on
&lt;a href=&#34;http://freenode.net&#34;&gt;Freenode&lt;/a&gt;, as usual, so feel free to come by and join
us!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OpenStack Ceilometer and Heat projects graduated</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/openstack-ceilometer-head-graduated"/>
    <updated>2013-02-27T14:49:45Z</updated>
    <published>2013-02-27T14:49:45Z</published>
    <id>/blog/2013/openstack-ceilometer-head-graduated</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;div class=&#34;pull-right clear&#34;&gt;
  &lt;img width=&#34;150&#34; src=&#34;/media/images/openstack-tech-committee.jpg&#34;&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;a href=&#34;http://www.openstack.org/foundation/technical-committee/&#34;&gt;OpenStack Technical
Committee&lt;/a&gt; have
voted these last weeks about graduation of
&lt;a href=&#34;https://launchpad.net/heat&#34;&gt;Heat&lt;/a&gt; and
&lt;a href=&#34;http://launchpad.net/ceilometer&#34;&gt;Ceilometer&lt;/a&gt;, to change their status from
&lt;strong&gt;incubation&lt;/strong&gt; to &lt;strong&gt;integrated&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The details of the discussion can be found in the
&lt;a href=&#34;http://eavesdrop.openstack.org/meetings/tc/2013/&#34;&gt;TC IRC meetings logs&lt;/a&gt; for
the brave. The results are:&lt;/p&gt;
&lt;dl&gt;
  &lt;dt&gt;Approve graduation of Heat (to be integrated in common Havana release)?&lt;/dt&gt;
  &lt;dd&gt;yes: 10, abstain: 1, no: 1&lt;/dd&gt;
  &lt;dt&gt;Approve graduation of Ceilometer (to be integrated in common Havana release)?&lt;/dt&gt;
  &lt;dd&gt;yes: 11, abstain: 1&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;Therefore both projects have been graduated from &lt;em&gt;Incubation&lt;/em&gt; to
&lt;em&gt;Integrated&lt;/em&gt; status. That means that Heat and Ceilometer will be released as
part as OpenStack for the next release cycle &lt;em&gt;Havana&lt;/em&gt;, due in Autumn 2013.&lt;/p&gt;
&lt;p&gt;For people being curious, we the Ceilometer team put up a &lt;a href=&#34;https://wiki.openstack.org/wiki/Ceilometer/Graduation&#34;&gt;nice wiki page
about our status and what we think we were ready to
jump&lt;/a&gt;. For the
curious, The &lt;a href=&#34;https://wiki.openstack.org/wiki/Governance/Foundation/TechnicalCommittee&#34;&gt;OpenStack Technical Committee
charter&lt;/a&gt;
has some explanations about the incubation and integration process.&lt;/p&gt;
&lt;h1&gt;What about Grizzly?&lt;/h1&gt;
&lt;p&gt;Both projects will be released with Grizzly too, obviously, since they
already follow the release process of OpenStack.&lt;/p&gt;
&lt;h1&gt;What about core?&lt;/h1&gt;
&lt;div class=&#34;pull-left clear&#34;&gt;
  &lt;img width=&#34;120&#34; src=&#34;/media/images/projects/openstack.png&#34;&gt;
&lt;/div&gt;

&lt;p&gt;The question that has been raised several times to me is if that means the
projects are becoming &lt;em&gt;Core&lt;/em&gt; projects. The answer is no, because how to
become a &lt;em&gt;Core&lt;/em&gt; project is still under discussion and is more a matter for
the &lt;em&gt;Board of Directors&lt;/em&gt; than the &lt;em&gt;Technical Committee&lt;/em&gt;. But this is
definitely a step in this direction.&lt;/p&gt;
&lt;p&gt;Anyway, from a technical point of view, this means both projects are now
onboard with other OpenStack components so you can enjoy them!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Cloud tools for Debian</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/cloud-init-utils-debian"/>
    <updated>2013-02-13T13:21:45Z</updated>
    <published>2013-02-13T13:21:45Z</published>
    <id>/blog/2013/cloud-init-utils-debian</id>
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
        <category   scheme="/blog/tags"
                term="ubuntu"
                label="Ubuntu" />
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
    
    <content type="html">
            &lt;p&gt;Recently, I&#39;ve worked on the cloud utilities that are provided as standard
in Ubuntu, and I ported them to Debian. Let&#39;s see how that brings Debian to
the cloud!&lt;/p&gt;
&lt;h1&gt;Basics of a cloud image&lt;/h1&gt;
&lt;p&gt;When starting an instance on a IaaS platform, your instance image is raw,
un-configured. Therefore, you need to have a way to configure it
automagically at boot time, based on what you want to do with it. Usually,
IaaS platforms provides for this a metadata server, like
&lt;a href=&#34;http://aws.amazon.com/ec2&#34;&gt;Amazon EC2&lt;/a&gt; does. It&#39;s a special HTTP server
listening on a special and hard-coded IP address that your instance can
request to know basic information about itself, like its hostname, and
retrieve basic user metadata to auto-configure itself. You can check the
&lt;a href=&#34;http://docs.openstack.org/trunk/openstack-compute/admin/content/metadata-service.html&#34;&gt;documentation about the OpenStack metadata service&lt;/a&gt;
for more information.&lt;/p&gt;
&lt;p&gt;Also, image have a predefined size at upload time. So when you run it on a
platform, the disk size you request is usually bigger than the size of your
image disk: you mayneed to resize and grow your image to use the full disk
space that is allocated to your instance.&lt;/p&gt;
&lt;h1&gt;Needed tools&lt;/h1&gt;
&lt;div class=&#34;pull-right&#34;&gt;
    &lt;img width=&#34;120&#34; src=&#34;/media/images/debian-cloud.jpg&#34;&gt;
&lt;/div&gt;

&lt;p&gt;To run a cloud platform, and especially
&lt;a href=&#34;http://aws.amazon.com/ec2&#34;&gt;Amazon EC2&lt;/a&gt; or
&lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt;, you need to configure and update your
image based on the context you&#39;re started in. This also includes extending
your template image disk to use the full available disk size provided to the
running instance.&lt;/p&gt;
&lt;p&gt;Ubuntu provides a set of cloud utils, which is actually composed of
different source packages (&lt;em&gt;cloud-init&lt;/em&gt;, &lt;em&gt;cloud-utils&lt;/em&gt; and
&lt;em&gt;clout-initiramfs-tools&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Combined, these 3 packages will allow you to run a number of step, from disk
resize at boot time to Puppet configuration handling.&lt;/p&gt;
&lt;p&gt;So &lt;em&gt;Ubuntu&lt;/em&gt; got this working right a long time ago, but unfortunately,
Debian was really late on that.&lt;/p&gt;
&lt;p&gt;Until now.&lt;/p&gt;
&lt;p&gt;I&#39;ve worked on getting these into Debian, and you can now find these 3
packages adapted and uploaded to Debian sid.&lt;/p&gt;
&lt;p&gt;All you need to do, is to build a Debian image and then run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;apt-get install cloud-init cloud-tools cloud-initiramfs-growroot&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
And voilà: at the next reboot, your instance will extend its root partition
size to the full available disk size, and ask the metadata server to
configure things like its hostname.&lt;/p&gt;
&lt;p&gt;The packages sources are available on Debian&#39;s git server for
&lt;a href=&#34;http://anonscm.debian.org/gitweb/?p=collab-maint/cloud-utils.git;a=summary&#34;&gt;cloud-utils&lt;/a&gt;
and
&lt;a href=&#34;http://anonscm.debian.org/gitweb/?p=collab-maint/cloud-initramfs-tools.git;a=summary&#34;&gt;cloud-initramfs-tools&lt;/a&gt;
and you can build them yourself until the packages are processed by
ftp-master and get out of the
&lt;a href=&#34;http://ftp-master.debian.org/new.html&#34;&gt;NEW queue&lt;/a&gt;. cloud-init on the other
hand is directly
&lt;a href=&#34;http://packages.debian.org/search?keywords=cloud-init&#34;&gt;available in sid&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of next steps would probably be to build or enhance a tool like
&lt;a href=&#34;https://launchpad.net/vmbuilder&#34;&gt;vmbuilder&lt;/a&gt; to be able to build
cloud-compatible Debian images with a simple command line.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Going to FOSDEM 2013</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/going-to-fosdem"/>
    <updated>2013-01-29T22:01:20Z</updated>
    <published>2013-01-29T22:01:20Z</published>
    <id>/blog/2013/going-to-fosdem</id>
        <category   scheme="/blog/tags"
                term="fosdem"
                label="Fosdem" />
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
    
    <content type="html">
            &lt;div class=&#34;pull-right&#34;&gt;
    &lt;img width=&#34;120&#34; src=&#34;/media/images/fosdem.png&#34;&gt;
&lt;/div&gt;

&lt;p&gt;For the first time, I&#39;ll be at &lt;a href=&#34;http://fosdem.org&#34;&gt;FOSDEM 2013&lt;/a&gt; in Brussels
on Sunday 2nd February 2013.&lt;/p&gt;
&lt;p&gt;You&#39;ll find me probably hanging out in the
&lt;a href=&#34;https://fosdem.org/2013/schedule/track/cloud&#34;&gt;cloud devroom&lt;/a&gt;
where I&#39;ll
&lt;a href=&#34;https://fosdem.org/2013/schedule/event/openstack_ceilometer/&#34;&gt;talk about Ceilometer&lt;/a&gt;
with my fellow developers &lt;a href=&#34;http://nicolas.barcet.com&#34;&gt;Nick Barcet&lt;/a&gt; and
&lt;a href=&#34;http://eoghang.blogspot.fr/&#34;&gt;Eoghan Glynn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also hope I&#39;ll find time to take a peek at some other talks, like
&lt;a href=&#34;http://tapoueh.org/blog/2013/01/29-FOSDEM-2013.html&#34;&gt;PostgreSQL&#39;s ones that Dimitri Fontaine will handle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you there!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Extending Swift with middleware: example with ClamAV</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/extending-swift-with-a-middleware-clamav"/>
    <updated>2013-01-22T09:37:45Z</updated>
    <published>2013-01-22T09:37:45Z</published>
    <id>/blog/2013/extending-swift-with-a-middleware-clamav</id>
        <category   scheme="/blog/tags"
                term="swift"
                label="Swift" />
        <category   scheme="/blog/tags"
                term="clamav"
                label="Clamav" />
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
    
    <content type="html">
            &lt;div class=&#34;pull-left&#34;&gt;
    &lt;img width=&#34;120&#34; src=&#34;/media/images/openstack-virus.jpg&#34;&gt;
&lt;/div&gt;

&lt;p&gt;In this article, I&#39;m going to explain you how you can extend
&lt;a href=&#34;http://launchpad.net/swift&#34;&gt;Swift&lt;/a&gt;, the &lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt;
Object Storage project, so it performs extra action on files at upload or at
download time.&lt;/p&gt;
&lt;p&gt;We&#39;re going to build an anti-virus filter inside Swift. The goal is to
refuse uploaded data if they contain a virus. To help us with virus
analyses, we&#39;ll use &lt;a href=&#34;http://www.clamav.net&#34;&gt;ClamAV&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;WSGI, paste and middleware&lt;/h1&gt;
&lt;div class=&#34;span3 pull-right thumbnail&#34;&gt;
    &lt;img src=&#34;/media/images/lolcat-tube.jpg&#34;&gt;
    &lt;p&gt;In a pipeline, a black cat can become a white cat with the help of
some middleware.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;To do our content analysis, the best place to hook in the Swift architecture
is at the beginning of every request, on &lt;strong&gt;swift-proxy&lt;/strong&gt;, before the file is
actually stored on the cluster. Swift proxy uses, like many other OpenStack
projects, &lt;a href=&#34;http://pythonpaste.org/&#34;&gt;paste&lt;/a&gt; to build his HTTP architecture.&lt;/p&gt;
&lt;p&gt;Paste uses WSGI and provides an architecture based on a pipeline. The
pipeline is composed of a succession of middleware, ending with one
application. Each middleware has the chance to look at the request or at the
response, can modify it, and then pass it to the following middleware. The
latest component of the pipeline is the real application, and in this case,
the Swift proxy server.&lt;/p&gt;
&lt;p&gt;If you&#39;ve already deployed Swift, you encountered a default pipeline in the
&lt;em&gt;swift-proxy.conf&lt;/em&gt; configuration file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;[pipeline:main]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;na&#34;&gt;pipeline&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;catch_errors healthcheck cache ratelimit tempauth proxy-logging proxy-server&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This is a really basic pipeline with a few middleware. The first one catches
error, the second one is in charge to return &lt;em&gt;200 OK&lt;/em&gt; response if you send a
&lt;em&gt;GET /healthcheck&lt;/em&gt; request on your proxy server. The third one is in charge
of caching, the fourth one is used for rate limiting, the fifth for
authentication, the sixth one for logging, and the final one is the actual
proxy server, in charge of proxying the request to the account, container,
or object servers (the others components of Swift). Of course, we could
remove or add any of the middleware here at our convenience.&lt;/p&gt;
&lt;p&gt;Be aware that the order matters: for example, if you put &lt;em&gt;healthcheck&lt;/em&gt; after
&lt;em&gt;tempauth&lt;/em&gt;, you won&#39;t be able to access the &lt;em&gt;/healthcheck&lt;/em&gt; URL without being
authenticated!&lt;/p&gt;
&lt;h1&gt;ClamAV&lt;/h1&gt;
&lt;div class=&#34;pull-left&#34;&gt;
    &lt;img width=&#34;100&#34; src=&#34;/media/images/clamav.png&#34;&gt;
&lt;/div&gt;

&lt;p&gt;If you don&#39;t know &lt;a href=&#34;http://clamav.org&#34;&gt;ClamAV&lt;/a&gt;, it&#39;s an antivirus engine
designed for detecting trojans, viruses, malware and other malicious
threats. Wwe&#39;re going to use it to scan every incoming file. To build the
middleware, we&#39;ll use the Python binding
&lt;a href=&#34;http://pypi.python.org/pypi/clamd&#34;&gt;pyclamd&lt;/a&gt;. The API is quite simple, see:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;pyclamd&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init_unix_socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;/var/run/clamav/clamd.ctl&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scan_stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EICAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;stream&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;Eicar-Test-Signature(44d88612fea8a8f36de82e1278abb02f:68)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scan_stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;safe!&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;bp&#34;&gt;None&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h1&gt;Anatomy of a WSGI middleware&lt;/h1&gt;
&lt;p&gt;Your WSGI middleware should consist of a callable object. Usually this is
done with a class implementing the &lt;em&gt;__call__&lt;/em&gt; method. Here&#39;s a basic
boilerplate:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;SwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Middleware doing virus scan for Swift.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;c&#34;&gt;# app is the final application&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__call__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;filter_factory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;global_conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local_conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;global_conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local_conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;clamav_filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clamav_filter&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
I&#39;m not going to expand more on why this is built this way, but if you want
to have more info on this kind of filter middleware, you can read
&lt;a href=&#34;http://pythonpaste.org/deploy/#paste-filter-factory&#34;&gt;their documentation on Paste&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This middleware will just do nothing as it is. It&#39;s going to simply pass all
requests it receives to the final application, and returns the result.&lt;/p&gt;
&lt;h1&gt;Testing our basic middleware&lt;/h1&gt;
&lt;div class=&#34;pull-right thumbnail&#34;&gt;
    &lt;img width=&#34;180&#34; src=&#34;/media/images/lolcat-testing.jpg&#34;&gt;
&lt;/div&gt;

&lt;p&gt;Now is a really good time to add unit tests. I hope you didn&#39;t think we were
going to write code without some tests, right? It&#39;s really easy to test a
middleware, as we&#39;re going to use &lt;a href=&#34;http://webob.org/&#34;&gt;WebOb&lt;/a&gt; for that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;unittest&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;webob&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;FakeApp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__call__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;FAKE APP&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;TestSwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unittest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TestCase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;setUp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FakeApp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;test_simple_request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blank&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;                                 &lt;span class=&#34;s&#34;&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assertEqual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;FAKE APP&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
We create a FakeApp class, that represents a fake WSGI application. You
could also use a real application, or write a fake application looking like
the one you want to test. It&#39;ll require more time, but your tests will be
closer to the reality.&lt;/p&gt;
&lt;p&gt;Here we write the simplest test we can for our middleware. We&#39;re just
sending a &lt;em&gt;GET /&lt;/em&gt; request to it, so it passes the request to the final
application and returns the result. It is transparent, it does nothing.&lt;/p&gt;
&lt;p&gt;Now, with that solid base we&#39;ll able to add more features and test these
features incrementally.&lt;/p&gt;
&lt;h1&gt;Plugging ClamAV in&lt;/h1&gt;
&lt;p&gt;With our base ready, we can start thinking about how to plug ClamAV in. What
we want to check here, is the content of the file when it&#39;s uploaded.
If we refer to the
&lt;a href=&#34;http://docs.openstack.org/api/openstack-object-storage/1.0/content/&#34;&gt;OpenStack object storage API&lt;/a&gt;
, a file upload is done via a &lt;em&gt;PUT&lt;/em&gt; request, so we&#39;re going to limit the
check to that kind of requests. Obviously, more checks could be added, but
we&#39;ll keep things simple here for the sake of comprehensibility.&lt;/p&gt;
&lt;p&gt;With WSGI, the content of the request is available in &lt;em&gt;env[&#39;wsgi.input&#39;]&lt;/em&gt; as
an object implementing a file interface. We&#39;ll scan that stream with ClamAV
to check for viruses.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;pyclamd&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;webob&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;SwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Middleware doing virus scan for Swift.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init_unix_socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;/var/run/clamav/clamd.ctl&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;c&#34;&gt;# app is the final application&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__call__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;PUT&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# We have to read the whole content in memory because pyclamd&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# forces us to, but this is a bad idea if the file is huge.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;scan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scan_stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;wsgi.input&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;scan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;403&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Virus &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; detected&amp;quot;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;scan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;stream&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;br /&gt;                                &lt;span class=&#34;n&#34;&gt;content_type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/plain&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;filter_factory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;global_conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local_conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;global_conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local_conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;clamav_filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clamav_filter&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
That&#39;s it. We only check for &lt;em&gt;PUT&lt;/em&gt; requests and if there&#39;s a virus in the
file, we return a 403 Forbidden error with the name of the detected virus,
bypassing entirely the rest of the middleware chain and the application
handling.&lt;/p&gt;
&lt;p&gt;Then, we can simply test it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;unittest&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;cStringIO&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;webob&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;FakeApp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__call__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;FAKE APP&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;TestSwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unittest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TestCase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;setUp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SwiftClamavMiddleware&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FakeApp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;test_put_empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blank&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;/v1/account/container/object&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;                                 &lt;span class=&#34;s&#34;&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assertEqual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;FAKE APP&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;test_put_no_virus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blank&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;/v1/account/container/object&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;                                 &lt;span class=&#34;s&#34;&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                 &lt;span class=&#34;s&#34;&gt;&amp;#39;wsgi.input&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;foobar&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assertEqual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;FAKE APP&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;test_put_virus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blank&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;/v1/account/container/object&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;                                 &lt;span class=&#34;s&#34;&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                 &lt;span class=&#34;s&#34;&gt;&amp;#39;wsgi.input&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StringIO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pyclamd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EICAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assertEqual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;403&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
The first test &lt;em&gt;test_put_empty&lt;/em&gt; simulates an empty &lt;em&gt;PUT&lt;/em&gt; request. The second
one, &lt;em&gt;test_put_no_virus&lt;/em&gt; simulates a regular &lt;em&gt;PUT&lt;/em&gt; request but with a simple
file containing no virus.&lt;/p&gt;
&lt;p&gt;Finally, the third and last test simulates the upload of a virus using the
&lt;a href=&#34;http://www.eicar.org/&#34;&gt;EICAR&lt;/a&gt; test file. This is a special test file that
is recognized as a virus, even if it&#39;s not real one. Very handy for testing
virus detection software!&lt;/p&gt;
&lt;h1&gt;Configuring Swift proxy&lt;/h1&gt;
&lt;p&gt;Our middleware is ready! We can configure Swift&#39;s proxy server to use it. We
need to add the following lines to our &lt;em&gt;swift-proxy.conf&lt;/em&gt; to teach it how to
load the filter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;[filter:clamav]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;na&#34;&gt;paste.filter_factory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;swiftclamav:filter_factory&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
We&#39;ll assume that our Python modules is named &lt;em&gt;swiftclamava&lt;/em&gt; here. Now that
we&#39;ve defined our filter and how to load it, we can use it in our pipeline:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;[pipeline:main]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;na&#34;&gt;pipeline&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;catch_errors healthcheck cache ratelimit tempauth clamav proxy-logging proxy-server&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Just before reaching the &lt;em&gt;proxy-server&lt;/em&gt;, and after the user being
authenticated, the content will be scanned for viruses. It&#39;s important here
to put this after authentication for example, because otherwise we may scan
content that will get rejected by the authtemp module, thus scanning for
nothing!&lt;/p&gt;
&lt;h1&gt;Beyond scanning&lt;/h1&gt;
&lt;p&gt;And voilà, we now have a simple middleware testing uploaded content and
refusing infected files. We could enhance it with various other things, like
configuration handling, but I&#39;ll let that as an exercise for the interested
readers.&lt;/p&gt;
&lt;p&gt;We didn&#39;t exploited it here, but note that you can also manipulate request
headers and modify them if needed. For example, we could have added a header
&lt;em&gt;X-Object-Meta-Scanned-By: ClamAV&lt;/em&gt; to indicates that the file has been
scanned by ClamAV.&lt;/p&gt;
&lt;p&gt;You should now be able to build your own middleware doing whatever you want
with uploaded data. Happy hacking!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Overriding cl-json object encoding</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/cl-postmodern-dao-json"/>
    <updated>2013-01-11T21:14:21Z</updated>
    <published>2013-01-11T21:14:21Z</published>
    <id>/blog/2013/cl-postmodern-dao-json</id>
        <category   scheme="/blog/tags"
                term="common-lisp"
                label="Common-Lisp" />
        <category   scheme="/blog/tags"
                term="lisp"
                label="Lisp" />
        <category   scheme="/blog/tags"
                term="json"
                label="Json" />
        <category   scheme="/blog/tags"
                term="postgresql"
                label="Postgresql" />
        <category   scheme="/blog/tags"
                term="postmodern"
                label="Postmodern" />
        <category   scheme="/blog/tags"
                term="cl-json"
                label="Cl-Json" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;http://common-lisp.net/project/cl-json/&#34;&gt;CL-JSON&lt;/a&gt; provides an encoder for
Lisp data structures and objects to JSON format. Unfortunately, in some
case, its default encoding mechanism for CLOS objects isn&#39;t exactly doing
the right thing. I&#39;ll show you how Common Lisp makes it easy to change that.&lt;/p&gt;
&lt;h1&gt;Identifying the problem&lt;/h1&gt;
&lt;h2&gt;CL-JSON &amp;amp; CLOS&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;CL-JSON&lt;/em&gt; mechanism encoding CLOS object is really neat. Let&#39;s see how it
works for a simple case:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;kitten&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:initarg&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;json:encode-json-to-string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;make-instance&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;kitten&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;black&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
will produce:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;tail&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;black&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Still using CL-JSON, we can also decode the JSON object to a CLOS object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;slot-value&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;json:with-decoder-simple-clos-semantics&lt;/span&gt;&lt;br /&gt;   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;json:decode-json-from-string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;{\&amp;quot;tail\&amp;quot;:\&amp;quot;black\&amp;quot;}&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;ss&#34;&gt;:tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
That code will return &lt;em&gt;&#34;black&#34;&lt;/em&gt;. Note that it&#39;s also possible to specify
which class should be used when decoding objects, but that&#39;s beyond the
purpose of this article.&lt;/p&gt;
&lt;h2&gt;Postmodern&lt;/h2&gt;
&lt;p&gt;Now, let&#39;s introduce &lt;a href=&#34;http://marijnhaverbeke.nl/postmodern/&#34;&gt;Postmodern&lt;/a&gt;, a
wonderful Common Lisp system providing access to the wonderful
&lt;a href=&#34;http://postgresql.org&#34;&gt;PostgreSQL&lt;/a&gt; database. It also provides a simple
system to map rows in a database to CLOS classes, called DAO for &lt;em&gt;Database
access objects&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;With this, we can easily store our &lt;em&gt;kitten&lt;/em&gt; into a table.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;kitten&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:initarg&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:metaclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;postmodern:dao-class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
If we try to encode this to JSON, it will produce the exact same result seen
previously.&lt;/p&gt;
&lt;p&gt;The problem is what happens when one of our column has a &lt;em&gt;NULL&lt;/em&gt; value.
Postmodern encodes this using the &lt;em&gt;:null&lt;/em&gt; symbol.&lt;/p&gt;
&lt;p&gt;So this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;kitten&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:initarg&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:col-type&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;s-sql:db-null&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:metaclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;postmodern:dao-class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:deftable&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;kitten&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:!dao-def&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:connect-toplevel&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;…&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:create-table&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;kitten&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;json:encode-json-to-string&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:make-dao&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;kitten&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
will return:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;{&amp;quot;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tail&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;}&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Fail! The fact that the column is &lt;em&gt;NULL&lt;/em&gt; is represented by the &lt;em&gt;:null&lt;/em&gt;
symbol. And CL-JSON encodes all symbols as string.&lt;/p&gt;
&lt;p&gt;This is not at all what we want here!&lt;/p&gt;
&lt;h1&gt;Overriding encode-json&lt;/h1&gt;
&lt;p&gt;CL-JSON provides and uses the &lt;em&gt;encode-json&lt;/em&gt; method to encode all kind of
object. It is defined as a &lt;em&gt;generic function&lt;/em&gt;, and a lot of different
methods are implemented to handle the different standard Common Lisp types.
The one used for &lt;em&gt;standard-object&lt;/em&gt; is defined liked that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defmethod&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;encode-json&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;standard-object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&#34;k&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt; &lt;span class=&#34;vg&#34;&gt;*json-output*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;s&#34;&gt;&amp;quot;Write the JSON representation (Object) of the CLOS object O to&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;s&#34;&gt;STREAM (or to *JSON-OUTPUT*).&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;with-object&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;map-slots&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;stream-object-member-encoder&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
All we need to do here, is to create a new method for our &lt;em&gt;kitten&lt;/em&gt; objects,
that handles correctly the &lt;em&gt;:null&lt;/em&gt; case.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;kitten&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:initarg&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:tail&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:col-type&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;s-sql:db-null&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:metaclass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;postmodern:dao-class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;kitten&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c1&#34;&gt;;; Switch package just to define the new method&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;in-package&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defmethod&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;encode-json&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;cl-user:kitten&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&#34;k&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;json:*json-output*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;s&#34;&gt;&amp;quot;Write the JSON representation (Object) of the postmodern DAO CLOS object&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;s&#34;&gt;O to STREAM (or to *JSON-OUTPUT*).&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;with-object&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;map-slots&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                 &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as-object-member&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;encode-json&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;               &lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c1&#34;&gt;;; Go back into our package&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;in-package&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cl-user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:deftable&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;kitten&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:!dao-def&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:connect-toplevel&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;…&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:create-table&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;kitten&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;json:encode-json-to-string&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postmodern:make-dao&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;kitten&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
With that new method, as soon as we encounter a &lt;em&gt;:null&lt;/em&gt; symbol as a value
for an object&#39;s slot, we replace it by &lt;em&gt;nil&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now if we try to encode another &lt;em&gt;kitten&lt;/em&gt;, we&#39;ll get:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;tail&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
which is far better for our JavaScript data consumers!&lt;/p&gt;
&lt;p&gt;In the end, I think that this kind of trick is feasible that easily because
of the way CLOS provides its generic method implementation.
The fact that methods don&#39;t belong to any class makes the extension of every
program, library and class so much easier. Doing this in another language
like Java would likely by impossible, and in Python it would unlikely be as
clean as it is done in Common Lisp.&lt;/p&gt;
&lt;p&gt;The ability to teach &lt;em&gt;any&lt;/em&gt; library about how it should handle your class
just by defining a new method is really handy!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Integrating &lt;i&gt;cl-irc&lt;/i&gt; and &lt;i&gt;cl-async&lt;/i&gt;</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2013/cl-irc-async"/>
    <updated>2013-01-04T12:51:23Z</updated>
    <published>2013-01-04T12:51:23Z</published>
    <id>/blog/2013/cl-irc-async</id>
        <category   scheme="/blog/tags"
                term="common-lisp"
                label="Common-Lisp" />
        <category   scheme="/blog/tags"
                term="lisp"
                label="Lisp" />
        <category   scheme="/blog/tags"
                term="irc"
                label="Irc" />
        <category   scheme="/blog/tags"
                term="cl-irc"
                label="Cl-Irc" />
        <category   scheme="/blog/tags"
                term="cl-async"
                label="Cl-Async" />
    
    <content type="html">
            &lt;p&gt;Recently, I&#39;ve started programming in &lt;a href=&#34;http://common-lisp.net&#34;&gt;Common Lisp&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My idea here is to use &lt;a href=&#34;http://www.cliki.net/cl-irc&#34;&gt;cl-irc&lt;/a&gt;, an IRC library
into an &lt;a href=&#34;http://en.wikipedia.org/wiki/Event_loop&#34;&gt;event loop&lt;/a&gt;. This can be
really useful, for example to trigger action based on time, using timers.&lt;/p&gt;
&lt;h1&gt;Creating a connection&lt;/h1&gt;
&lt;p&gt;The first step is to create a basic &lt;em&gt;cl-irc:connection&lt;/em&gt; object on our own.
This can be achieved easily with this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cl-irc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connect&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:make-connection&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:connection-type&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;cl-irc:connection&lt;/span&gt;&lt;br /&gt;                                              &lt;span class=&#34;ss&#34;&gt;:client-stream&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;br /&gt;                                              &lt;span class=&#34;ss&#34;&gt;:network-stream&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?&lt;/span&gt;&lt;br /&gt;                                              &lt;span class=&#34;ss&#34;&gt;:server-name&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This will return a &lt;em&gt;cl-irc:connection&lt;/em&gt; object, logging to stdout
(&lt;em&gt;:client-stream t&lt;/em&gt;) and having the server name &lt;em&gt;server&lt;/em&gt;. Note that the
server name could be any string.&lt;/p&gt;
&lt;p&gt;You probably noticed the &lt;em&gt;?&lt;/em&gt; I used as :network-stream value. This is not a
real and working value: this should be a stream established to the IRC
server you want to chat with. This is where we&#39;ll need to use
&lt;a href=&#34;http://orthecreedence.github.com/cl-async/tcp#tcp-connect&#34;&gt;&lt;code&gt;cl-async:tcp-connect&lt;/code&gt;&lt;/a&gt;
to establish a TCP connection.&lt;/p&gt;
&lt;p&gt;As you can read in this function&#39;s documentation, all we need to pass is the
server address, two callbacks for read and general events, and the &lt;em&gt;:stream&lt;/em&gt;
option to get a stream rather than a socket.&lt;/p&gt;
&lt;p&gt;So you would do something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cl-irc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cl-async&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection-socket-read&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;We should read the IRC message from ~a ~%&amp;quot;&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection-socket-event&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Socket event: ~a~%&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connect&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6667&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:make-connection&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:connection-type&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;cl-irc:connection&lt;/span&gt;&lt;br /&gt;                          &lt;span class=&#34;ss&#34;&gt;:client-stream&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;br /&gt;                          &lt;span class=&#34;ss&#34;&gt;:network-stream&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as:tcp-connect&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;br /&gt;                                                          &lt;span class=&#34;nf&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection-socket-read&lt;/span&gt;&lt;br /&gt;                                                          &lt;span class=&#34;nf&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection-socket-event&lt;/span&gt;&lt;br /&gt;                                                          &lt;span class=&#34;ss&#34;&gt;:stream&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                          &lt;span class=&#34;ss&#34;&gt;:server-name&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as:start-event-loop&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connect&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;irc.oftc.net&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
If you run this program, it will connect to the OFTC IRC server, and then
notice you each time the server is sending you a message.&lt;/p&gt;
&lt;p&gt;Therefore our problem here is how we you treat the message read from the
stream in &lt;code&gt;connection-socket-read&lt;/code&gt; and handle them in the name of
our connection object you used? We can&#39;t link both together at this point.&lt;/p&gt;
&lt;p&gt;We can&#39;t build a closure, because as the time we use &lt;em&gt;as:tcp-connect&lt;/em&gt; we
don&#39;t have the &lt;em&gt;cl-irc:connection&lt;/em&gt; instance. Also we can&#39;t change easily the
&lt;em&gt;read-cb&lt;/em&gt; parameter of our &lt;em&gt;network-stream&lt;/em&gt; established by &lt;em&gt;as:tcp-connect&lt;/em&gt;,
simply because &lt;em&gt;cl-async&lt;/em&gt; doesn&#39;t use to do allow that.&lt;/p&gt;
&lt;h1&gt;Building a closure&lt;/h1&gt;
&lt;p&gt;So one solution here is to hack &lt;em&gt;cl-irc:make-connection&lt;/em&gt; so we can build an
&lt;em&gt;cl-irc:connection&lt;/em&gt; instance without providing in advance the
&lt;em&gt;network-stream&lt;/em&gt;, allowing us to build a closure including the
&lt;em&gt;cl-irc:connection&lt;/em&gt; to read event for. This is what we&#39;re going to do in the
&lt;code&gt;connect&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cl-irc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cl-async&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:flexi-streams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection-socket-read&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc::read-irc-message&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;nv&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;message&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;nb&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:irc-message-event&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection-socket-event&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Socket event: ~a~%&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connect&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nickname&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;k&#34;&gt;&amp;amp;key&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;username&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;realname&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;c1&#34;&gt;;; Build an instance of cl-irc:connection, without any network/output stream&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;make-instance&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;cl-irc:connection&lt;/span&gt;&lt;br /&gt;                                    &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;username&lt;/span&gt;&lt;br /&gt;                                    &lt;span class=&#34;ss&#34;&gt;:password&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;password&lt;/span&gt;&lt;br /&gt;                                    &lt;span class=&#34;ss&#34;&gt;:server-name&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt;&lt;br /&gt;                                    &lt;span class=&#34;ss&#34;&gt;:server-port&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;br /&gt;                                    &lt;span class=&#34;ss&#34;&gt;:client-stream&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;         &lt;span class=&#34;c1&#34;&gt;;; Use as:tcp-connect to build our network stream, and build a&lt;/span&gt;&lt;br /&gt;         &lt;span class=&#34;c1&#34;&gt;;; closure calling `connection-socket-read&amp;#39; with our `connection&amp;#39;&lt;/span&gt;&lt;br /&gt;         &lt;span class=&#34;c1&#34;&gt;;; as arguments&lt;/span&gt;&lt;br /&gt;         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;network-stream&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as:tcp-connect&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;port&lt;/span&gt;&lt;br /&gt;                                         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                                           &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;declare&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;                                           &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection-socket-read&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;                                         &lt;span class=&#34;nf&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection-socket-event&lt;/span&gt;&lt;br /&gt;                                         &lt;span class=&#34;ss&#34;&gt;:stream&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c1&#34;&gt;;; Set the network stream on the connection&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;setf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:network-stream&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;network-stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c1&#34;&gt;;; Set the output stream on the connection&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;setf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:output-stream&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;         &lt;span class=&#34;c1&#34;&gt;;; This is grabbed from cl-irc:make-connection&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;flexi-streams:make-flexi-stream&lt;/span&gt;&lt;br /&gt;           &lt;span class=&#34;nv&#34;&gt;network-stream&lt;/span&gt;&lt;br /&gt;           &lt;span class=&#34;ss&#34;&gt;:element-type&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;character&lt;/span&gt;&lt;br /&gt;           &lt;span class=&#34;ss&#34;&gt;:external-format&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:utf8&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:eol-style&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:crlf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;c1&#34;&gt;;; Now handle the IRC protocol authentication pass&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;null&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;password&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:pass&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;password&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:nick&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nickname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:user-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;username&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nickname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;realname&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nickname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as:start-event-loop&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connect&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;irc.oftc.net&amp;quot;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6667&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;jd-blog&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
And here we are! If we run this, we&#39;re now using an event loop to run
&lt;code&gt;cl-irc&lt;/code&gt;. Each time the socket has something to read, the
function &lt;code&gt;connection-socket-read&lt;/code&gt; will be called on the
non-blocking mode socket. If there&#39;s no message to be read, then the
function will exit and the loop will continue to run.&lt;/p&gt;
&lt;h1&gt;Using timers&lt;/h1&gt;
&lt;p&gt;You can now modify the last line with this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;say-hello&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:privmsg&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;#jd-blog&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Hey I read your blog!&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as:delay&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;say-hello&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:time&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;60&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;as:start-event-loop&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;connect&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;irc.oftc.net&amp;quot;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6667&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;jd-blog&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;                         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cl-irc:join&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;#jd-blog&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;say-hello&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This will connect to the IRC server, join a channel and then say the same
sentence every minute.&lt;/p&gt;
&lt;p&gt;Challenge accomplished!&lt;/p&gt;
&lt;p&gt;And I&#39;d like to thank &lt;a href=&#34;http://blog.killtheradio.net/&#34;&gt;Andrew Lyon&lt;/a&gt;, the
author of &lt;a href=&#34;https://github.com/orthecreedence/cl-async&#34;&gt;cl-async&lt;/a&gt;, who has
been incredibly helpful with my recent experimentations in this area.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Ceilometer bug squash day &amp;#35;1</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/ceilometer-bug-squash-day-1"/>
    <updated>2012-12-24T17:45:00Z</updated>
    <published>2012-12-24T17:45:00Z</published>
    <id>/blog/2012/ceilometer-bug-squash-day-1</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;p&gt;In order to start the year in a good mood, what&#39;s the best than squashing
some bugs on OpenStack?&lt;/p&gt;
&lt;p&gt;Therefore, the Ceilometer team is pleased &lt;a href=&#34;http://lists.openstack.org/pipermail/openstack-dev/2012-December/004161.html&#34;&gt;to
announce&lt;/a&gt;
that it organizes a &lt;a href=&#34;http://wiki.openstack.org/Ceilometer/BugSquashingDay/20130104&#34;&gt;bug squashing day on the Friday 4th January
2013&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We wrote an extensive page about &lt;a href=&#34;http://wiki.openstack.org/Ceilometer/Contributing&#34;&gt;how you can contribute to
Ceilometer&lt;/a&gt;, from
updating the documentation, to fixing bugs. There&#39;s a lot you can do. We&#39;ve
good support for Ceilometer built into &lt;a href=&#34;http://devstack.org&#34;&gt;Devstack&lt;/a&gt;, so
installing a development platform is really easy.&lt;/p&gt;
&lt;p&gt;The main goal on this bug day will be put Ceilometer in the best possible
shape before the &lt;em&gt;grizzly-2&lt;/em&gt; milestone arrives (10th January 2013). This
version of Ceilometer will aim to keep compatibility with &lt;em&gt;Folsom&lt;/em&gt;, so early
deployers can enjoy some of our new features before upgrading to &lt;em&gt;Grizzly&lt;/em&gt;.
After that date, we&#39;ll start merging more extensive changes.&lt;/p&gt;
&lt;p&gt;We&#39;ll be hanging out on the &lt;em&gt;#openstack-metering&lt;/em&gt; IRC channel on
&lt;a href=&#34;http://freenode.net&#34;&gt;Freenode&lt;/a&gt;, as usual, so feel free to come by and join
us!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Logitech Unifying devices support in UPower</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/logitech-unifying-upower"/>
    <updated>2012-11-16T10:44:00Z</updated>
    <published>2012-11-16T10:44:00Z</published>
    <id>/blog/2012/logitech-unifying-upower</id>
        <category   scheme="/blog/tags"
                term="logitech"
                label="Logitech" />
        <category   scheme="/blog/tags"
                term="upower"
                label="Upower" />
        <category   scheme="/blog/tags"
                term="freedesktop"
                label="Freedesktop" />
    
    <content type="html">
            &lt;p&gt;A few months ago, &lt;a href=&#34;/blog/2012/logitech-k750-linux-support&#34;&gt;I wrote about my reverse engineering attempt to Logitech
Unifying devices&lt;/a&gt;. Back then, I
concluded my post with big hopes on the future after receiving a document
with some part of the specification of the HID++ 2.0 from Logitech.&lt;/p&gt;
&lt;p&gt;A couple of weeks ago, some of my summer work has been merged to
&lt;a href=&#34;http://upower.freedesktop.org/&#34;&gt;UPower&lt;/a&gt;, adding battery support for some
Logitech devices.&lt;/p&gt;
&lt;h1&gt;HID++&lt;/h1&gt;
&lt;p&gt;&lt;span class=&#34;pull-right&#34;&gt;
&lt;img alt=&#34;UPower&#34; src=&#34;/media/images/m705.jpg&#34; /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;As I discovered late in my first reverse engineering attempt, Logitech
developed a custom HID protocol named HID++. This protocol exists in two
versions, 1.0 and 2.0. Some devices talk with version 1 of the protocol
(like my M705 mouse) and some others talk with version 2 of the protocol
(like my K750 keyboard).&lt;/p&gt;
&lt;p&gt;Recently, I&#39;ve been able to be in touch with a Logitech engineer who worked
on the Linux support for the Unifying receiver, and he has been really
helpful and exposed me some details about this protocol.&lt;/p&gt;
&lt;p&gt;Logitech made the decision to publish their HID++ specification publicly
about a year ago, but still didn&#39;t do it. The internal review needed to
publish such documents hasn&#39;t be done yet. The &lt;a href=&#34;http://6xq.net/git/lars/lshidpp.git/plain/doc/logitech_hidpp_2.0_specification_draft_2012-06-04.pdf&#34;&gt;only published
draft&lt;/a&gt;
is just an extract of the specification, with even some typo in it as I
discovered.&lt;/p&gt;
&lt;p&gt;Some &lt;a href=&#34;https://drive.google.com/?tab=mo&amp;amp;pli=1&amp;amp;authuser=0#folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28&#34;&gt;other
documents&lt;/a&gt;
have been recently published, but I didn&#39;t have the time to review them.
They contains HID++ 1.0 specifications and some details I asked for about
the K750 keyboard.&lt;/p&gt;
&lt;h1&gt;UPower support&lt;/h1&gt;
&lt;p&gt;&lt;span class=&#34;pull-left&#34;&gt;
&lt;img alt=&#34;UPower&#34; src=&#34;/media/images/upower.png&#34; /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It took me sometime to get a full understanding of the protocol, its
different version etc. After reverse engineering my K750 keyboard, I&#39;ve also
reverse engineered the data stream used to get my M705 mouse battery status.
I&#39;ve also received some information about the HID++ 1.0 protocol, so I&#39;ve
been able to discover a bit more on what the packets mean. Most of my
discoveries are now used to do proper &lt;code&gt;#define&lt;/code&gt; in
&lt;a href=&#34;http://cgit.freedesktop.org/upower/tree/src/linux/up-device-lg-unifying.c&#34;&gt;&lt;code&gt;up-lg-unifying.c&lt;/code&gt;&lt;/a&gt;
so the code makes more sense.&lt;/p&gt;
&lt;p&gt;My &lt;a href=&#34;http://cgit.freedesktop.org/upower/commit/?id=2f03ad62b520fc5c02e3ff9eb5bffc4275eb88dc&#34;&gt;first
patch&lt;/a&gt;
implements a new property for UPower devices, named &lt;em&gt;luminosity&lt;/em&gt;, that use
with K750 keyboard to report the light level received. The &lt;a href=&#34;http://cgit.freedesktop.org/upower/commit/?id=95184593504bca5240ecd296db98954decd2c5a5&#34;&gt;second
patch&lt;/a&gt;
add support for Logitech Unifying devices (over USB only) and should work
with at least Logitech M705 and K750 devices. This should be available with
the next version of UPower, which should be 0.9.19.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;gnome-power-statistics for K750&#34; src=&#34;/media/images/gnome-power-statistics-k750.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;So far, Logitech has been kind enough to help me understanding part of the
protocol and even sent me a few devices so I can play and test my work with
them. Unfortunately, this will probably requires some work and time, and so
far Logitech was not able to help with that.&lt;/p&gt;
&lt;p&gt;There should be enough information out there to at least add support for
battery to HID++ 2.0 devices, and probably a few other things too. I hope
I&#39;d get the time do this at some point, but feel free to beat me in this
race!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OpenStack France meetup #2</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/openstack-france-meetup-2"/>
    <updated>2012-11-06T11:37:00Z</updated>
    <published>2012-11-06T11:37:00Z</published>
    <id>/blog/2012/openstack-france-meetup-2</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;p&gt;I was at the &lt;a href=&#34;http://www.meetup.com/OpenStack-France/events/84177022/&#34;&gt;OpenStack France meetup 2&lt;/a&gt; yesterday
evening.&lt;/p&gt;
&lt;p&gt;This has been a wonderful evening, talking about OpenStack and all with
around 30-40 people. I and &lt;a href=&#34;http://nicolas.barcet.com/&#34;&gt;Nick Barcet&lt;/a&gt;
presented &lt;a href=&#34;http://launchpad.net/ceilometer&#34;&gt;Ceilometer&lt;/a&gt; and have received
some good feedbacks about it. We should also thanks
&lt;a href=&#34;http://www.nebula.com/&#34;&gt;Nebula&lt;/a&gt;, who sponsored the evening, and &lt;a href=&#34;http://erwan.com/&#34;&gt;Erwan
Gallen&lt;/a&gt; since it was nicely organized, and free beers are
always enjoyable.&lt;/p&gt;
&lt;p&gt;For people interested, the &lt;a href=&#34;https://docs.google.com/presentation/d/1i30roVZp00Wvo46F4k5CT98sw2uMgaf5Lh3bSfiQ-Cg/edit&#34;&gt;slides of our Ceilometer presentations are
available&lt;/a&gt;.
This is a lighter and fresher version of the &lt;a href=&#34;https://docs.google.com/presentation/d/1ytYhQGR5SxoccZ-wuza2n0H2mS7HniP9HoFDUpuGDiM/edit&#34;&gt;slides used by Nick and Doug
at the OpenStack Design
Summit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/media/images/blog/2012/openstack-france-meetup-2-ceilometer.jpg&#34;
     class=&#34;thumbnail&#34;&gt;&lt;/p&gt;
&lt;iframe src=&#34;https://docs.google.com/presentation/embed?id=1i30roVZp00Wvo46F4k5CT98sw2uMgaf5Lh3bSfiQ-Cg&amp;start=false&amp;loop=false&amp;delayms=3000&#34;
frameborder=&#34;0&#34; height=&#34;479&#34; width=&#34;600&#34;  allowfullscreen=&#34;true&#34;
mozallowfullscreen=&#34;true&#34; webkitallowfullscreen=&#34;true&#34;&gt;&lt;/iframe&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Inside Synaps, a CloudWatch-like implementation for OpenStack</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/openstack-synaps-exploration"/>
    <updated>2012-10-22T11:16:00Z</updated>
    <published>2012-10-22T11:16:00Z</published>
    <id>/blog/2012/openstack-synaps-exploration</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
        <category   scheme="/blog/tags"
                term="heat"
                label="Heat" />
        <category   scheme="/blog/tags"
                term="synaps"
                label="Synaps" />
    
    <content type="html">
            &lt;p&gt;A few days ago, &lt;a href=&#34;http://www.samsung.com/&#34;&gt;Samsung&lt;/a&gt; released the source code
of &lt;a href=&#34;https://github.com/spcs/synaps&#34;&gt;Synaps&lt;/a&gt;, an implementation of the
&lt;a href=&#34;http://aws.amazon.com/cloudwatch/&#34;&gt;Amazon Web Service CloudWatch API&lt;/a&gt; for
&lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Being a developer on the &lt;a href=&#34;http://launchpad.net/ceilometer&#34;&gt;Ceilometer&lt;/a&gt;
project, I&#39;ve been curious to look on this project and how it could overlap
with Ceilometer or other projects like &lt;a href=&#34;http://www.heat-api.org&#34;&gt;Heat&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;What is CloudWatch?&lt;/h1&gt;
&lt;p&gt;CloudWatch is a monitoring system provided by Amazon on its Web Services
platform to monitor services. This allows you get notifications and trigger
an action on certain threshold.&lt;/p&gt;
&lt;p&gt;For example, this can be used to scale your architecture by monitoring the
number of requests you get on it and its general load by starting new
servers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/media/images/cloudwatch.jpg&#34;&gt;&lt;/p&gt;
&lt;h1&gt;Synaps&lt;/h1&gt;
&lt;p&gt;Synaps is written in around 7k lines of Python (with 28 % of which are
comments), reuses at least one common module of OpenStack
(&lt;em&gt;openstack.common.cfg&lt;/em&gt;) and copy some modules from Nova. One thing that
strikes me, is that there seems to be only a few unit tests compared to most
OpenStack projects. Also, many parts of the code and documentation contains
text written in korean, which won&#39;t be very helpful for most people! :-)
It uses some external technologies, like &lt;a href=&#34;http://storm-project.net/&#34;&gt;Storm&lt;/a&gt;,
&lt;a href=&#34;http://cassandra.apache.org/&#34;&gt;Cassandra&lt;/a&gt; to store its persistent data and
&lt;a href=&#34;http://pandas.pydata.org/&#34;&gt;Pandas&lt;/a&gt; to do data analysis.&lt;/p&gt;
&lt;p&gt;The API server provides an EC2 compatible API only: no OpenStack specific
API. This is probably not a bad thing for now, since I am not aware of any
work in this direction. The API access directly the Cassandra back-end for
read operation, but relies on RPC to do writes. This way, a set of daemon
handles the write using the Storm part of Synaps and do data aggregation.
The authentication only supports LDAP, but it should still be possible to
add a driver for Keystone.&lt;/p&gt;
&lt;p&gt;A Java and a Python SDK are provided to record metrics into Synaps, but
there&#39;s not enough documentation for it to be useful.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/media/images/SynapsDeployment.jpg&#34;&gt;&lt;/p&gt;
&lt;h1&gt;Overlap with Heat&lt;/h1&gt;
&lt;p&gt;For now, there&#39;s not a lot of overlap with Heat, because Heat does not
implement completely the CloudWatch API. Heat actually still misses a lot of
the CloudWatch functions. But as soon as it will implement the CloudWatch
API completely, the overlap will be complete with Synaps in this regard.&lt;/p&gt;
&lt;p&gt;One divergence point however, is that Heat uses RPC to access data from the
storage back-end via its engine (the central daemon), whereas Synaps
directly connects to Cassandra. Also, Heat relies on SQLAlchemy, like most
OpenStack projects needing a database.&lt;/p&gt;
&lt;h1&gt;Overlap with Ceilometer&lt;/h1&gt;
&lt;p&gt;One of the goal of Ceilometer is to provide data probes and pollsters for
all OpenStack components (Nova, Swift, Quantum…) whereas Synaps let the
OpenStack users to put any kind of metric inside it, and therefore doesn&#39;t
provide anything for now.&lt;/p&gt;
&lt;p&gt;But the storage of metrics is the main common point between Synaps and
Ceilometer. Synaps chose only one technology, Cassandra, to store its
metrics, whereas Ceilometer took care of building an abstraction layer for
the storage engine. Ceilometer currently allows an operator to use SQL or
MongoDB, but Cassandra could likely be added.&lt;/p&gt;
&lt;p&gt;Data metric consolidation is done by Synaps. This makes sense, since Synaps
don&#39;t need to have the full data history to trigger alarms. On the opposite,
Ceilometer needs to have a full history to allow things like billing, and
don&#39;t do any aggregation on data.&lt;/p&gt;
&lt;p&gt;Also, in Synaps, the data analysis is done using Pandas. This means the data
used are retrieved from the Cassandra back-end, and then transformed by
Pandas inside Synaps in something else. It&#39;s likely that in such a case,
Synaps should use CQL to achieve that. Ceilometer manipulates the data near
their storage: it means that the computation are done by back-end to be
efficient (SQL, mapreduce…).&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Considering Samsung open-sourced Synaps late in the development process, I
don&#39;t feel like they aimed to have it becoming a core component. This is
always sad, because the effort put into this implementation are big and it
would have probably little to add some abstraction layers to follow what
other OpenStack projects do. But this takes time and energy, and it&#39;s
understandable that Samsung didn&#39;t want to achieve this in a short time
frame.&lt;/p&gt;
&lt;p&gt;There&#39;s a part of the code and architecture that overlaps with Ceilometer
and Heat. Ceilometer is becoming a specialized point to store data metrics
from any source: so it&#39;s sad, but understandable, that Synaps did not tried
to reuse it. Fortunately, Heat is working with Ceilometer to achieve exactly
that. This means OpenStack would have only one metrics storage point, used
for billing, for monitoring and alarming.&lt;/p&gt;
&lt;p&gt;Therefore, I think Synaps is an implementation of CloudWatch that should be
looked at as an inspiration for Heat and Ceilometer to build a better and
more integrated solution!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Ceilometer 0.1 released</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/ceilometer-0.1-released"/>
    <updated>2012-10-12T17:45:00Z</updated>
    <published>2012-10-12T17:45:00Z</published>
    <id>/blog/2012/ceilometer-0.1-released</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;p&gt;After 6 months of development, we are proud to release the first release of
&lt;a href=&#34;http://launchpad.net/ceilometer&#34;&gt;Ceilometer&lt;/a&gt;, the
&lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt; Metering project. Ceilometer. This is a
first and amazing milestone for us: we follow all other projects by
releasing a version for Folsom!&lt;/p&gt;
&lt;p&gt;Using Ceilometer, you should now be able to meter your OpenStack cloud and
retrieve its usage to build statistics or bill your customer!&lt;/p&gt;
&lt;p&gt;You can read &lt;a href=&#34;https://lists.launchpad.net/openstack/msg17410.html&#34;&gt;our announcement on the OpenStack mailing list&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Architecture&lt;/h1&gt;
&lt;p&gt;We spent a good amount of time defining and refining &lt;a href=&#34;http://ceilometer.readthedocs.org/en/latest/architecture.html#high-level-description&#34;&gt;our
architecture&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://ceilometer.readthedocs.org/en/latest/architecture.html#high-level-description&#34;&gt;
  &lt;img class=&#34;thumbnail&#34; src=&#34;/media/images/Ceilometer_Architecture.png&#34;&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One of its important point, is that it has been designed to work without
modifying any of the existing core components. Patching OpenStack components
in an intrusive way to meter them was not an option for now, simply because
we had no legitimacy to do so. This may change in the future, and this will
likely be discussed next week during the &lt;a href=&#34;http://www.openstack.org/summit/san-diego-2012/&#34;&gt;OpenStack
Summit&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Meters&lt;/h1&gt;
&lt;p&gt;Initially, we defined a bunch of meters we&#39;d like to have for a first
release, and in the end, most of them are available. Some of them are still
missing, like OpenStack Object Storage (Swift) ones, mainly due to lack of
interest from the involved parties so far.&lt;/p&gt;
&lt;p&gt;Anyhow, with this first release, you should be able to meter your instances,
their network usage, memory, CPU. Images, networks and volumes and their
CRUD operations are metered too. For more detail, you can read the &lt;a href=&#34;http://ceilometer.readthedocs.org/en/latest/measurements.html&#34;&gt;complete
list of implemented
meters&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;REST API&lt;/h1&gt;
&lt;p&gt;The HTTP REST API has been partially implemented. The provided methods
should allow basic integration with a billing system.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://dreamhost.com/&#34;&gt;DreamHost&lt;/a&gt; is using Ceilometer in their deployment
architecture and coupling it with their billing system!&lt;/p&gt;
&lt;h1&gt;Towards Grizzly&lt;/h1&gt;
&lt;p&gt;We don&#39;t have a clear and established road-map for Grizzly yet.&lt;/p&gt;
&lt;p&gt;We already have a couple of patches waiting in the queue to be merged, like
the use of &lt;a href=&#34;https://review.openstack.org/#/c/13989/&#34;&gt;Keystone to authenticate API
request&lt;/a&gt; and the &lt;a href=&#34;https://review.openstack.org/#/c/14185/&#34;&gt;removal of Nova
DB access&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On my side, these last days I&#39;ve been working on a small debug user
interface for the API. Ceilometer API server will return this interface if
your do an API request from a browser (i.e. requesting
&lt;code&gt;text/html&lt;/code&gt; instead of &lt;code&gt;application/json&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;/media/images/ceilometer-debug-interface.png&#34; class=&#34;thumbnail&#34;
   style=&#34;width: 500px; margin: auto;&#34;&gt;
  &lt;img src=&#34;/media/images/ceilometer-debug-interface.png&#34;&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I hope this will help to discover Ceilometer API more easily for new comers
and leverage it to build powerful tools!&lt;/p&gt;
&lt;p&gt;Anyhow, we have tons of idea and work to do, and I&#39;m sure the upcoming weeks
will be very interesting. Also, we hope to be able to become an OpenStack
incubated project soon. So stay tuned!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Gnus notifications</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/gnus-notifications"/>
    <updated>2012-08-29T18:08:00Z</updated>
    <published>2012-08-29T18:08:00Z</published>
    <id>/blog/2012/gnus-notifications</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="notify"
                label="Notify" />
        <category   scheme="/blog/tags"
                term="gnus"
                label="Gnus" />
    
    <content type="html">
            &lt;p&gt;Today, &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/commit/?id=7b7db76666fae115c7ec0cc78ca96ea4e177ba4e&#34;&gt;I&#39;ve merged my Gnus notifications
module&lt;/a&gt;
inside Gnus git repository. This way, it will be available for everybody in
Emacs 24.2.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;gnus-notifications example&#34; src=&#34;/media/images/blog/2012/gnus-notifications.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This module allows you to be notified via &lt;code&gt;notifications-notify&lt;/code&gt;
(the Emacs implementation of the &lt;a href=&#34;http://www.galago-project.org/specs/notification/&#34;&gt;Freedesktop desktop notifications&lt;/a&gt;) on new
messages received in Gnus. It can also retrieves contacts photo via
&lt;em&gt;gravatar.el&lt;/em&gt; and &lt;em&gt;google-contacts.el&lt;/em&gt; to include them in the notification.&lt;/p&gt;
&lt;p&gt;To enable it in Emacs &amp;gt; 24.1, you just have to add the following line to
your Gnus configuration file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-hook&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;gnus-after-getting-new-news-hook&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;gnus-notifications&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
If you want to download it and use it stand-alone for a previous Emacs
version, you can &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/plain/lisp/gnus-notifications.el&#34;&gt;fetch the latest file
revision&lt;/a&gt;
and load it before adding the previously given line.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Sony Vaio Z Debian Linux support</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/sony-vaio-SVZ13-linux"/>
    <updated>2012-08-11T15:52:00Z</updated>
    <published>2012-08-11T15:52:00Z</published>
    <id>/blog/2012/sony-vaio-SVZ13-linux</id>
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
        <category   scheme="/blog/tags"
                term="linux"
                label="Linux" />
        <category   scheme="/blog/tags"
                term="sony"
                label="Sony" />
        <category   scheme="/blog/tags"
                term="hardware"
                label="Hardware" />
    
    <content type="html">
            &lt;p&gt;I had to install Debian Wheezy on a brand new Sony Vaio Z laptop with the
new Ivy Bridge architecture (SVZ1311C5E). I&#39;ll talk about this here, because
it&#39;s always nice to know that new hardware works quite fine (or not) under
Debian.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Sony Vaio Z 2012&#34; src=&#34;/media/images/sony-vaio-z-2012.jpg&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The laptop is delivered with Window 7, which I decided to remove entirely
anyway, and replace with Debian. I&#39;ve installed it with Linux 3.2 and then
ran Linux 3.4, 3.5 and 3.6-rc1.&lt;/p&gt;
&lt;h1&gt;USB booting&lt;/h1&gt;
&lt;p&gt;Don&#39;t ask me why, nor an Ubuntu or Debian USB installation booted, blocked
at SYSLINUX at best, or at a black screen. This does not work. I had to use
PXE to install Debian.&lt;/p&gt;
&lt;h1&gt;Storage&lt;/h1&gt;
&lt;p&gt;The only thing that can be surprising, is that the 128 GB SSD storage is
actually made of 2 64 GB Samsung SSD aggregated in a RAID 0 using &lt;em&gt;&lt;a href=&#34;http://www.intel.com/p/en_US/support/highlights/chpsts/imsm/&#34;&gt;Intel
Rapid Storage
Technology&lt;/a&gt;&lt;/em&gt;,
previously known as &lt;em&gt;Intel Matrix&lt;/em&gt;. This is supported by Linux using the
&lt;em&gt;dm-raid&lt;/em&gt; module. So this is a fake RAID, and you anyway can see the both
drives as &lt;em&gt;sda&lt;/em&gt; and &lt;em&gt;sdb&lt;/em&gt; under Linux.&lt;/p&gt;
&lt;p&gt;Unfortunately, this kind of RAID is not supported correctly by GRUB, and I
was unable to install it this way. Therefore, I decided to remove entirely
this fake RAID (which is possible via the BIOS) and use a Linux software
&lt;em&gt;md&lt;/em&gt; RAID 0 instead, plus crypto on top of it. That I know well and I trust. :)&lt;/p&gt;
&lt;h1&gt;Graphics&lt;/h1&gt;
&lt;p&gt;The Intel HD Graphics 4000 works fine. I&#39;m alsmo using the HDMI output,
which works fine. There&#39;s some GPU hanging (as seen on screen and in kernel
logs) in Linux up to 3.4, but with versions 3.5 and above, I didn&#39;t see any
problem so far.&lt;/p&gt;
&lt;h1&gt;Sound&lt;/h1&gt;
&lt;p&gt;The Intel HDA sound card works pretty well, both for playing and recording.
The main problem is that I hear a constant noise on the speakers, but
tweaking the ALSA mixers ends it at some point. There&#39;s still probably a
bug, not yet resolved in Linux 3.6-rc1.&lt;/p&gt;
&lt;h1&gt;Keyboard&lt;/h1&gt;
&lt;p&gt;The keyboard works fine, and the back-light too, via the &lt;em&gt;sony-laptop&lt;/em&gt;
kernel module. Wonderful.&lt;/p&gt;
&lt;h1&gt;Touchpad&lt;/h1&gt;
&lt;p&gt;Touchpad works fine.&lt;/p&gt;
&lt;h1&gt;Fingerprint&lt;/h1&gt;
&lt;p&gt;It does not work, and is not supported according to my research. Not that I
care about, but don&#39;t count on it. It&#39;s an AuthenTec AES1660.&lt;/p&gt;
&lt;h1&gt;Webcam&lt;/h1&gt;
&lt;p&gt;It works perfectly.&lt;/p&gt;
&lt;h1&gt;USB&lt;/h1&gt;
&lt;p&gt;Well, USB 3.0 does not work. I had to disable XHCI in the BIOS and use
the 2 ports as standard USB 2.0, otherwise I would just get errors from the
kernel. Still not working with Linux 3.6-rc1, and I&#39;ve no clue to debug, and
do not use USB 3.0 yet, so…&lt;/p&gt;
&lt;h1&gt;WiFi&lt;/h1&gt;
&lt;p&gt;The WiFi module (based on iwlwifi) works fine. The only problem with
NetworkManager is that the &lt;em&gt;sony-laptop&lt;/em&gt; offers a second rfkill switch and
NM does not know how to handle it correctly. &lt;a href=&#34;https://bugzilla.gnome.org/show_bug.cgi?id=680632&#34;&gt;A bug is opened about
this&lt;/a&gt; and I hope to be
able to write a patch or something at some point. Also, there seems to be
some quality issue with the &lt;em&gt;iwlwifi&lt;/em&gt; driver and 802.11n at this point. I&#39;m
losing connection quite often when the signal drops below 40 %. Loading the
module with &lt;em&gt;11n_disable=1&lt;/em&gt; helps a lot.&lt;/p&gt;
&lt;h1&gt;Ethernet&lt;/h1&gt;
&lt;p&gt;The gigabit Realtek Ethernet controller works perfectly.&lt;/p&gt;
&lt;h1&gt;Card reader&lt;/h1&gt;
&lt;p&gt;Works perfectly.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Ceilometer, the OpenStack metering project</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/openstack-metering-ceilometer"/>
    <updated>2012-07-27T12:37:00Z</updated>
    <published>2012-07-27T12:37:00Z</published>
    <id>/blog/2012/openstack-metering-ceilometer</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="ceilometer"
                label="Ceilometer" />
    
    <content type="html">
            &lt;p&gt;For the last months, I&#39;ve been working on a metering project for
&lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt;, so it&#39;s time to talk a bit about it.&lt;/p&gt;
&lt;p&gt;OpenStack is a growing cloud platform providing
&lt;acronym title=&#34;Infrastructure as a Service&#34;&gt;IaaS&lt;/a&gt;. A problem easily
identified by everyone building a public cloud platform is that nothing is
provided to retrieve the platform usage data. Some data are available in
some places, but not everything is, and you have to do a lot of processing
from the various components to get something useful in the end.
But in order to bill customers that are using your public cloud platform,
you need to do his.&lt;/p&gt;
&lt;p&gt;In this regard, a lot of companies running public OpenStack based
infrastructure wrote their own solution to cover this functional areas, and
to become able to bill theirs customers.&lt;/p&gt;
&lt;p&gt;To avoid everybody doing and maintaining such a stack in their corners, the
&lt;a href=&#34;http://launchpad.net/ceilometer&#34;&gt;Ceilometer&lt;/a&gt; has been created.&lt;/p&gt;
&lt;p&gt;The project aims to cover the metering aspect of the OpenStack components,
pulling usage data from every components and storing them into a single
place. It then offer a retrieving point for this data via a REST API.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://wiki.openstack.org/EfficientMetering&#34;&gt;initial specifications&lt;/a&gt;
have been written in April this year, and actual implementation started in
May. The project is currently worked on by me, Dreamhost and Canonical.&lt;/p&gt;
&lt;p&gt;We already have designed &lt;a href=&#34;http://wiki.openstack.org/EfficientMetering/ArchitectureProposalV1&#34;&gt;an
architecture&lt;/a&gt;
that we are implementing, and we hope to release a first usable version with
Folsom.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Ceilometer architecture&#34; src=&#34;/media/images/ceilometer-architecture.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;I did &lt;a href=&#34;https://docs.google.com/presentation/d/11ALGC4xuWcRvXKTSnnsteJUkArsTfQW-7IAfWRRI5kQ/edit#slide=id.p&#34;&gt;a
presentation&lt;/a&gt;
of this project yesterday at &lt;a href=&#34;http://xlcloud.org/bin/view/Main/&#34;&gt;XLCloud&lt;/a&gt;,
which has been very well received.&lt;/p&gt;
&lt;iframe src=&#34;https://docs.google.com/presentation/embed?id=11ALGC4xuWcRvXKTSnnsteJUkArsTfQW-7IAfWRRI5kQ&amp;start=false&amp;loop=false&amp;delayms=3000&#34;
        frameborder=&#34;0&#34; width=&#34;480&#34; height=&#34;389&#34; allowfullscreen=&#34;true&#34;
        mozallowfullscreen=&#34;true&#34; webkitallowfullscreen=&#34;true&#34;&gt;&lt;/iframe&gt;

&lt;p&gt;If you are interested in helping us and contributing, feel free to join us
during one of our &lt;a href=&#34;http://wiki.openstack.org/Meetings/MeteringAgenda&#34;&gt;weekly IRC
meeting&lt;/a&gt; or fix &lt;a href=&#34;https://bugs.launchpad.net/ceilometer&#34;&gt;some
bugs&lt;/a&gt;. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Emacs configuration published</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/emacs-configuration-published"/>
    <updated>2012-07-24T14:15:00Z</updated>
    <published>2012-07-24T14:15:00Z</published>
    <id>/blog/2012/emacs-configuration-published</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve finally published my Emacs configuration.&lt;/p&gt;
&lt;p&gt;This took me a while, since I had personal information inside (like
passwords). Recently, I&#39;ve been able to move them away and can now publish
everything in my &lt;a href=&#34;http://git.naquadah.org/?p=~jd/emacs.d.git;a=summary&#34;&gt;Git
repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s probably not yet usable from scratch, since I didn&#39;t include the
bootstrap code for &lt;a href=&#34;http://github.com/dimitri/el-get&#34;&gt;el-get&lt;/a&gt;. But you can
at least lurk and grab some ideas or lines of code. And do not hesitate to
ask me anything about it!&lt;/p&gt;
&lt;p&gt;Note that I&#39;m using Emacs development version (trunk), so it&#39;s possible that
some things do not work with (old) released Emacs versions.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">ERC notifications</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/erc-notifications"/>
    <updated>2012-07-21T13:32:00Z</updated>
    <published>2012-07-21T13:32:00Z</published>
    <id>/blog/2012/erc-notifications</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="notify"
                label="Notify" />
        <category   scheme="/blog/tags"
                term="erc"
                label="Erc" />
    
    <content type="html">
            &lt;p&gt;Today, &lt;a href=&#34;http://bzr.savannah.gnu.org/lh/emacs/trunk/revision/109176&#34;&gt;I&#39;ve merged my erc notifications
module&lt;/a&gt; inside
Emacs trunk. This way, it will be available for everybody in Emacs 24.2.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;erc-notifications example&#34; src=&#34;/media/images/erc-notifications.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This module allows you to be notified via &lt;code&gt;notifications-notify&lt;/code&gt;
(the Emacs implementation of the &lt;a href=&#34;http://www.galago-project.org/specs/notification/&#34;&gt;Freedesktop desktop
notifications&lt;/a&gt;) on
private message received on IRC, or when your nickname is mentioned on a
channel.&lt;/p&gt;
&lt;p&gt;To enable it in Emacs &amp;gt; 24.1, you just have to add the following line to your configuration
file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;add-to-list&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;erc-modules&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;notifications&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
If you want to download it and use it stand-alone for a previous Emacs
version, you can &lt;a href=&#34;http://bzr.savannah.gnu.org/lh/emacs/trunk/annotate/head:/lisp/erc/erc-notifications.el&#34;&gt;fetch the latest file
revision&lt;/a&gt;
and load it before adding the previously given line.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Logitech K750 keyboard and Unifying Receiver Linux support</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/logitech-k750-linux-support"/>
    <updated>2012-07-09T17:48:00Z</updated>
    <published>2012-07-09T17:48:00Z</published>
    <id>/blog/2012/logitech-k750-linux-support</id>
        <category   scheme="/blog/tags"
                term="linux"
                label="Linux" />
        <category   scheme="/blog/tags"
                term="usb"
                label="Usb" />
        <category   scheme="/blog/tags"
                term="logitech"
                label="Logitech" />
    
    <content type="html">
            &lt;p&gt;A year ago, I bought a &lt;a href=&#34;http://www.logitech.com/keyboards/keyboards/k750-keyboard&#34;&gt;Logitech Wireless Solar Keyboard
K750&lt;/a&gt;. I&#39;m
particularly picky on keyboards, but this one is good. It has an incredible
useful feature: while being wireless, it has no need for disposable or
rechargeable batteries, it uses solar power!&lt;/p&gt;
&lt;p&gt;My problem is that there&#39;s obviously no way to know the battery status from
Linux, the provided application only working on Windows.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Logitech Wireless Solar Keyboard K750&#34; src=&#34;/media/images/logitech-wireless-solar-keyboard-k750.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;And one dark night, while fragging on QuakeLive, my keyboard stopped
working: it had no battery left. This activity being quite energy consuming,
it emptied the whole battery.&lt;/p&gt;
&lt;p&gt;Someone should write code to get the battery status and light meter from
Linux: challenge accepted!&lt;/p&gt;
&lt;h1&gt;How the keyboard works&lt;/h1&gt;
&lt;p&gt;&lt;span class=&#34;pull-right&#34;&gt;
&lt;img alt=&#34;Logitech Unifying Receiver&#34; src=&#34;/media/images/logitech-unifying.jpg&#34; /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This keyboard, like many of the new wireless devices from Logitech, uses the
&lt;em&gt;Unifying&lt;/em&gt; interface. It&#39;s an USB receiver that can be attached up to 6
differents devices (mouse, keyboards…). On old Linux kernel, the &lt;em&gt;Unifying&lt;/em&gt;
receiver is recognized as only one keyboard and/or one mouse device.&lt;/p&gt;
&lt;p&gt;Recently, a driver called &lt;em&gt;hid-logitech-dj&lt;/em&gt; has been added to the Linux
kernel. With this driver, each device attached to the receiver is recognized
as one different device.&lt;/p&gt;
&lt;h1&gt;What the Logitech application does&lt;/h1&gt;
&lt;p&gt;&lt;span class=&#34;pull-left&#34;&gt;
&lt;img alt=&#34;Logitech Solar App&#34; src=&#34;/media/images/logitech-solar-app.png&#34; /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The Logitech application under Windows works that way: you launch it, and it
displays the battery charge level. On the keyboard, there&#39;s a special
&#34;light&#34; button (up right). When pressed, a LED will light up on the
keyboard: green if the keyboard is receiving enough light and is charging,
red if the keyboard does not receive enough light and is therefore
discharging. Pushing this same button while the application is running will
makes the light meter activated: the application will tell you how much
&lt;a href=&#34;http://en.wikipedia.org/wiki/Lux&#34;&gt;lux&lt;/a&gt; your keyboard is receiving.&lt;/p&gt;
&lt;h1&gt;Let&#39;s reverse engineer this&lt;/h1&gt;
&lt;p&gt;As far as I know, there&#39;s nothing in the USB HID protocol that handles this
kind of functionality (battery status, light meter…) in a standard way. So
the first task to accomplish is, unfortunately, to reverse engineer the
program.&lt;/p&gt;
&lt;p&gt;I discovered a bit too late that &lt;a href=&#34;http://www.youtube.com/watch?v=jMf55KVDPaE&#34;&gt;Drew Fisher did a good presentation on USB
reverse engineering at 28c3&lt;/a&gt;.
You might want to take a look at it if you want to reverse engineer on USB.
I did not need it, but I learned a few things.&lt;/p&gt;
&lt;p&gt;Anyway, my plan was the following: run the Logitech application inside a
virtual machine running Windows, give it direct access to the USB keyboard,
and sniff what happens on the USB wire.&lt;/p&gt;
&lt;p&gt;To achieve that, you need a virtual machine emulator that can do USB
pass-through. Both &lt;a href=&#34;http://www.linux-kvm.org/page/Main_Page&#34;&gt;KVM&lt;/a&gt; and
&lt;a href=&#34;https://www.virtualbox.org/&#34;&gt;VirtualBox&lt;/a&gt; can do that, but VirtualBox works
much better with USB and allow hot(un)plugging of devices, so I used it.&lt;/p&gt;
&lt;p&gt;To sniff what happens on the USB, you need to load the &lt;em&gt;usbmon&lt;/em&gt; Linux kernel
module. Simply doing &lt;code&gt;modprobe usbmon&lt;/code&gt; will work. You can then
use &lt;a href=&#34;http://www.wireshark.org/&#34;&gt;Wireshark&lt;/a&gt; which know how to use &lt;em&gt;usbmon&lt;/em&gt;
devices and understand the USB protocol.&lt;/p&gt;
&lt;h2&gt;USB stuff you need to know&lt;/h2&gt;
&lt;p&gt;You don&#39;t need to know much about USB to understand what I&#39;ll write about
below, but for the sake of comprehensibility I&#39;ll write a couple of things
here before jumping in.&lt;/p&gt;
&lt;p&gt;To communicate with an USB device, we communicate with one of its
&lt;em&gt;endpoints&lt;/em&gt;. Endpoints are regrouped into an &lt;em&gt;interface&lt;/em&gt;. Interfaces are
regrouped into a &lt;em&gt;configuration&lt;/em&gt;. A device might contains one or several
configurations.&lt;/p&gt;
&lt;p&gt;There&#39;s also several types of packets in the USB wire protocol, and at least
two of them interest us there, they are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interrupt packets, a packet send spontaneously;&lt;/li&gt;
&lt;li&gt;Controls packets, used for command and status operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of this and more is well (and better) explained in the &lt;a href=&#34;http://lwn.net/images/pdf/LDD3/ch13.pdf&#34;&gt;chapter
13&lt;/a&gt; of &lt;a href=&#34;http://lwn.net/Kernel/LDD3/&#34;&gt;Linux Device Drivers, Third
Edition&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Sniffed data&lt;/h2&gt;
&lt;p&gt;Once everything was set-up, I ran my beloved Wireshark. There&#39;s a
an &lt;abbr title=&#34;USB Request Block&#34;&gt;URB&lt;/abbr&gt; of type &lt;em&gt;interrupt&lt;/em&gt; sent each
time you press any key with some data in it. Therefore I advise you to plug
another keyboard (or use the laptop keyboard if you&#39;re doing this on a
laptop), otherwise you&#39;ll get crazy trying to sniff the keyboard you&#39;re
typing on.&lt;/p&gt;
&lt;p&gt;At this point, just launching the application does a bunch of USB traffic.
Pressing the &#34;light&#34; button on the keyboard makes even more USB packets
coming in and out. Here&#39;s the interesting packets that I noticed once I
excluded the noise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When pressing the &#34;light&#34; button, an URB of type &lt;em&gt;interrupt&lt;/em&gt; is sent by the
  keyboard to the computer;&lt;/li&gt;
&lt;li&gt;An URB &lt;em&gt;control&lt;/em&gt; packet is sent by the computer to the keyboard in
  response;&lt;/li&gt;
&lt;li&gt;Regularly URB &lt;em&gt;interrupt&lt;/em&gt; packets are sent just after.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With all this, the next step was clear: understand the packets and reproduce
that exchange under Linux.&lt;/p&gt;
&lt;h2&gt;What the packets mean&lt;/h2&gt;
&lt;h3&gt;The &#34;go for the light meter&#34; packet&lt;/h3&gt;
&lt;p&gt;The packet sent from the computer to the keyboard is the following.&lt;/p&gt;
&lt;figure&gt;
&lt;pre&gt;
Frame 17: 71 bytes on wire (568 bits), 71 bytes captured (568 bits)
    Frame Length: 71 bytes (568 bits)
    Capture Length: 71 bytes (568 bits)
USB URB
    URB id: 0xffff880161997240
    URB type: URB_SUBMIT (&#39;S&#39;)
    URB transfer type: URB_CONTROL (0x02)
    Endpoint: 0x00, Direction: OUT
        0... .... = Direction: OUT (0)
        .000 0000 = Endpoint value: 0
    Device: 6
    URB bus id: 1
    Device setup request: relevant (0)
    Data: present (0)
    URB sec: 1340124450
    URB usec: 495643
    URB status: Operation now in progress (-EINPROGRESS) (-115)
    URB length [bytes]: 7
    Data length [bytes]: 7
    [Response in: 18]
    [bInterfaceClass: HID (0x03)]
    URB setup
        bmRequestType: 0x21
            0... .... = Direction: Host-to-device
            .01. .... = Type: Class (0x01)
            ...0 0001 = Recipient: Interface (0x01)
    bRequest: SET_REPORT (0x09)
    wValue: 0x0210
        ReportID: 16
        ReportType: Output (2)
    wIndex: 2
    wLength: 7
0000  40 72 99 61 01 88 ff ff 53 02 00 06 01 00 00 00   @r.a....S.......
0010  22 ad e0 4f 00 00 00 00 1b 90 07 00 8d ff ff ff   &#34;..O............
0020  07 00 00 00 07 00 00 00 21 09 10 02 02 00 07 00   ........!.......
0030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  10 01 09 03 78 01 00                              ....x..
&lt;/pre&gt;
&lt;/figure&gt;

&lt;p&gt;What&#39;s here interesting is the last part representing the data. &lt;em&gt;wLength&lt;/em&gt;
says that the length of the data is 7 bytes, so let&#39;s take a look at those 7
bytes: &lt;code&gt;10 01 09 03 78 01 00&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Well, actually, you can&#39;t decode them like that, unless you&#39;re a freak or a
Logitech engineer. And I have actually no idea what they mean. But sending
this to the keyboard will trigger an interesting thing: the keyboard will
start sending URB interrupt with some data without you pressing any more key.&lt;/p&gt;
&lt;h3&gt;The &#34;light meter and battery values&#34; packet&lt;/h3&gt;
&lt;p&gt;This is most interesting packet. This is the one sent by the keyboard to the
host and that contains the data we want to retrieve.&lt;/p&gt;
&lt;figure&gt;
&lt;pre&gt;
Frame 1467: 84 bytes on wire (672 bits), 84 bytes captured (672 bits)
    Frame Length: 84 bytes (672 bits)
    Capture Length: 84 bytes (672 bits)
USB URB
    URB id: 0xffff88010c43c380
    URB type: URB_COMPLETE (&#39;C&#39;)
    URB transfer type: URB_INTERRUPT (0x01)
    Endpoint: 0x83, Direction: IN
        1... .... = Direction: IN (1)
        .000 0011 = Endpoint value: 3
    Device: 2
    URB bus id: 6
    Device setup request: not relevant (&#39;-&#39;)
    Data: present (0)
    URB sec: 1334953309
    URB usec: 728740
    URB status: Success (0)
    URB length [bytes]: 20
    Data length [bytes]: 20
    [Request in: 1466]
    [Time from request: 0.992374000 seconds]
    [bInterfaceClass: Unknown (0xffff)]
Leftover Capture Data: 1102091039000c061d474f4f4400000000000000

0000  80 c3 43 0c 01 88 ff ff 43 01 83 02 06 00 2d 00   ..C.....C.....-.
0010  5d c5 91 4f 00 00 00 00 a4 1e 0b 00 00 00 00 00   ]..O............
0020  14 00 00 00 14 00 00 00 00 00 00 00 00 00 00 00   ................
0030  02 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00   ................
0040  11 02 09 10 39 00 0c 06 1d 47 4f 4f 44 00 00 00   ....9....GOOD...
0050  00 00 00 00                                       ....

&lt;/pre&gt;
&lt;/figure&gt;

&lt;p&gt;This packets come in regularly (1 per second) on the wire for some time once
you sent the &#34;go for the light meter&#34; packet. At one point they are emitted
less often and do not contain the value for the light meter anymore,
suggesting that the control packet sent earlier triggers the activation of
the light meter for a defined period.&lt;/p&gt;
&lt;p&gt;Now you probably wonder where the data are in this. They&#39;re in the 20 bytes
leftover in the capture data part, indicated by Wireshark, at the end of the
packet: &lt;code&gt;11 02 09 10 39 00 0c 06 1d 47 4f 4f 44 00 00 00 00 00 00 00&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fortunately, it was easy to decode. Knowing we&#39;re looking for 2 values
(battery charge and light meter), we just need to observe and compare the
packet emitted on the wire with the values displayed by the Logitech Solar
App.&lt;/p&gt;
&lt;p&gt;To achieve this, I looked both at the &lt;em&gt;Logitech Solar App&lt;/em&gt; and &lt;em&gt;Wireshark&lt;/em&gt;
while bringing more and more light near the keyboard, increasing the lux
value received by the meter on the Solar App, and saw that the fields
represented in blue (see below) where changing in Wireshark. Since 2 bytes
were changing, I guessed that it was coded on 16 bits, and therefore it was
easy to correlate the value with the Solar App.&lt;/p&gt;
&lt;figure&gt;
&lt;pre&gt;
[ ....&lt;span style=&#34;color:red;&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color: blue;&#34;&gt;..&lt;/span&gt;..&lt;span style=&#34;color: green;&#34;&gt;GOOD&lt;/span&gt;....... ]
11 02 09 10 &lt;span style=&#34;color: red;&#34;&gt;39&lt;/span&gt; &lt;span style=&#34;color: blue;&#34;&gt;00 0c&lt;/span&gt; 06 1d &lt;span style=&#34;color: green;&#34;&gt;47 4f 4f 44&lt;/span&gt; 00 00 00 00 00 00 00
4 bytes - &lt;span style=&#34;color: red&#34;&gt;1 byte for battery charge&lt;/span&gt; - &lt;span style=&#34;color: blue;&#34;&gt;2 bytes for light meter&lt;/span&gt; - 2 bytes - &lt;span style=&#34;color: green&#34;&gt;4 bytes for GOOD&lt;/span&gt; - 7 bytes
&lt;/pre&gt;
&lt;/figure&gt;

&lt;p&gt;In this example, the battery has a charge of &lt;code&gt;0x39 = 57 %&lt;/code&gt; and
the light meter receives &lt;code&gt;0x0c = 12 lux&lt;/code&gt; of light. It&#39;s basically
dark, and that makes sense: it was night and the light was off in my office,
the only light being the one coming from my screen.&lt;/p&gt;
&lt;p&gt;I&#39;ve no idea what the &lt;code&gt;GOOD&lt;/code&gt; part of the packet is about, but
it&#39;s present in every packet and it&#39;s actually very handy to recognize such
a packet. Therefore I&#39;m considering this as some sort of useful mark for
now.&lt;/p&gt;
&lt;p&gt;For the other bytes, they were always the same (&lt;code&gt;0x11 0x2 0x9
0x10&lt;/code&gt; at the beginning, 7 times &lt;code&gt;0x00&lt;/code&gt; at the end). The 2
bytes between the light meter and GOOD probably mean something, but I&#39;ve no
idea what for now.&lt;/p&gt;
&lt;h1&gt;Building our solar app&lt;/h1&gt;
&lt;p&gt;Now we&#39;ve enough information to build our own very basic solar application.
We know how to triggers the light meter, and we know how to decode the
packets.&lt;/p&gt;
&lt;p&gt;We&#39;re going to write a small application using
&lt;a href=&#34;http://www.libusb.org/&#34;&gt;libusb&lt;/a&gt;. Here&#39;s a quick example. It&#39;s not perfect
and does not check for error codes, be careful.&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;cm&#34;&gt;/* Written by Julien Danjou &amp;lt;julien@danjou.info&amp;gt; in 2012 */&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;cp&#34;&gt;#include &amp;amp;lt;linux/hid.h&amp;amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;cp&#34;&gt;#include &amp;amp;lt;libusb.h&amp;amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cp&#34;&gt;#include &amp;amp;lt;stdio.h&amp;amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cp&#34;&gt;#include &amp;amp;lt;stdlib.h&amp;amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cp&#34;&gt;#include &amp;amp;lt;string.h&amp;amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_set_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;cm&#34;&gt;/* Look at the keyboard based on vendor and device id */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_device_handle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libusb_open_device_with_vid_pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x046d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xc52b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Found keyboard 0x%p&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_device&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libusb_get_device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libusb_device_descriptor&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_get_device_descriptor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bNumConfigurations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libusb_config_descriptor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;libusb_get_config_descriptor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        &lt;span class=&#34;cm&#34;&gt;/* We know we want interface 2 */&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libusb_interface&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iface&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;altsetting_index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;altsetting_index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num_altsetting&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;altsetting_index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libusb_interface_descriptor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iface_desc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iface&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;altsetting&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;al&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsetting_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iface_desc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bInterfaceClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LIBUSB_CLASS_HID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;n&#34;&gt;libusb_detach_kernel_driver&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;n&#34;&gt;libusb_claim_interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;65535&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x10\x02\x09\x03\x78\x01\x00&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libusb_control_transfer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                           &lt;span class=&#34;n&#34;&gt;LIBUSB_REQUEST_TYPE_CLASS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LIBUSB_RECIPIENT_INTERFACE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                           &lt;span class=&#34;n&#34;&gt;HID_REQ_SET_REPORT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                           &lt;span class=&#34;mh&#34;&gt;0x0210&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;payload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;actual_length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;actual_length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;strncmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;GOOD&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&#34;n&#34;&gt;libusb_interrupt_transfer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                                  &lt;span class=&#34;n&#34;&gt;iface_desc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;endpoint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bEndpointAddress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                                  &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;actual_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                    &lt;span class=&#34;kt&#34;&gt;uint16_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lux&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                    &lt;span class=&#34;n&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Charge: %d %%&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;Light: %d lux&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lux&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;                &lt;span class=&#34;n&#34;&gt;libusb_release_interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;n&#34;&gt;libusb_attach_kernel_driver&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;iface_index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;device_handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;libusb_exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/figure&gt;

&lt;p&gt;What the program is doing is the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Request for the Unifying Receiver device based on vendor and product ID&lt;/li&gt;
&lt;li&gt;Get the HID interface&lt;/li&gt;
&lt;li&gt;Detach the HID interface from the kernel driver&lt;/li&gt;
&lt;li&gt;Claim the interface&lt;/li&gt;
&lt;li&gt;Send a control packets, were parameters are defined using the same data we captured earlier&lt;/li&gt;
&lt;li&gt;Read interrupt packets coming in until we receive one we recognize (length
  20 containing the &#34;GOOD&#34; string)&lt;/li&gt;
&lt;li&gt;Decode the content (battery charge &amp;amp; light meter)&lt;/li&gt;
&lt;li&gt;Release the interface&lt;/li&gt;
&lt;li&gt;Reattach the kernel driver to the interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This gives the following:&lt;/p&gt;
&lt;pre&gt;
Found keyboard 0x0x24ec8e0
Charge: 64 %
Light: 21 lux
&lt;/pre&gt;

&lt;p&gt;Challenge accomplished!&lt;/p&gt;
&lt;h1&gt;To be continued&lt;/h1&gt;
&lt;p&gt;Unfortunately, this approach has at least one major drawback. We have to
disconnect the &lt;em&gt;Logitech Unifying Receiver&lt;/em&gt; from the kernel. That means that
while we&#39;re waiting for the packet, we&#39;re dropping packets corresponding to
other events from every connected device (key presses, pointer motions…).&lt;/p&gt;
&lt;p&gt;In order to solve that, I sent a request for help on the
&lt;a href=&#34;http://vger.kernel.org/vger-lists.html#linux-input&#34;&gt;linux-input&lt;/a&gt; mailing
list. That way, I learned that Logitech is actually using the HID++ protocol
to communicate with the devices using the Unifying Receiver. &lt;a href=&#34;http://6xq.net&#34;&gt;Lars-Dominik
Braun&lt;/a&gt; managed to get the HID++ specifications from Logitech
and &lt;a href=&#34;http://6xq.net/git/lars/lshidpp.git/plain/doc/logitech_hidpp_2.0_specification_draft_2012-06-04.pdf&#34;&gt;published
them&lt;/a&gt;
with their authorization.&lt;/p&gt;
&lt;p&gt;This opens a whole new world. With that document, I may be able to
understand the part I reverse engineered and convert this to a more useful
and generic library using the hidraw interface (so we don&#39;t have to
disconnect the devices from the kernel driver).&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Making the jump: working freelance</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/making-the-jump"/>
    <updated>2012-07-02T10:55:00Z</updated>
    <published>2012-07-02T10:55:00Z</published>
    <id>/blog/2012/making-the-jump</id>
        <category   scheme="/blog/tags"
                term="work"
                label="Work" />
    
    <content type="html">
            &lt;p&gt;For the last 10 years, I&#39;ve been working on many Free Software projects.
From &lt;a href=&#34;http://www.debian.org&#34;&gt;Debian&lt;/a&gt; to &lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt;,
through &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;,
&lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt;,
&lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt; and &lt;a href=&#34;http://julien.danjou.info/projects&#34;&gt;many
more&lt;/a&gt;. This obviously allowed me to
enhance my technical skills, but it also taught me about Free Software and
Open Source development processes, and how to work with and close to the
community.&lt;/p&gt;
&lt;p&gt;Working for almost 6 years at &lt;a href=&#34;http://easter-eggs.com&#34;&gt;Easter-eggs&lt;/a&gt; taught
me how to work in an autonomous manner, how to lead and manage a project.
And how to run a company, thanks to the cooperative status of this great
one.&lt;/p&gt;
&lt;p&gt;These are the reasons why I decided to leave my latest job and run my own
company to work as a &lt;a href=&#34;http://julien.danjou.info/freelance&#34;&gt;freelance consultant &amp;amp;
developer&lt;/a&gt; specialized in Free
Software, starting today.&lt;/p&gt;
&lt;p&gt;Therefore, I am now able and available to provide expertise and development
on Free Software, including upstream contribution. Especially on projects I
already worked on recently, like &lt;a href=&#34;http://www.openstack.org&#34;&gt;OpenStack&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">How to make Twitter&#39;s Bootstrap tabs bookmarkable</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/twitter-bootstrap-tabs-bookmark"/>
    <updated>2012-06-29T12:21:00Z</updated>
    <published>2012-06-29T12:21:00Z</published>
    <id>/blog/2012/twitter-bootstrap-tabs-bookmark</id>
        <category   scheme="/blog/tags"
                term="javascript"
                label="Javascript" />
        <category   scheme="/blog/tags"
                term="bootstrap"
                label="Bootstrap" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve been using &lt;a href=&#34;http://twitter.github.com/bootstrap/&#34;&gt;Twitter&#39;s bootstrap&lt;/a&gt;
library recently to build this Web site, and wondered how to be able to use
&lt;a href=&#34;http://twitter.github.com/bootstrap/javascript.html#tabs&#34;&gt;the
bootstrap-tab&lt;/a&gt;
Javascript plugin in a bookmark friendly manner.&lt;/p&gt;
&lt;p&gt;I ended up with a simple solution. These are my first steps in Javascript
and front-end manipulation, and it&#39;s really not my area of expertise, so
don&#39;t be harsh.&lt;/p&gt;
&lt;figure&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bootstrap_tab_bookmark&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;selector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;selector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;undefined&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;nx&#34;&gt;selector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;cm&#34;&gt;/* Automagically jump on good tab based on anchor */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;undefined&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;selector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;[href=#&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;]&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;show&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;update_location&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;href&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;cm&#34;&gt;/* Update hash based on tab */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;selector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;[data-toggle=pill]&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;click&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;update_location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;nx&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;selector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;[data-toggle=tab]&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;click&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;update_location&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/figure&gt;

&lt;p&gt;All you need is to use and call this function with a selector (only useful
if you have several tabs/pills divisions) when the document is ready.&lt;/p&gt;
&lt;p&gt;The first part takes care of showing the good tab based on the hash
contained in the URL. The second part takes care of changing the document
location to add the current tab to it when the user clicks.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OpenStack Swift eventual consistency analysis &amp; bottlenecks</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/openstack-swift-consistency-analysis"/>
    <updated>2012-04-23T12:06:00Z</updated>
    <published>2012-04-23T12:06:00Z</published>
    <id>/blog/2012/openstack-swift-consistency-analysis</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="swift"
                label="Swift" />
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;https://launchpad.net/swift&#34;&gt;Swift&lt;/a&gt; is the software behind the &lt;a href=&#34;http://openstack.org/projects/storage/&#34;&gt;OpenStack
Object Storage&lt;/a&gt; service.&lt;/p&gt;
&lt;p&gt;This service provides a simple storage service for applications using
&lt;a href=&#34;http://docs.openstack.org/api/openstack-object-storage/1.0/content/&#34;&gt;RESTful
interfaces&lt;/a&gt;,
providing maximum data availability and storage capacity.&lt;/p&gt;
&lt;p&gt;I explain here how some parts of the storage and replication in Swift works,
and show some of its current limitations.&lt;/p&gt;
&lt;p&gt;If you don&#39;t know Swift and want to read a more &#34;shallow&#34; overview first,
you can read John Dickinson&#39;s &lt;a href=&#34;http://programmerthoughts.com/openstack/swift-tech-overview/&#34;&gt;Swift Tech
Overview&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;How Swift storage works&lt;/h1&gt;
&lt;p&gt;If we refer to the &lt;a href=&#34;http://en.wikipedia.org/wiki/CAP_theorem&#34;&gt;CAP theorem&lt;/a&gt;,
Swift chose &lt;strong&gt;availability&lt;/strong&gt; and &lt;strong&gt;partition tolerance&lt;/strong&gt; and dropped
&lt;strong&gt;consistency&lt;/strong&gt;. That means that you&#39;ll always get your data, they will be
dispersed on many places, but you could get an old version of them (or no
data at all) in some odd cases (like some server overload or failure). This
compromise is made to allow maximum availability and scalability of the
storage platform.&lt;/p&gt;
&lt;p&gt;But there are mechanisms built into Swift to minimize the potential data
inconsistency window: they are responsible for data replication and
consistency.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://swift.openstack.org/&#34;&gt;official Swift documentation&lt;/a&gt; explains the
internal storage in a certain way, but I&#39;m going to write my own explanation
here about this.&lt;/p&gt;
&lt;h2&gt;Consistent hashing&lt;/h2&gt;
&lt;p&gt;Swift uses the principle of &lt;a href=&#34;http://en.wikipedia.org/wiki/Consistent_hashing&#34;&gt;consistent
hashing&lt;/a&gt;. It builds what it
calls a &lt;em&gt;ring&lt;/em&gt;. A ring represents the space of all possible computed hash
values divided in equivalent parts. Each part of this space is called a
&lt;em&gt;partition&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The following schema (stolen from the &lt;a href=&#34;http://wiki.basho.com/&#34;&gt;Riak&lt;/a&gt;
project) shows the principle nicely:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Consistent hashing ring&#34; src=&#34;/media/images/blog/2012/riak-ring.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;In a simple world, if you wanted to store some objects and distribute them
on 4 nodes, you would split your hash space in 4. You would have 4
partitions, and computing &lt;em&gt;hash(object) modulo 4&lt;/em&gt; would tell you where to
store your object: on node 0, 1, 2 or 3.&lt;/p&gt;
&lt;p&gt;But since you want to be able to extend your storage cluster to more nodes
without breaking the whole hash mapping and moving everything around, you
need to build a lot more partitions. Let&#39;s say we&#39;re going to build
2&lt;sup&gt;10&lt;/sup&gt; partitions. Since we have 4 nodes, each node will
have &lt;code&gt;2&lt;sup&gt;10&lt;/sup&gt; ÷ 4 = 256&lt;/code&gt; partitions. If we ever want to
add a 5&lt;sup&gt;th&lt;/sup&gt; node, it&#39;s easy: we just have to re-balance the
partitions and move 1⁄4 of the partitions from each node to this
5&lt;sup&gt;th&lt;/sup&gt; node. That means all our nodes will end up
with &lt;code&gt;2&lt;sup&gt;10&lt;/sup&gt; ÷ 5 ≈ 204&lt;/code&gt; partitions. We can also define a
&lt;em&gt;weight&lt;/em&gt; for each node, in order for some nodes to get more partitions than
others.&lt;/p&gt;
&lt;p&gt;With 2&lt;sup&gt;10&lt;/sup&gt; partitions, we can have up to 2&lt;sup&gt;10&lt;/sup&gt; nodes in our
cluster. Yeepee.&lt;/p&gt;
&lt;p&gt;For reference, Gregory Holt, one of the Swift authors, also wrote &lt;a href=&#34;http://www.tlohg.com/p/building-consistent-hashing-ring.html&#34;&gt;an
explanation post about the
ring&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Concretely, when building one Swift ring, you&#39;ll have to say how much
partitions you want, and this is what this value is really about.&lt;/p&gt;
&lt;h2&gt;Data duplication&lt;/h2&gt;
&lt;p&gt;Now, to assure availability and partitioning (as seen in the &lt;em&gt;CAP theorem&lt;/em&gt;)
we also want to store replicas of our objects. By default, Swift stores 3
copies of every objects, but that&#39;s configurable.&lt;/p&gt;
&lt;p&gt;In that case, we need to store each partition defined above not only on 1
node, but on 2 others. So Swift adds another concept: zones. A zone is an
isolated space that does not depends on other zone, so in case of an outage
on a zone, the other zones are still available. Concretely, a zone is likely
to be a disk, a server, or a whole cabinet, depending on the size of your
cluster. It&#39;s up to you to chose anyway.&lt;/p&gt;
&lt;p&gt;Consequently, each partitions has not to be mapped to 1 host only anymore,
but to N hosts. Each node will therefore store this number of partitions:&lt;/p&gt;
&lt;pre&gt;
number of partition stored on one node = number of replicas × total number of partitions ÷ number of node
&lt;/pre&gt;

&lt;p&gt;Examples:&lt;/p&gt;
&lt;blockquote&gt;
We split the ring in 2&lt;sup&gt;10&lt;/sup&gt; = 1024 partitions. We have 3 nodes. We want 3 replicas of data.&lt;br&gt;
→ Each node will store a copy of the full partition space: &lt;code&gt;3 × 2&lt;sup&gt;10&lt;/sup&gt; ÷ 3 = 2&lt;sup&gt;10&lt;/sup&gt; = 1024 partitions&lt;/code&gt;.
&lt;/blockquote&gt;

&lt;blockquote&gt;
We split the ring in 2&lt;sup&gt;11&lt;/sup&gt; = 2048 partitions. We have 5 nodes. We want 3 replicas of data.&lt;br&gt;
→ Each node will store &lt;code&gt;2&lt;sup&gt;11&lt;/sup&gt; × 3 ÷ 5 ≈ 1129 partitions&lt;/code&gt;.
&lt;/blockquote&gt;

&lt;blockquote&gt;
We split the ring in 2&lt;sup&gt;11&lt;/sup&gt; = 2048 partitions. We have 6 nodes. We want 3 replicas of data.&lt;br&gt;
→ Each node will store &lt;code&gt;2&lt;sup&gt;11&lt;/sup&gt; × 3 ÷ 6 = 1024 partitions&lt;/code&gt;.
&lt;/blockquote&gt;

&lt;h2&gt;Three rings to rule them all&lt;/h2&gt;
&lt;p&gt;In Swift, there is 3 categories of thing to store: &lt;em&gt;account&lt;/em&gt;, &lt;em&gt;container&lt;/em&gt;
and &lt;em&gt;objects&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;account&lt;/strong&gt; is what you&#39;d expect it to be, a user account. An account
contains &lt;strong&gt;containers&lt;/strong&gt; (the equivalent of Amazon S3&#39;s buckets). Each
container can contains user-defined key and values (just like a hash table
or a dictionary): values are what Swift call &lt;strong&gt;objects&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Swift wants you to build 3 different and independent rings to store its 3
kind of things (&lt;em&gt;accounts&lt;/em&gt;, &lt;em&gt;containers&lt;/em&gt; and &lt;em&gt;objects&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Internally, the two first categories are stored as
&lt;a href=&#34;http://www.sqlite.org/&#34;&gt;SQLite&lt;/a&gt; databases, whereas the last one is stored
using regular files.&lt;/p&gt;
&lt;p&gt;Note that this 3 rings can be stored and managed on 3 completely different
set of servers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Swift storage schema&#34; src=&#34;/media/images/blog/2012/openstack-swift-storage.png&#34; /&gt;&lt;/p&gt;
&lt;h1&gt;Data replication&lt;/h1&gt;
&lt;p&gt;Now that we have our storage theory in place (accounts, containers and
objects distributed into partitions, themselves stored into multiple zones),
let&#39;s go the replication practice.&lt;/p&gt;
&lt;p&gt;When you put something in one of the 3 rings (being an account, a container
or an object) it is uploaded into all the zones responsible for the ring
partition the object belongs to. This upload into the different zones is the
responsibility of the &lt;em&gt;swift-proxy&lt;/em&gt; daemon.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Swift proxy schema&#34; src=&#34;/media/images/blog/2012/openstack-swift-replication.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;But if one of the zone is failing, you can&#39;t upload all your copies in all
zones at the upload time. So you need a mechanism to be sure the failing
zone will catch up to a correct state at some point.&lt;/p&gt;
&lt;p&gt;That&#39;s the role of the &lt;em&gt;swift-{container,account,object}-replicator&lt;/em&gt;
processes. This processes are &lt;strong&gt;running on each node part of a zone&lt;/strong&gt; and
replicates their contents to nodes of the other zones.&lt;/p&gt;
&lt;p&gt;When they run, they walk through all the contents from all the partitions on
the whole file system and for each partition, issue a special &lt;em&gt;REPLICATE&lt;/em&gt;
HTTP request to all the other zones responsible for that same partition. The
other zone responds with information about the local state of the partition.
That allows the replicator process to decide if the remote zone has an
up-to-date version of the partition.&lt;/p&gt;
&lt;p&gt;In case of account and containers, it doesn&#39;t check at the partition level,
but check each account/container contained inside each partition.&lt;/p&gt;
&lt;p&gt;If something is not up-to-date, it will be pushed using &lt;em&gt;rsync&lt;/em&gt; by the
replicator process. This is why you&#39;ll read that the replication updates are
&lt;em&gt;&#34;push based&#34;&lt;/em&gt; in Swift documentation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;c&#34;&gt;# Pseudo code describing replication process for accounts&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# The principle is exactly the same for containers&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# Determine the partition used to store this account&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;hash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;number_of_partitions&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# The number of zone is the number of replicas configured&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_zones_storing_this_partition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;c&#34;&gt;# Send a HTTP REPLICATE command to the remote swift-account-server process&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;version_of_account&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send_HTTP_REPLICATE_for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version_of_account&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sync_to&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This replication process is &lt;em&gt;O(number of account × number of replicas)&lt;/em&gt;. The
more your number of account will increase and the more you will want
replicas for your data, the more the replication time for your accounts will
grow. The same rule applies for containers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;c&#34;&gt;# Pseudo code describing replication process for objects&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partitions_storing_objects&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# The number of zone is the number of replicas configured&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_zones_storing_this_partition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;c&#34;&gt;# Send a HTTP REPLICATE command to the remote swift-object-server process&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;verion_of_partition&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;send_HTTP_REPLICATE_for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version_of_partition&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# Use rsync to synchronize the whole partition&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# and all its objects&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rsync_to&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This replication process is
&lt;em&gt;O(number of objects partitions × number of replicas)&lt;/em&gt;. The more your
number of objects partitions will increase, and the more you will want
replicas for your data, the more the replication time for your objects will
grow.&lt;/p&gt;
&lt;p&gt;I think this is something important to know when deciding how to build your
Swift architecture. Choose the right number the number of replicas,
partitions and nodes.&lt;/p&gt;
&lt;h1&gt;Replication process bottlenecks&lt;/h1&gt;
&lt;p&gt;&lt;span class=&#34;pull-right&#34;&gt;
&lt;img alt=&#34;Copycat&#34; src=&#34;/media/images/blog/2012/copy-cat.jpg&#34; /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;File accesses&lt;/h2&gt;
&lt;p&gt;The problem, as you might have guessed, is that to replicate, &lt;strong&gt;it walks
through every damn things&lt;/strong&gt;, things being accounts, containers, or object&#39;s
partition hash files. This means it need to open and read (part of) a every
file your node stores to check that data need or not to be replicated!&lt;/p&gt;
&lt;p&gt;For accounts &amp;amp; containers replication, this is done every 30 seconds by
default, but it will likely take more than 30 seconds as soon as you hit
around 12 000 containers on a node (see measurements below). Therefore
you&#39;ll end up checking consistency of accounts &amp;amp; containers on each all node
&lt;strong&gt;all the time&lt;/strong&gt;, using obviously a lot of CPU time.&lt;/p&gt;
&lt;p&gt;For reference, &lt;a href=&#34;http://alexyang.sinaapp.com/?p=115&#34;&gt;Alex Yang also did an
analysis&lt;/a&gt; of that same problem.&lt;/p&gt;
&lt;h2&gt;TCP connections&lt;/h2&gt;
&lt;p&gt;Worst, the HTTP connections used to send the &lt;em&gt;REPLICATE&lt;/em&gt; commands are not
pooled: a new TCP connection is established each time something has to be
checked against the same thing stored on a remote zone.&lt;/p&gt;
&lt;p&gt;This is why you&#39;ll see in the &lt;a href=&#34;http://swift.openstack.org/deployment_guide.html&#34;&gt;Swift&#39;s Deployment
Guide&lt;/a&gt; this lines listed
under &lt;a href=&#34;http://swift.openstack.org/deployment_guide.html#general-system-tuning&#34;&gt;&#34;general system
tuning&#34;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;c1&#34;&gt;# disable TIME_WAIT.. wait..&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;na&#34;&gt;net.ipv4.tcp_tw_recycle&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;na&#34;&gt;net.ipv4.tcp_tw_reuse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c1&#34;&gt;# double amount of allowed conntrack&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;na&#34;&gt;net.ipv4.netfilter.ip_conntrack_max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;262144&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
In my humble opinion, this is more an ugly hack than a tuning. If you don&#39;t
activate this and if you have a lot of containers on your node, you&#39;ll end
up soon with thousands of connections in &lt;em&gt;TIME_WAIT&lt;/em&gt; state, and you indeed
risk to overload the IP conntrack module.&lt;/p&gt;
&lt;h2&gt;Container deletion&lt;/h2&gt;
&lt;p&gt;We also should talk about container deletion. When a user deletes a
container from its account, the container is &lt;strong&gt;marked as deleted&lt;/strong&gt;. And
that&#39;s it. It&#39;s not deleted. Therefore the SQLite database file representing
the container will continue to be checked for synchronization, over and
over.&lt;/p&gt;
&lt;p&gt;The only way to have a container permanently deleted is to &lt;strong&gt;mark an account
as deleted&lt;/strong&gt;. This way the &lt;em&gt;swift-account-reaper&lt;/em&gt; will delete all its
containers and, finally, the account.&lt;/p&gt;
&lt;h1&gt;Measurement&lt;/h1&gt;
&lt;p&gt;On a pretty big server, I measured the replications to be done at a speed of
around 350 {account,container,object-partitions}/second, which can be a real
problem if you chose to build a lots of partition and you have a low
&lt;em&gt;number_of_node ⁄ number_of_replicas&lt;/em&gt; ratio.&lt;/p&gt;
&lt;p&gt;For example, the default parameters runs the container replication every 30
seconds. To check replication status of 12 000 containers stored on one node
at the speed of 350 containers/seconds, you&#39;ll need around 34 seconds to do
so. In the end, you&#39;ll never stop checking replication of your containers,
and the more you&#39;ll have containers, the more your &lt;strong&gt;inconsistency window
will increase&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Until some of the code is fixed (the HTTP connection pooling probably being
the &#34;easiest&#34; one), I warmly recommend to chose correctly the different
Swift parameters for your setup. The replication process optimization
consists in having the minimum amount of partitions per node, which can be
done by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;decreasing the number of partitions&lt;/li&gt;
&lt;li&gt;decreasing the number of replicas&lt;/li&gt;
&lt;li&gt;increasing the number of node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For very large setups, some code to speed up accounts and containers
synchronization, and remove deleted containers will be required, but this
does not exist yet, as far as I know.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;The opinions expressed here represent my own and not those of my employer.&lt;/small&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">First release of PyMuninCli</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/pymunincli-0.1"/>
    <updated>2012-04-17T11:06:00Z</updated>
    <published>2012-04-17T11:06:00Z</published>
    <id>/blog/2012/pymunincli-0.1</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="munin"
                label="Munin" />
    
    <content type="html">
            &lt;p&gt;Today I release a &lt;a href=&#34;http://python.org&#34;&gt;Python&lt;/a&gt; client library to query
&lt;a href=&#34;http://munin-monitoring.org/&#34;&gt;Munin&lt;/a&gt; servers.&lt;/p&gt;
&lt;p&gt;I wrote it as part of some experiments I did a few weeks ago. I discovered
there was no client library to query a Munin server. There&#39;s
&lt;a href=&#34;http://aouyar.github.com/PyMunin/&#34;&gt;PyMunin&lt;/a&gt; or
&lt;a href=&#34;http://samuelks.com/python-munin/&#34;&gt;python-munin&lt;/a&gt; which help developing
Munin plugins, but nothing to access the &lt;em&gt;munin-node&lt;/em&gt; and retrieve its data.&lt;/p&gt;
&lt;p&gt;So I decided to write a quick and simple one, and it&#39;s released under the
name of &lt;a href=&#34;http://julien.danjou.info/software/pymunincli/&#34;&gt;PyMuninCli&lt;/a&gt;,
providing the &lt;em&gt;munin.client&lt;/em&gt; Python module.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">mod_defensible 1.5 released</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/mod_defensible-1.5"/>
    <updated>2012-04-03T15:48:00Z</updated>
    <published>2012-04-03T15:48:00Z</published>
    <id>/blog/2012/mod_defensible-1.5</id>
        <category   scheme="/blog/tags"
                term="apache"
                label="Apache" />
        <category   scheme="/blog/tags"
                term="dnsbl"
                label="Dnsbl" />
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
    
    <content type="html">
            &lt;p&gt;Apache 2.4 being out, I noticed that my good old
&lt;a href=&#34;http://julien.danjou.info/software/mod_defensible&#34;&gt;mod_defensible&lt;/a&gt; did not
compile anymore.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://httpd.apache.org/docs/2.4/developer/new_api_2_4.html&#34;&gt;changes in the new Apache 2.4
API&lt;/a&gt; were small
for its concern, so it was pretty easy to update this software to make it
compile again.&lt;/p&gt;
&lt;p&gt;Honestly, I&#39;m not sure that this module is really used into the wild, but I
still think that it can serve as a good prototype for doing other things so
I like keeping it around. :-)&lt;/p&gt;
&lt;p&gt;All this has been triggered by the Apache 2.4 arrival into Debian
experimental. Therefore &lt;a href=&#34;http://git.naquadah.org/?p=mod_defensible.git;a=shortlog;h=refs/heads/debian/unstable&#34;&gt;I&#39;ve updated the mod_defensible package to use the
new
dh_apache2&lt;/a&gt;,
and imported it into Git at the same time.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">xpyb 1.3 released</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/xpyb-1.3"/>
    <updated>2012-03-22T22:06:00Z</updated>
    <published>2012-03-22T22:06:00Z</published>
    <id>/blog/2012/xpyb-1.3</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="xcb"
                label="Xcb" />
        <category   scheme="/blog/tags"
                term="xpyb"
                label="Xpyb" />
        <category   scheme="/blog/tags"
                term="freedesktop"
                label="Freedesktop" />
        <category   scheme="/blog/tags"
                term="x11"
                label="X11" />
    
    <content type="html">
            &lt;p&gt;It took a while to get it out, but finally, 3 years after the latest release
(1.2), the version of 1.3 of &lt;a href=&#34;http://cgit.freedesktop.org/xcb/xpyb/&#34;&gt;xpyb&lt;/a&gt;
(the &lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt; Python bindngs) is out.&lt;/p&gt;
&lt;p&gt;This version has a lot of improvement, and major bug fixes (memory
corruption and memory leak were tracked down and fixed).&lt;/p&gt;
&lt;p&gt;One amazing feature that is now shipped with that release, is &lt;a href=&#34;http://julien.danjou.info/blog/2009/python-cairo-and-xcb-support&#34;&gt;my code to
export the xpyb API to other Python
modules&lt;/a&gt;,
allowing to draw with &lt;a href=&#34;http://www.cairographics.org/pycairo/&#34;&gt;Pycairo&lt;/a&gt; in
Python using XCB.&lt;/p&gt;
&lt;p&gt;Here is an example of a Python program that draws a spiral in a window using
xpyb and Pycairo. You need xpyb &amp;gt;= 1.3 and Pycairo &amp;gt;= 1.10 to make this
works.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;cairo&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;xcb&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;xcb.xproto&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HEIGHT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;600&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;600&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;draw_spiral&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;sd&#34;&gt;&amp;quot;&amp;quot;&amp;quot;Draw a spiral with lines!&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;wd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mo&#34;&gt;02&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;hd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mo&#34;&gt;02&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;move_to&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rel_line_to&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rel_line_to&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rel_line_to&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rel_line_to&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_source_rgb&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stroke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Connect to the X server&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xcb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Get the X server setup&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Generate X ID for our X &amp;quot;objects&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;window&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generate_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;pixmap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generate_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;gc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generate_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Create a new window&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CreateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root_depth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;c&#34;&gt;# Parent is the root window&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WindowClass&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;InputOutput&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root_visual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;n&#34;&gt;CW&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BackPixel&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CW&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EventMask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;white_pixel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EventMask&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ButtonPress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EventMask&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EnterWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EventMask&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;LeaveWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EventMask&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Exposure&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Create a pixmap: it will be used to draw with cairo&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CreatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root_depth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                       &lt;span class=&#34;n&#34;&gt;WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# We just need a GC to copy later the pixmap on the window, so create one&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# very simple&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CreateGC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Foreground&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Background&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                   &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;black_pixel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;white_pixel&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Create a cairo surface&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;surface&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cairo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;XCBSurface&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                            &lt;span class=&#34;n&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;roots&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allowed_depths&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;visuals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Create a cairo context with that surface&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cairo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;surface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Paint everything in white&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_source_rgb&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_operator&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cairo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OPERATOR_SOURCE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Draw our spiral&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;draw_spiral&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Map the window on the screen so it gets visible&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MapWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;c&#34;&gt;# Flush all X requests to the X server&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wait_for_event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xcb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ProtocolException&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Protocol error &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; received!&amp;quot;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__class__&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__name__&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# ExposeEvent are received when we need to refresh the content of the&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# window, so we copy the content of the pixmap (where cairo drew) in the&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# window&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;isinstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ExposeEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CopyArea&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# You click, I quit.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;elif&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;isinstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ButtonPressEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;n&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Seeing the complexity it is to draw something simple with this technology, I
somehow understand why nobody bothered to release or use the code during the
last 3 years.&lt;/p&gt;
&lt;p&gt;But hey, now that it&#39;s out, you can build the next Python based desktop
environment with bleeding edge technologies. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">10 years as a Debian developer</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/ten-years-as-a-debian-developer"/>
    <updated>2012-02-24T08:55:00Z</updated>
    <published>2012-02-24T08:55:00Z</published>
    <id>/blog/2012/ten-years-as-a-debian-developer</id>
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="xen"
                label="Xen" />
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="awesome"
                label="Awesome" />
        <category   scheme="/blog/tags"
                term="vhffs"
                label="Vhffs" />
        <category   scheme="/blog/tags"
                term="tuxfamily"
                label="Tuxfamily" />
    
    <content type="html">
            &lt;p&gt;Ten years ago, I joined the &lt;a href=&#34;http://www.debian.org&#34;&gt;Debian&lt;/a&gt; project as a developer.&lt;/p&gt;
&lt;p&gt;At that time, I was 18 and in my first year at university, hanging out with
the &lt;a href=&#34;http://tuxfamily.org&#34;&gt;TuxFamily&lt;/a&gt; system administrators, which included
3 french Debian developers (sjg, igenibel and creis).&lt;/p&gt;
&lt;p&gt;I was learning Debian packaging while working on &lt;a href=&#34;http://vhffs.org&#34;&gt;VHFFS&lt;/a&gt;,
and decided to package one or two non-yet-packaged software for Debian. My
friends pushed me into the &lt;a href=&#34;http://nm.debian.org&#34;&gt;NM process&lt;/a&gt;, and &lt;a href=&#34;https://nm.debian.org/nmstatus.php?email=acid@hno3.org&#34;&gt;less
than 2 months later&lt;/a&gt;
I was a Debian developer. One have to admit that back in the days, the NM
process was really fast if you were able to reply to the questions quickly.
:-) I think I became the youngest developer among Debian&#39;s ones.&lt;/p&gt;
&lt;p&gt;That was my first steps in a Free Software project, and it was really
exciting.&lt;/p&gt;
&lt;p&gt;In 10 years, I&#39;ve been doing a lot of different things for Debian. Sure,
I&#39;ve been using it all the years long, but let&#39;s recap a bit what I did,
from what I recall.&lt;/p&gt;
&lt;p&gt;My first Debian only project was
&lt;a href=&#34;http://packages.debian.org/apt-build&#34;&gt;apt-build&lt;/a&gt; around 2003, and later
&lt;a href=&#34;http://packages.debian.org/rebuildd&#34;&gt;rebuildd&lt;/a&gt; in 2007.&lt;/p&gt;
&lt;p&gt;I built the &lt;a href=&#34;https://alioth.debian.org/projects/pkg-xen/&#34;&gt;Xen packaging team&lt;/a&gt; in 2005,
I&#39;ve been a Stable Release Manager for a year in 2006, and did heavy bug
squashing to release Etch that same year.&lt;/p&gt;
&lt;p&gt;I also was an &lt;a href=&#34;https://nm.debian.org/whoisam.php&#34;&gt;Application Manager in
2006&lt;/a&gt; and managed the application of 2
Debian developers (&lt;a href=&#34;https://nm.debian.org/nmstatus.php?email=joseparrella%40cantv.net&#34;&gt;Jose
Parrella&lt;/a&gt;
and &lt;a href=&#34;https://nm.debian.org/nmstatus.php?email=debian%40damianv.com.ar&#34;&gt;Damián
Viano&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I admit I&#39;ve been less active in Debian after 2007, mainly because I was
busy working on &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;, &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;GNU
Emacs&lt;/a&gt; and others software.&lt;/p&gt;
&lt;p&gt;Since 2011, I joined the &lt;a href=&#34;http://alioth.debian.org/projects/openstack/&#34;&gt;OpenStack packaging
team&lt;/a&gt; and I&#39;m working on
OpenStack on a (almost) daily basis.&lt;/p&gt;
&lt;p&gt;I don&#39;t know how many packages I touched, managed or updated, but that
should be one or two hundreds. I still maintain &lt;a href=&#34;http://qa.debian.org/developer.php?login=acid&#34;&gt;53 of
them&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After all, the adventure has been really pleasant, and I had the chance to
work with and meet fabulous and smart people. I always liked this project
and what it&#39;s trying to do.&lt;/p&gt;
&lt;p&gt;After all these years, I&#39;m definitively staying!
See you in another 10 years, folks! :)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Google Calendar notifications using pynotify</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2012/google-calendar-pynotify"/>
    <updated>2012-01-03T18:55:00Z</updated>
    <published>2012-01-03T18:55:00Z</published>
    <id>/blog/2012/google-calendar-pynotify</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="gtk"
                label="Gtk" />
        <category   scheme="/blog/tags"
                term="notify"
                label="Notify" />
        <category   scheme="/blog/tags"
                term="googlecalendar"
                label="Googlecalendar" />
        <category   scheme="/blog/tags"
                term="gdata"
                label="Gdata" />
    
    <content type="html">
            &lt;p&gt;I use &lt;a href=&#34;http://google.com/calendar&#34;&gt;Google Calendar&lt;/a&gt; to manage my calendars,
and I really missed something to warn me whenever I have an appointment with
an alert set.&lt;/p&gt;
&lt;p&gt;So here is an example of a Python program to do such a thing. It is written using
the &lt;a href=&#34;http://code.google.com/p/gdata-python-client/&#34;&gt;Google Data APIs Python client library&lt;/a&gt;
and pynotify.&lt;/p&gt;
&lt;p&gt;I&#39;ll detail the code here, so you can build your own and adapt it to your needs.&lt;/p&gt;
&lt;p&gt;First, we need to import GTK+ and pynotify, and initialize it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;gtk&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;pynotify&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;pynotify&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Then, we need to import gdata Calendar API and connect to the calendar. I&#39;ll
use the simple email/password way to login, which is clearly not the best,
but it&#39;s also the simplest. Feel free to use OAuth 2.0. :-)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;n&#34;&gt;calendar_service&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gdata&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;calendar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CalendarService&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;calendar_service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;email&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;mygooglelogin&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;calendar_service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;mygooglepassword&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;calendar_service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ProgrammaticLogin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Now we&#39;re ready to request stuff and notify! First, request the events from
the default calendar.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;n&#34;&gt;feed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;calendar_service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetCalendarEventFeed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Now we can iterate over &lt;em&gt;feed&lt;/em&gt; and do various checks.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# If the event status is not confirmed, go to the next event.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event_status&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;CONFIRMED&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;c&#34;&gt;# Now iterate over all the event dates (usually it has one)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;when&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;c&#34;&gt;# Parse start and end time&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;strptime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;when&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;%Y-%m-&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%d&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;T%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;end_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;strptime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;when&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;%Y-%m-&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%d&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;T%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;ValueError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# ValueError happens on parsing error. Parsing errors&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# usually happen for &amp;quot;all day&amp;quot; events since they have&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# not time, but we do not care about this events.&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;n&#34;&gt;now&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;c&#34;&gt;# Check that the event hasn&amp;#39;t already ended&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;c&#34;&gt;# Check each alert&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reminder&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;when&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reminder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;c&#34;&gt;# We handle only reminders with method &amp;quot;alert&amp;quot;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;c&#34;&gt;# and whose start time minus the reminder delay has passed&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reminder&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;alert&amp;quot;&lt;/span&gt; \&lt;br /&gt;                        &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timedelta&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;60&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reminder&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;minutes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;c&#34;&gt;# Build the notification&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;n&#34;&gt;notification&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pynotify&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Notification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;summary&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                                         &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;c&#34;&gt;# Set an icon from the GTK+ stock icons&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;n&#34;&gt;notification&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_icon_from_pixbuf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gtk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render_icon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gtk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;STOCK_DIALOG_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;br /&gt;                                                                              &lt;span class=&#34;n&#34;&gt;gtk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ICON_SIZE_LARGE_TOOLBAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;n&#34;&gt;notification&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_timeout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;c&#34;&gt;# Show the notification&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&#34;n&#34;&gt;notification&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Running this program, you should see a notification if an appointment has an
alert to be raised at that time.&lt;/p&gt;
&lt;p&gt;This should be enough to start to build something.&lt;/p&gt;
&lt;p&gt;If you don&#39;t want to program this into Python, you might want to take a look
at &lt;a href=&#34;http://code.google.com/p/gcalcli/wiki/HowTo&#34;&gt;gcalcli&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Using GTK+ stock icons with pynotify</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/python-notify-with-gtk-stock-icon"/>
    <updated>2011-12-27T11:55:00Z</updated>
    <published>2011-12-27T11:55:00Z</published>
    <id>/blog/2011/python-notify-with-gtk-stock-icon</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="gtk"
                label="Gtk" />
        <category   scheme="/blog/tags"
                term="notify"
                label="Notify" />
    
    <content type="html">
            &lt;p&gt;It took me a while to find this, so I&#39;m just blogging it so other people
will be able to find it.&lt;/p&gt;
&lt;p&gt;I wanted to send a &lt;a href=&#34;http://www.galago-project.org/specs/notification/&#34;&gt;desktop
notification&lt;/a&gt; using
pynotify, but using a &lt;a href=&#34;http://developer.gnome.org/gtk/2.24/gtk-Stock-Items.html&#34;&gt;GTK+ stock
icons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the following snippet, I managed to do it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;pynotify&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;pynotify&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;myapp&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;gtk&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pynotify&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Notification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;summary&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Summary&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Message!&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set_icon_from_pixbuf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gtk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render_icon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gtk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;STOCK_HARDDISK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gtk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ICON_SIZE_LARGE_TOOLBAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Note that the use of a &lt;em&gt;Label&lt;/em&gt; is just to have a widget instanciated to use
the &lt;em&gt;render_icon()&lt;/em&gt; method. It could be any widget type as far as I
understand.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">My OpenStack work</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/my-openstack-work"/>
    <updated>2011-12-16T17:34:00Z</updated>
    <published>2011-12-16T17:34:00Z</published>
    <id>/blog/2011/my-openstack-work</id>
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
    
    <content type="html">
            &lt;p&gt;Like I already wrote here last week, I&#39;ve been heavily working on
&lt;a href=&#34;http://openstack.org&#34;&gt;OpenStack&lt;/a&gt; for the last weeks.&lt;/p&gt;
&lt;p&gt;My first assignment was to package OpenStack for Debian. The packages
already present in unstable were mainly done by &lt;a href=&#34;http://thomas.goirand.fr/&#34;&gt;Thomas
Goirand&lt;/a&gt;, who based its work on the one done in
&lt;a href=&#34;http://ubuntu.com&#34;&gt;Ubuntu&lt;/a&gt;. Therefore, the packages where not in a very
good shape for Debian.&lt;/p&gt;
&lt;p&gt;Today Ghe Rivero and I (members of the &lt;a href=&#34;https://alioth.debian.org/projects/openstack&#34;&gt;OpenStack Debian packaging
team&lt;/a&gt;) managed to push the
&lt;a href=&#34;https://launchpad.net/openstack/+milestone/essex-2&#34;&gt;OpenStack Essex 2
milestone&lt;/a&gt; into unstable
with great success. You can now test and deploy OpenStack Essex 2 very easily!&lt;/p&gt;
&lt;p&gt;Packaging OpenStack &lt;a href=&#34;https://review.openstack.org/#dashboard,1669&#34;&gt;made me write several
patches&lt;/a&gt;, mainly related to
packaging, patches which were all accepted and merged by upstream. This is
nice because most of the OpenStack Debian packages lost their
&lt;em&gt;debian/patches&lt;/em&gt; directories now!&lt;/p&gt;
&lt;p&gt;Finally, I&#39;ve finished to implement one blueprint I really missed: the
&lt;a href=&#34;https://blueprints.launchpad.net/nova/+spec/support-kvm-boot-from-iso&#34;&gt;ability to boot from an ISO
image&lt;/a&gt;
using &lt;a href=&#34;http://libvirt.org&#34;&gt;libvirt&lt;/a&gt;. The code still needs a review, but it
should be included in the Essex 3 milestone if everything&#39;s right.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">New job, new blog</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/new-job-new-blog"/>
    <updated>2011-12-07T13:47:00Z</updated>
    <published>2011-12-07T13:47:00Z</published>
    <id>/blog/2011/new-job-new-blog</id>
        <category   scheme="/blog/tags"
                term="work"
                label="Work" />
        <category   scheme="/blog/tags"
                term="openstack"
                label="Openstack" />
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
    
    <content type="html">
            &lt;p&gt;It has been a while since I blogged but I&#39;ve been very busy, with my new job and this new blog!&lt;/p&gt;
&lt;h1&gt;New job!&lt;/h1&gt;
&lt;p&gt;I quitted my job last September, and found another one that I started in
October. I&#39;m now the lead developer of &lt;a href=&#34;http://www.enovance.com/fr/produits-solutions/opencloud-opensource/enovance-labs&#34;&gt;eNovance
Labs&lt;/a&gt;,
where I work on the &lt;a href=&#34;http://openstack.org/&#34;&gt;OpenStack&lt;/a&gt; project. So far, this allowed me to contribute heavily to the &lt;a href=&#34;https://alioth.debian.org/projects/openstack&#34;&gt;Debian packaging of OpenStack&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;New blog!&lt;/h1&gt;
&lt;p&gt;In the meantime, I took some time to redesign my personal homepage and this
blog, which is now using &lt;a href=&#34;https://github.com/hyde/hyde&#34;&gt;Hyde&lt;/a&gt;, the
&lt;a href=&#34;http://python.org&#34;&gt;Python&lt;/a&gt; equivalent of &lt;a href=&#34;http://jekyllrb.com/&#34;&gt;Jekyll&lt;/a&gt;,
which is in &lt;a href=&#34;http://www.ruby-lang.org/&#34;&gt;Ruby&lt;/a&gt;. Since I dislike Ruby
(sorry), I preferred to use a Python based generator, and I admit Hyde is really
cool.
Since I really suck at Web design, this one is obviously based on &lt;a href=&#34;http://twitter.github.com/bootstrap/&#34;&gt;Twitter&#39;s bootstrap&lt;/a&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Google Contacts for Emacs</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/google-contacts-for-emacs"/>
    <updated>2011-09-26T13:01:00Z</updated>
    <published>2011-09-26T13:01:00Z</published>
    <id>/blog/2011/google-contacts-for-emacs</id>
        <category   scheme="/blog/tags"
                term="googlecontacts"
                label="Googlecontacts" />
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;I finally finished a thing I was really missing: accessing my Google
Contacts from Emacs.&lt;/p&gt;
&lt;p&gt;That&#39;s now possible, thanks to my new
&lt;a href=&#34;/software/google-contacts.el&#34;&gt;google-contacts.el&lt;/a&gt;
package.&lt;/p&gt;
&lt;video controls=&#34;controls&#34;&gt;
&lt;source src=&#34;/media/videos/google-contacts.el/emacs-google-contacts.ogv&#34; type=&#34;video/ogg&#34; /&gt;
&lt;/video&gt;

&lt;p&gt;It includes searching for any contact and displaying the result in a window.
You can also jump to a contact from &lt;a href=&#34;http://gnus.org&#34;&gt;Gnus&lt;/a&gt; by pressing a
key, and complete e-mail addresses while composing a mail.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OAuth 2.0 for Emacs</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/oauth-2.0-for-emacs"/>
    <updated>2011-09-23T18:01:00Z</updated>
    <published>2011-09-23T18:01:00Z</published>
    <id>/blog/2011/oauth-2.0-for-emacs</id>
        <category   scheme="/blog/tags"
                term="oauth"
                label="Oauth" />
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;This week, I&#39;ve finished my &lt;a href=&#34;http://oauth.net/2/&#34;&gt;OAuth 2.0&lt;/a&gt;
client implementation for &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;GNU Emacs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have &lt;a href=&#34;http://bzr.savannah.gnu.org/lh/emacs/elpa/revision/126?start_revid=126&#34;&gt;imported it&lt;/a&gt;
into &lt;a href=&#34;http://elpa.gnu.org/&#34;&gt;GNU ELPA&lt;/a&gt; so Emacs 24 users will be soon able to
install it using the new Emacs packaging system.&lt;/p&gt;
&lt;p&gt;OAuth 2.0 can be used to access, among others,
&lt;a href=&#34;http://code.google.com/apis/accounts/docs/OAuth2.html&#34;&gt;Google APIs&lt;/a&gt; or the
&lt;a href=&#34;http://developers.facebook.com/docs/authentication/&#34;&gt;Facebook Graph API&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Quitting my job</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/quitting-my-job"/>
    <updated>2011-08-29T10:57:00Z</updated>
    <published>2011-08-29T10:57:00Z</published>
    <id>/blog/2011/quitting-my-job</id>
        <category   scheme="/blog/tags"
                term="work"
                label="Work" />
    
    <content type="html">
            &lt;p&gt;After more than 5 years at &lt;a href=&#34;http://www.easter-eggs.com&#34;&gt;Easter-eggs&lt;/a&gt; as a
system engineer, I&#39;ll be leaving my job soon.&lt;/p&gt;
&lt;p&gt;It has been a fabulous adventure, also due to the &#34;cooperative&#34; nature of
the company. I&#39;ve enjoyed worked here, with great people. I do wish them
luck for the future. Looking at the numerous things I did for the past
years, it has been quite productive!&lt;/p&gt;
&lt;p&gt;Therefore, I&#39;ll be looking for a new job in the next weeks, which will
probably keep me busy a bit. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Python sets comparisons</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/python-sets-comparisons"/>
    <updated>2011-05-17T14:01:00Z</updated>
    <published>2011-05-17T14:01:00Z</published>
    <id>/blog/2011/python-sets-comparisons</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
    
    <content type="html">
            &lt;p&gt;This week I lost some time playing with &lt;a href=&#34;http://python.org&#34;&gt;Python&lt;/a&gt;&#39;s
&lt;a href=&#34;http://docs.python.org/library/stdtypes.html#set&#34;&gt;sets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After digging into
Python source code, I finally discovered there is what seems to be little
bug. Anyway, it has been &#34;fixed&#34; in Python 3, fortunately. I did not find if
it was reported somewhere, but since it&#39;s fixed, it&#39;s not a big deal.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;n&#34;&gt;Python&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.7&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Apr&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2011&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;53&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;33&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GCC&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;4.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux2&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;credits&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;license&amp;quot;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__eq__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;             &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()])&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This clearly did not make any sense to me. I&#39;ve then tested under
Python 3.2:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;n&#34;&gt;Python&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;May&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2011&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;19&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;59&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;25&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GCC&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;4.6&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20110428&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prerelease&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux2&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;credits&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;license&amp;quot;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__eq__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;             &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()])&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;ne&#34;&gt;TypeError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unhashable&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
At least, raising an error is saner. It actually helped me to understand
what I needed to do to have my sets working correctly with Python 2:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;n&#34;&gt;Python&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.7&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Apr&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2011&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;53&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;33&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GCC&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;4.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux2&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;credits&amp;quot;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;license&amp;quot;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__eq__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;             &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__hash__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;             &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;123456789&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()])&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Why not Lua</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/why-not-lua"/>
    <updated>2011-04-26T18:53:00Z</updated>
    <published>2011-04-26T18:53:00Z</published>
    <id>/blog/2011/why-not-lua</id>
        <category   scheme="/blog/tags"
                term="lua"
                label="Lua" />
    
    <content type="html">
            &lt;p&gt;Since my latest announcement of the &lt;a href=&#34;/blog/2011/lua-workshop-at-Fabelier-tmplab&#34;&gt;Lua workshop&lt;/a&gt;, I received a couple of
emails asking why I discourage the use of &lt;a href=&#34;http://lua.org&#34;&gt;Lua&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Actually, I already wrote out many of &lt;a href=&#34;/blog/2008/rants-about-lua&#34;&gt;the things I dislike about Lua&lt;/a&gt;. I
won&#39;t come back on this technical issues here, but since Lua 5.2 is not yet
released (it&#39;s still at alpha stage), they are still relevant nowadays.&lt;/p&gt;
&lt;h1&gt;Stack based API is harder&lt;/h1&gt;
&lt;p&gt;The ease of integration of Lua into a C program is one of the point of Lua.
They claim it&#39;s very easy to integrate Lua into your C application, because
it does not use pointer, nor reference counting, nor anything that requires
a minimum amount of skills to be used.&lt;/p&gt;
&lt;p&gt;It uses a virtual stack based approach. You push or pop things on a stack,
and refers to them using a relative or absolute index.&lt;/p&gt;
&lt;p&gt;In order to people who never wrote Lua code to understand, here&#39;s a quick
example on how this work. The &lt;em&gt;L&lt;/em&gt; pointer is a Lua environment.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;cm&#34;&gt;/* Create a table on the stack: index 1 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_newtable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;/* Push a string on the stack: index 2 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_pushstring&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;/* Push a number on the stack: index 3 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_pushnumber&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;123&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;/* Set newtable[&amp;quot;hello&amp;quot;] = 123 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_settable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
You first push a table (in Lua, a table is almost equivalent to what you&#39;d
call a hash table in other language), then push the key, the value, and do
the assignment operation. In the settable, we use -3 as index, meaning the
&#34;3rd item on the stack counting from top&#34;. We could also have written
&lt;em&gt;lua_settable(L, 1)&lt;/em&gt;, since the table is also the first item on the stack from
the bottom.&lt;/p&gt;
&lt;p&gt;So far, so good.&lt;/p&gt;
&lt;p&gt;Problems arise when you do more complicated stuff. My previous example is
what you would typically find in a tutorial, but of course, real life is
different, and usually more complex. If you cut the things in different
parts, it can start to be more complicated.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;cm&#34;&gt;/* Create a table on the stack: index 1 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_newtable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;/* Push a string on the stack: index 2 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_pushstring&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;/* Push a number on the stack: index 3 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_pushnumbe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mycomputingfunction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;/* Set newtable[&amp;quot;hello&amp;quot;] = 123 */&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;n&#34;&gt;lua_settable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Here, we do exactly the same thing, but we do not push &lt;em&gt;123&lt;/em&gt; directly: we
compute it.&lt;/p&gt;
&lt;p&gt;And here&#39;s the trick: if your computing function is also using the Lua
stack, things can become &lt;em&gt;very&lt;/em&gt; messy. As long as your computing function use
the stack cleanly by pushing and poping all its item, and returning the
stack &lt;strong&gt;in the same state it was before&lt;/strong&gt;, you&#39;re safe. The problem is that in a
complex program, you also write bugs. You do not chose to, but you do. And
sometimes, you forget to pop one of the item you fetched from a table.&lt;/p&gt;
&lt;p&gt;Imagine that &lt;em&gt;mycomputingfunction&lt;/em&gt; is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;nf&#34;&gt;mycomputingfunctiong&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;cm&#34;&gt;/* Just push the table we want to fetch&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;cm&#34;&gt;     the number from on the stack */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;n&#34;&gt;pushatableonstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;n&#34;&gt;lua_pushstring&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;mykey&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;n&#34;&gt;lua_gettable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lua_tonumber&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This function works perfectly. It pushes a table, then a key (&lt;em&gt;&#34;mykey&#34;&lt;/em&gt;), then
fetches mytable[&#34;mykey&#34;] and pops the key (lua_gettable does push value/pop
key itself), and then returns the numeric value of the last item (the
fetched one) of the stack.&lt;/p&gt;
&lt;p&gt;However, this function has a bug: it does not pop the table! This does not
prevent the function to work. It does not raise a segmentation fault. It
does not show any problem under &lt;a href=&#34;http://www.gnu.org/software/gdb/&#34;&gt;gdb&lt;/a&gt;. It does not show any leak under
&lt;a href=&#34;http://valgrind.org/&#34;&gt;Valgrind&lt;/a&gt;. It does now show any problem under &lt;strong&gt;any standard C debugging tool&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But when you&#39;ll start using it, your program will start to do weird things,
and you&#39;ll have to spend a huge amount of time debugging it manually,
dumping the stack content at each step of your program to watch out what&#39;s
wrong.&lt;/p&gt;
&lt;p&gt;Another bad thing, that can happen, is some code poping accidentally an item
from the stack, or worst, from an empty stack. This does not raise any error
on the Lua side, but will break your program in very unfunny way.&lt;/p&gt;
&lt;p&gt;Even if I&#39;ve been very meticulous writing &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;, but we hit that problem
regularly.&lt;/p&gt;
&lt;p&gt;The easiest workaround is to use &lt;em&gt;lua_settop(L, 0)&lt;/em&gt; to reset the stack to 0
element. Doing this regularly (like after each program event or treatment)
can remove left-over items and avoid the never ending stack grow you may
experience if your left-over items continue to pile up. Did I tell you I
dislike work-around?&lt;/p&gt;
&lt;p&gt;You could also use &lt;em&gt;lua_call()&lt;/em&gt;, which would avoid such an error, but this
would require a huge amount of indirection, and would make write more
(useless) code.&lt;/p&gt;
&lt;p&gt;This kind of problem does not exists with pointer based API. If you screw
things up, the problem will cause a segmentation fault or leak memory, or
cause things you can (easily) debug with standard tools like gdb or
Valgrind.&lt;/p&gt;
&lt;h1&gt;No reference counting is a pain in the ass&lt;/h1&gt;
&lt;p&gt;Userdata objects are variable Lua size objects embedding a C struct you
define. It&#39;s the equivalent of an object in object oriented language.&lt;/p&gt;
&lt;p&gt;Lua does not provide any reference counting for the userdata objects. That
means you can push this objects on the stack, use them, but they cannot
directly reference each others. If you have a &#34;car&#34; userdata and a &#34;wheel&#34;
one, the car cannot hold directly a reference to the wheel. This is not
possible because userdata are allocated and garbage collected by Lua, and
there&#39;s no way to increase the reference counting yourself.&lt;/p&gt;
&lt;p&gt;So the common hack is to store the wheel into a table as a value, and store
the table index as an integer into the car data structure.&lt;/p&gt;
&lt;p&gt;This obviously makes memory leaks tracking harder, add huge level of
reference indirection in usage (still more code), and does not make the
whole process less error prone (at least in my opinion).&lt;/p&gt;
&lt;h1&gt;No paradigm makes you lose time&lt;/h1&gt;
&lt;p&gt;Lua is proud to come with no paradigm and to provide metatables.
&lt;a href=&#34;http://julien.danjou.info/blog/2008.html#_Rants_about_Lua&#34;&gt;I already showed 3 years ago that it has big flaws&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To me, this ain&#39;t no good. Lua is not functional, nor it is object oriented.&lt;/p&gt;
&lt;p&gt;Most people, including me, want one of this paradigm, or any else. Plain old
imperative is not enough.&lt;/p&gt;
&lt;p&gt;So you&#39;ll start to build more, or to use something like &lt;a href=&#34;http://loop.luaforge.net/&#34;&gt;LOOP&lt;/a&gt;, which
implements an object model. You&#39;ll implement your paradigm. I say life is
too short to (re)write a paradigm.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt; we wanted to have an object oriented approach (this is kind of
typical in such a graphical application context), so we tried to build one.
To me, this started to be a show stopper when I realized that I&#39;ve ended
writing Python object model into Lua while developing &lt;em&gt;awesome (which aims to
be a window manager, not a language)&lt;/em&gt;. This is one of the reason I stopped
hacking on Lua things.&lt;/p&gt;
&lt;p&gt;I liked Python object model and wanted to have it in Lua, and spending time
rewriting Python is just not worth it. I probably should have chose Python,
not Lua. YMMV.&lt;/p&gt;
&lt;h1&gt;Embedding may not be a good choice&lt;/h1&gt;
&lt;p&gt;This is not Lua related, but I want to mention it. Googling for
&#34;&lt;a href=&#34;http://www.google.fr/search?q=embedding+vs+extending&#34;&gt;embedding vs extending&lt;/a&gt;&#34; will probably tell you more about why you should
double check that you really need to embed Lua rather than to extend it.&lt;/p&gt;
&lt;h1&gt;Being small is not an excuse&lt;/h1&gt;
&lt;p&gt;One common argument to choose Lua is that it has a small footprint. Yeah,
that&#39;s true, but that&#39;s useless. Bummer! When I program, I don&#39;t have any
resource usage pressure. People who have such pressure are either paranoids
or playing in the world of embedded computers. This is also a no more
existing conception since quad core processors equiped phones are coming
into the market. I&#39;m rather confident that what we used to call embedded
devices are just dead and are now plain computers. But as usual, YMMV.&lt;/p&gt;
&lt;p&gt;So start to forget about it, run in your underpants and yelling &#34;yay we
killed that shit!&#34;, and then use real computers stuff. :-)&lt;/p&gt;
&lt;p&gt;Even &lt;a href=&#34;http://shootout.alioth.debian.org/u32/lua.php&#34;&gt;if benchmarks show how Lua is damn fast&lt;/a&gt;, remember what a benchmark
proves: that you can do useless things very fast.&lt;/p&gt;
&lt;h1&gt;Too few extension modules&lt;/h1&gt;
&lt;p&gt;This is not directly Lua&#39;s fault, but there&#39;s too few extension modules for
Lua. The community is quite small compared to other big languages&#39; ones.&lt;/p&gt;
&lt;h1&gt;So think twice&lt;/h1&gt;
&lt;p&gt;before you choose Lua (or any other language). My recommendations these days
would be not to embed, but to extend. If you really have no choice and need
to embed a language into your application, &lt;a href=&#34;http://www.gnu.org/s/guile/&#34;&gt;GNU Guile&lt;/a&gt; is probably worth
considering, because it&#39;s a Scheme and therefore a functional language :-),
and because it can provides also different languages.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://git.savannah.gnu.org/gitweb/?p=guile.git;a=shortlog;h=refs/heads/lua&#34;&gt;Including Lua&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Lua workshop at Fabelier/tmplab</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/lua-workshop-at-Fabelier-tmplab"/>
    <updated>2011-04-14T14:04:00Z</updated>
    <published>2011-04-14T14:04:00Z</published>
    <id>/blog/2011/lua-workshop-at-Fabelier-tmplab</id>
        <category   scheme="/blog/tags"
                term="lua"
                label="Lua" />
    
    <content type="html">
            &lt;p&gt;It seems I&#39;ll be at the &lt;a href=&#34;http://fabelier.org/lua-programming-language-by-julien-danjou/&#34;&gt;Lua workshop at Fabelier/tmplab&lt;/a&gt; on April 28th 2011,
where I&#39;ll try to present and talk about &lt;a href=&#34;http://lua.org&#34;&gt;Lua&lt;/a&gt;, how to use it, and why you
should probably not use it. ;-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Using advanced filter with mod_authnz_ldap</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/using-advanced-filter-with-mod_authnz_ldap"/>
    <updated>2011-04-04T14:02:00Z</updated>
    <published>2011-04-04T14:02:00Z</published>
    <id>/blog/2011/using-advanced-filter-with-mod_authnz_ldap</id>
        <category   scheme="/blog/tags"
                term="ldap"
                label="Ldap" />
        <category   scheme="/blog/tags"
                term="apache"
                label="Apache" />
    
    <content type="html">
            &lt;p&gt;As you may know, Apache&#39;s &lt;a href=&#34;http://httpd.apache.org/docs/2.2/mod/mod_authnz_ldap.html&#34;&gt;mod_authzn_ldap&lt;/a&gt; allows to authenticate users in
Apache HTTP server using an LDAP server. Unfortunately, it has a little
implementation flaw.&lt;/p&gt;
&lt;p&gt;The filter used to authenticate the user is built by abusing the &lt;a href=&#34;http://www.ietf.org/rfc/rfc2255.txt&#34;&gt;RFC 2255&lt;/a&gt;
which specifies the LDAP URL format. This format has an &#34;attribute&#34; field
which is normally used to specify which attributes should be returned. But
&lt;em&gt;mod_authzn_ldap&lt;/em&gt; uses this attribute to compare with the username given by
the client. That means that you have to have an attribute in your LDAP
entries which matches the username, and you have to use it in the
&#34;attribute&#34; part of the URL to get things working.&lt;/p&gt;
&lt;p&gt;Therefore, I wrote a patch to add a format string in the LDAP URL in order
to user the provided username in the filter, and ignore the attribute part
of the URL, which has no use in such a context anyway.&lt;/p&gt;
&lt;p&gt;The bug has been opened in ASF Bugzilla and has number &lt;a href=&#34;https://issues.apache.org/bugzilla/show_bug.cgi?id=51005&#34;&gt;#51005&lt;/a&gt;, with the
patch. The patch is backward compatible with the current configuration
format, which is not the best choice in theory, but probably the more
pragmatic.&lt;/p&gt;
&lt;p&gt;I&#39;ve no clue on the typical delay for patches in clusion in Apache HTTP
server, so le
t&#39;s just wait&#39;n see.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Org contacts now part of org-contrib</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/org-contacts-now-part-of-org-contrib"/>
    <updated>2011-03-18T18:08:00Z</updated>
    <published>2011-03-18T18:08:00Z</published>
    <id>/blog/2011/org-contacts-now-part-of-org-contrib</id>
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
        <category   scheme="/blog/tags"
                term="orgcontacts"
                label="Orgcontacts" />
    
    <content type="html">
            &lt;p&gt;Thanks to my recent promotion allowing me to commit directly in Org-mode,
I&#39;ve moved &lt;a href=&#34;/software/org-contacts.el&#34;&gt;Org-contacts&lt;/a&gt;
into the contrib directory of the &lt;a href=&#34;http://www.orgmode.org&#34;&gt;Orgmode&lt;/a&gt;
distribution.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Second OrgCamp Paris</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/second-orgcamp-paris"/>
    <updated>2011-03-11T17:01:00Z</updated>
    <published>2011-03-11T17:01:00Z</published>
    <id>/blog/2011/second-orgcamp-paris</id>
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
    
    <content type="html">
            &lt;p&gt;I&#39;ll be at the &lt;a href=&#34;http://www.lifehacking.fr/mediawiki/index.php/OrgModeCampAvril2011&#34;&gt;OrgCamp April 2011&lt;/a&gt; in Paris next month. However, I&#39;m not yet
sure of what I&#39;ll talk about this time.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Org camp logo&#34; src=&#34;http://orgmode.org/worg/images/orgcamps/orgcamp-paris-january-2011.png&#34; /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">My latest contributions to the Emacs&#39; world</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/my-latest-contributions-to-the-emacs-world"/>
    <updated>2011-03-01T14:36:00Z</updated>
    <published>2011-03-01T14:36:00Z</published>
    <id>/blog/2011/my-latest-contributions-to-the-emacs-world</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="git"
                label="Git" />
        <category   scheme="/blog/tags"
                term="gnus"
                label="Gnus" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
        <category   scheme="/blog/tags"
                term="erc"
                label="Erc" />
    
    <content type="html">
            &lt;p&gt;I spend too much time writing Emacs Lisp code these days. Unfortunately, the
more I do the more I find new useful tools to improve my work-flow and save
time for doing more Lisp. D&#39;oh.&lt;/p&gt;
&lt;p&gt;I did not work on any big thing these last weeks, so I&#39;m thinking it&#39;s a
good time to talk about the various code and patches I sent to multiple
Emacs packages.&lt;/p&gt;
&lt;h1&gt;el-get&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dimitri/el-get&#34;&gt;el-get&lt;/a&gt;,
a fabulous tool that installs and handles all the external Emacs
packages I use. A friendly war started on the &lt;a href=&#34;http://blog.gmane.org/gmane.emacs.el-get.devel&#34;&gt;development list&lt;/a&gt; about
autoloads handling. The discussion was overall pointless, since we had a
very hard time to communicate our ideas, and we did not understand each
others several times.&lt;/p&gt;
&lt;p&gt;In the end, &lt;em&gt;el-get&lt;/em&gt; now supports autoload correctly and do not load
automatically all your packages, improving the startup time, and using the
Emacs way to do things. Which is always better, obviously.&lt;/p&gt;
&lt;h1&gt;git-commit-mode&lt;/h1&gt;
&lt;p&gt;I&#39;ve started to use &lt;a href=&#34;https://github.com/rafl/git-commit-mode&#34;&gt;git-commit-mode&lt;/a&gt; some times ago. I usually use &lt;em&gt;git-commit&lt;/em&gt;
with the &lt;em&gt;-v&lt;/em&gt; option to see what I&#39;m committing. I though it would be useful
to color the diff with &lt;em&gt;diff-mode&lt;/em&gt;, so I &lt;a href=&#34;https://github.com/rafl/git-commit-mode/commit/3e2d1047fff31358c39486cd890d1eb87a464404&#34;&gt;wrote a patch&lt;/a&gt; just to do that, which
was merged today by Florian.&lt;/p&gt;
&lt;h1&gt;magit&lt;/h1&gt;
&lt;p&gt;Some weeks ago, I decided to give a try to &lt;a href=&#34;http://philjackson.github.com/magit/&#34;&gt;magit&lt;/a&gt;, and loved it. I am not
always using it, but for basic operations it is very useful. But I really
soon found some things I did not like and therefore send patches to enhance
it.&lt;/p&gt;
&lt;p&gt;First, I&#39;ve added &lt;a href=&#34;https://github.com/philjackson/magit/commit/0314e7fd1df2b37b3cd1699afdf2dc3b98aee2d1&#34;&gt;a patch to honor status.showUntrackedFiles&lt;/a&gt; which I use in
my home directory. In the mean time, I&#39;ve also added
&lt;a href=&#34;https://github.com/philjackson/magit/commit/43cd05081b7e60d3f2dcce696f3a07c135f4e306&#34;&gt;a patch to allow adding an arbitrary file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yesterday, I sent another &lt;a href=&#34;https://github.com/philjackson/magit/pull/128&#34;&gt;pull request&lt;/a&gt;, not closed for now, which adds the
&lt;a href=&#34;https://github.com/jd/magit/commit/73afce9f0220146a55c6c63735ce48561a277632&#34;&gt;possibility to visit files in another window&lt;/a&gt; from a diff file, and
&lt;a href=&#34;https://github.com/jd/magit/commit/82d43edb123f493d639ef0835734e58fca1b8c0a&#34;&gt;the support for add-change-log-entry&lt;/a&gt; directly from the displayed diff.
Useful for these old projects still using &lt;em&gt;ChangeLog&lt;/em&gt; files but accessible
through git (hi Emacs &amp;amp; Gnus!).&lt;/p&gt;
&lt;h1&gt;Gnus&lt;/h1&gt;
&lt;p&gt;Nothing remarkable, but I write a couple of &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/commit/?id=3ccee76adca8a830cf781e697119b980cd9fcbe1&#34;&gt;fixes&lt;/a&gt;
and &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/commit/?id=01c211faea248b5d9e35f3662670bb8d12b9b137&#34;&gt;enhancements&lt;/a&gt; to the
Sieve manage mode, to the &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/commit/?id=d715adda2809176649227153d9e97564e755efb6&#34;&gt;Gravatar code&lt;/a&gt; and cleaned-up some very very old
code. Also added the possibility to
&lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/commit/?id=2bd6537597f51762a4b04f81c70d8f2be5dcb690&#34;&gt;set list-identifier as a group parameter&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Org-mode&lt;/h1&gt;
&lt;p&gt;I spent most of my time working on my &lt;a href=&#34;http://git.naquadah.org/?p=~jd/org-mode.git;a=shortlog;h=refs/heads/jd/agenda-format&#34;&gt;jd/agenda-format&lt;/a&gt; branch, which is soon
to be merged. I&#39;ve also just got developer access to the Org-mode patch work
and repository, so I&#39;ll be able to break things even more! ;-)&lt;/p&gt;
&lt;h1&gt;ERC&lt;/h1&gt;
&lt;p&gt;I &lt;a href=&#34;http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=391de97a758c44e5d38e0c8f0bd50fe5eae09d5f&#34;&gt;fixed&lt;/a&gt; &lt;strong&gt;the&lt;/strong&gt; bug that annoyed me for a long time. Now &lt;em&gt;erc-track&lt;/em&gt; does not
reset the last channel status on window visibility changes not made by the
user.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Handling my music collection with git-annex</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/handling-my-music-collection-with-git-annex"/>
    <updated>2011-02-23T17:44:00Z</updated>
    <published>2011-02-23T17:44:00Z</published>
    <id>/blog/2011/handling-my-music-collection-with-git-annex</id>
        <category   scheme="/blog/tags"
                term="git"
                label="Git" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;http://git-annex.branchable.com/&#34;&gt;git-annex&lt;/a&gt; is a recent tool allowing to manage files with git without having
theirs contents checked into git.&lt;/p&gt;
&lt;p&gt;I&#39;ve been looking at it with some interest in
the past few weeks in order to use it to handle my music collection on the
various computers I use.&lt;/p&gt;
&lt;p&gt;My laptop just got a new SSD drive which is quite small and cannot handle
the whole collection. By using git-annex, I&#39;m now able to only check out
part of my music collection and keeping it synchronized with all my others
computers.&lt;/p&gt;
&lt;p&gt;Using &lt;em&gt;git-annex&lt;/em&gt; is pretty trivial once you understand the concepts.&lt;/p&gt;
&lt;p&gt;I&#39;ve set up a a git repository in my &lt;em&gt;Music&lt;/em&gt; directory, like that:&lt;/p&gt;
&lt;pre&gt;
% git init
Initialized empty Git repository in /home/jd/Music
&lt;/pre&gt;

&lt;p&gt;Then I initialized git annex:&lt;/p&gt;
&lt;pre&gt;
% git annex init &#34;Music on keller&#34;
&lt;/pre&gt;

&lt;p&gt;So now I&#39;m able to import all my date into git annex. &lt;em&gt;git-annex&lt;/em&gt; offers
several backends to store data. WORM is the default, but is not a good
choice for file that could be modified, and music files can be, at least
when editing the metadata. Therefore, I chose the slow but more reliable
SHA1 backend.&lt;/p&gt;
&lt;pre&gt;
% git annex add --backend=SHA1 .
&lt;/pre&gt;

&lt;p&gt;That can be long, so you should be patient. Then you should commit the fact
you annexed files:&lt;/p&gt;
&lt;pre&gt;
% git commit -a -m &#34;Imported my music collection&#34;
[master 82d060f] Imported my music collection
&lt;/pre&gt;

&lt;p&gt;Now, it&#39;s done. You can go on another computer and clone the repo:&lt;/p&gt;
&lt;pre&gt;
% git clone ssh://keller/~/Music
% cd Music
% git annex get &#34;Incubus - Light Grenades&#34;
&lt;/pre&gt;

&lt;p&gt;And then let the magic happens. It will retrieve the whole directory for
you. Do not forgot to commit the fact that you got those album on that
machine!&lt;/p&gt;
&lt;p&gt;The concept used by git-annex is quite simple. All files are replaced by
symlinks pointing to &lt;em&gt;.git-annex/SHA1:filechecksum.log&lt;/em&gt;. This file contains
lines, whose format is:&lt;/p&gt;
&lt;pre&gt;
retrieval-timestamp is-file-present uuid-of-the-repository
&lt;/pre&gt;

&lt;p&gt;Indicating if the file is present in a repository. This logs file are
commited into the repository, whereas the real content is stored in the
&lt;em&gt;.git/annex&lt;/em&gt; directory and therefore not commited.&lt;/p&gt;
&lt;p&gt;I recommend to take a look to the &lt;a href=&#34;http://git-annex.branchable.com/walkthrough/&#34;&gt;walkthrough&lt;/a&gt; page to get more idea and what
you can and &lt;a href=&#34;http://git-annex.branchable.com/not/&#34;&gt;cannot&lt;/a&gt; do with git-annex.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Announcing Org-contacts</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/announcing-org-contacts"/>
    <updated>2011-02-08T12:22:00Z</updated>
    <published>2011-02-08T12:22:00Z</published>
    <id>/blog/2011/announcing-org-contacts</id>
        <category   scheme="/blog/tags"
                term="orgcontacts"
                label="Orgcontacts" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
    
    <content type="html">
            &lt;p&gt;When I started to use Emacs, I got hooked by many stuff like &lt;a href=&#34;http://gnus.org&#34;&gt;Gnus&lt;/a&gt; and
&lt;a href=&#34;http://orgmode.org&#34;&gt;Org-mode&lt;/a&gt;. One thing I quickly started to hate is how the Lisp code can be
old and unmaintained. That especially applies to &lt;a href=&#34;http://bbdb.sourceforge.net&#34;&gt;BBDB&lt;/a&gt;, which has been
unmaintained for years, and has very very very old and obsolete code.&lt;/p&gt;
&lt;p&gt;Therefore I&#39;ve decided to develop my own BBDB replacement based on my lovely
Org-mode. It&#39;s called &lt;a href=&#34;http://julien.danjou.info/org-contacts.html&#34;&gt;org-contacts&lt;/a&gt;, and it allows you to handle your contact
like anything you would handle in Org. This way you can manage them the way
you want, without any preset fields or any assumptions like BBDB has.&lt;/p&gt;
&lt;p&gt;I had the chance to present it at the Paris OrgCamp a couple of weeks ago,
and due to the enthusiastic audience I had, I&#39;m now releasing it to the wide
Internet.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Naquadah theme for Emacs</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/naquadah-theme-for-Emacs"/>
    <updated>2011-01-31T16:31:00Z</updated>
    <published>2011-01-31T16:31:00Z</published>
    <id>/blog/2011/naquadah-theme-for-Emacs</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;I often post Emacs screenshots on this blog, and consequently receive a
bunch of request for my Emacs theme. Therefore I decided to &lt;a href=&#34;http://git.naquadah.org/?p=naquadah-theme.git;a=summary&#34;&gt;publish it&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Emacs snapshot Ubuntu packages</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/Emacs-snapshot-Ubuntu-packages"/>
    <updated>2011-01-24T15:13:00Z</updated>
    <published>2011-01-24T15:13:00Z</published>
    <id>/blog/2011/Emacs-snapshot-Ubuntu-packages</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="ubuntu"
                label="Ubuntu" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;http://emacs.naquadah.org&#34;&gt;Emacs snapshot packages for Ubuntu&lt;/a&gt; are now available, thanks to
&lt;a href=&#34;http://blog.tapoueh.org&#34;&gt;Dimitri Fontaine&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OrgCamp Paris 2011 review</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/orgcamp-paris-2011-review"/>
    <updated>2011-01-23T13:26:00Z</updated>
    <published>2011-01-23T13:26:00Z</published>
    <id>/blog/2011/orgcamp-paris-2011-review</id>
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
        <category   scheme="/blog/tags"
                term="orgcontacts"
                label="Orgcontacts" />
    
    <content type="html">
            &lt;p&gt;Yesterday afternoon, I was at the first &lt;a href=&#34;http://www.lifehacking.fr/mediawiki/index.php/OrgModeCampJanvier2011&#34;&gt;OrgCamp in Paris&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was my first attendance to a
&lt;a href=&#34;http://en.wikipedia.org/wiki/BarCamp&#34;&gt;BarCamp&lt;/a&gt;, and I really liked it. It&#39;s
basically the first geek event I do not find boring nor useless.&lt;/p&gt;
&lt;p&gt;There was about 18-20 persons participating, which was quite high, since we
all initially though we would have been only 5.&lt;/p&gt;
&lt;p&gt;We had several presentations of various features and personal usages of
&lt;a href=&#34;http://www.orgmode.org][Org-mode]].%20For%20my%20part,%20I&#39;ve%20quickly%20presented%20the%20agenda,%20and%20my%20[[http://bbdb.sourceforge.net/&#34;&gt;BBDB&lt;/a&gt;
replacement named &lt;strong&gt;org-contacts&lt;/strong&gt; (I&#39;ll probably talk about it on this blog in
another post later).&lt;/p&gt;
&lt;p&gt;The only downside was that Bastien (the new Org-mode maintainer) was not
able to come and join us. On the other side, there were so much to tell for
a first time, I did not have so much time to code. I only have been able to
&lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-orgmode/2011-01/msg01002.html&#34;&gt;fix one bug&lt;/a&gt; reported during my agenda presentation.&lt;/p&gt;
&lt;p&gt;In the end, the overall atmosphere was very enthusiastic and friendly, which
was extremely pleasant. The #org-mode-fr IRC channel has been created on
&lt;a href=&#34;http://freenode.net&#34;&gt;Freenode&lt;/a&gt;, following this event. Feel free to join us.&lt;/p&gt;
&lt;p&gt;Since people liked it so badly, it seems there should be another barcamp in
the next months. Stay tuned.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Code fontification with Gnus and Org-mode</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/code-fontification-with-gnus-and-orgmode"/>
    <updated>2011-01-20T14:45:00Z</updated>
    <published>2011-01-20T14:45:00Z</published>
    <id>/blog/2011/code-fontification-with-gnus-and-orgmode</id>
        <category   scheme="/blog/tags"
                term="gnus"
                label="Gnus" />
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve added code fontification using &lt;a href=&#34;http://orgmode.org/manual/Working-With-Source-Code.html#Working-With-Source-Code&#34;&gt;Org src blocks&lt;/a&gt;
inside &lt;a href=&#34;http://gnus.org&#34;&gt;Gnus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Gnus fontification&#34; src=&#34;/media/images/blog/2011/gnus-org-buffer-fontification.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This interprets the block as an Org buffer and fontify it accordingly if
&lt;em&gt;org-src-fontify-natively&lt;/em&gt; it set to &lt;em&gt;t&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&#34;http://news.gmane.org/find-root.php?message_id=%3c80k4lj78ui.fsf%40mundaneum.com%3e&#34;&gt;Sébastien Vauban for the original idea&lt;/a&gt; and implementation. Now it
works out of the box without any customization.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OrgCamp 2011</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/orgcamp-2011"/>
    <updated>2011-01-17T13:51:00Z</updated>
    <published>2011-01-17T13:51:00Z</published>
    <id>/blog/2011/orgcamp-2011</id>
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
    
    <content type="html">
            &lt;p&gt;I&#39;ll be at the &lt;a href=&#34;http://www.lifehacking.fr/mediawiki/index.php/OrgModeCampJanvier2011&#34;&gt;OrgCamp 2011&lt;/a&gt; in Paris next Saturday.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;OrgCamp logo&#34; src=&#34;http://orgmode.org/worg/images/orgcamps/orgcamp-paris-january-2011.png&#34; /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Emacs snapshot Debian packages</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2011/emacs-snapshot-debian-packages"/>
    <updated>2011-01-12T15:54:00Z</updated>
    <published>2011-01-12T15:54:00Z</published>
    <id>/blog/2011/emacs-snapshot-debian-packages</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve decided to take over the maintenance of the unofficial &lt;em&gt;emacs-snapshot&lt;/em&gt;
Debian packages that were maintained by &lt;a href=&#34;http://emacs.orebokech.com&#34;&gt;Romain Francoise&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They are available on a &lt;a href=&#34;http://emacs.naquadah.org&#34;&gt;dedicated page&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Color contrast correction</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/color-contrast-correction"/>
    <updated>2010-11-23T16:14:00Z</updated>
    <published>2010-11-23T16:14:00Z</published>
    <id>/blog/2010/color-contrast-correction</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;I finally took some time to finish my color contrast corrector.&lt;/p&gt;
&lt;p&gt;It&#39;s now able to compare two colors and to tell if they are readable when
used as foreground and background color for text rendering. If they are too
close, the code corrects both colors so to they&#39;ll become distant enough to
be readable.&lt;/p&gt;
&lt;p&gt;To do that, it uses color coordinates in the &lt;a href=&#34;http://en.wikipedia.org/wiki/Lab_color_space&#34;&gt;CIE L&lt;em&gt;a&lt;/em&gt;b* colorspace&lt;/a&gt;. This allows to determine the luminance difference between 2 colors very easily by
comparing the &lt;em&gt;L&lt;/em&gt; component of the coordinates. The default threshold used to
determine readability based on luminance difference is 40 (on 100), which
seems to give pretty good results so far.&lt;/p&gt;
&lt;p&gt;Then it uses the &lt;a href=&#34;http://en.wikipedia.org/wiki/Color_difference#CIEDE2000&#34;&gt;CIE Delta E 2000&lt;/a&gt; formula to obtain the distance between
colors. A distance of 6 is considered to be enough for the colors to be
distinctive in our case, but that can be adjusted anyway. That depends on
reader&#39;s eyes.&lt;/p&gt;
&lt;p&gt;If both the color and luminance distances are big enough, the color pair is
considered readable when used upon each other.&lt;/p&gt;
&lt;p&gt;If these criteria are not satisfied, the code simply tries to correct the
color by adjusting the &lt;em&gt;L&lt;/em&gt; (luminance) component of the colors so their
difference is 40. Optionally, the background color can be fixed so only the
foreground color would be adjusted; this is especially handy when the color
background is not provided by any external style, but it the screen one
(like the Emacs frame background in my case).&lt;/p&gt;
&lt;p&gt;Here is an example result generated over 10 pairs of random colors. Left
colors are randomly generated, and right colors are the corrected one.&lt;/p&gt;
&lt;style type=&#34;text/css&#34;&gt;
    &lt;!--
      .ATTRLIST {
        /* (:background &#34;#9c0060&#34; :foreground &#34;#ff55b9&#34;) */
        color: #ff55b9;
        background-color: #9c0060;
      }
      .ATTRLIST-1 {
        /* (:background &#34;medium violet red&#34; :foreground &#34;DeepPink1&#34;) */
        color: #ff1493;
        background-color: #c71585;
      }
      .ATTRLIST-10 {
        /* (:background &#34;grey43&#34; :foreground &#34;chartreuse3&#34;) */
        color: #66cd00;
        background-color: #6e6e6e;
      }
      .ATTRLIST-11 {
        /* (:background &#34;#9e78ed&#34; :foreground &#34;#f0fff0&#34;) */
        color: #f0fff0;
        background-color: #9e78ed;
      }
      .ATTRLIST-12 {
        /* (:background &#34;MediumPurple2&#34; :foreground &#34;honeydew&#34;) */
        color: #f0fff0;
        background-color: #9f79ee;
      }
      .ATTRLIST-13 {
        /* (:background &#34;#131313&#34; :foreground &#34;#6c6c6c&#34;) */
        color: #6c6c6c;
        background-color: #131313;
      }
      .ATTRLIST-14 {
        /* (:background &#34;grey13&#34; :foreground &#34;grey36&#34;) */
        color: #5c5c5c;
        background-color: #212121;
      }
      .ATTRLIST-15 {
        /* (:background &#34;#9faec0&#34; :foreground &#34;#005700&#34;) */
        color: #005700;
        background-color: #9faec0;
      }
      .ATTRLIST-16 {
        /* (:background &#34;SlateGray4&#34; :foreground &#34;forest green&#34;) */
        color: #228b22;
        background-color: #6c7b8b;
      }
      .ATTRLIST-17 {
        /* (:background &#34;#4a6b4b&#34; :foreground &#34;#cccccc&#34;) */
        color: #cccccc;
        background-color: #4a6b4b;
      }
      .ATTRLIST-18 {
        /* (:background &#34;DarkSeaGreen4&#34; :foreground &#34;gray67&#34;) */
        color: #ababab;
        background-color: #698b69;
      }
      .ATTRLIST-2 {
        /* (:background &#34;#9cff38&#34; :foreground &#34;#b28282&#34;) */
        color: #b28282;
        background-color: #9cff38;
      }
      .ATTRLIST-3 {
        /* (:background &#34;chartreuse1&#34; :foreground &#34;RosyBrown3&#34;) */
        color: #cd9b9b;
        background-color: #7fff00;
      }
      .ATTRLIST-4 {
        /* (:background &#34;#525252&#34; :foreground &#34;#cfb58c&#34;) */
        color: #cfb58c;
        background-color: #525252;
      }
      .ATTRLIST-5 {
        /* (:background &#34;gray33&#34; :foreground &#34;NavajoWhite3&#34;) */
        color: #cdb38b;
        background-color: #545454;
      }
      .ATTRLIST-6 {
        /* (:background &#34;#6c9fa4&#34; :foreground &#34;#0000e1&#34;) */
        color: #0000e1;
        background-color: #6c9fa4;
      }
      .ATTRLIST-7 {
        /* (:background &#34;CadetBlue4&#34; :foreground &#34;blue1&#34;) */
        color: #0000ff;
        background-color: #53868b;
      }
      .ATTRLIST-8 {
        /* (:background &#34;linen&#34; :foreground &#34;DeepPink2&#34;) */
        color: #ee1289;
        background-color: #faf0e6;
      }
      .ATTRLIST-9 {
        /* (:background &#34;#5e5e5e&#34; :foreground &#34;#79de25&#34;) */
        color: #79de25;
        background-color: #5e5e5e;
      }
    --&gt;
    &lt;/style&gt;

&lt;pre&gt;
&lt;span class=&#34;ATTRLIST-18&#34;&gt;bg: DarkSeaGreen4 fg: gray67 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-18&#34;&gt;                             &lt;/span&gt;&lt;span class=&#34;ATTRLIST-17&#34;&gt;bg: #4a6b4b fg: #cccccc
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-16&#34;&gt;bg: SlateGray4 fg: forest green -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-16&#34;&gt;                          &lt;/span&gt;&lt;span class=&#34;ATTRLIST-15&#34;&gt;bg: #9faec0 fg: #005700
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-14&#34;&gt;bg: grey13 fg: grey36 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-14&#34;&gt;                                    &lt;/span&gt;&lt;span class=&#34;ATTRLIST-13&#34;&gt;bg: #131313 fg: #6c6c6c
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-12&#34;&gt;bg: MediumPurple2 fg: honeydew -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-12&#34;&gt;                           &lt;/span&gt;&lt;span class=&#34;ATTRLIST-11&#34;&gt;bg: #9e78ed fg: #f0fff0
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-10&#34;&gt;bg: grey43 fg: chartreuse3 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-10&#34;&gt;                               &lt;/span&gt;&lt;span class=&#34;ATTRLIST-9&#34;&gt;bg: #5e5e5e fg: #79de25
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-8&#34;&gt;bg: linen fg: DeepPink2 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-8&#34;&gt;                                  &lt;/span&gt;&lt;span class=&#34;ATTRLIST-8&#34;&gt;bg: linen fg: DeepPink2
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-7&#34;&gt;bg: CadetBlue4 fg: blue1 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-7&#34;&gt;                                 &lt;/span&gt;&lt;span class=&#34;ATTRLIST-6&#34;&gt;bg: #6c9fa4 fg: #0000e1
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-5&#34;&gt;bg: gray33 fg: NavajoWhite3 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-5&#34;&gt;                              &lt;/span&gt;&lt;span class=&#34;ATTRLIST-4&#34;&gt;bg: #525252 fg: #cfb58c
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-3&#34;&gt;bg: chartreuse1 fg: RosyBrown3 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-3&#34;&gt;                           &lt;/span&gt;&lt;span class=&#34;ATTRLIST-2&#34;&gt;bg: #9cff38 fg: #b28282
&lt;/span&gt;&lt;span class=&#34;ATTRLIST-1&#34;&gt;bg: medium violet red fg: DeepPink1 -&amp;gt;&lt;/span&gt;&lt;span class=&#34;ATTRLIST-1&#34;&gt;                      &lt;/span&gt;&lt;span class=&#34;ATTRLIST&#34;&gt;bg: #9c0060 fg: #ff55b9
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;All this has been written in Emacs Lisp. The code is now available in &lt;a href=&#34;http://www.gnus.org&#34;&gt;Gnus&lt;/a&gt;
(and therefore in Emacs 24) in the packages &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/tree/lisp/color-lab.el&#34;&gt;color-lab&lt;/a&gt; and &lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/tree/lisp/shr-color.el&#34;&gt;shr-color&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A future work would be to add support for colour blindness.&lt;/p&gt;
&lt;p&gt;As a side note, several people pointed me at the
&lt;a href=&#34;http://www.w3.org/TR/WCAG10/&#34;&gt;WCAG&lt;/a&gt; formulas to determine luminance and
contrast ratio. These are probably good criteria to choose your color when
designing a user interface. However, they are not enough to determine if
displayed color will be readable. This means you can use them if you are a
designer, but IMHO they are pretty weak for detecting and correcting colors
you did not choose.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Elisp color manipulation routines</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/elisp-color-manipulation-routines"/>
    <updated>2010-11-20T22:11:00Z</updated>
    <published>2010-11-20T22:11:00Z</published>
    <id>/blog/2010/elisp-color-manipulation-routines</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;Last week, I spent some time implementing various color manipulation
routines. The ultimate goal was to find a way to determine if a text in
a certain color was readable on a background with a different color.&lt;/p&gt;
&lt;p&gt;Something I failed to do so far, despite my research in the area.&lt;/p&gt;
&lt;p&gt;However, since I think my code could be useful for other people, I&#39;ve set up
a tiny &lt;a href=&#34;http://git.naquadah.org/?p=~jd/color-el.git;a=summary&#34;&gt;git repository&lt;/a&gt; with the routines I wrote.&lt;/p&gt;
&lt;p&gt;The funniest one to implement was
&lt;a href=&#34;http://en.wikipedia.org/wiki/Color_difference#CIEDE2000&#34;&gt;CIEDE2000&lt;/a&gt;. I
verified my code with the data given in &lt;a href=&#34;http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf&#34;&gt;the specifications&lt;/a&gt; and can assure it&#39;s correct. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Org-mode and holidays</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/org-mode-and-holidays"/>
    <updated>2010-11-15T16:11:00Z</updated>
    <published>2010-11-15T16:11:00Z</published>
    <id>/blog/2010/org-mode-and-holidays</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;http://orgmode.org&#34;&gt;Org-mode&lt;/a&gt; has a nice option which allows you to show
week-end days in a different color in your agenda. That means that Saturday
and Sunday (when I do not work) are fontified with &lt;em&gt;org-agenda-date-weekend&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But there are other days I do not work, like my vacations or holidays.&lt;/p&gt;
&lt;p&gt;Therefore, I&#39;ve wrote a patch to add &lt;em&gt;`org-agenda-day-face-function&#39;&lt;/em&gt; which is
optionally called to determine what should be the face used to fontify a
day. &lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-orgmode/2010-11/msg00542.html&#34;&gt;This&lt;/a&gt; allows me to use the same face for holidays and for week-end days, like for last Thursday which was an holiday in France.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Emacs orgmode and holidays screenshot&#34; src=&#34;/media/images/blog/2010/emacs-org-mode-holidays.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;That patch has been merged in Org last week.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Google Maps for Emacs: moving, caching and home</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/google-maps-for-emacs-moving-caching-home"/>
    <updated>2010-11-08T12:33:00Z</updated>
    <published>2010-11-08T12:33:00Z</published>
    <id>/blog/2010/google-maps-for-emacs-moving-caching-home</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="googlemaps"
                label="Googlemaps" />
    
    <content type="html">
            &lt;p&gt;Last week, I worked on my
&lt;a href=&#34;http://julien.danjou.info/google-maps-el.html&#34;&gt;Google Maps for Emacs&lt;/a&gt;
extension. I&#39;ve introduced a new format handling for locations which include
the longitude and latitude. The initial format was just a string describing
the location, which was obviously too limited.&lt;/p&gt;
&lt;p&gt;It now prints coordinates of the different elements when the mouse is over
the map, with other information.&lt;/p&gt;
&lt;p&gt;It also center the map on &lt;em&gt;M-x google-maps&lt;/em&gt; and set a default zoom level. This
is something which was not set because it&#39;s not a good idea to set center
coordinates in order to see all points on the map automatically. But you can
still remove the centering by pressing &lt;em&gt;&#34;C&#34;&lt;/em&gt;. On the other hand, setting it
automatically allows to move the map easily, and I think that what most
users want to do.&lt;/p&gt;
&lt;p&gt;I&#39;ve also added a &#34;place my home on the map&#34; feature, accessible by pressing
&lt;em&gt;&#34;h&#34;&lt;/em&gt; on any map. That adds a marker according to the location set in Emacs
using the &lt;em&gt;calendar-&lt;/em&gt; variables.&lt;/p&gt;
&lt;p&gt;This feature is also available under [[http://orgmode.org][Org]] by pressing &lt;em&gt;C-u C-c M-l&lt;/em&gt;, which
shows the location of your appointment with your home on the map too.&lt;/p&gt;
&lt;p&gt;Finally, you also get caching so it does not request images you already
seen, which makes the moving nicer and faster to use, and prompt history.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Google Maps move screenshot&#34; src=&#34;/media/images/blog/2010/emacs-google-maps-move.png&#34; /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Icon category support in Org-mode</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/icon-category-support-in-org-mode"/>
    <updated>2010-11-04T13:11:00Z</updated>
    <published>2010-11-04T13:11:00Z</published>
    <id>/blog/2010/icon-category-support-in-org-mode</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
    
    <content type="html">
            &lt;p&gt;My latest patch for &lt;a href=&#34;http://orgmode.org&#34;&gt;Org mode&lt;/a&gt; has been accepted by
Carsten today. It adds support for custom category icons in all views, like
agenda or todo.&lt;/p&gt;
&lt;p&gt;You just need to configure &lt;em&gt;org-agenda-category-icon-alist&lt;/em&gt; and it will work
out of the box.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Org-mode category support screenshot&#34; src=&#34;/media/images/blog/2010/emacs-org-category-icons.png&#34; /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Transparent GIF support in Emacs 24</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/transparent-gif-support-in-emacs24"/>
    <updated>2010-11-02T11:43:00Z</updated>
    <published>2010-11-02T11:43:00Z</published>
    <id>/blog/2010/transparent-gif-support-in-emacs24</id>
        <category   scheme="/blog/tags"
                term="gif"
                label="Gif" />
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;Last week, I wrote a &lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-devel/2010-10/msg01009.html&#34;&gt;couple of patches&lt;/a&gt; to add support for transparency when Emacs is displaying &lt;a href=&#34;http://en.wikipedia.org/wiki/Graphics_Interchange_Format&#34;&gt;GIF&lt;/a&gt; images.&lt;/p&gt;
&lt;p&gt;Until now, it was displaying the color used to define transparency in the
file data. Now it displays the image correctly by using the frame color as
the transparency color, like it&#39;s done for other image formats.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Emacs 24 displaying a GIF image&#34; src=&#34;/media/images/blog/2010/emacs-gif-transparent.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The patches have not been merged yet, but will probably be soon.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">No more dashes in Emacs 24 mode-line</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/no-more-dashes-in-emacs24-mode-line"/>
    <updated>2010-10-20T13:01:00Z</updated>
    <published>2010-10-20T13:01:00Z</published>
    <id>/blog/2010/no-more-dashes-in-emacs24-mode-line</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;We all know the good old Emacs mode-line you got under every window. Since
the beginning (a long time ago), it starts and ends with dashes. I&#39;ve
proposed &lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-devel/2010-10/msg00675.html&#34;&gt;a patch&lt;/a&gt;
to remove them.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Emacs with dashes in the mode line&#34; src=&#34;/media/images/blog/2010/emacs-dashes.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Emacs without dashes in the mode line&#34; src=&#34;/media/images/blog/2010/emacs-no-dashes.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This has been merged in Emacs 24. You won&#39;t see any more ugly dashes in
graphical mode.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Enhancing Emacs mouse avoidance</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/enhancing-emacs-mouse-avoidance"/>
    <updated>2010-10-19T19:23:00Z</updated>
    <published>2010-10-19T19:23:00Z</published>
    <id>/blog/2010/enhancing-emacs-mouse-avoidance</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;Recent &lt;em&gt;Emacs&lt;/em&gt; versions have a wonderful capacity to hide the mouse pointer as
soon as you type and insert characters in a buffer. This is controlled by
the &lt;em&gt;`make-pointer-invisible&#39;&lt;/em&gt; variable, which is set to t by default.&lt;/p&gt;
&lt;p&gt;However that does not hide the pointer when simply moving the cursor on
screen. Therefore, I&#39;ve started to use &lt;em&gt;`mouse-avoidance-mode&#39;&lt;/em&gt;, which make
the mouse pointer jump if your cursor hits it.&lt;/p&gt;
&lt;p&gt;Unfortunately, if your cursor hits the invisible mouse pointer,
&lt;em&gt;`mouse-avoidance-mode&#39;&lt;/em&gt; makes it jump too, because it does not know it is
invisible.&lt;/p&gt;
&lt;p&gt;Well, it &lt;em&gt;did&lt;/em&gt; not know. Now it does, &lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-devel/2010-10/msg00574.html&#34;&gt;thanks to my patches&lt;/a&gt;
which have been merged in Emacs 24. Using the new function
&lt;strong&gt;frame-pointer-invisible-p&lt;/strong&gt;, one can know if the mouse pointer has been
hidden by Emacs. Therefore I enhanced `mouse-avoidance-mode&#39; to use it, and
everything is alright now. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Why notmuch is not much good</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/why-notmuch-is-not-much-good"/>
    <updated>2010-10-07T13:22:00Z</updated>
    <published>2010-10-07T13:22:00Z</published>
    <id>/blog/2010/why-notmuch-is-not-much-good</id>
        <category   scheme="/blog/tags"
                term="sieve"
                label="Sieve" />
        <category   scheme="/blog/tags"
                term="mail"
                label="Mail" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve recently got a mail from one of my faithful reader, asking why not
considering &lt;a href=&#34;http://notmuchmail.org/&#34;&gt;notmuch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Actually, I think notmuch already exists in a better way, and that&#39;s called
&lt;a href=&#34;http://en.wikipedia.org/wiki/Internet_Message_Access_Protocol&#34;&gt;IMAP&lt;/a&gt; and &lt;a href=&#34;http://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)&#34;&gt;Sieve&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What &lt;em&gt;notmuch&lt;/em&gt; does, is tagging your mail with tags (obviously), based on
filtering rules you write. The big downside is that you have to tag all your
mails on your computer.&lt;/p&gt;
&lt;p&gt;And if you use several computers, you&#39;ll have to tag several times your
mails. And you&#39;ll have to find a way to maintain your rules to be identical
on all your computers. That does not scale.&lt;/p&gt;
&lt;p&gt;Using Sieve for mail filtering, one can do already that actually, and much
more.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;notmuch&lt;/em&gt; rule like:&lt;/p&gt;
&lt;pre&gt;
notmuch tag +intel from:intel.com and not tag:intel
&lt;/pre&gt;

&lt;p&gt;Can be written as a Sieve rule like:&lt;/p&gt;
&lt;pre&gt;
if address :all :contains &#34;From&#34; &#34;intel.com&#34; {
    addflag &#34;intel&#34;;
}
&lt;/pre&gt;

&lt;p&gt;The flags extension for Sieve is explained in &lt;a href=&#34;http://tools.ietf.org/html/rfc5232&#34;&gt;RFC5232&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Sieve based solution has the advantage of being treated server side, and
therefore not subject to multiple or different MUA usages. It&#39;s also fast,
if you use a good IMAP server like &lt;a href=&#34;http://www.dovecot.org&#34;&gt;Dovecot&lt;/a&gt;, which has indexing, etc.&lt;/p&gt;
&lt;p&gt;Furthermore, Sieve can obviously do a lot more than tagging, like splitting
into different mailboxes, filtering with regexp usage, vacation, etc.&lt;/p&gt;
&lt;p&gt;And if you want to fetch your mail locally, you can synchronize the IMAP box
entirely with any software able to (like &lt;a href=&#34;http://github.com/jgoerzen/offlineimap/wiki&#34;&gt;OfflineIMAP&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Now, what&#39;s probably missing, is a correct support for IMAP flags on various
MUA around. But that&#39;s not something &lt;em&gt;notmuch&lt;/em&gt; helps to solve either. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Gnus and Gravatar support</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/gnus-gravatar-support"/>
    <updated>2010-09-25T09:38:00Z</updated>
    <published>2010-09-25T09:38:00Z</published>
    <id>/blog/2010/gnus-gravatar-support</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="gnus"
                label="Gnus" />
        <category   scheme="/blog/tags"
                term="gravatar"
                label="Gravatar" />
    
    <content type="html">
            &lt;p&gt;This last couple of days I&#39;ve been dedicated making &lt;a href=&#34;http://www.gnus.org&#34;&gt;Gnus&lt;/a&gt;… fresher.&lt;/p&gt;
&lt;p&gt;I&#39;ve decided to give a whirl on &lt;a href=&#34;http://www.gravatar.com&#34;&gt;Gravatar&lt;/a&gt; support. I already tried the
&lt;em&gt;gravatar.el&lt;/em&gt; lying on the Interweb, but well, it was crap: it used &lt;em&gt;wget&lt;/em&gt; to
fetch pictures, therefore was totally synchronous. Reading each mail was
slower. The cache did not even have TTL, as far as I recall.&lt;/p&gt;
&lt;p&gt;So, I&#39;ve now wrote &lt;strong&gt;&lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/tree/lisp/gravatar.el&#34;&gt;gravatar.el&lt;/a&gt;&lt;/strong&gt; implementing the Gravatar API. Asynchronously
of course. With cache, TTL, etc. Perfect. :-)&lt;/p&gt;
&lt;p&gt;Then I&#39;ve composed &lt;strong&gt;&lt;a href=&#34;http://git.gnus.org/cgit/gnus.git/tree/lisp/gnus-gravatar.el&#34;&gt;gnus-gravatar.el&lt;/a&gt;&lt;/strong&gt;, implementing a washing function adding
Gravatar for &lt;em&gt;From&lt;/em&gt; field and/or &lt;em&gt;Cc/To&lt;/em&gt; fields, like done for &lt;a href=&#34;https://www.cs.indiana.edu/picons/&#34;&gt;picons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I was expecting, the patch was badly received by the GNU guys, which
start talking about thinks like external resources, privacy, non-free
software, etc. Boring.&lt;/p&gt;
&lt;p&gt;Fortunately, Lars allowed me to push the patch in git so everybody can give
it a try. I&#39;m now waiting for feedbacks in order to know if I will have to
maintain this patch outside Gnus, or not.&lt;/p&gt;
&lt;p&gt;Here&#39;s the mandatory screen-shot.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Gnus showing a Gravatar&#34; src=&#34;/media/images/blog/2010/gnus-gravatar.png&#34; /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Gnus news is good news!</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/gnus-news-is-good-news"/>
    <updated>2010-09-23T10:21:00Z</updated>
    <published>2010-09-23T10:21:00Z</published>
    <id>/blog/2010/gnus-news-is-good-news</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="gnus"
                label="Gnus" />
    
    <content type="html">
            &lt;p&gt;As I already wrote too many times, I&#39;ve started to use
&lt;a href=&#34;http://gnus.org&#34;&gt;Gnus&lt;/a&gt; 6 months ago, and never looked back.&lt;/p&gt;
&lt;p&gt;At that time, I joined the &lt;a href=&#34;http://gnus.org/resources.html&#34;&gt;ding mailing list&lt;/a&gt; in order to ask some dumb
questions and, once, send a patch. There were very low activity on that
list.&lt;/p&gt;
&lt;p&gt;Until Lars, the original Gnus author, came back.&lt;/p&gt;
&lt;p&gt;Three weeks ago, he started to wrote a new wash function to render &lt;a href=&#34;http://en.wikipedia.org/wiki/HTML&#34;&gt;HTML&lt;/a&gt;
mails properly, with pictures. It&#39;s named &lt;strong&gt;`gnus-html&#39;&lt;/strong&gt;, and is (for now)
based on &lt;a href=&#34;http://w3m.sourceforge.net&#34;&gt;w3m&lt;/a&gt; (but not on &lt;a href=&#34;http://emacs-w3m.namazu.org/&#34;&gt;emacs-w3m&lt;/a&gt;, which is not part of Emacs).&lt;/p&gt;
&lt;p&gt;Last week, I&#39;ve sent a set of patches to replace the usage of &lt;a href=&#34;http://curl.haxx.se&#34;&gt;curl&lt;/a&gt; by the
standard &lt;strong&gt;`url-retrieve&#39;&lt;/strong&gt; function to fetch images, plus various enhancement.
It seems that my work was good enough that Lars offered me write access to
the git repository. I can therefore mess up the Gnus entirely. Hurrah!&lt;/p&gt;
&lt;p&gt;I&#39;ve continued to work on &lt;strong&gt;gnus-html&lt;/strong&gt; and recently merged a set of patches
improving image retrieval (which is now done in parallel) and starting to
use &lt;strong&gt;`url-cache&#39;&lt;/strong&gt; to cache image for a defined period of time. Of course, I
found a bunch of tiny bug and special case while reading RSS feeds and
various HTML mails, and fixed them all along.&lt;/p&gt;
&lt;p&gt;Lars added a &lt;a href=&#34;http://xmlsoft.org&#34;&gt;libxml&lt;/a&gt; binding for Emacs 24, providing the &lt;strong&gt;`html-parse-string&#39;&lt;/strong&gt;
function. His future plan seems to be the abandon of w3m in favor of a
native parsing via libxml to render HTML, and therefore, HTML mails.&lt;/p&gt;
&lt;p&gt;I should also mention the new &lt;strong&gt;`nnimap&#39;&lt;/strong&gt; back-end; Gnus has been designed to
read &lt;a href=&#34;http://en.wikipedia.org/wiki/Network_News_Transfer_Protocol&#34;&gt;NNTP&lt;/a&gt; newsgroups, and not mails. Consequently, it had a very poor
behaviour when used with a back-end such has (IMAP)[http://en.wikipedia.org/wiki/Internet_Message_Access_Protocol].&lt;/p&gt;
&lt;p&gt;Lars took a week to rewrite entirely our dear &lt;strong&gt;`nnimap&#39;&lt;/strong&gt; back-end, and make it
act in a more expected way. There&#39;s still a bunch of bug and code to write,
but it is at least usable and seems faster than the old code.&lt;/p&gt;
&lt;p&gt;Last thing I did was to rewrite the icon support in the group buffer. When I
started to use Gnus, I was curious and tried to configure this. I never
managed to make it work, and now know and understand why it was broken. So I
ended rewriting entirely, and now it works. I never though I would
understand, fix, and commit this code when reading the Gnus documentation
this winter, but hell yeah, I did.&lt;/p&gt;
&lt;p&gt;Now I&#39;ve still several little project to improve things in all sort of area.
We&#39;ll see what I&#39;ll do next. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Emacs, Org, whatever the weather!</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/emacs-org-whatever"/>
    <updated>2010-09-08T22:44:00Z</updated>
    <published>2010-09-08T22:44:00Z</published>
    <id>/blog/2010/emacs-org-whatever</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
        <category   scheme="/blog/tags"
                term="googleweather"
                label="Googleweather" />
    
    <content type="html">
            &lt;p&gt;Another week, another &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt; extension!&lt;/p&gt;
&lt;p&gt;I had (once again) a wonderful idea: what if I could have the weather
forecasts in my &lt;a href=&#34;http://orgmode.org&#34;&gt;Org&lt;/a&gt; agenda? Wouldn&#39;t that be wonderful?&lt;/p&gt;
&lt;p&gt;My quest started by looking for a service offering a good weather forecast
API. I found nothing simple as the hidden Google Weather API, which is nice,
but… not documented. Not at all. Not a single line. Nah.&lt;/p&gt;
&lt;p&gt;Then, I wrote a &lt;strong&gt;google-weather&lt;/strong&gt; extension, implementing a basic Emacs Lisp
API to retrieve data from the Google service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;nv&#34;&gt;ELISP&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;google-weather-data-&amp;gt;forecast&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;google-weather-get-data&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Paris&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;p&#34;&gt;(((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2010&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;53&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;high&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;63&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://www.google.com/ig/images/weather/rain.gif&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;condition&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Rain&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2010&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;53&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;high&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;69&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://www.google.com/ig/images/weather/chance_of_rain.gif&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;condition&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Scattered Showers&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2010&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;54&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;high&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;72&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://www.google.com/ig/images/weather/partly_cloudy.gif&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;condition&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Partly Cloudy&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2010&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;55&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;high&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;75&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;icon&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://www.google.com/ig/images/weather/partly_cloudy.gif&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;condition&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Partly Cloudy&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
My API even implements data caching, which is nice to speed up the agenda
display.&lt;/p&gt;
&lt;p&gt;By the way, I think my next job will be to hack on the &lt;em&gt;url-cache&lt;/em&gt; feature of
Emacs, which is utterly buggy and has probably never be used. But that&#39;s
another topic.&lt;/p&gt;
&lt;p&gt;Finally, I just had to write another module on top of that to export the
forecasts to Org. A screen shot is probably better than a long and boring
explanation, so here&#39;s the result.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Org agenda with weather&#34; src=&#34;/media/images/blog/2010/org-google-weather.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;My only regret is that the icons provided by Google are ugly squares, so I
did not want to use them. On the other hand, I did not found any icon set
that would have all the icons Google provides (around 20). So I felt back on
the &lt;a href=&#34;http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html&#34;&gt;icon naming specification&lt;/a&gt; to map the Google images to standard images.
Any better idea would be welcome, of course.&lt;/p&gt;
&lt;p&gt;All the information can be found on the
&lt;a href=&#34;http://julien.danjou.info/software/google-weather.el&#34;&gt;Google Weather for Emacs extension homepage&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Emacs and OfflineIMAP</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/emacs-and-offlineimap"/>
    <updated>2010-09-03T15:08:00Z</updated>
    <published>2010-09-03T15:08:00Z</published>
    <id>/blog/2010/emacs-and-offlineimap</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="offlineimap"
                label="Offlineimap" />
    
    <content type="html">
            &lt;p&gt;I recently decided to use
&lt;a href=&#34;http://wiki.github.com/jgoerzen/offlineimap/&#34;&gt;OfflineIMAP&lt;/a&gt; to synchronize
my mails on my laptop. It&#39;s a great piece of software, and allows me to read
my mail while I&#39;m offline.&lt;/p&gt;
&lt;p&gt;I use it with &lt;a href=&#34;http://www.gnus.org&#34;&gt;Gnus&lt;/a&gt;, of course. But I lacked a proper way to integrate
OfflineIMAP with it, so I decided to write a little Emacs extension to run
and monitor OfflineIMAP directly from Emacs.&lt;/p&gt;
&lt;p&gt;Here comes &lt;a href=&#34;http://julien.danjou.info/software/offlineimap.el&#34;&gt;offlineimap.el&lt;/a&gt;, an Emacs extension to run OfflineIMAP directly
within Emacs. It will display OfflineIMAP output in a buffer, and optionally
shows the current OfflineIMAP operation in the mode line.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Emacs with offlineimap.el&#34; src=&#34;/media/images/blog/2010/offlineimap-el.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;By default the status is in the mode line only if you are in the Gnus group
buffer. But that&#39;s customizable, of course, since this is Emacs!&lt;/p&gt;
&lt;p&gt;If you are using &lt;a href=&#34;http://github.com/dimitri/el-get&#34;&gt;el-get&lt;/a&gt;, there&#39;s already a recipe to install it!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Emacs, Google Maps and BBDB</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/emacs-google-maps-bbdb"/>
    <updated>2010-08-18T00:00:00Z</updated>
    <published>2010-08-18T00:00:00Z</published>
    <id>/blog/2010/emacs-google-maps-bbdb</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="bbdb"
                label="Bbdb" />
        <category   scheme="/blog/tags"
                term="googlemaps"
                label="Googlemaps" />
    
    <content type="html">
            &lt;p&gt;Today&#39;s fun idea was to put all my contacts stored into &lt;a href=&#34;http://bbdb.sourceforge.net/&#34;&gt;BBDB&lt;/a&gt; on a Google
Maps&#39; map, using my &lt;a href=&#34;http://julien.danjou.info/software/google-maps.el&#34;&gt;Google Maps extension for Emacs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the help of a few lines of Lisp glue:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;google-maps-static-show&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;ss&#34;&gt;:markers&lt;/span&gt;&lt;br /&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;mapcar&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;address-entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;concat&lt;/span&gt;&lt;br /&gt;         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;mapconcat&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;ss&#34;&gt;&amp;#39;identity&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;elt&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;address-entry&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;elt&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;address-entry&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;elt&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;address-entry&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;elt&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;address-entry&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;elt&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;address-entry&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;&lt;br /&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;mapcan&lt;/span&gt;&lt;br /&gt;   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;lambda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;     &lt;span class=&#34;c1&#34;&gt;;; We need to copy the returned list, because mapcan will modify it later&lt;/span&gt;&lt;br /&gt;     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;copy-list&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;bbdb-record-addresses&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;record&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&lt;br /&gt;   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;bbdb-records&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
we can make that:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Google Maps with BBDB contacts&#34; src=&#34;/media/images/blog/2010/emacs-google-maps-bbdb.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s really simplistic, but I did not need more to have fun. :-)
This could be extended to set a specific marker and/or color for each
contact, with a legend. I&#39;ll let that as an exercise for my readers.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Updating muse-el in Debian</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/updating-muse-el-in-Debian"/>
    <updated>2010-08-15T20:43:00Z</updated>
    <published>2010-08-15T20:43:00Z</published>
    <id>/blog/2010/updating-muse-el-in-Debian</id>
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
        <category   scheme="/blog/tags"
                term="muse"
                label="Muse" />
    
    <content type="html">
            &lt;p&gt;The Debian package of &lt;a href=&#34;http://mwolson.org/projects/EmacsMuse.html&#34;&gt;Emacs Muse&lt;/a&gt; was maintained by &lt;a href=&#34;http://mwolson.org/web/WelcomePage.html&#34;&gt;Michael W. Wolson&lt;/a&gt;, who is
also the upstream author of that software.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://blog.mwolson.org/tech/projects/emacs_muse_3.20_released.html&#34;&gt;He announced months ago that Muse needed a new upstream maintainer.&lt;/a&gt; That&#39;s
not something I&#39;m willing to do, since I really think Muse has been
superseded by &lt;a href=&#34;http://www.orgmode.org&#34;&gt;Org mode&lt;/a&gt; nowadays.&lt;/p&gt;
&lt;p&gt;However, I&#39;m still using Muse to maintain this blog with my &lt;a href=&#34;http://julien.danjou.info/software/muse-blog&#34;&gt;muse-blog&lt;/a&gt;
extension, since Org still lacks some infrastructure to maintain and publish
a blog.&lt;/p&gt;
&lt;p&gt;Therefore, I adopted the &lt;a href=&#34;http://packages.qa.debian.org/m/muse-el.html&#34;&gt;Emacs Muse Debian package&lt;/a&gt; and updated it to the
latest version!&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Update on rainbow-mode</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/update-on-rainbow-mode"/>
    <updated>2010-08-10T00:00:00Z</updated>
    <published>2010-08-10T00:00:00Z</published>
    <id>/blog/2010/update-on-rainbow-mode</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;http://julien.danjou.info/software/rainbow-mode&#34;&gt;rainbow-mode&lt;/a&gt; had a big
success and good feedbacks when I released it for the first time a couple of
months ago.&lt;/p&gt;
&lt;p&gt;Several users asked to me request its inclusion into &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt;. Therefore, some
days ago, &lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-devel/2010-07/msg01290.html&#34;&gt;I proposed to merge it inside Emacs trunk&lt;/a&gt;. My request has been
denied, but the mode has been added to the &lt;a href=&#34;http://elpa.gnu.org&#34;&gt;Emacs 24 package repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the mean time, I&#39;ve added support for &lt;a href=&#34;http://www.w3.org/TR/css3-color/#hsl-color&#34;&gt;hsl() and hsla()&lt;/a&gt; support, and added
&lt;a href=&#34;http://www.w3.org/TR/css3-color/#svg-color&#34;&gt;CSS 3/SVG color names&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Porting D-Bus to XCB: story of a failure</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/porting-dbus-on-xcb"/>
    <updated>2010-07-29T00:00:00Z</updated>
    <published>2010-07-29T00:00:00Z</published>
    <id>/blog/2010/porting-dbus-on-xcb</id>
        <category   scheme="/blog/tags"
                term="dbus"
                label="Dbus" />
        <category   scheme="/blog/tags"
                term="xcb"
                label="Xcb" />
    
    <content type="html">
            &lt;p&gt;Even if &lt;a href=&#34;/blog/2010/thoughts-and-rambling-on-the-X-protocol&#34;&gt;I recently stated I lost some of my
faith&lt;/a&gt;
in &lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt;, I still sometimes hack things to add
support for it.&lt;/p&gt;
&lt;p&gt;These last days, I&#39;ve worked on a &lt;a href=&#34;http://dbus.freedesktop.org&#34;&gt;D-Bus&lt;/a&gt; port from Xlib to XCB. The port was
quite straight forward, since there&#39;s only a little piece of D-Bus using X,
which is &lt;em&gt;dbus-launch&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I though D-Bus was a good candidate, since it&#39;s part of the &lt;a href=&#34;http://www.freedesktop.org&#34;&gt;Freedesktop&lt;/a&gt;
initiative. Therefore, I was expecting a warm welcome and some enthusiasm
from a fellow project.&lt;/p&gt;
&lt;p&gt;My contribution got one useful review, and a &lt;a href=&#34;http://lists.freedesktop.org/archives/dbus/2010-July/013185.html&#34;&gt;cold reply from Thiago Macieira&lt;/a&gt;
(a &lt;a href=&#34;http://www.kde.org&#34;&gt;KDE&lt;/a&gt;/&lt;a href=&#34;http://qt.nokia.com&#34;&gt;Qt&lt;/a&gt;/&lt;a href=&#34;http://www.nokia.com&#34;&gt;Nokia&lt;/a&gt; developer):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No, sorry, I don&#39;t agree..
I&#39;ve just checked and my Solaris machine doesn&#39;t have XCB.
Please do not remove the X11 code. You may &lt;em&gt;add&lt;/em&gt; the XCB code, but you cannot
remove the X11 code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not really the kind of answer I expected, actually. I then reworked
the code to &lt;a href=&#34;http://lists.freedesktop.org/archives/dbus/2010-July/013192.html&#34;&gt;please Thiago&lt;/a&gt;, and added some &lt;em&gt;#ifdef&lt;/em&gt; to add XCB support to
D-Bus, with a fallback to libx11 where XCB would not be available.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://lists.freedesktop.org/archives/dbus/2010-July/013196.html&#34;&gt;Havoc Pennington replied&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given that libX11 now uses xcb as backend, I don&#39;t understand the
value of porting to use libxcb directly when there isn&#39;t an issue of
round trips or other stuff. It will just make #ifdef hell, while the
X11 API is an API that works on both xcb and non-xcb platforms.
Maybe people should be thinking about porting xcb to non-Linux
platforms? The X protocol should be the same on other UNiX, so xcb in
theory ought to work fine if you just compiled it on Solaris/BSD, same
as GTK or dbus or Qt would work fine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The last part &#34;Maybe people should be thinking about porting xcb to
non-Linux platforms?&#34; is still unclear to me, even though
&lt;a href=&#34;http://lists.freedesktop.org/archives/dbus/2010-July/013197.html&#34;&gt;I asked Havoc to explain what he meant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, &lt;a href=&#34;http://lists.freedesktop.org/archives/dbus/2010-July/013198.html&#34;&gt;Thiago refused to merge the patch&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] thanks for the patch, but like Havoc I am unsure of the value. We can&#39;t
drop the X11 codepaths now because too many systems exist without
XCB. Adding the XCB codepaths only made it more complex, even though you did
a good job.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I can&#39;t disagree with that conclusion: using both XCB and X11 make the code
unreadable for little gain. That&#39;s why I did replace libx11 by XCB directly
in the first version of the patch. On the other hand, D-Bus people does not
seems to really care about making their software evolve in the right
direction, even if that requires users to upgrade their systems.&lt;/p&gt;
&lt;p&gt;I think D-Bus using and depending on XCB would have been a good point to
push adoption of XCB. Unfortunately, it seems you can&#39;t even rely of
projects of the same initiative (i.e. Freedesktop) to work together to make
things a little bit better.&lt;/p&gt;
&lt;p&gt;After 5 years of existence, XCB is still not so obvious to people, and
making it adopt is going to be a challenge for the next years. The upside is
that &lt;a href=&#34;http://www.x.org/wiki/Releases/7.6&#34;&gt;new X.org 7.6 will bring XCB with it&lt;/a&gt;, as part of the katamari.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">M-x google-maps</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/google-maps.el"/>
    <updated>2010-06-28T00:00:00Z</updated>
    <published>2010-06-28T00:00:00Z</published>
    <id>/blog/2010/google-maps.el</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
        <category   scheme="/blog/tags"
                term="googlemaps"
                label="Googlemaps" />
    
    <content type="html">
            &lt;p&gt;Since I have started to use &lt;a href=&#34;http://www.orgmode.org&#34;&gt;Org-mode&lt;/a&gt;, I though it was missing something to
have appointment locations on a map. Of course, it&#39;s easy to get a &lt;em&gt;LOCATION&lt;/em&gt;
property from an entry, and then &lt;em&gt;browse-url&lt;/em&gt; on &lt;a href=&#34;http://maps.google.com&#34;&gt;Google Maps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But it is &lt;strong&gt;too&lt;/strong&gt; easy for me, so once again I said: challenge accepted! I will
bring Google Maps into Emacs!&lt;/p&gt;
&lt;p&gt;After several hours of work, the &lt;a href=&#34;http://julien.danjou.info/software/google-maps.el&#34;&gt;google-maps.el project&lt;/a&gt; shows a map!&lt;/p&gt;
&lt;p&gt;It fully implements the &lt;a href=&#34;http://code.google.com/apis/maps/documentation/staticmaps/&#34;&gt;Google Static Maps API&lt;/a&gt; and the
&lt;a href=&#34;http://code.google.com/apis/maps/documentation/geocoding/&#34;&gt;Google Maps Geocoding API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can type &lt;strong&gt;M-x google-maps&lt;/strong&gt; and type some place to see it marked on map. Of
course you can do much more, as seen in the screen shot above.&lt;/p&gt;
&lt;p&gt;I&#39;ve also completed all of this with a small &lt;em&gt;org-location-google-maps.el&lt;/em&gt; which
simply show a Google Maps&#39; map for the location of an event in &lt;em&gt;Org mode&lt;/em&gt; by
pressing C-c M-l in an Org buffer or in the Org agenda.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Announcing rainbow-mode</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/announcing-rainbow-mode"/>
    <updated>2010-06-16T00:00:00Z</updated>
    <published>2010-06-16T00:00:00Z</published>
    <id>/blog/2010/announcing-rainbow-mode</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
    
    <content type="html">
            &lt;p&gt;While customizing &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt; this last weeks, I had the need to customize also
the color theme.&lt;/p&gt;
&lt;p&gt;Color themes are always a pain in the ass to edit, because you&#39;re supposed
to read color strings like &lt;em&gt;#aabbcc&lt;/em&gt; and guess what colors they represent.&lt;/p&gt;
&lt;p&gt;This is why I wrote &lt;em&gt;[[http://julien.danjou.info/rainbow-mode.html][rainbow-mode]]&lt;/em&gt;, a minor mode for Emacs that will highlight
strings that represents color, using the color they represent.&lt;/p&gt;
&lt;p&gt;This support hexadecimal syntax, HTML color name, X color names and rgb()
CSS syntax.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Screenshot of Emacs with rainbow-mode activated&#34; src=&#34;/media/images/blog/2010/rainbow-mode.png&#34; /&gt;&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Desktop notification support for Emacs</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/desktop-notification-support-for-Emacs"/>
    <updated>2010-06-09T00:00:00Z</updated>
    <published>2010-06-09T00:00:00Z</published>
    <id>/blog/2010/desktop-notification-support-for-Emacs</id>
        <category   scheme="/blog/tags"
                term="freedesktop"
                label="Freedesktop" />
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="notify"
                label="Notify" />
    
    <content type="html">
            &lt;p&gt;This last weeks, I&#39;ve worked on implementing the
&lt;a href=&#34;http://www.galago-project.org/specs/notification/&#34;&gt;Desktop Notification Specification&lt;/a&gt; into &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It allows sending desktop notification in a very simple way.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;notifications-notify&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;ss&#34;&gt;:title&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;You&amp;#39;ve got mail!&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;ss&#34;&gt;:body&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;There&amp;#39;s 34 mails unread&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;ss&#34;&gt;:app-icon&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;~/.emacs.d/icons/mail.png&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&#34;ss&#34;&gt;:urgency&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;low&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
It supports the protocol signals (&lt;em&gt;NotificationClosed&lt;/em&gt; and &lt;em&gt;ActionInvoked&lt;/em&gt;) and
the two main methods (&lt;em&gt;Notify&lt;/em&gt; and &lt;em&gt;CloseNotification&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;The methods specification are implemented entirely (hints, replaces,
actions, icon, etc).&lt;/p&gt;
&lt;p&gt;The signals are supported via callbacks function provided on the
notification creation.&lt;/p&gt;
&lt;p&gt;It have been merged into Emacs trunk today.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;2010-06-09  Julien Danjou  &amp;lt;julien@danjou.info&amp;gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; * net/notifications.el: New file.&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This also allowed me to discover, raise and fix a
&lt;a href=&#34;http://lists.gnu.org/archive/html/emacs-devel/2010-06/msg00228.html&#34;&gt;bug&lt;/a&gt;
in the D-Bus binding of Emacs, which will be probably fixed in trunk soon.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Announcing erc-track-score</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/announcing-erc-track-score"/>
    <updated>2010-06-07T00:00:00Z</updated>
    <published>2010-06-07T00:00:00Z</published>
    <id>/blog/2010/announcing-erc-track-score</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="erc"
                label="Erc" />
    
    <content type="html">
            &lt;p&gt;A couple of months ago, I&#39;ve started using &lt;a href=&#34;http://www.emacswiki.org/emacs/ERC&#34;&gt;ERC&lt;/a&gt; to hang out on &lt;a href=&#34;http://en.wikipedia.org/wiki/Internet_Relay_Chat&#34;&gt;IRC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;ve read all the pages on &lt;a href=&#34;http://www.emacswiki.org/&#34;&gt;EmacsWiki&lt;/a&gt; about it, just to see how far I
could customize it.&lt;/p&gt;
&lt;p&gt;I must admit that I was not disappointed, even if I expected to be. It&#39;s
quite a nice software, and once well configured it&#39;s more convenient that my
old [[http://www.irssi.org][irssi]] setup.&lt;/p&gt;
&lt;p&gt;While browsing EmacsWiki, I read an interesting idea about channel
scoring/temperature on the [[http://www.emacswiki.org/emacs/ErcChannelTracking#toc9][erc-track]] page. The idea is to see if it&#39;s worth
jumping to an IRC channel to see what people are talking about.&lt;/p&gt;
&lt;p&gt;Challenge accepted!&lt;/p&gt;
&lt;p&gt;I sat up and started to dig though ERC source code to find the information I
needed about variables and functions.&lt;/p&gt;
&lt;p&gt;I finally did write something nice, which I called &lt;a href=&#34;http://julien.danjou.info/software/erc-track-score&#34;&gt;erc-track-score&lt;/a&gt;.
And yet another piece of software I wrote for my lovely &lt;a href=&#34;http://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;How does it work? Ha-ha, I was sure you would ask. You&#39;re so predictable,
dude! Read the following, and you&#39;ll know everything you ever wanted to know
about it since the moment you read the title of that blog entry.&lt;/p&gt;
&lt;p&gt;Which probably turned you on.&lt;/p&gt;
&lt;p&gt;Nasty you.&lt;/p&gt;
&lt;p&gt;First of all, the score of a channel starts at zero. Zero means &#34;seriously,
don&#39;t bother, nothing is happening here&#34;.&lt;/p&gt;
&lt;p&gt;Upon each new message arrival, the score is incremented by 1. If a new
message contains a keyword, your nickname or is sent by a pal, the score is
increased by configurable values, by default between 2 and 20 points,
depending on the match type. On the other hand, when a message is send by
some fool, the score is decreased by 1 by default.&lt;/p&gt;
&lt;p&gt;Obviously, if the score is going negative, you really should not jump to the
channel.&lt;/p&gt;
&lt;p&gt;Finally, the score is permanently and slowly brought back to 0. By default,
the score is decreased by 1 point every 10 seconds.&lt;/p&gt;
&lt;p&gt;Overall, reading the score should gives you a good idea of the channel
temperature.&lt;/p&gt;
&lt;p&gt;I&#39;m still not sure what is the best formula to compute the score, but so far
the default values seem quite good. We&#39;ll see.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Thoughts and rambling on the X protocol</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/thoughts-and-rambling-on-the-X-protocol"/>
    <updated>2010-06-01T00:00:00Z</updated>
    <published>2010-06-01T00:00:00Z</published>
    <id>/blog/2010/thoughts-and-rambling-on-the-X-protocol</id>
        <category   scheme="/blog/tags"
                term="x11"
                label="X11" />
        <category   scheme="/blog/tags"
                term="ewmh"
                label="Ewmh" />
    
    <content type="html">
            &lt;p&gt;Two years ago, while working on &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;, I joined the &lt;a href=&#34;http://www.freedesktop.org&#34;&gt;Freedesktop&lt;/a&gt; initiative
to work on &lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt;. I had to learn the arcane of the X11 protocol and all the
mysterious and old world that goes with it.&lt;/p&gt;
&lt;p&gt;Now that I&#39;ve swum all this months in this mud, I just feel like I need to
share my thoughts about what become a mess over the decades.&lt;/p&gt;
&lt;h1&gt;When I was unborn…&lt;/h1&gt;
&lt;p&gt;…the &lt;a href=&#34;http://en.wikipedia.org/wiki/Toto_(band)&#34;&gt;Toto&lt;/a&gt; band were releasing their &lt;a href=&#34;http://en.wikipedia.org/wiki/Africa_(Toto_song)&#34;&gt;song &#34;Africa&#34;&lt;/a&gt; and some smart guys were
working on a windowing system: the X Window System (this is its full name)
which therefore has a (too) long history. The latest version of its
protocol, the 11th one, has been designed in the 80&#39;s. You can learn more
about the history in the &lt;a href=&#34;http://en.wikipedia.org/wiki/X_Window_System&#34;&gt;Wikipedia article about X&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In 2010, we still listen disco music and we still use various protocols
designed in the 80&#39;s and even before X. Music have evolved, protocols have
evolved, and so did X11.&lt;/p&gt;
&lt;p&gt;The problem is that X11 did not evolve that well. The guys at MIT-and-some
other-places-with-very-smart-people-in-it created X version 1 in 1984, and
updated it until X version 11 (the one we&#39;re still using) in 1987. Eleven
version in 3 years, that was following the &#34;release early, release often&#34;
model. But I don&#39;t know why, it just stopped to happen for the last 23 years
(that&#39;s not totally true: they added (and then deprecated) many extensions.)&lt;/p&gt;
&lt;p&gt;I don&#39;t know what changes have been made in the first 11 major versions of
the X protocol, but I&#39;m rather sure we should have deserve a couple of major
version updates this last 2 decades.&lt;/p&gt;
&lt;p&gt;In my humble opinion, X11 was not designed to live 23 years. But hey, I&#39;m
not blaming anyone here: I was 4 years old and playing Lego ® when they
released this latest version of the X protocol, so there is little chance
I&#39;d have done something better.&lt;/p&gt;
&lt;h1&gt;We won&#39;t fix. We&#39;ll work-around.&lt;/h1&gt;
&lt;p&gt;That is probably one of the guideline of the X protocol for the last
years. And don&#39;t misread me: I&#39;m not bashing anyone thereafter.&lt;/p&gt;
&lt;p&gt;Since the X11 protocol was aging, the X guys started to add &lt;a href=&#34;http://en.wikipedia.org/wiki/X_Window_System_protocols_and_architecture#Extensions&#34;&gt;extensions&lt;/a&gt;. They
added tons of them over the years. This, in application of one of
&lt;a href=&#34;http://en.wikipedia.org/wiki/X_Window_System_protocols_and_architecture#Design_principles&#34;&gt;the early principles of X&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;It is as important to decide what a system is not as to decide what it
 is. Do not serve all the world&#39;s needs; rather, make the system extensible
 so that additional needs can be met in an upwardly compatible fashion.&lt;/p&gt;
&lt;p&gt;All of them with no exception were added because, bad luck, the X11 protocol
did not anticipated the things that happened in the last 23 years, like
video, OpenGL, multiple monitors, or the pleasure to draw oval windows. Some
of this extensions are still in use, while some of them have been dropped.&lt;/p&gt;
&lt;p&gt;While this is not a bad thing to extends the protocol, it seems like a bad
thing to try to fix the protocol with for example the &lt;a href=&#34;http://en.wikipedia.org/wiki/XFixes&#34;&gt;XFixes extension&lt;/a&gt;, even
with all the good intentions Keith Packard might have in his greatness.&lt;/p&gt;
&lt;h1&gt;Actually it&#39;s even worst than you think&lt;/h1&gt;
&lt;p&gt;The X11 protocol (without extensions) defines about 120 types of requests:
create a window, move a window, etc.&lt;/p&gt;
&lt;p&gt;Nowadays, there&#39;s at least 25 % of them which are useless: usage of
server-side font, or the drawing of squares and polygon, are unused by any
modern application or toolkit. All of this is superseded by requests from
extensions, like the &lt;a href=&#34;http://en.wikipedia.org/wiki/XRender&#34;&gt;XRender&lt;/a&gt; one.&lt;/p&gt;
&lt;p&gt;The handling of multiple monitors displays has totally been screwed up. X11
has been designed to work in &lt;a href=&#34;http://en.wikipedia.org/wiki/Zaphod_Beeblebrox#Cultural_references&#34;&gt;Zaphod&lt;/a&gt; mode (independent monitors). But
&lt;a href=&#34;http://en.wikipedia.org/wiki/Xinerama&#34;&gt;Xinerama&lt;/a&gt;, and nowadays &lt;a href=&#34;http://en.wikipedia.org/wiki/XRandR&#34;&gt;XRandR&lt;/a&gt; have replaced it up: recent X servers
(released after ~2007) does not support Zaphod mode anymore, even if it&#39;s a
core piece of the X11 protocol.&lt;/p&gt;
&lt;p&gt;Worst: on many requests, there&#39;s limitation or design flaws, like described
in this document: &lt;a href=&#34;http://www.std.org/~msm/common/protocol.pdf&#34;&gt;Why X Is Not Our Ideal Window System&lt;/a&gt; by DEC researchers.&lt;/p&gt;
&lt;h1&gt;We&#39;ll add more broken standard on top of that&lt;/h1&gt;
&lt;p&gt;Following &lt;a href=&#34;http://en.wikipedia.org/wiki/X_Window_System_protocols_and_architecture#Design_principles&#34;&gt;its early principle&lt;/a&gt;, X does not define policies but only
mechanisms, which seems like a good thing,&lt;/p&gt;
&lt;p&gt;Consequently, people started writing specifications to determine a number of
stuff and dogmas: &lt;a href=&#34;http://en.wikipedia.org/wiki/ICCCM&#34;&gt;ICCCM&lt;/a&gt;. That was 22 years ago in 1988. It&#39;s useless to add
that many things in this specification are now obsolete, useless, or that it
misses many modern stuff.&lt;/p&gt;
&lt;p&gt;I was not the only one to think that. The people from what will be the major
desktop environments, &lt;a href=&#34;http://www.kde.org&#34;&gt;KDE&lt;/a&gt; and &lt;a href=&#34;http://www.gnome.org&#34;&gt;GNOME&lt;/a&gt;, saw that too in the 90&#39;s while I was
learning to count. So they wrote &lt;a href=&#34;http://en.wikipedia.org/wiki/Extended_Window_Manager_Hints&#34;&gt;EWMH&lt;/a&gt;, another standard that comes on top of
ICCCM and extends it with nifty features like maximization, full screen
mode, etc.&lt;/p&gt;
&lt;p&gt;The problem is that this standard has also been written by narrow-minded
people who at that time, were working on GNOME or KDE (and maybe
others). This desktop environments were having and still have some strong
concepts of how should work a desktop: &#34;it should have work-spaces&#34;, &#34;a
window is only on one workspace&#34;, &#34;we only see a workspace at a time&#34;, &#34;you
do not have multiple screens&#34;, etc.&lt;/p&gt;
&lt;h1&gt;Dude, we don&#39;t care: we have toolkits!&lt;/h1&gt;
&lt;p&gt;This vision of how the desktop should work have now been written in marble
in all applications and libraries implementing EWMH, like &lt;a href=&#34;http://www.gtk.org&#34;&gt;GTK+&lt;/a&gt; or &lt;a href=&#34;http://qt.nokia.com&#34;&gt;Qt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nowadays, everybody forgot about all of this standards. Toolkits have
implemented this, circumvented the X11 protocol limitation and flaws, and
nobody wants to look back.&lt;/p&gt;
&lt;p&gt;Like all standards, obviously some people implemented them badly. This had
some side effects, like [OpenOffice acting like a pager].&lt;/p&gt;
&lt;h1&gt;We don&#39;t look back? Worst, we forgot where we came from!&lt;/h1&gt;
&lt;p&gt;With all these layers of bad designed standards, the desktop continued to
evolve for more than a decade. They continued to add more standard, the more
recent ones being based on D-Bus like the &lt;a href=&#34;http://www.galago-project.org/specs/notification/&#34;&gt;Desktop Notification Specification&lt;/a&gt;
or the latest &lt;a href=&#34;http://www.notmart.org/misc/statusnotifieritem/index.html&#34;&gt;Status Notifier Specification&lt;/a&gt; developed by KDE.&lt;/p&gt;
&lt;p&gt;The Status Notifier is a new implementation of the good old system tray
based on &lt;a href=&#34;http://en.wikipedia.org/wiki/XEmbed][XEmbed]],%20using%20[[http://en.wikipedia.org/wiki/D-Bus&#34;&gt;D-Bus&lt;/a&gt; instead of the X11 mechanisms, and adding the
possibility to show the system tray with something else than icons.&lt;/p&gt;
&lt;p&gt;This specification draft saw an important issue and design flaw raised by
Wolfgang Draxinger in &lt;a href=&#34;http://lists.freedesktop.org/archives/xdg/2010-May/011516.html&#34;&gt;this thread on the XDG mailing-list&lt;/a&gt;. What Wolfgang
points out, is that X is network-oriented, and D-Bus is not. Therefore,
making the Status Notifier specification to use D-Bus to pass system tray
messages around is a bad idea, since running a X application from host A on
host B will draw the system tray on the wrong host!&lt;/p&gt;
&lt;p&gt;Apparently, reading the thread, this &lt;a href=&#34;http://lists.freedesktop.org/archives/xdg/2010-May/011531.html&#34;&gt;does not fear some of the KDE people&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;of course this is a bizarre corner case not worth much thought. at least
 that&#39;s what you&#39;ll think until you actually run into it yourself (be it
 because you are testing something or because you are setting up some
 weird kiosk environment).&lt;/p&gt;
&lt;p&gt;What Oswald describes as a corner case is an actual common use case for many
of us. Of course, YMMV.&lt;/p&gt;
&lt;p&gt;From my point of view, this is a step back in the wrong direction. But we
can conclude that the network part of X is now worthless, to at least KDE.&lt;/p&gt;
&lt;h1&gt;I used to believe in XCB&lt;/h1&gt;
&lt;p&gt;When I joined Freedesktop, it was to work on XCB, the X C Binding. XCB is a
nice, clean, 21st century technology based API to play with the X11
protocol. Its code is auto generated based on XML file describing the
protocol.&lt;/p&gt;
&lt;p&gt;In comparison, Xlib is 80&#39;s obfuscated code with almost no comments and
hard-coded things. Only a few people can understand some of its corner like
its i18n or XKB implementations. And all its code is &lt;em&gt;synchronous&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For people not knowing it yet, X is a network protocol where you send
request (like a GET in HTTP) and then get a response. Xlib forces the
application to wait for the reply to its request, so the application is
blocked until the X server sends the reply to the request. XCB on the other
hand does not block and allows the application to send a batch of requests,
do some other stuff in the mean time, and then gets the replies.&lt;/p&gt;
&lt;p&gt;It&#39;s like your Web browser would send one request at a time to a Web server,
and would wait until you downloaded all the images one by one to display the
page.&lt;/p&gt;
&lt;p&gt;In cases where X and all its clients are on the same host, the latency is
small and not really visible, therefore the gain for XCB to be asynchronous
is small. On slow network however, the gain can be huge, as proved in the
&lt;a href=&#34;http://bugs.freedesktop.org/show_bug.cgi?id=4232&#34;&gt;rewrite of xlsclients with XCB by Peter Harris&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the long standing goal of the XCB folks is to kick-out Xlib, to
increase speed and hides latency in X11 applications. That requires to port
many libraries, because almost none of them (&lt;a href=&#34;http://www.cairographics.org&#34;&gt;Cairo&lt;/a&gt; being an exception)
supports XCB.&lt;/p&gt;
&lt;p&gt;From where I stand, I don&#39;t really see if the work is worth it now. The
desktop world is trusted by GNOME and KDE, meaning GTK+ and Qt. It seems
none of this toolkits are interested to work on XCB, neither on the X
protocol. They probably put hard effort in bypassing X limitation and flaws,
and they now sit on top of crap of workarounds and broken-by-design-standard
implementation. It seems to me they don&#39;t want to go back in the layers and
improves things.&lt;/p&gt;
&lt;p&gt;They&#39;re too high to go back down and they don&#39;t see what the gain would be.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.enlightenment.org/][Enlightenment]]%20with%20its%20[[http://www.enlightenment.org/p.php?p=about&amp;amp;l=en&#34;&gt;EFL&lt;/a&gt; was the first toolkit to have an XCB back-end
with the work of Vincent Torri. Unfortunately, the back-end is not
maintained and nobody cares about it. Last time I tried it, it did not
compile at all.&lt;/p&gt;
&lt;h1&gt;X12?&lt;/h1&gt;
&lt;p&gt;There&#39;s a page called &lt;a href=&#34;http://www.x.org/wiki/Development/X12&#34;&gt;X12&lt;/a&gt; on the Freedesktop wiki, listing all the things
that should be fixed some days. Unfortunately, the list continues to grow up
an no one talks about working on X12.&lt;/p&gt;
&lt;p&gt;On the other hand, there&#39;s a handset of people trying to work when they will
have time on &lt;a href=&#34;http://www.freedesktop.org/wiki/Software/XKeyboardConfig/XKB2Dreams&#34;&gt;XKB2&lt;/a&gt;, the second version of the &#34;let&#39;s-try-to-fix-up-the
keyboard-part-of-the-protocol-we-wrote-23-years-ago-a-second-time&#34;
extension.&lt;/p&gt;
&lt;p&gt;To me, it does not seem X12 will happen in the next decade neither.&lt;/p&gt;
&lt;h1&gt;Alternative?&lt;/h1&gt;
&lt;p&gt;Do we got alternative to X? There&#39;s &lt;a href=&#34;http://en.wikipedia.org/wiki/Wayland_(display_server)&#34;&gt;Wayland&lt;/a&gt;, but it&#39;s far from being
usable. There&#39;s &lt;a href=&#34;http://www.directfb.org/&#34;&gt;DirectFB&lt;/a&gt;, but that&#39;s not very portable. None seems candidate
to replace X some days to me.&lt;/p&gt;
&lt;p&gt;Anyhow, none of the main toolkits around support this alternative. GTK+
once supported DirectFB, but as far as I know, it is not supported nor works
nowadays, as stated by &lt;a href=&#34;http://np237.livejournal.com/27459.html&#34;&gt;Josselin Mouette&lt;/a&gt;. This is why recent versions of the
Debian installer have migrated to X for the graphic part, thanks to Cyril
Brulebois work.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;XCB has been around for more than half-a-decade, and very few people showed
interested in it. As far as I can see, nobody is interested to use the X
protocol and everybody tries to encapsulate it in some higher-level API as
soon as possible to stop seeing it. This leads to poorly written application
and toolkits, with a lot of ugly hack.&lt;/p&gt;
&lt;p&gt;All of that also means that starting to write applications and graphical
toolkits based on XCB would be a very interesting project, but that would
lead to spend too much time learning to circumvent the X protocol flaws,
things that have been done in years by predecessors like Qt and GTK+.&lt;/p&gt;
&lt;p&gt;Major toolkits implementations have almost nothing to win in going back in
the dark water of X. I guess most of their folks prefer to work on shiny 3D
effects based on your GPS location, rather than redefining better basis for
everyone.&lt;/p&gt;
&lt;p&gt;The manpower available in the X world is very small. Debian lacking of X
maintainers is just the summit of that. There is very smart and very
competent and skilled guys in the X world, as you can see by simply reading
blog posts on &lt;a href=&#34;http://planet.freedesktop.org&#34;&gt;Planet Freedesktop&lt;/a&gt; for example (me excluded). Unfortunately,
there&#39;s not enough of them to cover all the things involved in X: input
devices, graphics devices, new protocol extension specification and so
on. The X server is really late, and it seems most of the developers prefers
to work on the server itself than on the protocol behalf. Which is
understandable.&lt;/p&gt;
&lt;p&gt;I&#39;m curious to see where all of that will lead in the upcoming years. I&#39;ve
been walking in the X world hallways for about 3 years now, and I feel
desktop alternatives to KDE and GNOME will all die sooner or later. The time
were you could choose between a dozen &#34;modern&#34; window managers has passed
away.&lt;/p&gt;
&lt;p&gt;After all, maybe that is simply Darwinism applied to computer software.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Making startup-notification XCB native</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/making-startup-notification-XCB-native"/>
    <updated>2010-05-24T18:05:00Z</updated>
    <published>2010-05-24T18:05:00Z</published>
    <id>/blog/2010/making-startup-notification-XCB-native</id>
        <category   scheme="/blog/tags"
                term="freedesktop"
                label="Freedesktop" />
        <category   scheme="/blog/tags"
                term="xcb"
                label="Xcb" />
        <category   scheme="/blog/tags"
                term="startupnotification"
                label="Startupnotification" />
    
    <content type="html">
            &lt;p&gt;I&#39;m trying to work on XCB this week. And today I&#39;ve started to accomplish
the second step of a long term goal: making an X11 only library using &lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt; as
its primary interface instead of Xlib.&lt;/p&gt;
&lt;p&gt;Last year, I had extended the API of &lt;a href=&#34;http://www.freedesktop.org/wiki/Software/startup-notification&#34;&gt;startup-notification&lt;/a&gt; to support XCB as
a back-end.  This had been made possible by factorizing some code,
duplicating the X11 code and translating it into equivalent XCB.&lt;/p&gt;
&lt;p&gt;Today, I&#39;ve accomplished the second step, being dropping the Xlib code
inside startup-notification to keep only the XCB one.&lt;/p&gt;
&lt;p&gt;For this, I used the x11-xcb library, which is available when Xlib is
compiled with XCB as its transport, which is nowadays the standard.&lt;/p&gt;
&lt;p&gt;This library provides the function &lt;em&gt;XGetXCBConnection&lt;/em&gt;, which can convert a
&lt;em&gt;Display&lt;/em&gt; pointer to a &lt;em&gt;xcb_connection_t&lt;/em&gt; pointer. Consequently, it&#39;s now
possible to write and execute XCB based code and being compatible with Xlib.&lt;/p&gt;
&lt;p&gt;I&#39;ve made some benchmark of my work for the occasion, in order to measure
what the gain is.&lt;/p&gt;
&lt;p&gt;The first table described 1000 launches of a fake application (a modified
version of the startup-notification test suite actually). The X server is
local (the latency is very minimal then). The gain is computed between the
same back-end type for the total time. &lt;strong&gt;Full XCB&lt;/strong&gt; is the &#34;version&#34; I&#39;m
working on.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Version - Back-end&lt;/th&gt;
      &lt;th&gt;User time (seconds)&lt;/th&gt;
      &lt;th&gt;Kernel time (seconds)&lt;/th&gt;
      &lt;th&gt;Total time (seconds)&lt;/th&gt;
      &lt;th&gt;Gain&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;0.10 - libx11&lt;/td&gt;
      &lt;td&gt;3.20&lt;/td&gt;
      &lt;td&gt;7.42&lt;/td&gt;
      &lt;td&gt;12.989&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.10 - libxcb&lt;/td&gt;
      &lt;td&gt;2.76&lt;/td&gt;
      &lt;td&gt;7.36&lt;/td&gt;
      &lt;td&gt;12.414&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Full XCB - libx11&lt;/td&gt;
      &lt;td&gt;2.74&lt;/td&gt;
      &lt;td&gt;7.50&lt;/td&gt;
      &lt;td&gt;12.380&lt;/td&gt;
      &lt;td&gt;4.6 %&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Full XCB - libxcb&lt;/td&gt;
      &lt;td&gt;2.72&lt;/td&gt;
      &lt;td&gt;7.16&lt;/td&gt;
      &lt;td&gt;12.037&lt;/td&gt;
      &lt;td&gt;3.0 %&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The user time and kernel time are provided but are not really
interesting. XCB does not offers a big gain in CPU execution time, but is
more about latency. Anyhow, there&#39;s always a gain with XCB.&lt;/p&gt;
&lt;p&gt;This second table describe the same test but running only 100 times over a
slow network.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Version - Back-end&lt;/th&gt;
      &lt;th&gt;Total time (seconds)&lt;/th&gt;
      &lt;th&gt;Gain&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;0.10 - libx11&lt;/td&gt;
      &lt;td&gt;76&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0.10 - libxcb&lt;/td&gt;
      &lt;td&gt;35&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Full XCB - libx11&lt;/td&gt;
      &lt;td&gt;72&lt;/td&gt;
      &lt;td&gt;5.2 %&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Full XCB - libxcb&lt;/td&gt;
      &lt;td&gt;33&lt;/td&gt;
      &lt;td&gt;5.7%&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The gain is relatively small, about 5 %. But anyhow, there&#39;s still a
gain. Note that the difference between the execution time of the same test
written in XCB and Xlib is just huge. I&#39;ve tried to optimize the Xlib test,
but I did not manage to win more seconds.&lt;/p&gt;
&lt;p&gt;In conclusion, considering that startup-notification is only used when an
application launches another application, the perceivable gain might be even
smaller. But anyhow, I think it&#39;s worth it.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Announcing muse-blog</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/announcing-muse-blog"/>
    <updated>2010-05-19T17:00:00Z</updated>
    <published>2010-05-19T17:00:00Z</published>
    <id>/blog/2010/announcing-muse-blog</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="muse"
                label="Muse" />
    
    <content type="html">
            &lt;p&gt;Digging into the fabulous world of Emacs and Lisp, I wanted to use it to
build my personal Web site and my blog.&lt;/p&gt;
&lt;p&gt;I already moved from &lt;a href=&#34;http://ikiwiki.info/&#34;&gt;ikiwiki&lt;/a&gt; to
[[http://mwolson.org/projects/EmacsMuse.html][Emacs Muse]] for my HTML pages
some weeks ago.&lt;/p&gt;
&lt;p&gt;Muse provides an extension to maintain a journal, called
&lt;em&gt;muse-journal&lt;/em&gt;. Unfortunately, it was far to fulfill all my needs, and I
decided that it would be a good exercise to write a better extension.&lt;/p&gt;
&lt;p&gt;Consequently, I started to wrote my own extension, which I named &lt;a href=&#34;http://julien.danjou.info//muse-blog.html&#34;&gt;muse-blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And this is now what is used to build this blog. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Entering the Emacs world</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/entering-the-emacs-world"/>
    <updated>2010-05-17T18:36:00Z</updated>
    <published>2010-05-17T18:36:00Z</published>
    <id>/blog/2010/entering-the-emacs-world</id>
        <category   scheme="/blog/tags"
                term="emacs"
                label="Emacs" />
        <category   scheme="/blog/tags"
                term="gnus"
                label="Gnus" />
        <category   scheme="/blog/tags"
                term="orgmode"
                label="Orgmode" />
        <category   scheme="/blog/tags"
                term="muse"
                label="Muse" />
    
    <content type="html">
            &lt;p&gt;In February 2009, my friend &lt;a href=&#34;http://blog.tapoueh.org&#34;&gt;dim&lt;/a&gt; tried to force me using Emacs. I know a
couple of people using it and &lt;a href=&#34;http://www.gnus.org&#34;&gt;Gnus&lt;/a&gt; for reading their mail, and it always
made me curious.&lt;/p&gt;
&lt;p&gt;At that time, more than a year ago, Emacs 22 and Gnus did not seem usable
from my point of view.&lt;/p&gt;
&lt;p&gt;But around mid February, with the help of dim, I tried again to start using
Emacs.&lt;/p&gt;
&lt;p&gt;Actually, this was not something new for me. I (very basically) used Emacs
between 2000 and 2006. In 2006, when I finished the university and started
working at &lt;a href=&#34;http://www.easter-eggs.com][Easter-eggs]],%20I%20met%20a%20couple%20of%20[[http://www.vim.org&#34;&gt;vim&lt;/a&gt; enthusiasts. They taught me
how to use it in various ways, and I started to know more about vim than
Emacs, so I switched.&lt;/p&gt;
&lt;p&gt;This time, I started by configuring it, but reading the manual and also
learning a bit of Lisp. It took me several weeks, but step by step I learned
many, many things. And I must admit, I liked it.&lt;/p&gt;
&lt;p&gt;I&#39;ve configured and starting to use some very important mode, like Gnus,
&lt;a href=&#34;http://mwolson.org/projects/EmacsMuse.html][Muse]],%20the%20famous%20[[http://www.orgmode.org&#34;&gt;Org mode&lt;/a&gt; or even ERC.&lt;/p&gt;
&lt;p&gt;I&#39;ll probably talk about various Emacs related things in the near future,
since I already wrote more than a thousand lines of Lisp in the last 2
months.&lt;/p&gt;
&lt;p&gt;Anyhow, I&#39;d just conclude by asserting that my new Emacs/Gnus/Org/ERC setup
beats my old vim/mutt/nothing/irssi to the death with a baseball bat. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">On media players: 2 years after</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2010/on-media-players-2-years-after"/>
    <updated>2010-01-22T18:36:00Z</updated>
    <published>2010-01-22T18:36:00Z</published>
    <id>/blog/2010/on-media-players-2-years-after</id>
        <category   scheme="/blog/tags"
                term="audacious"
                label="Audacious" />
        <category   scheme="/blog/tags"
                term="sonata"
                label="Sonata" />
        <category   scheme="/blog/tags"
                term="mpd"
                label="Mpd" />
    
    <content type="html">
            &lt;p&gt;Two years ago, I switched from my beloved &lt;em&gt;xmms&lt;/em&gt; to
&lt;a href=&#34;http://audacious-media-player.org/&#34;&gt;audacious&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During this 2 years with Audacious, I suffered a bit. It was working quite
fine, but I saw no big progress around it. Life happened, and I had to use a
network system to play music. I started to use PulseAudio over TCP, but it
does not work well, and does not work at all with Audacious (and even if the
plugin is provided by upstream). So I decided to dump it.&lt;/p&gt;
&lt;p&gt;And some days ago I discovered &lt;a href=&#34;http://www.musicpd.org/&#34;&gt;Sonata&lt;/a&gt;, a
[MPD](http://sonata.berlios.de/] client. I never liked MPD so far because
all clients I found were lame.&lt;/p&gt;
&lt;p&gt;But I really like Sonata. It allows me to listen music the way I still want:
load everything in one playlist, listen everything randomly or type a
song/artist to jump to it directly in the current playlist. It even has some
nice feature (lyrics, so I&#39;ll be able to song out loud, covers, tag
editing…) and is written in Python and GTK+ (some days I may even hack it!).&lt;/p&gt;
&lt;p&gt;You can rest in peace x11amp :-p&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Python cairo and XCB support</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/python-cairo-and-xcb-support"/>
    <updated>2009-12-22T00:00:00Z</updated>
    <published>2009-12-22T00:00:00Z</published>
    <id>/blog/2009/python-cairo-and-xcb-support</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="cairo"
                label="Cairo" />
        <category   scheme="/blog/tags"
                term="xcb"
                label="Xcb" />
    
    <content type="html">
            &lt;p&gt;&lt;a href=&#34;http://www.cairographics.org&#34;&gt;cairo&lt;/a&gt; has a &lt;a href=&#34;http://www.cairographics.org/pycairo/&#34;&gt;Python binding
(pycairo)&lt;/a&gt; since a long time, and
some months ago a &lt;a href=&#34;http://cgit.freedesktop.org/xcb/xpyb/&#34;&gt;Python binding for XCB
(xpyb)&lt;/a&gt; has been released.&lt;/p&gt;
&lt;p&gt;Pycairo has no support for creating Xlib surfaces. You can get a Xlib
surface from PyGTK and then use Pycairo to draw on it, but there&#39;s no way to
create one directly.&lt;/p&gt;
&lt;p&gt;What I&#39;ve done is make Pycairo aware of xpyb so it can creates directly an
XCB surface from a XCB connection and a drawable.&lt;/p&gt;
&lt;p&gt;As said in &lt;a href=&#34;http://lists.freedesktop.org/archives/xcb/2009-December/005438.html&#34;&gt;my mail to the XCB
list&lt;/a&gt;,
I&#39;m now waiting for a review before pushing this upstream. :-)&lt;/p&gt;
&lt;p&gt;For the first time, I guess, XCB has beat Xlib support! ;-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Teething troubles</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/teething-troubles"/>
    <updated>2009-12-20T00:00:00Z</updated>
    <published>2009-12-20T00:00:00Z</published>
    <id>/blog/2009/teething-troubles</id>
        <category   scheme="/blog/tags"
                term="python"
                label="Python" />
        <category   scheme="/blog/tags"
                term="cython"
                label="Cython" />
    
    <content type="html">
            &lt;p&gt;It&#39;s not that often that I start something from scratch. It&#39;s an amazing
feeling to start a new project, to start writing something new. I like
that. It&#39;s creation, it&#39;s an artistic part of our computing stuff. I feel
like a code artist.&lt;/p&gt;
&lt;p&gt;And what I like even more is that little feeling that you are going in an
unknown land. Some area in this tech world where nobody ever came before
you, or only a few pioneers.&lt;/p&gt;
&lt;p&gt;That&#39;s the sensation I got starting to using
&lt;a href=&#34;http://www.cython.org&#34;&gt;Cython&lt;/a&gt;, &lt;a href=&#34;http://www.python.org&#34;&gt;Python 3&lt;/a&gt; and
various other tools. I just spent half of my time trying to fix problems,
rather than working on &lt;em&gt;my&lt;/em&gt; code. Problems in autoconf macro not knowing
Python 2.6 or Python 3.1. Problems and limitations in Cython. And problem in
Python.&lt;/p&gt;
&lt;p&gt;That last one was a hard one. I&#39;m still a beginner in the Python world: I
barely know anything. And I was trying to use something nobody never did:
building an embedded Python with a set of built-in modules.&lt;/p&gt;
&lt;p&gt;I spent hours trying to find why one type of module importing was badly
failing. I finally found the answer thanks to a guy. who has the same
problem A guy ? No. A pioneer. What do I say? A hero. He&#39;s been my
week-hero! Thank you Miguel Lobo because you found the bug I chased for
hours and because you even reported it as &lt;a href=&#34;http://bugs.python.org/issue1644818&#34;&gt;issue
1644818&lt;/a&gt;, including a patch! How not
damn wonderful is that?&lt;/p&gt;
&lt;p&gt;I will not bore you with the technical details of that bug, since nobody
cares. Nobody cares, even the Python guys, since that bug has been opened
for 3 years, and nobody even reviewed in that time. I found an old thread
about that bug where some guys were wanking about how they should do the
review, because Miguel pushed for several weeks to have a review, back in
2007.&lt;/p&gt;
&lt;p&gt;But that bug was in my way. I had to do something. So I prepared my mail
reader, mounted my web browser and here I was for a uniq quest: getting a
Python bug fixed.&lt;/p&gt;
&lt;p&gt;At that point, if you did not stop reading earlier, you might get very
excited. Don&#39;t be, spoiler, it&#39;s still not fixed. You&#39;ll have to wait the
end of the season and see all the episodes I&#39;ll have to write to get the end
of the story!&lt;/p&gt;
&lt;p&gt;Let&#39;s continue.&lt;/p&gt;
&lt;p&gt;I had to create an account on the Python bug tracking system. That was a
trivial task for a man like me (you bet). Then, I launched a verbal attack,
something you rarely see in a bug tracking system. Something I knew would
awake any developer caring about their software.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Julien Danjou:
Is there any chance to see this &lt;em&gt;bug&lt;/em&gt; fixed someday?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had the deep feeling that my quest was starting here. How many days would
I have to wait until I get an answer? Time was passing. Minutes were ticking
while I was waiting, sat in a comfortable sofa in a softly lighted room. It
seemed like all my life was shorter than the delay I had to wait to get an
answer.&lt;/p&gt;
&lt;p&gt;After waiting for hours, suddenly, and only 15 minutes later, I got an
answer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Martin v. Löwis:
Please ask on python-dev. I may be willing to revive my five-for-one offer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Martin? Don&#39;t know that guy. Who is he? Who is he like? Will he fix that
bug? What is this offer? So many question without an answer. But he asked to
ask on python-dev, and I said: challenged accepted! I will write a mail to
python-dev to get that bug fixed.&lt;/p&gt;
&lt;p&gt;Which I did. I sent a short (but well written you know, I made efforts)
&#34;WTF?&#34; to pyhon-dev.&lt;/p&gt;
&lt;p&gt;And then the guy asked me to review 5 bugs so he will review and fix this
one. And this is how I said that he was pissing me off for blackmailing me
to fix a bug that was its &#34;duty&#34;.&lt;/p&gt;
&lt;p&gt;Therefore, this is the end of the story so far. Will that bug be fixed some
day? There&#39;s a hope, because another guy jumped in and took the bug
assignment.&lt;/p&gt;
&lt;p&gt;To be continued.&lt;/p&gt;
&lt;p&gt;My conclusion about all that story: that is a little rude to start something
new, with new tools, and get quickly into teething troubles. It&#39;s even more
harsh to enter a community because you just found bugs, and be not very well
received when you ask to apply a 10 lines long fix somebody wrote 3 years
ago to fix it.&lt;/p&gt;
&lt;p&gt;I&#39;ll probably still use Python :-), but I get a darker image of its
community now.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Courier to Dovecot migration</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/courier-to-dovecot-migration"/>
    <updated>2009-10-02T00:00:00Z</updated>
    <published>2009-10-02T00:00:00Z</published>
    <id>/blog/2009/courier-to-dovecot-migration</id>
        <category   scheme="/blog/tags"
                term="dovecot"
                label="Dovecot" />
        <category   scheme="/blog/tags"
                term="mail"
                label="Mail" />
        <category   scheme="/blog/tags"
                term="imap"
                label="Imap" />
    
    <content type="html">
            &lt;p&gt;This week, I&#39;ve managed to migrate from
&lt;a href=&#34;http://www.courier-mta.org/imap/&#34;&gt;courier-imap&lt;/a&gt; to
&lt;a href=&#34;http://www.dovecot.org&#34;&gt;dovecot&lt;/a&gt; at work. I always had a good experience
with dovecot, and I still have one.&lt;/p&gt;
&lt;p&gt;Dovecot performances are very good in comparison with courier. With that
switch, we dropped the CPU usage of the server from 25 % to 10 %, and it&#39;s
damn faster now. I have no idea why, but I think that it&#39;s better written
looking at the code, and also that its usage of index files helps a lot.&lt;/p&gt;
&lt;p&gt;We got no problem getting things work with public folders either, so the
switch was almost painless.&lt;/p&gt;
&lt;p&gt;The only problem we had is that Dovecot is too smart for some MUA.
Consequently, we hit an &lt;a href=&#34;http://dev.mutt.org/trac/ticket/969&#34;&gt;8 years old Mutt bug #969&lt;/a&gt;,
which I also reported to the
Debian BTS as &lt;a href=&#34;http://bugs.debian.org/549204&#34;&gt;#549204&lt;/a&gt; with a
not-well-tested-but-seems-to-work patch.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&#34;http://www.claws-mail.org/&#34;&gt;Claws mail&lt;/a&gt;, we also found a &lt;a href=&#34;http://dovecot.org/pipermail/dovecot/2009-October/043236.html&#34;&gt;bug in
dovecot
1.2.5&lt;/a&gt;, which
should be fixed soon. Dovecot upstream is very responsive and that&#39;s always
something nice to know when you use a free software.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Various news: what happend during summer</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/various-news"/>
    <updated>2009-09-22T00:00:00Z</updated>
    <published>2009-09-22T00:00:00Z</published>
    <id>/blog/2009/various-news</id>
        <category   scheme="/blog/tags"
                term="lua"
                label="Lua" />
        <category   scheme="/blog/tags"
                term="awesome"
                label="Awesome" />
        <category   scheme="/blog/tags"
                term="gsoc"
                label="Gsoc" />
    
    <content type="html">
            &lt;p&gt;It&#39;s been a while since I blogged about something. So here&#39;s a bunch of
things I&#39;ve done the last month.&lt;/p&gt;
&lt;h1&gt;Holidays&lt;/h1&gt;
&lt;p&gt;Well, I&#39;ve been in holidays one week. :-P&lt;/p&gt;
&lt;h1&gt;awesome&lt;/h1&gt;
&lt;p&gt;There have been a huge number of changes between 3.3 (released in June) and
3.4 (almost relesed). I wrote a small but very useful object layer on top of
Lua, which adds a class/object system a bit like
&lt;a href=&#34;http://www.gtk.org&#34;&gt;gobject&lt;/a&gt;. I&#39;ve also replaced all the hooks by
per-class/object signals. Finally, the awesome Lua basement are cleaner than
they were before, and the extendability is improved. How nice.&lt;/p&gt;
&lt;p&gt;We&#39;re trying to release 3.4 (rc2 should be out soon), but the development
pace is a bit slower than a year before. We&#39;re basically almost 2 months
late on what was our previous release rate. Not a big deal however.&lt;/p&gt;
&lt;p&gt;I&#39;ve started working on 3.5 slowly. It gonna get amazing new features
too. :-)&lt;/p&gt;
&lt;h1&gt;Google Summer Of Code 2009&lt;/h1&gt;
&lt;p&gt;I&#39;ve mentored Mariusz Ceier on &lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt; GSoC. He
worked on adding Xinput2 and XKB extensions. And he managed to do this. His
work should be imported ASAP, the discussion has started on XCB maling list
last week.&lt;/p&gt;
&lt;p&gt;In exchange, Google offered me (and to every mentor) an awful blue t-shirt!
Thanks Google! :-P&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">TODO list management</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/todo-list-management"/>
    <updated>2009-07-10T00:00:00Z</updated>
    <published>2009-07-10T00:00:00Z</published>
    <id>/blog/2009/todo-list-management</id>
        <category   scheme="/blog/tags"
                term="todo"
                label="Todo" />
    
    <content type="html">
            &lt;p&gt;My fellow Debian developer &lt;a href=&#34;http://blog.steve.org.uk&#34;&gt;Steve Kemp&lt;/a&gt; told us
about his &lt;a href=&#34;http://blog.steve.org.uk/why_do_you_keep_torturing_yourself_.html&#34;&gt;TODO list
management&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While reading his post, I was constantly thinking &#34;been there, been there
buddy&#34;. Yeah, I&#39;ve been.&lt;/p&gt;
&lt;p&gt;I had the same problem since months, impossibility to track the things I had
to do, being computer related stuff or real life ones. The bad thing is that
until you write them down, you keep them in mind, and that&#39;s exhausting. You
know you have, let&#39;s say 5, things to do, but unless you write this 5 items
down in a TODO list, you will keep thinking about it once in a while. And
that&#39;s a real lost time.&lt;/p&gt;
&lt;p&gt;And that&#39;s totally inefficient: imagine you though &#34;it&#39;d be nice if I could
buy a USB stick next time I buy some hardware&#34;. Well, unless you actually
write this somewhere and have the habit to check the &#34;To Buy&#34; category of
your TODO list, you&#39;re going to buy a replacement hard drive in a hurry some
day, and forget about your USB stick.&lt;/p&gt;
&lt;p&gt;I think the good practice, which I really recommend to everyone, is to write
down as soon as possible what you think you have to do. Don&#39;t write it on a
small paper you will lose, write it in a TODO list, a paper or electronic
one, whatever, but write it, and stop thinking about it. When you&#39;ll have
time, you&#39;ll get your TODO list from your pocket and give a look at it,
doing what you can do at that moment. Once in a while, you check that list.&lt;/p&gt;
&lt;p&gt;Personally, the tool I chose to handle my TODO list is a Palm Centro phone,
which I got for only a hundred of euros. It runs the good old PalmOS, which
basically know how to handle TODO list and plannings better than all phones
I saw so far (and yes, probably better than your iPhone).&lt;/p&gt;
&lt;p&gt;My choice was based on the fact that I&#39;ve random ideas almost everywhere:
that means while hacking, but also while walking in the street, while being
in the train or while sleeping (yeah, already happened). And the only thing
I always carry with me is my phone, in my pocket.&lt;/p&gt;
&lt;p&gt;However, Steve choice may be nice if you have Internet access on your phone,
which I haven&#39;t since it&#39;s too expensive for what it is, in my opinion. :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Upgrading to dovecot 1.2: hello Sieve!</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/upgrading-to-dovecot-1.2-hello-sieve"/>
    <updated>2009-07-09T00:00:00Z</updated>
    <published>2009-07-09T00:00:00Z</published>
    <id>/blog/2009/upgrading-to-dovecot-1.2-hello-sieve</id>
        <category   scheme="/blog/tags"
                term="sieve"
                label="Sieve" />
        <category   scheme="/blog/tags"
                term="dovecot"
                label="Dovecot" />
        <category   scheme="/blog/tags"
                term="mail"
                label="Mail" />
        <category   scheme="/blog/tags"
                term="imap"
                label="Imap" />
    
    <content type="html">
            &lt;p&gt;Last year, I told you I wanted to use
&lt;a href=&#34;http://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)&#34;&gt;Sieve&lt;/a&gt; to
filter my mail. I did not switch, because of the lacking implementation of
some Sieve features inside &lt;a href=&#34;http://www.dovecot.org&#34;&gt;Dovecot&lt;/a&gt;, my preferred
IMAP server.&lt;/p&gt;
&lt;p&gt;After that disapointement, I kept my 8 years old mail setup, being &lt;em&gt;fetchmail&lt;/em&gt;
running on my workstation and throwing the mails in &lt;em&gt;procmail&lt;/em&gt;, then using
&lt;em&gt;mutt&lt;/em&gt; locally to read the maildirs. But that&#39;s over.&lt;/p&gt;
&lt;p&gt;I got a laptop to replace my workstation. It was not possible to continue
using such a mail setup, since my laptop can be offline, and so would be my
mails.&lt;/p&gt;
&lt;p&gt;So I decided to upgrade Dovecot to 1.2. I used the &lt;em&gt;dovecot-1.2-work&lt;/em&gt;
Subversion branch of our lovely Debian maintainers, and built a Debian
package for Lenny. The upgrade from 1.1 was almost painless, since the
configuration file did not change heavily.&lt;/p&gt;
&lt;p&gt;Then I started to write my little Sieve script. Sieve is a very nice
language. Almost user friendly. So in 20 lines I rewrote all my procmail
stuff, matching things like &lt;em&gt;List-Id&lt;/em&gt; with regex to put the mails
automagically in the right folder. I reconfigured &lt;em&gt;mutt&lt;/em&gt; to use IMAP, and it
works fine. I even reimported my old Maildir via IMAP using &lt;em&gt;mutt&lt;/em&gt; too.&lt;/p&gt;
&lt;p&gt;I am now a happy IMAP user.&lt;/p&gt;
&lt;p&gt;For people wondering why I wanted to switch away from &lt;em&gt;procmail&lt;/em&gt; to &lt;em&gt;Sieve&lt;/em&gt;: the
reason is that Sieve script can be uploaded remotely via &lt;em&gt;managesieve&lt;/em&gt;. This
means you do not need FTP/SSH/whatever access to put your script. You can,
for example, use &lt;em&gt;connect-sieve&lt;/em&gt; or the Sieve plugin for Thunderbird/Icedove.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Taking the other direction</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/taking-the-other-direction"/>
    <updated>2009-04-15T00:00:00Z</updated>
    <published>2009-04-15T00:00:00Z</published>
    <id>/blog/2009/taking-the-other-direction</id>
        <category   scheme="/blog/tags"
                term="awesome"
                label="Awesome" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve started to develop &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt; more than 18
months ago, and somehow I feel it&#39;s time to stop a bit and think where we
come from and where we are going to.&lt;/p&gt;
&lt;h1&gt;The motivation&lt;/h1&gt;
&lt;p&gt;I never though I&#39;d be written a window manager one day. That seems kinda
stupid when you see how many window manager there&#39;s around.&lt;/p&gt;
&lt;p&gt;As many people, I&#39;ve tested and have been using tons of window manager:
&lt;a href=&#34;http://www.windowmaker.info&#34;&gt;Window Maker&lt;/a&gt;,
&lt;a href=&#34;http://www.fluxbox.org&#34;&gt;Fluxbox&lt;/a&gt;, etc.&lt;/p&gt;
&lt;p&gt;In August 2007, I was using &lt;a href=&#34;http://www.fvwm.org&#34;&gt;fvwm&lt;/a&gt; since 2004 and was
quite happy with it. I used the famous &lt;a href=&#34;http://www.fvwm-crystal.org&#34;&gt;fvwm
crystal&lt;/a&gt; as a configuration starter and then
rewrote lots of stuff. Digging into &#39;&#39;fvwm&#39;&#39; configuration files was boring,
and since I&#39;m lazy, I never really configured it to fit entirely my needs.&lt;/p&gt;
&lt;p&gt;The thing is that, in July 2007, my workstation died. I bought a new one
based on the &lt;em&gt;amd64&lt;/em&gt; architecture. Too bad, with this new box, &lt;em&gt;fvwm&lt;/em&gt; decided
that it will not longer runs and was segfaulting almost every time I logged
in.&lt;/p&gt;
&lt;p&gt;I was &lt;strong&gt;really&lt;/strong&gt; upset. Another failure in the window manager world. So I
decided to get the yearly ride of testing many window managers. I went on
the no more developed stuff like the *boxes, ion3, etc… but well, I did not
like them, there were not powerful enough, too bugged or upstream was
insane.&lt;/p&gt;
&lt;p&gt;Then I found &lt;a href=&#34;http://www.xmonad.org&#34;&gt;xmonad&lt;/a&gt;. The Haskell configuration file
format made my cry. I did not want to learn Haskell, it seemed too
obfuscated to me. At that time it was even not packaged for
&lt;a href=&#34;http://www.debian.org&#34;&gt;Debian&lt;/a&gt;, so I gave up. But I found&lt;/p&gt;
&lt;h1&gt;The jdwm&lt;/h1&gt;
&lt;p&gt;I just added a &#39;j&#39; in front of &lt;em&gt;dwm&lt;/em&gt; and started to hack it days and nights
to add many feature I missed, like multi-head, etc… On 5th September 2007, I
created a git repository to host my code.&lt;/p&gt;
&lt;h1&gt;That&#39;s gonna be… awesome.&lt;/h1&gt;
&lt;p&gt;Five days later, on 10th September, I finally
found a name for my new pet: &lt;strong&gt;awesome&lt;/strong&gt;, borrowed from &lt;a href=&#34;http://en.wikipedia.org/wiki/Barney_Stinson&#34;&gt;Barney
Stinson&lt;/a&gt; who heavily uses and
abuses this word.&lt;/p&gt;
&lt;h2&gt;The 1.x branch&lt;/h2&gt;
&lt;p&gt;The first releases until December were noted 1.x. It was just a better &lt;em&gt;dwm&lt;/em&gt;
with a simple flat configuration file.. The configuration file used
&lt;a href=&#34;http://www.hyperrealm.com/libconfig/&#34;&gt;libconfig&lt;/a&gt;, but it was a very poor
choice. And I was not able to put in into Debian because of
&lt;a href=&#34;http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=441200&#34;&gt;name clash&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The 2.x branch&lt;/h2&gt;
&lt;p&gt;The 2.x branch came in January 2008 with a brand new configuration file
format based on &lt;a href=&#34;http://www.nongnu.org/confuse/&#34;&gt;libconfuse&lt;/a&gt;, which was a
bit more powerful. Many concepts and features that have been added in this
branch are still used in the current 3.x branch.&lt;/p&gt;
&lt;p&gt;At this time, between December 2007 and April 2008, the community was
growing smoothly.&lt;/p&gt;
&lt;p&gt;But as I said, awesome 2 was based on a flat configuration file. That raised
a problem very soon: users expectation were growing and the development team
(me and a couple of regular contributors) was unable to cope with them.&lt;/p&gt;
&lt;p&gt;One of the event that started to change my mind was the support for
titlebars.&lt;/p&gt;
&lt;p&gt;When I&#39;ve added titlebar support, it was minimal. It was on top of a window,
with the window title. Dot. Then I&#39;ve started to add a lot of options, like
the application icon drawing, the position (left, right, bottom) etc.&lt;/p&gt;
&lt;p&gt;And then users started to ask for more, like: &#34;add titlebar on windows only
when the window is floating&#34;.&lt;/p&gt;
&lt;p&gt;That&#39;s ok, but that&#39;s complicated: that&#39;s again &lt;strong&gt;another&lt;/strong&gt; option to do some
stuff conditionally. And then, why don&#39;t add titlebar on windows when
&lt;insert random events here&gt;?&lt;/p&gt;
&lt;h2&gt;The 3.x branch&lt;/h2&gt;
&lt;h3&gt;Why&lt;/h3&gt;
&lt;p&gt;At that time, around April 2008, I&#39;d totally stopped development. I was
trying to find a solution which was simple and powerful. But after 2 weeks
of thinking, I was not able to find anything else than: use a real language
for configuration.&lt;/p&gt;
&lt;p&gt;So, I&#39;ve started prototyping awesome 3 using &lt;a href=&#34;http://www.lua.org&#34;&gt;Lua&lt;/a&gt;. The
choice was not obvious, and despite the problem &lt;em&gt;Lua&lt;/em&gt; might suffer, it&#39;s one
of the easiest language to integrate into an existing application.&lt;/p&gt;
&lt;p&gt;But, let&#39;s go a little back: in January 2008, Arnaud Fontaine contacted me
because he was interested to use &lt;em&gt;awesome&lt;/em&gt; as one of its school project. He
decided to port &lt;em&gt;awesome&lt;/em&gt; from &lt;em&gt;Xlib&lt;/em&gt; to
&lt;em&gt;&lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt;&lt;/em&gt;, a modern asynchronous X library.&lt;/p&gt;
&lt;p&gt;His work took some time, but in May 2008, Arnaud did finished to port git
master version of &lt;em&gt;awesome&lt;/em&gt; to use &lt;em&gt;XCB&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Consequently, I decided to start a new major branch, using &lt;em&gt;XCB&lt;/em&gt; instead of
&lt;em&gt;Xlib&lt;/em&gt; (no change for users in this regard) and &lt;em&gt;Lua&lt;/em&gt; instead of our previous
flat configuration file format.&lt;/p&gt;
&lt;h3&gt;Development&lt;/h3&gt;
&lt;p&gt;It took me a while to get from here to there, but in September 2008, it was
ready. We had a simple Lua API, and the XCB port was working perfectly.&lt;/p&gt;
&lt;p&gt;It took us some time to release and have something totally working, because
we had to work on &lt;em&gt;XCB&lt;/em&gt; and contribute back to the project. It was really not
ready to use by an application, but we did great work in this area and it&#39;s
now really fine.&lt;/p&gt;
&lt;h3&gt;We&#39;re still here&lt;/h3&gt;
&lt;p&gt;Releases continue to happens, 3.1 around December 2008, and 3.2 around March
2009. 3.3 should be here in June.&lt;/p&gt;
&lt;p&gt;One of the drawback we had, is that we moved many stuff from C to Lua. Why?
Because writing things in Lua is quicker and easier to maintain than C, and
makes thing more configurable for the user.&lt;/p&gt;
&lt;p&gt;For example, the layout algorithm used to organize window were written in C
until 3.2 came out. At that time, users had no choice than using a set of
predefined layout to organize their windows.&lt;/p&gt;
&lt;p&gt;Starting with 3.2, if they have minimal knowledge about geometry, they can
start writing a layout function organising windows on the screen.&lt;/p&gt;
&lt;p&gt;But this kind of API changes was a bit rough for users, since they had to
port some part of their configuration file to the new API.  The thing is
that the project was still a &lt;em&gt;teenager&lt;/em&gt; at that time, not really knowing were
it will go. But I&#39;m happy to announce that API breakage are more and more
rare (so far only one minor between 3.2 and 3.3), and anyway always for the
Good.&lt;/p&gt;
&lt;p&gt;But I admit that it built a bad reputation around &lt;em&gt;awesome 3.x&lt;/em&gt; during its
first month of existence.&lt;/p&gt;
&lt;h1&gt;Future direction&lt;/h1&gt;
&lt;p&gt;I am currently working on 3.3 development. We have still many things to do.
Time passing, we get more idea, and more users. And more users bring more
ideas. We also have many more contributors, and some guys are even taking
maintainer-ship of some code area.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;My post title is &#34;Taking the other direction&#34; because I feel this way.&lt;/p&gt;
&lt;p&gt;I&#39;ve got that feeling that some approaches in projects like GNOME are
sometimes bad. Please don&#39;t misread me, I know we are not playing in the
same yard.&lt;/p&gt;
&lt;p&gt;When adding a key shortcut for starting an application makes you dig into
&lt;em&gt;gconf&lt;/em&gt;, I wonder how this is a win for the user.&lt;/p&gt;
&lt;p&gt;Well, it&#39;s probably a win for the end-user, but I surely am not one of
them. And I don&#39;t intend to target them with my software, anyway.&lt;/p&gt;
&lt;p&gt;And now, when I hear things like GNOME 3.0 and the &#34;&lt;a href=&#34;http://live.gnome.org/GnomeShell]&#34;&gt;desktop shell&lt;/a&gt;&#34; approach, that makes me smile.
Guys, it was time, but have luck. What I see from here, is that any desktop
control interface is wrong somehow, and that there&#39;s no approach that can
fulfill all users wishes.&lt;/p&gt;
&lt;p&gt;I think that we, the awesome development team (no pun intended) took the
direction of building a frame-work window manager rather than a solution
written in marble.&lt;/p&gt;
&lt;p&gt;We (partially) solved the issue of UI ergonomic by not writing one and
allowing the user to write his own. I don&#39;t say that&#39;s easy to do for most
of users, but it&#39;s doable.&lt;/p&gt;
&lt;p&gt;And I think it&#39;s worth it: I use window managers since I use Linux, around
1998. If something like &#39;&#39;awesome&#39;&#39; came 5 years ago, I&#39;d be using it so
far, because you can write &lt;em&gt;Fluxbox&lt;/em&gt; or &lt;em&gt;WindowMaker&lt;/em&gt; using &lt;em&gt;awesome&lt;/em&gt; in a hundred
of Lua code. And you can write your own version of it. And it starts in less
than 3 seconds, supporting almost all standard desktop specification (ICCCM,
EWMH, XDG, system tray, message notification, D-Bus, etc), whereas many of
the window mangers do not.&lt;/p&gt;
&lt;p&gt;You can even write and play &lt;a href=&#34;http://awesome.naquadah.org/apidoc/modules/invaders.html&#34;&gt;space
invaders&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, I&#39;m happy about the the road we took so far, and hope we will
continue into that direction. The rants I read about our project are not
that big, compared to the kudos we received.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">OpenOffice is better as a pager than as a text processor</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/openoffice-better-as-a-pager"/>
    <updated>2009-02-11T00:00:00Z</updated>
    <published>2009-02-11T00:00:00Z</published>
    <id>/blog/2009/openoffice-better-as-a-pager</id>
    
    <content type="html">
            &lt;p&gt;Since several month, &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt; users have
reported a bug with &lt;a href=&#34;http://www.openoffice.org&#34;&gt;OpenOffice.org&lt;/a&gt;. When using
OOo and clicking on a menu, or using the mouse wheel to read a document, the
currently selected tag (desktop) will change automagically to another one.&lt;/p&gt;
&lt;p&gt;I&#39;ve digged into awesome and found that awesome received a
_NET_CURRENT_DESKTOP request. As defined by
&lt;a href=&#34;http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#id2550663&#34;&gt;EWMH&lt;/a&gt;,
this kind of request are sent by a pager to change the active desktop.&lt;/p&gt;
&lt;p&gt;That was weird. Nobody is using a pager here. So, I just kicked my gdb out,
attached it to OOo, breaking on &lt;em&gt;XSendEvent&lt;/em&gt; call. And I got it:&lt;/p&gt;
&lt;pre&gt;
Breakpoint 1, XSendEvent (dpy=0x1a00080, w=483, propagate=0, event_mask=1572864, event=0x7fff1fd70d70)
   at ../../src/SendEvent.c:46
(gdb) bt
#0  XSendEvent (dpy=0x1a00080, w=483, propagate=0, event_mask=1572864, event=0x7fff1fd70d70)
   at ../../src/SendEvent.c:46
#1  0x00007f8c0ab4193f in vcl_sal::WMAdaptor::switchToWorkArea ()
  from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#2  0x00007f8c0aafdbd8 in X11SalFrame::Show ()
  from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#3  0x00007f8c1378623c in Window::Show ()
  from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#4  0x00007f8c13785f40 in Window::Show ()
  from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#5  0x00007f8c1372cb54 in FloatingWindow::StartPopupMode ()
  from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#6  0x00007f8c1373c877 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#7  0x00007f8c1373ccf2 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#8  0x00007f8c1373ce84 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#9  0x00007f8c13795e7f in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#10 0x00007f8c13797e74 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#11 0x00007f8c13796748 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#12 0x00007f8c0aafe6f8 in X11SalFrame::HandleMouseEvent ()
  from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#13 0x00007f8c0ab040c2 in X11SalFrame::Dispatch ()
  from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#14 0x00007f8c0ab31625 in SalX11Display::Yield ()
  from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#15 0x00007f8c0ab356f3 in ?? () from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#16 0x00007f8c0ab2df1f in SalXLib::Yield () from /usr/lib/openoffice/basis3.0/program/libvclplug_genlx.so
#17 0x00007f8c135b050e in Application::Yield ()
  from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#18 0x00007f8c135b0587 in Application::Execute ()
  from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#19 0x00007f8c17517e80 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libsofficeapp.so
#20 0x00007f8c135b4b24 in ?? () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#21 0x00007f8c135b4bc5 in SVMain () from /usr/lib/openoffice/program/../basis-link/program/libvcllx.so
#22 0x00007f8c1754ca6c in soffice_main ()
  from /usr/lib/openoffice/program/../basis-link/program/libsofficeapp.so
#23 0x000000000040105b in main ()
&lt;/pre&gt;

&lt;p&gt;I started digging more into the code, and this is what I finally found in
&lt;em&gt;salframe.cxx&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;
        // #i45160# switch to desktop where a dialog with parent will appear
        if( mpParent &amp;&amp; mpParent-&gt;m_nWorkArea != m_nWorkArea )
            GetDisplay()-&gt;getWMAdaptor()-&gt;switchToWorkArea(mpParent-&gt;m_nWorkArea );
&lt;/pre&gt;

&lt;p&gt;Beautiful! It even has a comment with a IssueZilla bug number. Let&#39;s go and
see where it comes from.&lt;/p&gt;
&lt;p&gt;After 10 minutes of research to find that fucking IZ, I finally found the
link to the &lt;a href=&#34;http://www.openoffice.org/issues/show_bug.cgi?id=45160&#34;&gt;issue #45160&lt;/a&gt;. The bug is
IMHO not related to OOo but to a window manager doing poor job.&lt;/p&gt;
&lt;p&gt;I&#39;ve found that an awesome user already reported an bug… err, wait, I mean
an issue as &lt;a href=&#34;http://www.openoffice.org/issues/show_bug.cgi?id=96684&#34;&gt;issue #96684&lt;/a&gt; (remember
there&#39;s no bug in OOo, only issues) and I commented about it.&lt;/p&gt;
&lt;p&gt;It seems OOo developers have agreed to fix that bug eventually.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">startup-notification ported to XCB</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2009/startup-notification-ported-to-XCB"/>
    <updated>2009-01-29T16:17:00Z</updated>
    <published>2009-01-29T16:17:00Z</published>
    <id>/blog/2009/startup-notification-ported-to-XCB</id>
        <category   scheme="/blog/tags"
                term="freedesktop"
                label="Freedesktop" />
        <category   scheme="/blog/tags"
                term="startupnotification"
                label="Startupnotification" />
        <category   scheme="/blog/tags"
                term="xcb"
                label="Xcb" />
    
    <content type="html">
            &lt;p&gt;Since Tuesday, I&#39;ve begun to work on &lt;a href=&#34;http://xcb.freedesktop.org&#34;&gt;XCB&lt;/a&gt;
portage of the
&lt;a href=&#34;http://www.freedesktop.org/software/startup-notification/&#34;&gt;startup-notification&lt;/a&gt;
library.&lt;/p&gt;
&lt;p&gt;I&#39;ve just completed the job, and &lt;a href=&#34;http://lists.freedesktop.org/archives/xdg/2009-January/010176.html&#34;&gt;send a bunch of patches to the XDG mailing list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If the patches are merged, which I don&#39;t doubt, I&#39;ll be able to use this lib
into &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;, which would be nice step to the
Freedesktop standard compliance I like to make.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Rants about Lua</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2008/rants-about-lua"/>
    <updated>2008-12-30T11:23:00Z</updated>
    <published>2008-12-30T11:23:00Z</published>
    <id>/blog/2008/rants-about-lua</id>
        <category   scheme="/blog/tags"
                term="lua"
                label="Lua" />
    
    <content type="html">
            &lt;p&gt;I&#39;ve started using &lt;a href=&#34;http://www.lua.org&#34;&gt;Lua&lt;/a&gt; some months ago, while looking
for a more powerful way to configure &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;.
At this time, around March 2008, Lua seemed to be the best language to
integrate inside the core system of &lt;em&gt;awesome&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I still think that Lua was a good choice, but after 8 months, it shows some
important drawbacks.&lt;/p&gt;
&lt;p&gt;I&#39;ll try to keep my explanation simple and to make you understand
everything, even if you do not know Lua.&lt;/p&gt;
&lt;p&gt;I refer here to Lua version 5.1.&lt;/p&gt;
&lt;h1&gt;Design flaws&lt;/h1&gt;
&lt;h2&gt;Length operator&lt;/h2&gt;
&lt;p&gt;Lua has a length operator on its objects, known as &#39;&#39;#&#39;&#39;. It can be used to
get the size of various objects.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;lol&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This operator works for table, string, etc… It&#39;s possible to define this
operator by setting a &lt;em&gt;__len&lt;/em&gt; meta-method on a userdata value.&lt;/p&gt;
&lt;p&gt;The problem is that you cannot redefine it on string or table objects, see:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;hello&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;world&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;setmetatable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;18&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Indeed, looking at the Lua core code:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OP_LEN&lt;/span&gt;: &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&lt;em&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ttype&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LUA_TTABLE&lt;/span&gt;: &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;setnvalue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ra&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cast_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;luaH_getn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hvalue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))));&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LUA_TSTRING&lt;/span&gt;: &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;setnvalue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ra&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cast_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsvalue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;nl&#34;&gt;default:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;  &lt;span class=&#34;cm&#34;&gt;/&lt;/em&gt; try metamethod &lt;em&gt;/&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;n&#34;&gt;Protect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;br /&gt;              &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;call_binTM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;luaO_nilobject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ra&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TM_LEN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;br /&gt;                &lt;span class=&#34;n&#34;&gt;luaG_typeerror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;get length of&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;br /&gt;            &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
You clearly see that tables and strings always use the internal length
operator, never the &lt;/em&gt;__len* meta-method.&lt;/p&gt;
&lt;p&gt;That&#39;s for me a design problem, which will cause more trouble. We&#39;ll see
later.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;index and &lt;/strong&gt;newindex metamethods&lt;/h2&gt;
&lt;p&gt;Lua defines two useful meta-methods, which are &lt;em&gt;&lt;strong&gt;index&lt;em&gt; and &lt;/em&gt;&lt;/strong&gt;newindex&lt;/em&gt;. Both
can be set on a table or any other object.  &lt;em&gt;&lt;strong&gt;index&lt;em&gt; will be called upon each
read access to an undefined key on an object, and &lt;/em&gt;&lt;/strong&gt;newindex&lt;/em&gt; upon each write
access.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;-- function are not defined, this is just an example&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;setmetatable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;myindexfunction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__newindex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mynewindexfunction&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;hello&amp;quot;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;-- This will call __newindex metamethod&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;-- This will call __index metamethods&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;-- This will NOT call __index&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
The last line does not call &lt;em&gt;__index&lt;/em&gt; meta-method because &lt;em&gt;a[1]&lt;/em&gt; does
exists. This is a problem when you want to use table as object, because
sometimes you want to monitor access to the table elements.&lt;/p&gt;
&lt;p&gt;This can be easily worked around using a proxy system: you don&#39;t store
things in the table you manipulate, but in another table.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;realtable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;-- function are not defined, this is just an example:&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;setmetatable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;myindexfunction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__newindex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mynewindexfunction&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Where meta-methods are something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;myindexfunction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;realtable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;mynewindexfunction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class=&#34;n&#34;&gt;realtable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
This way, our &lt;em&gt;a&lt;/em&gt; table will always be empty, and &lt;em&gt;realtable&lt;/em&gt; will have the
data. At every read or write access to &lt;em&gt;a&lt;/em&gt;, the meta-methods will be
called. This is very convenient and widely used hack.&lt;/p&gt;
&lt;p&gt;But this has serious drawbacks: as we saw before, the length operator (&lt;em&gt;#&lt;/em&gt;)
cannot be redefined on a table. That means &lt;em&gt;#a&lt;/em&gt; will always be 0, and you
cannot get the table length anymore, except by defining another method or a
special attribute.&lt;/p&gt;
&lt;p&gt;Also, Lua has several functions in the &lt;em&gt;table&lt;/em&gt; library that are used to
manipulate table in a easy way. The problem is that standard functions like
&lt;em&gt;table.insert&lt;/em&gt; or &lt;em&gt;table.remove&lt;/em&gt; do raw accesses to the table. Meaning that if
you do &lt;em&gt;table.insert(a, 1, 1)&lt;/em&gt; it will insert the value 1 at the key 1 into &lt;em&gt;a&lt;/em&gt;,
&lt;strong&gt;without&lt;/strong&gt; calling the &lt;em&gt;__newindex&lt;/em&gt; meta-methods, breaking all your beautiful
object-oriented model.&lt;/p&gt;
&lt;p&gt;Another solution is to use a userdata object, like done in the Lua &lt;em&gt;newproxy&lt;/em&gt;
function (which is under-documented).&lt;/p&gt;
&lt;p&gt;The problem is that it breaks all the other functions that are waiting for a
table as argument, because they see a userdata, not a table. So this time
&lt;em&gt;table.insert&lt;/em&gt; is now more usable, which somehow fixes the problem, but not in
the right way IMHO.  However, this allows to use the &lt;em&gt;__len&lt;/em&gt; meta-method.&lt;/p&gt;
&lt;h1&gt;Development model&lt;/h1&gt;
&lt;p&gt;The development model of Lua is, from my point of view, non-existent.&lt;/p&gt;
&lt;p&gt;There is no public version control system repository available, so there&#39;s
no chance to really contribute to Lua. It seems only a defined set of people
work on it and therefore, the development system is very closed to my eyes,
in comparison of usual projects.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I still think Lua is a good choice, because it is very easy to integrate
into any C program, and to expand to fulfill your needs. However, some bad
design choices were made, and the poor and closed development model chosen
does not allow to have a good overview of the future of Lua.&lt;/p&gt;
&lt;p&gt;This has been &lt;a href=&#34;http://lua-users.org/lists/lua-l/2008-06/msg00407.html&#34;&gt;well stated by the authors
themselves&lt;/a&gt;.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Security bug found in Imlib2</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2008/security-bug-found-in-imlib2"/>
    <updated>2008-11-22T00:00:00Z</updated>
    <published>2008-11-22T00:00:00Z</published>
    <id>/blog/2008/security-bug-found-in-imlib2</id>
        <category   scheme="/blog/tags"
                term="cve"
                label="Cve" />
        <category   scheme="/blog/tags"
                term="imlib"
                label="Imlib" />
        <category   scheme="/blog/tags"
                term="security"
                label="Security" />
    
    <content type="html">
            &lt;p&gt;Yeah, I&#39;m the proud discover of
&lt;a href=&#34;http://www.securityfocus.com/bid/32371&#34;&gt;CVE-2008-5187&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s my first time, it does mean something to me. ;-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">The eggtray problem</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2008/the-eggtray-problem"/>
    <updated>2008-10-03T00:00:00Z</updated>
    <published>2008-10-03T00:00:00Z</published>
    <id>/blog/2008/the-eggtray-problem</id>
        <category   scheme="/blog/tags"
                term="x11"
                label="X11" />
        <category   scheme="/blog/tags"
                term="gtk"
                label="Gtk" />
        <category   scheme="/blog/tags"
                term="systray"
                label="Systray" />
        <category   scheme="/blog/tags"
                term="freedesktop"
                label="Freedesktop" />
    
    <content type="html">
            &lt;p&gt;I still don&#39;t know why but many GTK+ applications use something called
eggtrayicon. As far as I know, &lt;em&gt;eggtrayicon.c&lt;/em&gt; is a file written in 2002 by
Anders Carlsson which implements the &lt;a href=&#34;http://standards.freedesktop.org/systemtray-spec/latest/&#34;&gt;Freedesktop.org system
tray&lt;/a&gt; procotol for
GTK+ applications.&lt;/p&gt;
&lt;p&gt;Problem is that this C file is used in dozens of programs and maybe more,
and is a bit bugged. I&#39;ve already send patches for
&lt;a href=&#34;http://www.nongnu.org/mailnotify/&#34;&gt;mail-notification&lt;/a&gt; and
&lt;a href=&#34;http://audacious-media-player.org&#34;&gt;Audacious&lt;/a&gt;.
&lt;a href=&#34;http://www.pidgin.im/&#34;&gt;pidgin&lt;/a&gt; is the first fixed implementation I found
and works quite well. Many other applications are probably affected.&lt;/p&gt;
&lt;p&gt;That seems to me like a real problem. Multiple copy of bad code instead of
using &lt;a href=&#34;http://library.gnome.org/devel/gtk/2.14/GtkStatusIcon.html&#34;&gt;native GTK+ system tray
implementation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So please stop using this bad implementation…&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Unexpected VARMon new release</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2008/unexpected-varmon-new-release"/>
    <updated>2008-08-18T00:00:00Z</updated>
    <published>2008-08-18T00:00:00Z</published>
    <id>/blog/2008/unexpected-varmon-new-release</id>
        <category   scheme="/blog/tags"
                term="linux"
                label="Linux" />
    
    <content type="html">
            &lt;p&gt;This has been 4 years since I released a new upstream release of
&lt;a href=&#34;http://julien.danjou.info/software/varmon&#34;&gt;VARMon&lt;/a&gt;, the DAC960
administration tool.&lt;/p&gt;
&lt;p&gt;There was a bug first discovered in
&lt;a href=&#34;http://bugs.debian.org/401236&#34;&gt;#401236&lt;/a&gt;. It has been fixed in Debian with
an ugly fix, which did not work finally for a long time. Recently
&lt;a href=&#34;http://bugs.debian.org/491505&#34;&gt;#491505&lt;/a&gt; got opened too, which was the same
as the previous one. But this time I got access to hardware, thanks to
Christoph! And I finally fixed the bug. I&#39;ve even be able to test the fixes
I wrote years ago for all of the compilation warnings.&lt;/p&gt;
&lt;p&gt;That&#39;s a shame that the problem was caused by dead code from the previous
upstream, and that I did not realize that sooner. Kids, do not let dead
debug code in your program at home.&lt;/p&gt;
&lt;p&gt;So I&#39;ve finally been able to release a new 1.2.1 version which maybe the
last release for the next decade! ;-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">ATL1E support in 2.6.26-1</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2008/atl1e-support-in-2.6.26-1"/>
    <updated>2008-07-31T11:59:00Z</updated>
    <published>2008-07-31T11:59:00Z</published>
    <id>/blog/2008/atl1e-support-in-2.6.26-1</id>
        <category   scheme="/blog/tags"
                term="linux"
                label="Linux" />
        <category   scheme="/blog/tags"
                term="debian"
                label="Debian" />
    
    <content type="html">
            &lt;p&gt;Ben Armstrong opened an &lt;a href=&#34;http://bugs.debian.org/492029&#34;&gt;ITP for the ATL1E NIC
driver&lt;/a&gt;, which is found on some Asus EeePC
laptops. So, as suggested by Maximilian Attems, &lt;a href=&#34;http://lists.debian.org/debian-kernel/2008/07/msg00638.html&#34;&gt;I provided a clean patch
for this
driver&lt;/a&gt;, made
from a cherry-pick from the linux-netdev 2.6.27 tree. It has been committed
into the 2.6.26-1 Debian kernel, which will be furnished with Lenny.&lt;/p&gt;
&lt;p&gt;What&#39;s fun, is that in the mean time, I got a new computer at work. Wait,
it&#39;s not fun yet. Because what I did not know is that it&#39;s made of an
&lt;a href=&#34;http://asus.com/products.aspx?l1=3&amp;amp;l2=11&amp;amp;l3=709&amp;amp;l4=0&amp;amp;model=2164&amp;amp;modelmenu=1&#34;&gt;Asus P5Q motherboard&lt;/a&gt;
which runs a NIC needing the ATL1E driver (and now you see why it&#39;s fun).&lt;/p&gt;
&lt;p&gt;So I&#39;ve just upgraded to 2.6.26-1-amd64 and I&#39;m glad that my own work is
useful to me (and will be probably be to others as well). :-)&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">EWMH and XRandR</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2007/ewmh-and-xrandr"/>
    <updated>2007-12-27T19:48:00Z</updated>
    <published>2007-12-27T19:48:00Z</published>
    <id>/blog/2007/ewmh-and-xrandr</id>
        <category   scheme="/blog/tags"
                term="x11"
                label="X11" />
        <category   scheme="/blog/tags"
                term="ewmh"
                label="Ewmh" />
    
    <content type="html">
            &lt;p&gt;Today I decided to add some &lt;a href=&#34;http://en.wikipedia.org/wiki/EWMH&#34;&gt;EWMH&lt;/a&gt;
support to &lt;a href=&#34;http://awesome.naquadah.org&#34;&gt;awesome&lt;/a&gt;. It now supports a bunch
of this extensions quite nicely.&lt;/p&gt;
&lt;p&gt;However, while reading the
&lt;a href=&#34;http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html&#34;&gt;spec&lt;/a&gt; and
writing the code, it appears that this forces a window manager to behave in
only one way: have a poor desktop support, and no multi-head/XRandR/Xinerama
support at all.&lt;/p&gt;
&lt;p&gt;The main caveats are that in Xinerama/XRandR mode, you&#39;ll have only one root
window. And the root window is where you must store the NET_WM X properties…
So you cannot handle screens in a independant way like &lt;em&gt;awesome&lt;/em&gt; does. That&#39;s
really a shame.&lt;/p&gt;
&lt;p&gt;There&#39;s also a big problem for window managers like &lt;em&gt;awesome&lt;/em&gt; which are happy
to draw several desktops at the same time. There&#39;s no support for stuff like
that.&lt;/p&gt;
&lt;p&gt;So far, I think EWMH is nice but is really too narrow-minded for software
and people who want to think window management in a different way.&lt;/p&gt;
          </content>
  </entry>
    <entry>
    <title type="html">Kicking out Web spammers with DNSBL</title>
    <author><name>Julien Danjou</name></author>
    <link href="http://julien.danjou.info/blog/2007/kicking-out-web-spammers-with-dnsbl"/>
    <updated>2007-01-15T11:33:00Z</updated>
    <published>2007-01-15T11:33:00Z</published>
    <id>/blog/2007/kicking-out-web-spammers-with-dnsbl</id>
        <category   scheme="/blog/tags"
                term="apache"
                label="Apache" />
        <category   scheme="/blog/tags"
                term="dnsbl"
                label="Dnsbl" />
        <category   scheme="/blog/tags"
                term="mod_defensible"
                label="Mod_Defensible" />
        <category   scheme="/blog/tags"
                term="security"
                label="Security" />
    
    <content type="html">
            &lt;p&gt;Every project has its story. Every war has its winner, and its
casualties. They were 20 millions men, fighting for their freedom.&lt;/p&gt;
&lt;p&gt;And you&#39;ll never know their story.&lt;/p&gt;
&lt;p&gt;Because during last week, I was looking why my Web server was so heavily
loaded. And I discovered that my blog was attacked by spammers trying to
post comments. They were stopped by a great plug-in named &lt;em&gt;spamplemousse&lt;/em&gt;,
which use spam keywords and DNSBL to drop spam comments. However, this
plug-in is written in PHP, like the rest of my blog, so it loads Apache and
MySQL in a way that is no more acceptable: the page have still to be
rendered for this !@#$ spammers.&lt;/p&gt;
&lt;p&gt;Consequently, I decided to write a Apache 2.x module which will just drop a
&lt;em&gt;403 Forbidden&lt;/em&gt; error page in the spammers&#39; head using DNSBL servers. Here it
is, and it is called &lt;a href=&#34;/software/mod_defensible&#34;&gt;mod_defensible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m using it since 3 days now, and I got some pretty interesting result and
less load on my Web server, so &lt;em&gt;c&#39;est tout bon&lt;/em&gt;.&lt;/p&gt;
          </content>
  </entry>
  </feed>
