Ch-M.Dhttp://blog.chmd.fr/2020-01-06T14:30:00+01:00Scripting sudo with pass2020-01-06T14:30:00+01:002020-01-06T14:30:00+01:00Toftag:blog.chmd.fr,2020-01-06:/scripting-sudo-with-pass.html<p>Like a lot of folks, I use <a href="https://www.passwordstore.org/">zx2c4's pass</a>. Like even more
people, I use sudo for administrative tasks on my machines.</p>
<h2>Seamless integration</h2>
<p>A lot of tools (<a href="http://www.offlineimap.org/">offlineimap</a>, <a href="https://github.com/docker/docker-credential-helpers">docker</a>, <a href="https://www.sudo.ws/man/1.8.15/sudoers.man.html">ansible-vault</a>...)
offer a way to provide the password through an external command. This is
where <code>pass</code> excels. By allowing you …</p><p>Like a lot of folks, I use <a href="https://www.passwordstore.org/">zx2c4's pass</a>. Like even more
people, I use sudo for administrative tasks on my machines.</p>
<h2>Seamless integration</h2>
<p>A lot of tools (<a href="http://www.offlineimap.org/">offlineimap</a>, <a href="https://github.com/docker/docker-credential-helpers">docker</a>, <a href="https://www.sudo.ws/man/1.8.15/sudoers.man.html">ansible-vault</a>...)
offer a way to provide the password through an external command. This is
where <code>pass</code> excels. By allowing you to extract any password with a simple
command line, it lets you have all of your passwords in one place, with no
overhead in your workflow.</p>
<h2>What about sudo?</h2>
<p>If you want to run a sudo command without typing the password
interactively, you would normally use the <a href="https://www.sudo.ws/man/1.8.15/sudoers.man.html">NOPASSWD</a> option in
<code>/etc/sudoers</code>. I do not find it desirable: should you leave a console
unattended, this exposes you to somebody running administrative commands
too easily.</p>
<p>So can you instead tell sudo to use pass for the password input? Sort of.
The <code>-A</code> <a href="https://www.sudo.ws/man/1.8.3/sudo.man.html">command line option</a> is designed to provide the password
through an helper program. To quote the manpage:</p>
<blockquote>
<p>If the -A (askpass) option is specified, a (possibly graphical) helper
program is executed to read the user's password and output the password
to the standard output. If the <code>SUDO_ASKPASS</code> environment variable is set,
it specifies the path to the helper program.</p>
</blockquote>
<p>Let's take advantage of this!</p>
<h2>Implementation</h2>
<p>I store in pass my different "<code>user@host</code>" passwords under the path
<code>host/<user>@<host></code>. If you adopt the same convention, this is what you can
do:</p>
<p>Save the following file as executable under <code>~/.local/bin/sudo-askpass</code></p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
pass show hosts/<span class="k">$(</span>whoami<span class="k">)</span>@<span class="k">$(</span>hostname<span class="k">)</span> <span class="p">|</span> head -n1
</pre></div>
<p>Insert your password in pass accordingly</p>
<div class="highlight"><pre><span></span>pass edit hosts/<span class="k">$(</span>whoami<span class="k">)</span>@<span class="k">$(</span>hostname<span class="k">)</span>
</pre></div>
<p>And now if you run</p>
<div class="highlight"><pre><span></span><span class="nb">export</span> <span class="nv">SUDO_ASKPASS</span><span class="o">=</span><span class="nv">$HOME</span>/.local/bin/sudo-askpass
sudo -A whoami
</pre></div>
<p>The answer should be <code>root</code>. Neat, but not seamless, since you need the -A
switch. You <em>could</em> solve the problem by adding these 2 lines in your shell
startup file</p>
<div class="highlight"><pre><span></span><span class="nb">export</span> <span class="nv">SUDO_ASKPASS</span><span class="o">=</span><span class="nv">$HOME</span>/.local/bin/sudo-askpass
<span class="nb">alias</span> <span class="nv">sudo</span><span class="o">=</span><span class="s1">'sudo -A'</span>
</pre></div>
<p>However, programs which invoke <code>sudo</code> (such as <a href="https://github.com/Jguer/yay">yay</a>) will not know about
this alias, and you will still be required to type your password
interactively. What I do instead is to create my own sudo executable with
higher precedence in the path whicht insert the proper options before
invoking the real binary:</p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
<span class="nv">SCRIPTDIR</span><span class="o">=</span><span class="k">$(</span>dirname <span class="k">$(</span>which <span class="nv">$0</span><span class="k">))</span>
<span class="nv">PATH_WITHOUT_SCRIPTDIR</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> <span class="nv">$PATH</span> <span class="p">|</span> tr <span class="s2">":"</span> <span class="s2">"\n"</span> <span class="p">|</span> grep -v <span class="s2">"</span><span class="nv">$SCRIPTDIR</span><span class="s2">"</span> <span class="p">|</span> tr <span class="s2">"\n"</span> <span class="s2">":"</span><span class="k">)</span>
<span class="nv">REAL_SUDO</span><span class="o">=</span><span class="k">$(</span>env <span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH_WITHOUT_SCRIPTDIR</span> which sudo<span class="k">)</span>
<span class="nb">exec</span> env <span class="nv">SUDO_ASKPASS</span><span class="o">=</span><span class="nv">$HOME</span>/.local/bin/sudo-askpass <span class="nv">$REAL_SUDO</span> --askpass <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</pre></div>
<p>If your distribution follows the <a href="http://man7.org/linux/man-pages/man7/file-hierarchy.7.html">systemd file hierarchy</a>, you can save
this file under <code>~/.local/bin/sudo</code> and it will happily take precedence
over the real sudo.</p>
<h2>Keychain</h2>
<p>I employ a similar trick for unlocking my ssh keys with keychain. I store
in pass the password of the private ssh key of <code><user>@<host></code> as
<code>ssh/<user>@<host></code>. The following file is saved as executable under
<code>~/.local/bin/ssh-askpass</code></p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
pass show ssh/<span class="k">$(</span>whoami<span class="k">)</span>@<span class="k">$(</span>hostname<span class="k">)</span> <span class="p">|</span> head -n1
</pre></div>
<p>And this goes in my shell startup file</p>
<div class="highlight"><pre><span></span><span class="o">{</span><span class="nb">type</span> keychain > /dev/null<span class="o">}</span> <span class="o">&&</span> <span class="o">{</span><span class="nb">type</span> ssh-askpass > /dev/null<span class="o">}</span> <span class="o">&&</span> <span class="se">\</span>
<span class="nb">source</span> <<span class="o">(</span><span class="nv">SSH_ASKPASS</span><span class="o">=</span>ssh-askpass keychain --quiet --eval id_rsa </dev/null<span class="o">)</span>
</pre></div>
<h2>More to come</h2>
<p>If you have a look at my <a href="https://github.com/chmduquesne/dotfiles">dotfiles</a>, you will realize that there is
more to this setup. The main additional thing to know is that I use a
<a href="https://www.yubico.com/">smartcard</a> to handle the gpg decryption, so that no machine contains
the gpg key that I use with <code>pass</code>. This will likely be the purpose of a
different article. Until then and as always, I am gladly taking any
comment.</p>
<p>Happy sudo-ing!</p>Looping simultaneously over multiple lists in legacy shells2018-05-30T23:11:00+02:002018-05-30T23:11:00+02:00Toftag:blog.chmd.fr,2018-05-30:/looping-simultaneously-over-multiple-lists-in-legacy-shells.html<p>I was recently confronted to the problem of looping over multiple lists
simultaneously in a legacy shell, and coming up with an elegant solution
was an interesting challenge. Legacy shells do not support arrays, which
means there is no structure you can directly address with an index i in
order …</p><p>I was recently confronted to the problem of looping over multiple lists
simultaneously in a legacy shell, and coming up with an elegant solution
was an interesting challenge. Legacy shells do not support arrays, which
means there is no structure you can directly address with an index i in
order to get the iᵗʰ element. How can one then process multiple lists
simultaneously in order to get the first element of each list, then the
second element of each list, then the third... and so on?</p>
<h2>A python analogy</h2>
<p>In python, there is a neat buitin called <code>zip</code>. Essentially, <code>zip</code> takes an
arbitrary set of lists as an argument, and returns an iterator of tuples,
such that the first tuple is composed of the first element of each list,
the second tuple has the second element of each list, and so on. It always
goes better with an example:</p>
<div class="highlight"><pre><span></span><span class="err">>>> for t in zip(['a', 'b', 'c', 'd'], [1, 2, 3, 4], ['!', '@', '#', '%']):</span>
<span class="err">... print(t)</span>
<span class="err">...</span>
<span class="err">('a', 1, '!')</span>
<span class="err">('b', 2, '@')</span>
<span class="err">('c', 3, '#')</span>
<span class="err">('d', 4, '%')</span>
</pre></div>
<p>The question is, how can we produce a similar function in a legacy shell?</p>
<h2>Let's specify</h2>
<p>Our goal is to produce a shell function that we will also conveniently
name <code>zip</code>. Of course, this function must work in legacy shells such as
ash or dash. It will expect an unspecified number of lists as arguments,
and return a flattened list of tuples, where the iᵗʰ tuple is composed of
all of the iᵗʰ elements of each list. Like in python, if the lists
provided as arguments are not of equal lengths, the result will be cut at
the shortest length. Here are examples of expected behaviour:</p>
<div class="highlight"><pre><span></span><span class="o">#</span> <span class="mi">3</span> <span class="n">lists</span> <span class="k">of</span> <span class="n">same</span> <span class="k">length</span>
<span class="err">$</span> <span class="n">zip</span> <span class="ss">"a b c d"</span> <span class="ss">"1 2 3 4"</span> <span class="ss">"! @ # %"</span>
<span class="n">a</span> <span class="mi">1</span> <span class="o">!</span>
<span class="n">b</span> <span class="mi">2</span> <span class="o">@</span>
<span class="k">c</span> <span class="mi">3</span> <span class="o">#</span>
<span class="n">d</span> <span class="mi">4</span> <span class="o">%</span>
<span class="o">#</span> <span class="mi">1</span> <span class="n">list</span>
<span class="err">$</span> <span class="n">zip</span> <span class="ss">"a b c d"</span>
<span class="n">a</span>
<span class="n">b</span>
<span class="k">c</span>
<span class="n">d</span>
<span class="o">#</span> <span class="mi">2</span> <span class="n">lists</span> <span class="k">of</span> <span class="n">different</span> <span class="k">length</span>
<span class="err">$</span> <span class="n">zip</span> <span class="ss">"a b"</span> <span class="ss">"1 2 3"</span>
<span class="n">a</span> <span class="mi">1</span>
<span class="n">b</span> <span class="mi">2</span>
<span class="o">#</span> <span class="mi">0</span> <span class="n">list</span>
<span class="err">$</span> <span class="n">zip</span>
</pre></div>
<p>How to use it would then just be a matter of using the set builtin:</p>
<div class="highlight"><pre><span></span>$ <span class="nv">list1</span><span class="o">=</span><span class="s2">"1 2 3 4"</span>
$ <span class="nv">list2</span><span class="o">=</span><span class="s2">"a b c d"</span>
$ <span class="nb">set</span> <span class="k">$(</span>zip <span class="s2">"</span><span class="nv">$list1</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$list2</span><span class="s2">"</span><span class="k">)</span>
$ <span class="k">for</span> i in <span class="k">$(</span>seq <span class="m">1</span> <span class="m">4</span><span class="k">)</span><span class="p">;</span> <span class="k">do</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="s2">"processing </span><span class="nv">$1</span><span class="s2"> and </span><span class="nv">$2</span><span class="s2">"</span><span class="p">;</span> <span class="se">\</span>
<span class="nb">shift</span> <span class="m">2</span><span class="p">;</span> <span class="se">\</span>
<span class="k">done</span>
processing <span class="m">1</span> and a
processing <span class="m">2</span> and b
processing <span class="m">3</span> and c
processing <span class="m">4</span> and d
</pre></div>
<h2>The implementation</h2>
<p>It is often not obvious to the beginner how to create variable names out
of other variables. For example, the name <code>list$i</code> is an illegal variable
name, so you cannot do:</p>
<div class="highlight"><pre><span></span><span class="err">i=1</span>
<span class="err">list$i="a b c"</span>
</pre></div>
<p>What is the way to get around that? The answer is <code>eval</code>, of course!</p>
<div class="highlight"><pre><span></span><span class="err">i=1</span>
<span class="err">eval "list$i='a b c'"</span>
</pre></div>
<p>So our zip function begins like this</p>
<div class="highlight"><pre><span></span><span class="err">zip(){</span>
<span class="err"> nlists=$#</span>
<span class="err"> for i in $(seq 1 $nlists); do</span>
<span class="err"> eval "list$i='$1'"</span>
<span class="err"> shift</span>
<span class="err"> done</span>
<span class="err"> # the input lists are now in the variable named list1, list2....</span>
<span class="err"> [...]</span>
<span class="err">}</span>
</pre></div>
<p>We would like to loop over all lists, extract the first element, append it
to the tuple, and update the list to reflect the tail. The least error
prone way I have found to extract the first element is to use a printf
construct</p>
<div class="highlight"><pre><span></span>$ <span class="nb">printf</span> <span class="s2">"%s\n"</span> a b c d
a
b
c
d
</pre></div>
<p>This prints all element of the list line by line. One can easily combine
it with <code>head -n1</code> and <code>tail -n+2</code> to get the head or the tail of the
list.</p>
<div class="highlight"><pre><span></span><span class="err">head=$(printf '%s\n' $list | head -n1)</span>
<span class="err">tail=$(printf '%s\n' $list | tail -n+2)</span>
</pre></div>
<p>It works more reliably, for example, than using the buitin <code>set</code> to put the
elements of the list in the argument list <code>$1</code>, <code>$2</code></p>
<div class="highlight"><pre><span></span><span class="err">set $list</span>
<span class="err">head=$1</span>
<span class="err">shift</span>
<span class="err">tail="$*"</span>
</pre></div>
<p>Why? The reason is that if the first argument is the string litteral <code>-</code>, set
will not behave the way we want! The second part of the function therefore
looks like this, with a bunch of <code>eval</code>s</p>
<div class="highlight"><pre><span></span><span class="err">while true; do</span>
<span class="err"> tuple=""</span>
<span class="err"> for i in $(seq 1 $nlists); do</span>
<span class="err"> eval "[ -z \"\$list$i\" ] && return 0"</span>
<span class="err"> eval "head=\$(printf '%s\\n' \$list$i | head -n1)"</span>
<span class="err"> eval "list$i=\$(printf '%s\\n' \$list$i | tail -n+2)"</span>
<span class="err"> tuple="$tuple $head"</span>
<span class="err"> done</span>
<span class="err"> echo "$tuple"</span>
<span class="err">done</span>
</pre></div>
<p>This looks about right: when one of the lists is empty, we know we will
not be able to complete the current tuple, so we return immediately
without further <code>echo</code>ing. The devil is in the details, because if
provided with zero argument, this function will loop forever. However, we
really want to start looping if and only if there are arguments. This
could be achieved by changing</p>
<div class="highlight"><pre><span></span><span class="err">while true; do</span>
</pre></div>
<p>to</p>
<div class="highlight"><pre><span></span><span class="err">while [ $nlists != 0 ]; do</span>
</pre></div>
<p>I don't find this construct very readable, as it makes it look like this
condition could change during the loops. I'd rather add the check</p>
<div class="highlight"><pre><span></span><span class="err">[ $nlist = 0 ] && return 0</span>
</pre></div>
<p>at the beginning of the function.</p>
<h2>The result</h2>
<p>Here is how the code looks at the end. I think this could be a fun
interview question!</p>
<div class="highlight"><pre><span></span><span class="err">zip(){</span>
<span class="err"> nlists=$#</span>
<span class="err"> [ $nlists = 0 ] && return 0</span>
<span class="err"> for i in $(seq 1 $nlists); do</span>
<span class="err"> eval "list$i='$1'"</span>
<span class="err"> shift</span>
<span class="err"> done</span>
<span class="err"> while true; do</span>
<span class="err"> tuple=""</span>
<span class="err"> for i in $(seq 1 $nlists); do</span>
<span class="err"> eval "[ -z \"\$list$i\" ] && return 0"</span>
<span class="err"> eval "head=\$(printf '%s\\n' \$list$i | head -n1)"</span>
<span class="err"> eval "list$i=\$(printf '%s\\n' \$list$i | tail -n+2)"</span>
<span class="err"> tuple="$tuple $head"</span>
<span class="err"> done</span>
<span class="err"> echo "$tuple"</span>
<span class="err"> done</span>
<span class="err">}</span>
</pre></div>
<p>Do you think it can be improved? Do you have your own different technique
to achieve this? Let me know in the comments!</p>SSH over SSL, episode 4: a HAproxy based configuration2014-10-19T17:40:00+02:002014-10-19T17:40:00+02:00Toftag:blog.chmd.fr,2014-10-19:/ssh-over-ssl-episode-4-a-haproxy-based-configuration.html<h2>Purpose of this article</h2>
<p>In this article, I am describing how to SSH to a remote server as
discreetly as possible, by concealing the SSH packets into SSL. The
server will still be able to run an SSL website.</p>
<h2>Rationale</h2>
<p>In most cases, when your outgoing firewall blocks ssh, you …</p><h2>Purpose of this article</h2>
<p>In this article, I am describing how to SSH to a remote server as
discreetly as possible, by concealing the SSH packets into SSL. The
server will still be able to run an SSL website.</p>
<h2>Rationale</h2>
<p>In most cases, when your outgoing firewall blocks ssh, you can work around
with <a href="http://www.rutschle.net/tech/sslh.shtml">sslh</a>, a tool that listens
on the port 443 server-side, and selectively forwards, depending on the
packet type, the incoming TCP connections to a local SSH or SSL service.
You can then happily ssh to your server on the port 443 (normally
dedicated to HTTPS), and also run a website on the same server so your
connections look you are just harmlessly visiting this website. However,
if your firewall is really sneaky, it will detect that you are sending the
wrong packet type to the SSL port, and block your connection. In this
case, there is not much choice: we must hide the SSH connection into a
real SSL tunnel.</p>
<h2>Comment for the long time readers</h2>
<p>I know, I know: I covered this topic a few times already (here are the
<a href="/ssh-over-ssl-a-quick-and-minimal-config.html">first</a>,
<a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">second</a>,
and <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">third</a>
episodes). All of these setups were relying on a feature of HTTP 1.1
called CONNECT. However, it turns out that most webserver do not implement
this CONNECT feature. As a consequence, if you wanted to do this, you were
more or less stuck with Apache. This time, we are breaking free from
Apache, with a HAproxy-based configuration. We will use HAproxy advanced
packet inspection capabilities to implement a switch of protocol, the same
way sslh works.</p>
<h2>Server configuration</h2>
<p>Some assumptions:</p>
<ul>
<li>The port 443 of your server is publicly reachable</li>
<li>It runs ssh (but no need for the port 22 to be reachable)</li>
<li>Some web server is running on the port 80 and it supports the
'X-Forwarded-Proto' header (see the documentation of your webserver to
enable that).</li>
<li>You have generated ssl certificates (you copied the public key and the
private key in the same file /etc/ssl/private/certs.pem)</li>
</ul>
<p>Now, you need to setup HAproxy. HAproxy defines backends and frontends, and it
can communicate with these backends both at the HTTP and at the TCP level. Let
us start with the backends:</p>
<p>The web server backend: we tell HAproxy that a server is running on the
port 80, and speaks HTTP. On this backend, we add a X-Forwarded-Proto
header, such that the web server knows that the clients are connecting
securely. If you expose the same backend with HAproxy on the port 80,
don't forget to filter the X-Forwarded-Proto header!</p>
<div class="highlight"><pre><span></span><span class="err">backend secure_http</span>
<span class="err"> reqadd X-Forwarded-Proto:\ https</span>
<span class="err"> rspadd Strict-Transport-Security:\ max-age=31536000</span>
<span class="err"> mode http</span>
<span class="err"> option httplog</span>
<span class="err"> option forwardfor</span>
<span class="err"> server local_http_server 127.0.0.1:80</span>
</pre></div>
<p>The ssh server:</p>
<div class="highlight"><pre><span></span><span class="err">backend ssh</span>
<span class="err"> mode tcp</span>
<span class="err"> option tcplog</span>
<span class="err"> server ssh 127.0.0.1:22</span>
<span class="err"> timeout server 2h</span>
</pre></div>
<p>And now, the magic. This happens in the frontend section. We listen in TCP mode
and inspect the connections. Depending on whether we see ssh or not, we hook it
to one of the backends.</p>
<div class="highlight"><pre><span></span><span class="n">frontend</span> <span class="n">ssl</span>
<span class="n">bind</span> <span class="n">X</span><span class="p">.</span><span class="n">X</span><span class="p">.</span><span class="n">X</span><span class="p">.</span><span class="n">X</span><span class="p">:</span><span class="mi">443</span> <span class="n">ssl</span> <span class="n">crt</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">private</span><span class="o">/</span><span class="n">certs</span><span class="p">.</span><span class="n">pem</span> <span class="k">no</span><span class="o">-</span><span class="n">sslv3</span>
<span class="k">mode</span> <span class="n">tcp</span>
<span class="k">option</span> <span class="n">tcplog</span>
<span class="n">tcp</span><span class="o">-</span><span class="n">request</span> <span class="n">inspect</span><span class="o">-</span><span class="n">delay</span> <span class="mi">5</span><span class="n">s</span>
<span class="n">tcp</span><span class="o">-</span><span class="n">request</span> <span class="n">content</span> <span class="n">accept</span> <span class="k">if</span> <span class="n">HTTP</span>
<span class="n">acl</span> <span class="n">client_attempts_ssh</span> <span class="n">payload</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="p">)</span> <span class="o">-</span><span class="n">m</span> <span class="n">bin</span> <span class="mi">5353482</span><span class="n">d322e30</span>
<span class="n">use_backend</span> <span class="n">ssh</span> <span class="k">if</span> <span class="o">!</span><span class="n">HTTP</span>
<span class="n">use_backend</span> <span class="n">ssh</span> <span class="k">if</span> <span class="n">client_attempts_ssh</span>
<span class="n">use_backend</span> <span class="n">secure_http</span> <span class="k">if</span> <span class="n">HTTP</span>
</pre></div>
<p>Once you are done, you can test if this works by connecting on the server
with openssl.</p>
<div class="highlight"><pre><span></span><span class="err">openssl s_client -connect server.com:443 -quiet</span>
</pre></div>
<p>If you see a string that looks like</p>
<div class="highlight"><pre><span></span><span class="err">SSH-2.0-OpenSSH_6.6.1p1 Debian-7</span>
</pre></div>
<p>then everything went fine!</p>
<h2>Connecting from an SSH client</h2>
<p>To connect to your server from linux, just drop this in your ~/.ssh/config:</p>
<div class="highlight"><pre><span></span><span class="err">Host server.com</span>
<span class="err"> ProxyCommand openssl s_client -connect server.com:443 -quiet</span>
</pre></div>
<p>If you are on windows and you cannot install anything client side, there
is also a solution for you. Download socat and putty (none of them
requires admin rights). Then, with socat, run:</p>
<div class="highlight"><pre><span></span><span class="err">socat TCP-LISTEN:8888 OPENSSL:server.com:443,verify=0</span>
</pre></div>
<p>And with putty, direct your client to 127.0.0.1 on the port 8888.</p>
<h2>For the technically aware readers</h2>
<p>So how does this work exactly? Basically, the <a href="https://tools.ietf.org/html/rfc4253#section-4.2">RFC 4253, section
4.2</a> states that clients
must send a string that starts with 'SSH-2.0' (this is also how sslh does
it). Moreover, 5353482d322e30 is the binary representation of the string
'SSH-2.0'. So everything boils down to this line:</p>
<div class="highlight"><pre><span></span><span class="err">acl client_attempts_ssh payload(0,7) -m bin 5353482d322e30</span>
</pre></div>
<p>When a new connection is made on the port 443, HAproxy decrypts the SSL
layer, and checks whether the stream of data sent by the client starts
with this string. We use the result of this condition to choose the
backend. This handles the case of 'active' SSH clients (like
openssh-client on linux), who send a packet as soon as they connect.
There are also 'passive' SSH clients (like putty), who wait for the server
to send a string. These clients will get that string after 5 seconds (the
inspect-delay).</p>
<h2>Conclusion</h2>
<p>Happy SSH!</p>Editing a CV in markdown with pandoc2013-10-30T15:53:00+01:002013-10-30T15:53:00+01:00Toftag:blog.chmd.fr,2013-10-30:/editing-a-cv-in-markdown-with-pandoc.html<p>CV maintainance is one of these painful and repetitive tasks that you
don't want to burn too much time on. For a while, I have been using latex
with the excellent <a href="http://www.ctan.org/pkg/moderncv">moderncv class</a>, but
the pdf format has annoying limitations:</p>
<ul>
<li>Seeing a pdf document in a browser is not as …</li></ul><p>CV maintainance is one of these painful and repetitive tasks that you
don't want to burn too much time on. For a while, I have been using latex
with the excellent <a href="http://www.ctan.org/pkg/moderncv">moderncv class</a>, but
the pdf format has annoying limitations:</p>
<ul>
<li>Seeing a pdf document in a browser is not as nice as seeing an html
webpage;</li>
<li>Human Resources usually prefer to work with word documents.</li>
</ul>
<p>I thus decided to switch to the markdown syntax, and to generate various
formats with pandoc. The code of my résumé now looks like this:</p>
<div class="highlight"><pre><span></span><span class="gh">Cave Johnson</span>
<span class="gh">============</span>
----
> Science isn't about WHY. It's about WHY NOT!
----
<span class="gh">Corporate Experience</span>
<span class="gh">--------------------</span>
1940-1980
: <span class="ge">*CEO of Aperture Science*</span> (Upper Michigan, USA).
Supervised the development of various gels, and of a Portable
Quantum Tunneling Device.
<span class="gh">Hobbies</span>
<span class="gh">-------</span>
Interests
: Refining moon rocks
</pre></div>
<p>The file can then be compiled in various formats. To obtain the html
version:</p>
<div class="highlight"><pre><span></span><span class="err">pandoc --standalone --from markdown --to html -o index.html index.md</span>
</pre></div>
<p>But the default ouptut is rather ugly. That is why I wrote <a href="//resume.chmd.fr/style.css">a
CSS</a> to go with the html generated by pandoc.
It is inspired by moderncv, and specially adapted for this use case. The
command line becomes:</p>
<div class="highlight"><pre><span></span><span class="err">pandoc --standalone -c style.css --from markdown --to html -o index.html index.md</span>
</pre></div>
<p>Now that you are at it, you can also generate a word document or even some
plain text file. No need to build a new one in a hurry!</p>
<div class="highlight"><pre><span></span><span class="err">pandoc --from markdown --to docx -o index.docx index.md</span>
<span class="err">pandoc --standalone --smart --from markdown --to plain -o index.txt index.md</span>
</pre></div>
<p>You can get a look at what it looks like on <a href="//resume.chmd.fr">my own
résumé</a>. The full code can be found on
<a href="https://git.chmd.fr/?p=resume.git">git.chmd.fr</a> (and
<a href="https://github.com/chmduquesne/resume">github</a>).</p>Using openid and the likes to protect static content (lighttpd)2013-10-29T14:22:00+01:002013-10-29T14:22:00+01:00Toftag:blog.chmd.fr,2013-10-29:/using-openid-and-the-likes-to-protect-static-content-lighttpd.html<p>I <a href="http://blog.chmd.fr/sigal-a-static-gallery-generator.html">recently</a>
set up a self-hosted gallery for my pictures. Obviously, I did this
because I wanted to stop giving my content to external platforms, but also
to gain some level of privacy: I want to limit the number of people who
are able to look at these pictures.</p>
<p>While …</p><p>I <a href="http://blog.chmd.fr/sigal-a-static-gallery-generator.html">recently</a>
set up a self-hosted gallery for my pictures. Obviously, I did this
because I wanted to stop giving my content to external platforms, but also
to gain some level of privacy: I want to limit the number of people who
are able to look at these pictures.</p>
<p>While setting up the gallery was relatively easy, restricting the access
was an interesting problem. I did not want to use a global
<code>username:password</code> combination, because this kind of credentials
inevitably become public at some point. A different combination for each
user would have been better, but some people are not as careful as I am
with their own credentials, and they may just give away their own access
to others. It is also a lot of maintenance, and I don't want to deal with
the risks involved with securely processing my friends' passwords.</p>
<p>I then had a look at single sign on solutions such as openid. This kind of
technology was appealing, for several reasons:</p>
<ul>
<li>No password to process on my side</li>
<li>People would identify with a very personal account (gmail, facebook),
that they are unlikely to be willing to share with anyone else.</li>
<li>It is very easy to use for the end user.</li>
</ul>
<p>I have thus been looking for a solution to get openid/oauth authentication
to cooperate with lighttpd in order to protect my new gallery. After some
work, I came up with <a href="https://git.chmd.fr/?p=lighttpd-external-auth;a=blob_plain;f=external-auth.lua">a lua magnet
script</a>
that does the job. It is inspired by <a href="https://github.com/tai/mod-auth-ticket-for-lighttpd">this
module</a>, but it does
not require to be compiled and works out of the box on recent versions of
lighttpd (e.g. debian stable). I also believe that it offers <a href="https://github.com/tai/mod-auth-ticket-for-lighttpd/issues/4">a better
security</a>.</p>
<p>It works pretty well! You can try to visit
<a href="https://gallery.chmd.fr">gallery.chmd.fr</a> and you should be presented
with my very own login page. Should you try to login, the script will
gently tell you that though your openid/oauth login was successful, you
cannot access the gallery because it is a privilege reserved to the people
I explicitly authorized. Beware that if you are not using linux, you might
experiment a warning from your browser: that is because I use a
certificate signed by <a href="http://www.cacert.org/">cacert</a>, a community-driven
certificate authority whose root certificate is not included in commercial
OS (yet).</p>
<p>If you want to use this script on your own lighttpd server, I have set up
a <a href="http://lighttpd-external-auth.chmd.fr/">dedicated website</a> to explain
how to proceed. Check it out!</p>
<p>One last thing: I am not a security expert, and I did this for fun. I
believe it is pretty secure (provided you trust the third parties
involved, of course), but I still have to warn you: don't use this to
protect important documents. If you have knowledge about security and want
to comment - or even better: to contribute - be my guest!</p>Git on lighttpd2013-08-08T16:09:00+02:002013-08-08T16:09:00+02:00Toftag:blog.chmd.fr,2013-08-08:/git-on-lighttpd.html<h1>Intro</h1>
<p>I switched to lighttpd. The main reason for this change was the ease of
configuration: for example, with apache, when you want to serve the same
website with and without ssl, you end up doing something like this:</p>
<div class="highlight"><pre><span></span># file: /etc/apache2/sites-available/domain.com.conf
<span class="nt"><VirtualHost</span> <span class="err">*:80</span><span class="nt">></span>
Include /etc …</pre></div><h1>Intro</h1>
<p>I switched to lighttpd. The main reason for this change was the ease of
configuration: for example, with apache, when you want to serve the same
website with and without ssl, you end up doing something like this:</p>
<div class="highlight"><pre><span></span># file: /etc/apache2/sites-available/domain.com.conf
<span class="nt"><VirtualHost</span> <span class="err">*:80</span><span class="nt">></span>
Include /etc/apache2/domain.com.inc.conf
<span class="nt"></VirtualHost></span>
<span class="nt"><VirtualHost</span> <span class="err">*:443</span><span class="nt">></span>
Include /etc/apache2/domain.com.inc.conf
SSLEngine On
SSLCertificateFile /etc/ssl/private/domain.com.pem
<span class="nt"></VirtualHost></span>
# file: /etc/apache2/sites-available/domain.com.inc.conf
ServerName domain.com
DocumentRoot /var/www/domain.com
</pre></div>
<p>Including the website config as a separate file is pretty much the only
way to accomplish this without duplicating this config in both
virtualhosts. That is two files to maintain, for one domain. If you want
to do this for every domain you control, you have to multiply the files
and includes.</p>
<p>Doing this with lighttpd is really easier:</p>
<div class="highlight"><pre><span></span><span class="err"># file /etc/lighttpd/lighttpd.conf</span>
<span class="err">$SERVER["socket"] == ":443" {</span>
<span class="err"> ssl.engine = "enable"</span>
<span class="err"> ssl.pemfile = "/etc/ssl/private/domain.com.pem"</span>
<span class="err">}</span>
<span class="err">$HTTP["host"] == "domain.com" {</span>
<span class="err"> server.document-root = "/var/www/domain.com"</span>
<span class="err">}</span>
</pre></div>
<h1>git and lighttpd</h1>
<p>Now, let's do cool things. One of the subdomains I own is dedicated to
hosting my public git repositories. I (quite obviously) named it
<a href="http://git.chmd.fr">http://git.chmd.fr</a>. I want to use it for:</p>
<ul>
<li>Serving a gitweb instance to browse all repositories, such that
<a href="https://git.chmd.fr/?p=netmon.git">https://git.chmd.fr/?p=netmon.git</a>
takes you to browsing the repository of netmon.</li>
<li>Serving the git protocol, such that
<code>git clone https://git.chmd.fr/netmon.git</code> clones this repository.</li>
</ul>
<p>Combining the two was tricky, but I ended up finding how to proceed. Here
is the relevant part of my config:</p>
<div class="highlight"><pre><span></span><span class="err">$</span><span class="n">HTTP</span><span class="p">[</span><span class="ss">"host"</span><span class="p">]</span> <span class="o">==</span> <span class="ss">"git.chmd.fr"</span> <span class="err">{</span>
<span class="o">#</span> <span class="n">This</span> <span class="n">takes</span> <span class="n">care</span> <span class="k">of</span> <span class="n">serving</span> <span class="n">gitweb</span>
<span class="n">server</span><span class="p">.</span><span class="n">document</span><span class="o">-</span><span class="n">root</span> <span class="o">=</span> <span class="ss">"/usr/share/gitweb"</span>
<span class="n">cgi</span><span class="p">.</span><span class="n">assign</span> <span class="o">=</span> <span class="p">(</span> <span class="ss">".cgi"</span> <span class="o">=></span> <span class="ss">""</span> <span class="p">)</span>
<span class="n">server</span><span class="p">.</span><span class="n">indexfiles</span> <span class="o">=</span> <span class="p">(</span> <span class="ss">"gitweb.cgi"</span> <span class="p">)</span>
<span class="o">#</span> <span class="k">And</span> <span class="n">this</span> <span class="n">condition</span> <span class="n">matches</span> <span class="n">git</span> <span class="n">objects</span>
<span class="err">$</span><span class="n">HTTP</span><span class="p">[</span><span class="ss">"url"</span><span class="p">]</span> <span class="o">=~</span> <span class="ss">"(?x)^/(.*/(HEAD | info/refs | objects/(info/[^/]+ | [0-9a-f]{2}/[0-9a-f]{38} | pack/pack-[0-9a-f]{40}\.(pack|idx)) | git-(upload|receive)-pack))$"</span> <span class="err">{</span>
<span class="k">alias</span><span class="p">.</span><span class="n">url</span> <span class="o">+=</span> <span class="p">(</span> <span class="ss">""</span> <span class="o">=></span> <span class="ss">"/usr/lib/git-core/git-http-backend"</span><span class="p">)</span>
<span class="n">cgi</span><span class="p">.</span><span class="n">assign</span> <span class="o">=</span> <span class="p">(</span><span class="ss">""</span> <span class="o">=></span> <span class="ss">""</span><span class="p">)</span>
<span class="n">setenv</span><span class="p">.</span><span class="k">add</span><span class="o">-</span><span class="n">environment</span> <span class="o">=</span> <span class="p">(</span>
<span class="ss">"GIT_PROJECT_ROOT"</span> <span class="o">=></span> <span class="ss">"/home/www/git-public-repos/"</span><span class="p">,</span>
<span class="ss">"GIT_HTTP_EXPORT_ALL"</span> <span class="o">=></span> <span class="ss">""</span>
<span class="p">)</span>
<span class="err">}</span>
<span class="err">}</span>
</pre></div>
<p>Combined with the trick from above, you can get this to work on both http
and https. I hope this will help others!</p>Sigal, a static gallery generator2013-07-20T15:11:00+02:002013-07-20T15:11:00+02:00Toftag:blog.chmd.fr,2013-07-20:/sigal-a-static-gallery-generator.html<p>I wanted to self-host my pictures. Nothing crazy, just a way to share them
with my friends without using a third party service. At first, I thought
about writing a lighttpd module that would generate thumbnails. Then I
thought about a using a php script, but all of them have …</p><p>I wanted to self-host my pictures. Nothing crazy, just a way to share them
with my friends without using a third party service. At first, I thought
about writing a lighttpd module that would generate thumbnails. Then I
thought about a using a php script, but all of them have too many options,
and are too complicated for what I intended to do. I wanted something
simple and secure (e.g. no upload interface)! Then I thought about how
this blog is built: using a static blog generator! Did it exist for
galleries?</p>
<p>It turns out that yes, there are <a href="http://www.nico.schottelius.org/docs/static-image-gallery-generator-comparison/">plenty of
solutions</a>
available. I tested some of them, and I found that
<a href="http://sigal.saimon.org">sigal</a> was my prefered one.</p>
<p>Sigal is beautiful, and minimalistic. It lets you theme your gallery with
jinja templates, exactly like pelican. Furthermore, it is mature and very
well maintained (my main concern when I install something): there is a
testsuite, a good online documentation (not that it needs it, it is dead
simple to use) and continuous integration. There is even
<a href="http://saimon.org/sigal-demo/colorbox/">two</a>
<a href="http://saimon.org/sigal-demo/galleria/">demo</a> galleries, for you to test
it live before installing it. And of course, for maximal conveniency,
there is a python package, that you can install very simply: just run</p>
<div class="highlight"><pre><span></span><span class="err">pip install sigal</span>
</pre></div>
<p>The only thing that I was missing was video support. I sometimes film
short movies with my cameras, and I want to include them in the pictures
that I am sharing. I thus decided to give a go to the code, in order to
see if it easy to patch. It turned out to be rather easy. There's a <a href="https://github.com/saimn/sigal/pull/18">pull
request</a> pending...</p>
<p>TL;DR you should try sigal!</p>Jabber notifications on ssh login2012-09-19T15:33:00+02:002012-09-19T15:33:00+02:00Toftag:blog.chmd.fr,2012-09-19:/jabber-notifications-on-ssh-login.html<p>I coined this little trick the other day, I thought I might share it. I
wanted, for fun, to be notified on gtalk everytime someone logs in my
server. You never know, maybe I could discover unexpected connections. It
turned out to be possible, and the whole thing costed me …</p><p>I coined this little trick the other day, I thought I might share it. I
wanted, for fun, to be notified on gtalk everytime someone logs in my
server. You never know, maybe I could discover unexpected connections. It
turned out to be possible, and the whole thing costed me reading a couple
of manpages and typing 5 lines of code.</p>
<p>Before you do the same thing with you own server, let me claim here that I
am absolutely not a security expert. It is more an experiment than
anything else, so I suggest being really careful and read all the manpages
involved if you want to do the same thing. Also, I'd be happy to be
notified of any potential threat in the comments.</p>
<p>Basically, you can have PAM (Pluggable Authentication Modules, the thing
that handles authentication on Linux) execute external commands. The
module in question is called <code>pam_exec</code>, and it is often used to rebuild
databases e.g. when passwords are changed. It can also be activated when
someone logs in. The manpage explains that the following PAM items are
exported as environment variables to the program executed:</p>
<div class="highlight"><pre><span></span><span class="err"> PAM_RHOST, PAM_RUSER, PAM_SERVICE, PAM_TTY, PAM_USER, PAM_TYPE</span>
</pre></div>
<p>I decided to use it to my advantage. I created on jabber.org an account
for my server. I added it in my gmail friends, and I wrote this little
script, using sendxmpp (saved as <code>/usr/local/bin/login_notify</code>):</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/bin/sh</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="nv">$PAM_USER</span><span class="s2">@`hostname` logged from </span><span class="nv">$PAM_RHOST</span><span class="s2">"</span> <span class="p">|</span> <span class="se">\</span>
sendxmpp -u server_account -j jabber.org -p xxxx me@gmail.com >/dev/null <span class="m">2</span>><span class="p">&</span><span class="m">1</span> <span class="p">&</span>
<span class="nb">exit</span> <span class="m">0</span>
</pre></div>
</td></tr></table>
<p>Note that the sendxmpp command runs in background and that its exit status
is ignored. Otherwise PAM would wait for the command to return before
letting me in, and it would deny me the access if the notification failed
to be delivered. Two things I clearly want to avoid.</p>
<p>Then, the following line goes at the end of <code>/etc/pam.d/sshd</code>:</p>
<div class="highlight"><pre><span></span><span class="err">session optional pam_exec.so /usr/local/bin/login_notify</span>
</pre></div>
<p>There you go, notifications each time someone logs in.</p>
<h1>Are you doing this for real? Read on...</h1>
<p>Ok, just a couple of extra instructions for you:</p>
<ul>
<li>Be really really careful before modifying <code>/etc/pam.d/sshd</code>. If you
put a bogus command in there, you might screw up your remote access.
Please double check that the command <code>/usr/local/bin/login_notify</code> is
running with no error. Only when you are sure of that, you can add the
line to <code>/etc/pam.d/sshd</code>.</li>
<li>Don't forget to <code>chmod +x /usr/local/bin/login_notify</code></li>
<li>When you run <code>/usr/local/bin/login_notify</code>, you should receive a
jabber message. If you don't, then you have to verify that you can
actually send messages to your gmail account. Use a jabber client
and try to have a conversation with your gmail account. Then, try to
use <code>sendxmpp</code>, then try again with the <code>login_notify</code> script.</li>
<li>My instructions are probably incomplete. Use your brain to fill in the
blanks.</li>
</ul>Choose your passphrase with a die2012-08-01T17:25:00+02:002012-08-01T17:25:00+02:00Toftag:blog.chmd.fr,2012-08-01:/choose-your-passphrase-with-a-die.html<p>Lurking on the archlinux <a href="https://wiki.archlinux.org/index.php/Disk_Encryption#Choosing_a_strong_passphrase">wiki</a>, I found a very interesting resource
for choosing a strong, easy to remember passphrase. It's called the
<a href="http://world.std.com/~reinhold/diceware.html">diceware method</a>. You basically pick a die and throw it repeatedly
to determine the words of your passphrase.</p>
<p>To associate a word with the results of the die …</p><p>Lurking on the archlinux <a href="https://wiki.archlinux.org/index.php/Disk_Encryption#Choosing_a_strong_passphrase">wiki</a>, I found a very interesting resource
for choosing a strong, easy to remember passphrase. It's called the
<a href="http://world.std.com/~reinhold/diceware.html">diceware method</a>. You basically pick a die and throw it repeatedly
to determine the words of your passphrase.</p>
<p>To associate a word with the results of the die, you are given a list of
words that looks like what follows:</p>
<div class="highlight"><pre><span></span><span class="err">...</span>
<span class="err">46154 ox</span>
<span class="err">46155 oxyda</span>
<span class="err">46156 oxyde</span>
<span class="err">46161 oxyder</span>
<span class="err">46162 oy</span>
<span class="err">46163 oz</span>
<span class="err">46164 ozone</span>
<span class="err">46165 ozones</span>
<span class="err">46166 p</span>
<span class="err">46211 pa</span>
<span class="err">46212 pacha</span>
<span class="err">46213 pack</span>
<span class="err">46214 packs</span>
<span class="err">46215 pacte</span>
<span class="err">...</span>
</pre></div>
<p>The numbers indicate what word you should pick on the base of 5 throws.
For example if you throw 4, 6, 1, 5, 5, you should pick the word 46155,
which is "oxyda". You then repeat this process until you have 6 or 7
words. Pick the words in the order you got them, and you now have a new
secure passphrase.</p>
<p>What I like about this method is that it is <strong>fully automated</strong>, yet
perfectly secure. You don't have to worry about making a choice: the die
makes it for you, and you still end up with something that is easy to
remember.</p>
<p>Sure, I read <a href="http://xkcd.com/936/">xkcd</a> and I was already using long sentences that made
sense only if you are me, but this method beats mine, since there is no
way I was picking these words randomly.</p>
<p>Since I could not find a list of french words, I quickly made <a href="https://github.com/chmduquesne/diceware-fr">my own</a>.</p>Operations Research and Beer drinking2011-11-19T17:06:00+01:002011-11-19T17:06:00+01:00Toftag:blog.chmd.fr,2011-11-19:/operations-research-and-beer-drinking.html<p>I am just returning from Charlotte NC, where I had an amazing time at the
INFORMS 2011 conference. Being in the airport waiting for my flight, I
figured out I could use this spare time to share a cool story about
Operations Research.</p>
<p>I happen to be a beer lover …</p><p>I am just returning from Charlotte NC, where I had an amazing time at the
INFORMS 2011 conference. Being in the airport waiting for my flight, I
figured out I could use this spare time to share a cool story about
Operations Research.</p>
<p>I happen to be a beer lover. If you're anything like me, you probably know
Belgium produces among the best beers in the world. You also probably know
about the <a href="http://en.wikipedia.org/wiki/Trappist_beer">trappist beers</a>, which are some of the most famous and
tastiest beers brewed in the area.</p>
<p>Two years ago, <a href="http://mickaelistria.wordpress.com/">one of my friends</a> had a crazy idea: He looked at a
map, locating the trappist abbeys producing those excellent beers, and
noticed they all were not very far from each other. He thus proposed a
tour of Belgium that would visit all of them, by bicycle. I was
immediately very enthusiastic about the idea and started to think about
how to make it become true.</p>
<h2>Planning the trip</h2>
<p>So, given 7 cities and a tour to plan (The french abbey of <a href="http://fr.wikipedia.org/wiki/Abbaye_du_Mont_des_Cats">Mont des
Cats</a> and the german abbey of <a href="http://trappist-beers.com/8th-trappist-beer-not-from-mont-des-cats-france-but-from-abbey-zundert-netherlands/">Maria Toevlucht</a> had not announced
their plans of brewing their own beers at the time), can you guess what am
I immediately thought about? That's right, the <a href="http://en.wikipedia.org/wiki/Travelling_salesman_problem">Travelling Salesman
Problem</a>! Of course, the problem itself is NP-hard, but in practice,
with an instance of this size, it is doable manually.</p>
<p>I could have done it by myself, but this was a unique opportunity to use
<a href="http://www.tsp.gatech.edu/maps/index.html">the online solver</a> from the <a href="http://www.tsp.gatech.edu/index.html">TSP website</a> of the university of
Georgia Tech! Since we did not actually needed to go back to the first
abbey, I removed the longest edge.</p>
<p>I know what you are thinking: "Are you kidding me? A TSP Problem? If you
remove an edge, this is not a tour, this is an Hamiltonian Path!". You are
completely right, I did not solve the right problem. The thing is, I did
not know any Online Hamiltonian Path Solver at the time, and this was
probably the coolest use I could ever make of Concorde. Still a good
story, isn't it?</p>
<h2>Doing it!</h2>
<p>Here is the trip as we planned it:</p>
<iframe src="https://www.google.com/maps/embed?pb=!1m54!1m12!1m3!1d1397173.317358605!2d3.0095418362486455!3d50.56817093554189!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!4m39!3e1!4m3!3m2!1d50.048396999999994!2d4.311786!4m5!1s0x47ea8dcefbfe2723%3A0xa95a58f49956f256!2sOrval%2C+Florenville%2C+Belgique!3m2!1d49.6368489!2d5.3472466999999995!4m5!1s0x47c1c946c89a1663%3A0x40099ab2f4d6f20!2sRochefort%2C+Belgique!3m2!1d50.1596036!2d5.2221665!4m3!3m2!1d51.255824999999994!2d5.478648!4m5!1s0x47c6bfc0840d7433%3A0x966840aaf3612c5e!2sKoningshoeven%2C+5018+Tilburg%2C+Pays-Bas!3m2!1d51.551590999999995!2d5.111403!4m5!1s0x47c4003a88a0c5d5%3A0xce12a24262bd5c02!2sWestmalle%2C+Royaume+de+Belgique!3m2!1d51.2968136!2d4.694263299999999!4m5!1s0x47dcc122bb1a2a8d%3A0xc9b50882de0f3896!2sWestvleteren%2C+Vleteren%2C+Belgique!3m2!1d50.927605299999996!2d2.716907!5e1!3m2!1sfr!2sus!4v1448815744468" width="425" height="350" frameborder="0" style="border:0" allowfullscreen></iframe>
<p>We ended up being two (me and my flatmate of the time - Mickael could not
make it) with train tickets to Belgium. Cool facts about this trip:</p>
<ul>
<li>We discussed with "le grand maître de <a href="http://www.confreries.be/conf/grusalle/index.htm">la confrérie de la grusalle et de
la trappiste de Rochefort</a>".</li>
</ul>
<p><img alt="grand_maitre_rochefort.jpg" src="images/grand_maitre_rochefort.jpg"></p>
<ul>
<li>We drank some "petit orval", a beer that you can find only at the abbey
and at the bar (<a href="http://www.orval.be/fr/accueil/auberge.html">l'auberge de l'Ange Gardien</a>) and we learned about
the <a href="http://en.wikipedia.org/wiki/Orval_Abbey#The_legend_of_Orval">legend of Orval</a>.</li>
<li>The lady at the little shop in front of the abbey of Koningshoven (the
one that brews <a href="http://fr.wikipedia.org/wiki/La_Trappe">la Trappe</a>) was so amazed of what we were doing that
she gave us a pack of 4 different flavors of Trappes which we brought
back to France.</li>
<li>In Gent, there is a barber which is called bar-bier, who serves bier
while shaving the clients (check it out on <a href="https://goo.gl/maps/g4byF8u2f6F2">google street view</a>!).</li>
</ul>
<p><img alt="gent_barbier.jpg" src="images/gent_barbier.jpg"></p>
<ul>
<li>Gent and Antwerpen are two of the most beautiful cities I have ever
seen.</li>
</ul>
<p>The only sad thing about this trip is that we could not get to drink any
Westvleteren : it is actually <a href="http://en.wikipedia.org/wiki/Westvleteren_Brewery#Availability">quite hard to get some</a>, given the fact
the monks over there have chosen to only produce as much beer as needed to
finance the community: when we arrived, they did not have any beer left.</p>
<h2>Conclusion</h2>
<p>Three months ago, one of my best friends had the opportunity to get some
Westvleteren and he invited me to taste them, offering me the opportunity
to "finish my trip". For the record, the Westvleteren 12 is ranked the
best beer in the world by <a href="http://www.ratebeer.com/">ratebeer.com</a>. Needless to say, I enjoyed
it very much. He let me keep the capsules as a souvenir:</p>
<p><img alt="westvleteren.jpg" src="images/westvleteren.jpg"></p>
<p><a href="images/belgium_trip.jpg"><img alt="Our actual map during the trip" src="images/belgium_trip.resized.jpg" title="Our actual map during the trip"></a></p>Releasing Michel, a flat-text-file-to-google-tasks uploader2011-09-22T00:00:00+02:002011-09-22T00:00:00+02:00Toftag:blog.chmd.fr,2011-09-22:/releasing-michel-a-flat-text-file-to-google-tasks-uploader.html<p>When it comes to handling my todo list, I'm a huge fan of flat text files.
The main reason why I prefer them over anything else is that I find it
far easier to display it with notification popups this way.</p>
<p>I also heavily rely on gmail to organise myself …</p><p>When it comes to handling my todo list, I'm a huge fan of flat text files.
The main reason why I prefer them over anything else is that I find it
far easier to display it with notification popups this way.</p>
<p>I also heavily rely on gmail to organise myself. When I am reading emails
and organizing my life, it feels natural to use gtasks to take notes for
later.</p>
<p>Since I both use text files and gtasks, I was missing was a way to sync
them together. Unfortunately, for a long time, google <a href="http://code.google.com/p/gdata-issues/issues/detail?id=987">made us wait</a>
for a gtask API. But no more! I discovered at the beginning of the week
that they had <a href="http://googleappsdeveloper.blogspot.com/2011/05/getting-organized-with-tasks-api.html">announced</a> a brand new RESTful interface.</p>
<p>I decided to give it a go and I have written a small program that suit my
needs to help me handle my todo list text file. So here comes <a href="https://github.com/chmduquesne/michel">Michel</a>,
your friendly mate that helps you managing your todo list. It features two
commands</p>
<div class="highlight"><pre><span></span><span class="err">michel pull</span>
<span class="err">michel push <file></span>
</pre></div>
<p>which respectively push and pull taks in a text fashion.</p>
<p>The code is on <a href="https://github.com/chmduquesne/michel">github</a>. Just like any python package, you should be
able to install it using easy_install (provided you install pyxdg with
your standard package manager, since it does not seem to be installable
from easy_install).</p>
<div class="highlight"><pre><span></span><span class="err">easy_install michel</span>
</pre></div>Going static2011-09-15T20:10:00+02:002011-09-15T20:10:00+02:00Toftag:blog.chmd.fr,2011-09-15:/going-static.html<p>I eventually got sick of wordpress and of my former hoster <a href="http://free.fr">free.fr</a>.
Wordpress is probably awesome if you are a team of 15 authors who want to
handle mass production of articles with a nice web interface. On the other
hand, it needs constant updates, and the last ones …</p><p>I eventually got sick of wordpress and of my former hoster <a href="http://free.fr">free.fr</a>.
Wordpress is probably awesome if you are a team of 15 authors who want to
handle mass production of articles with a nice web interface. On the other
hand, it needs constant updates, and the last ones where requiring a
version of php that my hoster did not provide.</p>
<p>Looking for an alternative, I found the <a href="http://nicdumz.fr/blog/2010/12/why-blogofile/">argument of nicdumz about
blogofile</a> pretty much convincing: why use php and databases where flat
html files could be just enough? I have thus decided to go for a static
website generator, and while I am at it, to host my blog on amazon s3.
This brings me the confort of writing my articles on vim, to version them
on git and to manage the whole process from a makefile.</p>
<h1>Moving</h1>
<p>If anyone who reads me plans to make such a move (wordpress to pelican),
I'll summarize the steps I went through.</p>
<h2>Extracting your articles</h2>
<p>Being open and in the spirit of every good free software, wordpress lets
you export your blog using an xml format. Pelican can <a href="https://github.com/ametaireau/pelican/blob/master/tools/pelican-import">take advantage</a>
of this xml file to generate rst files using pandoc. Or if you are lazy,
you can just provide an rss feed to the pelican importer, but you'll still
miss a way to get the comments.</p>
<h2>Extracting your comments</h2>
<p>Pelican does not provide a comment system by itself, but integrates nicely
with <a href="http://disqus.com/">disqus</a>. Just make an account and upload the Wordpress xml export
file I mentioned. Disqus provides a way to import comments from such a
file. You will later be able to reattach threads to their articles by
providing a csv map file following the syntax:</p>
<div class="highlight"><pre><span></span><span class="err">old_url, new_url</span>
</pre></div>
<h2>Setting up an amazon account</h2>
<p>The next step is to set up an amazon account for use with s3, and to buy a
domain name if you don't already own one. I bought the latter using
<a href="http://www.gandi.net/">gandi.net</a>, and I used <a href="https://github.com/enigmacurry/vaporfile">vaporfile</a> to set up an amazon bucket. I
don't see much to add here, given the fact vaporfile provides a friendly
wizard that tells you what to do quite accurately.</p>
<h1>What I could not fix</h1>
<p>The blog entries on my previous blog were obtained through links looking
like</p>
<div class="highlight"><pre><span></span><span class="err">"http://chm.duquesne.free.fr/blog/?p=xxx"</span>
</pre></div>
<p>Whereas on the new version, they look like</p>
<div class="highlight"><pre><span></span><span class="err">"http://blog.chmd.fr/title-of-the-article.html"</span>
</pre></div>
<p>It would have been cool to be able to put 301 redirect entries in a
.htaccess, for the sake of SEO-friendliness. However, this would require
some url rewriting, which <a href="http://free.fr">free</a> does not support. I decided to skip
this step. I am keeping <a href="https://github.com/chmduquesne/blog/blob/master/legacy/urlmap.csv">a map</a> between the former and the new urls,
just in case I'd have the courage to write these redirections in php...</p>plowbot, a jabber bot that downloads links from 1-click hosters2011-07-26T13:46:00+02:002011-07-26T13:46:00+02:00Toftag:blog.chmd.fr,2011-07-26:/plowbot-a-jabber-bot-that-downloads-links-from-1-click-hosters.html<p>I wrote a jabber bot that does just one thing: it uses <a href="https://code.google.com/p/plowshare/">plowshare</a> to
download what you paste. It is quite minimalist and thus does not offer
queue management features nor advanced captcha solving possibilities, so
you should not try to use it on links plowshare can't break automatically
(basically …</p><p>I wrote a jabber bot that does just one thing: it uses <a href="https://code.google.com/p/plowshare/">plowshare</a> to
download what you paste. It is quite minimalist and thus does not offer
queue management features nor advanced captcha solving possibilities, so
you should not try to use it on links plowshare can't break automatically
(basically <a href="https://code.google.com/p/plowshare/wiki/Readme">those that use recaptcha</a>), otherwise it will eventually
freeze. I used python-jabberbot, and to maximize the simplicity I store
the user configuration in json in an xdg fashion (which happened to be
both user-friendly -probably - and easy to write - certainly). If you want
to fork it and add whatever you find useful, it's on github:</p>
<p><a href="https://github.com/chmduquesne/plowbot">https://github.com/chmduquesne/plowbot</a></p>
<p>I am personally quite satisfied with it (it fits my limited usage
for this kind of service), but I am open to pull requests. Of
course, I also made an AUR package for arch users, which adds an rc
script for starting it at boot as your prefered user.</p>SSH over SSL, episode 3: Avoiding using a patched apache.2011-07-11T13:12:00+02:002011-07-11T13:12:00+02:00Toftag:blog.chmd.fr,2011-07-11:/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html<p>If you are reading this, you might be interested in the full list of my
articles about doing SSH over SSL. I have been improving my configuration
over the years, so the more recent, the better:</p>
<ul>
<li>2010-11-12: <a href="/ssh-over-ssl-a-quick-and-minimal-config.html">Quick and minimal config</a></li>
<li>2010-11-15: <a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">Replacing proxytunnel with socat</a></li>
<li>2011-07-11: <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">Avoiding using a …</a></li></ul><p>If you are reading this, you might be interested in the full list of my
articles about doing SSH over SSL. I have been improving my configuration
over the years, so the more recent, the better:</p>
<ul>
<li>2010-11-12: <a href="/ssh-over-ssl-a-quick-and-minimal-config.html">Quick and minimal config</a></li>
<li>2010-11-15: <a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">Replacing proxytunnel with socat</a></li>
<li>2011-07-11: <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">Avoiding using a patched Apache</a></li>
<li>2014-10-19: <a href="/ssh-over-ssl-episode-4-a-haproxy-based-configuration.html">HAproxy based configuration</a></li>
</ul>
<hr>
<p>Another episode of my adventures of firewall bypassing...</p>
<p>In order to use the http CONNECT method to tunnel ssh, you have to
configure apache as I previously showed in <a href="../ssh-over-ssl-a-quick-and-minimal-config.html">a previous post</a>. Sadly,
the current version of apache does not allow to do it over https. There
has been a <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=29744">bug report</a> for years and various patches have been
proposed, but as far as I know, still not any of these patches made it to
the official release.</p>
<p>My solution so far was to apply the patch manually and recompile the
relevant module. Doing this for every release can be annoying, so I've
been looking for a different solution that would not involve recompiling
apache.</p>
<p><strong>Edit 2015-05-07:</strong> This bug has been fixed for 3 years. I still
recommend not to use the CONNECT method, because only apache supports it
and it will force you to use it. There are cooler, faster webservers out
there. Using the HAproxy based configuration is by far the most flexible
way I know (it allows you to use any web server, apache included).</p>
<p>The workaround I now use is fun enough for me to talk about it here. Since
apache has no problem with the CONNECT method when SSL is not involved, I
have decided to do the SSL part by myself. Thus, I configure apache to
serve normally on the port 80, and I use stunnel to secure apache on the
port 443. Here is how I do it: I remove the SSL part of my apache config
and I add in my (normal, unencrypted) apache configuration:</p>
<div class="highlight"><pre><span></span>ProxyRequests On
AllowConnect 22
<span class="nt">< Proxy</span> <span class="err">*</span><span class="nt">></span>
Order deny,allow
Deny from all
<span class="nt"></Proxy></span>
<span class="nt"><Proxy</span> <span class="err">127.0.0.1</span><span class="nt">></span>
Order deny,allow
Allow from all
<span class="nt"></Proxy></span>
</pre></div>
<p>Then, I install stunnel, and I set it up to listen on the port 443
(https) and to forward it to the port 80 (http).</p>
<div class="highlight"><pre><span></span><span class="n">cert</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">stunnel</span><span class="o">/</span><span class="n">stunnel</span><span class="p">.</span><span class="n">pem</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="o">[</span><span class="n">https</span><span class="o">]</span><span class="w"></span>
<span class="n">accept</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">443</span><span class="w"></span>
<span class="k">connect</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">80</span><span class="w"></span>
<span class="n">TIMEOUTclose</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
</pre></div>
<p>stunnel requires a bit of configuration. From the <a href="http://www.stunnel.org/?page=docs">documentation</a>, here
is how to generate a certificate:</p>
<div class="highlight"><pre><span></span><span class="err">cd /etc/stunnel</span>
<span class="err">openssl req -new -x509 -days 365 -nodes -config stunnel.cnf -out stunnel.pem -keyout stunnel.pem</span>
<span class="err">chown stunnel:stunnel stunnel.pem</span>
<span class="err">chmod 600 stunnel.pem</span>
</pre></div>
<p>I also nedded to add in /etc/hosts.allow</p>
<div class="highlight"><pre><span></span><span class="n">sshd</span><span class="o">:</span> <span class="n">ALL</span>
<span class="n">stunnel</span><span class="o">:</span> <span class="n">ALL</span>
<span class="n">https</span><span class="o">:</span> <span class="n">ALL</span>
</pre></div>
<p>And that is all. I restart stunnel and httpd and I can enjoy SSH
over SSL. (actually since I did not want double encryption, I have
started to do telnet over SSL, but that is more or less the same
story).</p>
<p>Other alternatives I have considered:</p>
<ul>
<li>Switching from apache to another http server: it turns out I was unable
to find any other http server supporting the http CONNECT method (at
least thttpd, lighttpd and nginx don't support it)</li>
<li>Using a perl script that serves on the port 443, waiting for the CONNECT
method and forwarding every other message to apache (see
<a href="http://www.karlrunge.com/x11vnc/connect_switch">connect_switch</a>)</li>
</ul>
<p>I did not try this second method, but it seems rather cool. If
anyone does and has any success with it, please leave a comment
here, I am interested. I would also be interested if someone knows
any http server lighter than apache and guaranteed to support the
CONNECT method...</p>[Je préfère ton clone] padopi2011-06-19T14:13:00+02:002011-06-19T14:13:00+02:00Toftag:blog.chmd.fr,2011-06-19:/je-prefere-ton-clone-padopi.html<p>Je reprends du service sur ce blog pour parler d'un petit projet
libre qui m'a fait bien rigoler: padopi. C'est une application web
qui permet d'envoyer des faux mails à vos amis pour leur faire
croire qu'ils se sont fait coincer à télécharger. Bon, les mails en
question se terminent …</p><p>Je reprends du service sur ce blog pour parler d'un petit projet
libre qui m'a fait bien rigoler: padopi. C'est une application web
qui permet d'envoyer des faux mails à vos amis pour leur faire
croire qu'ils se sont fait coincer à télécharger. Bon, les mails en
question se terminent par une petite phrase qui explique que c'est
une blague, mais sinon c'est criant de vérité (il parait qu'ils
sont inspirés du véritable mail hadopi). Je vous préviens:
l'utilisation de ce genre de service est probablement
répréhensible, mais ça ne vous empêche pas de récupérer le code du
projet sur github:</p>
<div class="highlight"><pre><span></span><span class="err">git clone https://github.com/padopi/padopi</span>
</pre></div>
<p>Ou bien, si vous préférez mon clone (Ho ho ho):</p>
<div class="highlight"><pre><span></span><span class="err">git clone https://github.com/chmduquesne/padopi</span>
</pre></div>
<p>Aller, en bonus, la pub de référence :)</p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/3WfdBQhGBgU" frameborder="0" allowfullscreen></iframe>Using a shell version of supergenpass from vimperator/pentadactyl2010-12-20T18:39:00+01:002010-12-20T18:39:00+01:00Toftag:blog.chmd.fr,2010-12-20:/using-a-shell-version-of-supergenpass-from-vimperatorpentadactyl.html<p>Last week, I was glad to be a <a href="http://supergenpass.com/">supergenpass</a>
user: <a href="http://www.businessinsider.com/gawker-hacked-2010-12">gawker.com was
hacked</a> and a huge
number of their username/password hashes was exposed. While I am not
happy with the fact my email was part of the leak and I've stopped reading
anything from them, I know there …</p><p>Last week, I was glad to be a <a href="http://supergenpass.com/">supergenpass</a>
user: <a href="http://www.businessinsider.com/gawker-hacked-2010-12">gawker.com was
hacked</a> and a huge
number of their username/password hashes was exposed. While I am not
happy with the fact my email was part of the leak and I've stopped reading
anything from them, I know there are very little chances for me to get
problems with that, because the password I used on their site was not
reused elsewhere.</p>
<p>But <a href="http://akibjorklund.com/2009/supergenpass-is-not-that-secure">supergenpass is not that
secure</a>.
Any script executed in the same page as supergenpass is able to see your
master password. If the webmaster of the site you are visiting is evil, he
could grab your master password and hack all your accounts. If you are a
vimperator/pentadactyl user, it is easy to fix that, by executing
supergenpass as a shell command (What follows is from my pentadactylrc):</p>
<div class="highlight"><pre><span></span><span class="err">map -modes=n,v <C-F6> y:!~/.scripts/supergenpass<Space>'<S-Insert>'<Return><Esc>2gi<S-Insert><Return></span>
<span class="err">map -modes=i <C-F6> <Esc><C-F6></span>
</pre></div>
<p>Where <code>~/.scripts/supergenpass</code> is a python supergenpass script I
customized for my needs (it uses the gtk-based ssh-askpass program to get
the password, instead of using the python getpass library, which is
command line based). You'll find it in <a href="https://bitbucket.org/chmduquesne/dotfiles/src/624d4f104f7d/scripts/supergenpass">my
dotfiles</a>.
Original version from <a href="http://michael.gorven.za.net/blog/2009/06/18/supergenpass-cellphones-command-line">Michael
Gorven</a>.</p>
<p>A little explanation:</p>
<ul>
<li><code>CTRL-F6</code> is the shortcut to trigger the script (I've been using it for
ages, it is originally the default shortcut used in the <a href="https://addons.mozilla.org/fr/firefox/addon/3282/">password hasher
firefox extension</a>).</li>
<li><code>y</code> yanks the url,</li>
<li><code>:!~/.scripts/supergenpass<Space>'<S-Insert>'<Return></code> will call the
program <code>~/.scripts/supergenpass</code> with the content of the clipboard
(using <code>Shift+Insert</code>)</li>
<li><code><Esc>2gi</code> will then focus the second field (I usually call it once I've
filled my login)</li>
<li>and <code><S-Insert></code> will paste the clipboard (now filled with the generated
password) in this focused field.</li>
</ul>Saving your crontab in your dotfiles2010-12-02T19:25:00+01:002010-12-02T19:25:00+01:00Toftag:blog.chmd.fr,2010-12-02:/saving-your-crontab-in-your-dotfiles.html<p>In order to share them across several machine, like a lot of people, I
synchronize my dotfile using a DVCS on <a href="http://bitbucket.org/chmduquesne/dotfiles">a public
repository</a>. I save as much
stuff as I can, provided it does not contains sensitive stuff like
passwords. Problem: How do you save your crontab? I finally …</p><p>In order to share them across several machine, like a lot of people, I
synchronize my dotfile using a DVCS on <a href="http://bitbucket.org/chmduquesne/dotfiles">a public
repository</a>. I save as much
stuff as I can, provided it does not contains sensitive stuff like
passwords. Problem: How do you save your crontab? I finally had a look at
the crontab manual to realize that crontab could be called on a file. The
following line goes into my <code>~/.zshrc</code>:</p>
<div class="highlight"><pre><span></span><span class="err">alias crontab-e='vi ~/.crontab && crontab ~/.crontab'</span>
</pre></div>
<p>Edit: I now find even better to use a shell function rather than an
alias:</p>
<div class="highlight"><pre><span></span><span class="err"># CRONTAB</span>
<span class="err">if test -z $CRONTABCMD; then</span>
<span class="err"> # allows to source zshrc twice</span>
<span class="err"> export CRONTABCMD=$(which crontab)</span>
<span class="err"> crontab()</span>
<span class="err"> {</span>
<span class="err"> if [[ $@ == "-e" ]]; then</span>
<span class="err"> vim ~/.crontab && $CRONTABCMD ~/.crontab</span>
<span class="err"> else</span>
<span class="err"> $CRONTABCMD $@</span>
<span class="err"> fi</span>
<span class="err"> }</span>
<span class="err"> $CRONTABCMD ~/.crontab</span>
<span class="err">fi</span>
</pre></div>Notifications from google calendar on my desktop2010-11-23T15:11:00+01:002010-11-23T15:11:00+01:00Toftag:blog.chmd.fr,2010-11-23:/notifications-from-google-calendar-on-my-desktop.html<p>I just added this in a crontab:</p>
<div class="highlight"><pre><span></span><span class="err">*/30 * * * * DISPLAY=:0.0 gcalcli remind 240 'notify-send -t 300000 -i myniceicon.svg "Calendar" \%s'</span>
</pre></div>
<p>So every 30 minutes, I get a notification with a 5 minutes timeout
for upcoming events in the next 4 hours. I really don't need more.</p>SSH over SSL, episode 2: replacing proxytunnel with socat2010-11-15T23:53:00+01:002010-11-15T23:53:00+01:00Toftag:blog.chmd.fr,2010-11-15:/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html<p>If you are reading this, you might be interested in the full list of my
articles about doing SSH over SSL. I have been improving my configuration
over the years, so the more recent, the better:</p>
<ul>
<li>2010-11-12: <a href="/ssh-over-ssl-a-quick-and-minimal-config.html">Quick and minimal config</a></li>
<li>2010-11-15: <a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">Replacing proxytunnel with socat</a></li>
<li>2011-07-11: <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">Avoiding using a …</a></li></ul><p>If you are reading this, you might be interested in the full list of my
articles about doing SSH over SSL. I have been improving my configuration
over the years, so the more recent, the better:</p>
<ul>
<li>2010-11-12: <a href="/ssh-over-ssl-a-quick-and-minimal-config.html">Quick and minimal config</a></li>
<li>2010-11-15: <a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">Replacing proxytunnel with socat</a></li>
<li>2011-07-11: <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">Avoiding using a patched Apache</a></li>
<li>2014-10-19: <a href="/ssh-over-ssl-episode-4-a-haproxy-based-configuration.html">HAproxy based configuration</a></li>
</ul>
<hr>
<p>Last week, I wrote <a href="../ssh-over-ssl-a-quick-and-minimal-config.html">an article</a> about how to quickly set up a server
and a client for doing ssh over ssl. In this article, I was using
proxytunnel, but I realized today that it could probably be replaced with
socat (socat can do almost anything)...</p>
<p>The principle is simple: Following the first part of
the tutorial, you make your server accept proxy_connect requests
to its private port localhost:22 through its public port 443,
encapsulating the whole thing in SSL (as a reminder, 22 and 443 are
respectively the standard ports for ssh and ssl).</p>
<p>We now want to configure the ssh clients in order to connect through this
ssl tunnel. I said I was configuring the clients with proxytunnel. The
exact command (in .ssh/config) was:</p>
<div class="highlight"><pre><span></span><span class="err">proxytunnel -q -E -p server.com:443 -d 127.0.0.1:22</span>
</pre></div>
<p>I'll explain it:</p>
<ul>
<li><code>-q</code> is for quiet</li>
<li><code>-E</code> is for encrypting between the proxy and us</li>
<li><code>-p</code> is for choosing the proxy</li>
<li><code>-d</code> is for requesting a destination (from the proxy point of view)</li>
</ul>
<p>So basically, this means: "connect stdio to server.com on port 443 (-p
server.com:443) , in an encrypted way (-E), then from this server, require
to be connected to 127.0.0.1:22 (-d 127.0.0.1:22)".</p>
<p>For those who like to play with all sorts of streams, socat is really the
best tool ever invented. I was wondering if I could reproduce
proxytunnel's behavior with socat, and it turns out you can. Here is how
to proceed: First, create an ssl tunnel between your client's
localhost:1080 and server.com:443:</p>
<div class="highlight"><pre><span></span><span class="err">socat TCP-LISTEN:1080 OPENSSL:server.com:443</span>
</pre></div>
<p>This way, the port 443 of server.com is now available unencrypted
on localhost:1080 Then, use socat and its proxy mode to ask for
localhost:1080 (which is actually server.com:443 unencrypted) to
connect to localhost:22 (which is then server.com:22).</p>
<div class="highlight"><pre><span></span><span class="err">socat - PROXY:127.0.0.1:127.0.0.1:22,proxyport=1080</span>
</pre></div>
<p>Bingo! You should see the ssh prompt. For the fun, I replaced in my
.ssh/config the former</p>
<div class="highlight"><pre><span></span><span class="err">ProxyCommand proxytunnel -q -E -p server.com:443 -d 127.0.0.1:22</span>
</pre></div>
<p>with</p>
<div class="highlight"><pre><span></span><span class="err">ProxyCommand socat TCP-LISTEN:1080 OPENSSL:server.com:443,verify=0 & socat - PROXY:127.0.0.1:127.0.0.1:22,proxyport=1080</span>
</pre></div>
<p><strong>Edit 2015-05-07</strong>: See <a href="https://blog.chmd.fr/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html#comment-2010371675">Vincent's
comment</a>
for a cool idea to wrap the ssh command with the <code>-fMN</code> options.</p>
<p>It works just fine. There is however a flaw in what I did: I use a
hardcoded port, thus I can't establish two ssh connections at the
same time. Forwarding the server.com:443 on localhost:1080 fails
the second time, since this port is already occupied by the first
connection. The best way to fix that would be to use stdio for the
proxy_connect requests, instead of a port of localhost (since the
number of these port is limited). However, with my version of socat
(1.7.1.3), I don't see how to proceed differently: the PROXY method
requires three arguments and one of them is a port. If one of my
readers has a suggestion, he/she's welcome. This remains a cool hack!</p>
<p><strong>Edit</strong>: The great <a href="https://darkpan.com/">Marco Fontani</a> gave a cool solution (see the
comments). Here is how my .ssh/config looks like:</p>
<div class="highlight"><pre><span></span><span class="err">Host server.com</span>
<span class="err"> ProxyCommand socat TCP-LISTEN:1080 OPENSSL:server.com:443,verify=0 & sleep 1 && socat - PROXY:127.0.0.1:127.0.0.1:22,proxyport=1080</span>
<span class="err"> DynamicForward 1080</span>
<span class="err"> ServerAliveInterval 60</span>
<span class="err"> ControlMaster auto</span>
<span class="err"> ControlPath ~/.ssh/tmp/%h_%p_%r</span>
</pre></div>SSH over SSL, a quick and minimal config.2010-11-12T11:52:00+01:002010-11-12T11:52:00+01:00Toftag:blog.chmd.fr,2010-11-12:/ssh-over-ssl-a-quick-and-minimal-config.html<p>If you are reading this, you might be interested in the full list of my
articles about doing SSH over SSL. I have been improving my configuration
over the years, so the more recent, the better:</p>
<ul>
<li>2010-11-12: <a href="/ssh-over-ssl-a-quick-and-minimal-config.html">Quick and minimal config</a></li>
<li>2010-11-15: <a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">Replacing proxytunnel with socat</a></li>
<li>2011-07-11: <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">Avoiding using a …</a></li></ul><p>If you are reading this, you might be interested in the full list of my
articles about doing SSH over SSL. I have been improving my configuration
over the years, so the more recent, the better:</p>
<ul>
<li>2010-11-12: <a href="/ssh-over-ssl-a-quick-and-minimal-config.html">Quick and minimal config</a></li>
<li>2010-11-15: <a href="/ssh-over-ssl-episode-2-replacing-proxytunnel-with-socat.html">Replacing proxytunnel with socat</a></li>
<li>2011-07-11: <a href="/ssh-over-ssl-episode-3-avoiding-using-a-patched-apache.html">Avoiding using a patched Apache</a></li>
<li>2014-10-19: <a href="/ssh-over-ssl-episode-4-a-haproxy-based-configuration.html">HAproxy based configuration</a></li>
</ul>
<hr>
<p>So you are behind a vicious firewall that filters outgoing ssh and
vpn, and the only safe way out is SSL. In this article, I'll
describe how to SSH over SSL to a machine that runs an ssh server
and apache2. This machine will still be able to run an SSL website.
Clients will connect using a standard ssh client and proxytunnel.</p>
<h1>Server configuration</h1>
<p>I assume that:</p>
<ul>
<li>The server is accessible on the port 443 through the "server.com" domain
name (otherwise using the raw ip will do the trick).</li>
<li>It also runs an ssh server (but no need for the port 22 to be
reachable).</li>
<li>You already have set up certificates for SSL</li>
<li>You've enabled the modules for ssl (a2enmod ssl)</li>
<li>You're running the default ssl website in
/etc/apache2/sites-available/default-ssl and it is enabled (a2ensite
default-ssl)</li>
<li>You've enabled necessary modules for proxying and using proxy connect
methods (a2enmod proxy proxy_connect proxy_http)</li>
</ul>
<h1>File /etc/apache2/sites-available/default-ssl</h1>
<p>It's minimalistic on purpose, so you can see what is really needed.</p>
<div class="highlight"><pre><span></span><span class="nt"><IfModule</span> <span class="err">mod_ssl.c</span><span class="nt">></span>
<span class="nt"><VirtualHost</span> <span class="err">_default_:443</span><span class="nt">></span>
# enable ssl
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
# proxytunnel
Include /etc/apache2/proxytunnel/main.conf
<span class="nt"></VirtualHost></span>
<span class="nt"></IfModule></span>
</pre></div>
<h1>File /etc/apache2/proxytunnel/main.conf</h1>
<p>It enables forward proxying for anyone, but only if the client asks for
127.0.0.1:22 (other requests will be denied). This results in exposing the
port 22 (ssh) of your server through a proxy, in an encrypted way.</p>
<div class="highlight"><pre><span></span>ProxyRequests On
AllowConnect 22
<span class="nt"><Proxy</span> <span class="err">*</span><span class="nt">></span>
Order deny,allow
Deny from all
<span class="nt"></Proxy></span>
<span class="nt"><Proxy</span> <span class="err">127.0.0.1</span><span class="nt">></span>
Order deny,allow
Allow from all
<span class="nt"></Proxy></span>
</pre></div>
<h1>Client configuration</h1>
<p>I assume that:</p>
<ul>
<li>An ssh client is installed</li>
<li>proxytunnel is installed</li>
</ul>
<p>First, you'll need to test your server setting using proxytunnel alone.
Since debugging encryption problems can be tedious, at first, I suggest
you set up your server to provide the proxy in a non encrypted way,
commenting the three SSL related lines (you can switch to encrypted when
it works). Proxytunnel can "chain" two proxies (a local one, and a remote
one), but if the place you connect from does not use such a setting, here
is how you can proceed:</p>
<div class="highlight"><pre><span></span><span class="err">proxytunnel -E -p server.com:443 -d 127.0.0.1:22 -v</span>
</pre></div>
<p>-v is for verbose. Replace it with -q (quiet) if it works. You can say it
works when you are prompted an ssh login. Apache2 used to have <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=29744">a bug</a>
with proxy_connect and SSL, so using encryption may require some extra
work (like patching and recompiling the mod_proxy shared libraries or
using the latest alpha).</p>
<h1>File .ssh/config</h1>
<p>Once you're done, just drop the working command line in the .ssh/config of
your clients:</p>
<div class="highlight"><pre><span></span><span class="err">Host server.com</span>
<span class="err"> ProxyCommand proxytunnel -q -E -p server.com:443 -d 127.0.0.1:22</span>
<span class="err"> DynamicForward 1080</span>
<span class="err"> ServerAliveInterval 60</span>
</pre></div>
<p>If you are stuck, I recommend you read <a href="http://www.saulchristie.co.uk/how-to/bypass-firewalls">this excellent article</a>. One
problem remains with this config: If the traffic is correctly monitored,
the ip of you server could be logged (even though it will be impossible to
prove you have been doing something not allowed). First, you should run an
https website on this ip (like a blog, or a code repository), in order to
make this traffic more realistic. What could also be cool would be to
chain proxies, <a href="http://lifehacker.com/5484934/run-your-own-free-proxy-through-the-google-app-engine">using for example the appengine</a>. This way your traffic
will look like it's going to google.</p>Vim: complete C++ accurately, pulling informations from the compiler, with gccsense and clang_complete2010-10-27T23:11:00+02:002010-10-27T23:11:00+02:00Toftag:blog.chmd.fr,2010-10-27:/vim-complete-c-accurately-pulling-informations-from-the-compiler-with-gccsense-and-clang_complete.html<p>It has been a while since I first dreamt about a reliable way to complete
C++ code within vim. Sure, there was omnicppcomplete, which was able to
complete more or less accurately from ctags databases, but the quality of
the completion was greatly dependent on your coding style (I never …</p><p>It has been a while since I first dreamt about a reliable way to complete
C++ code within vim. Sure, there was omnicppcomplete, which was able to
complete more or less accurately from ctags databases, but the quality of
the completion was greatly dependent on your coding style (I never could
get myself used to put all my methods declarations on the same line).
What we missed was a clever completion plugin, something that would be
able to look deep inside the code, to resolve the types of the object you
are refering to and to provide the set of accurate methods. Actually, we
needed a plugin that would have the same knowledge the compiler has. That
is a huge task, which is probably the reason why it has been let aside for
so long. But recently, almost at the same time, two plugins have
appeared, based on this idea.</p>
<p>The first plugin, clang_complete, uses a feature from the compiler
clang++, from the llvm project. This new C++ compiler aims at being as
reliable as g++. Though as far as I know, it is still not ready for
production, it recently compiled boost, so expect to hear about it again.
clang++ features the ability to complete a given line of code from the
command line, and our first plugin is based on this feature: see
<a href="http://www.vim.org/scripts/script.php?script_id=3302">http://www.vim.org/scripts/script.php?script</a> for more information.</p>
<p>The second plugin is based on a crazy gcc modification called
gcc-code-assist. The author has hacked in gcc's code and provides a
replacement for gcc that also builds a sqlite database at the same time
you build your code with it. Then a command line tool called gccsense
allows to query this database. Basically, you just replace gcc with
gcc-code-assist in your makefile, and you install the plugin provided on
the author's website: <a href="http://cx4a.org/software/gccsense/">http://cx4a.org/software/gccsense/</a>. The
modified gcc is really easy to compile, I even made a package for
archlinux that you can find on AUR. Obviously, this stuff is very unlikely
to make it to gcc's upstream...</p>
<p>So, what to use? Well, if clang++ builds your project without errors, I'd
go for it, because this is for sure a feature that will continue to be
maintained by the llvm crew. Otherwise, gccsense should work exactly like
gcc-4.4. Honestly, I did not have the chance to really test any of them,
so it will be difficult to provide good feedback for me. If someone has
the opportunity to test it, please leave a comment!</p>Google releasing a constraint programming library2010-09-25T00:31:00+02:002010-09-25T00:31:00+02:00Toftag:blog.chmd.fr,2010-09-25:/google-releasing-a-constraint-programming-library.html<p>As an Operation Research engineer/PhD student, I was very interested to
discover that Google just released a project in my field. It is simply
called "or-tools" and contains a constraint programming solver.</p>
<p>While CP is not my primary field of study, I know the basics and I gave a …</p><p>As an Operation Research engineer/PhD student, I was very interested to
discover that Google just released a project in my field. It is simply
called "or-tools" and contains a constraint programming solver.</p>
<p>While CP is not my primary field of study, I know the basics and I gave a
quick look, just in order to know how big it was and what I would fine
inside. Technically, I liked what I saw: What is actually inside is C++,
wrapped in a swig interface. There are 58 C++ files (24 of them are
headers) and a total number of 35998 lines of code, which is reasonable (=
rather big, but still readable by 1/2 persons) for a project in this
language. Embedding C++ in script languages is probably the best way I
know to get the best of the two worlds since you get the power of scripts,
and the speed of C++. While this technique is very efficient and more and
more projects are using it, Operations Research is a field where things
are usually moving slowly in terms of technology, so I was glad to see
that google engineers are doing it, it might show the way for the rest of
the community.</p>
<p>The project is supposed to build on the 3 major platforms. For linux, it
just uses a simple Makefile, which I liked even more: Having used
autotools a lot, I think I can now say I only have pure hate for them
(they never made things simpler) and I just want to hug every programmers
that are handling things with simple Makefiles.</p>
<p>There are examples in python and in C++ that are classic CP
exercises for students (at least I already knew most of them). The
only thing I did not like was the fact they are using subversion. I
find it easier to hack in projects when they are distributed with
DCVS. But I guess the guys who did this don't need my opinion,
since it is not the first time they are writing code. I was curious
and googled the name of the commiter: apparently he's a former
engineer from ilog (now part of IBM), which is famous in the OR
field for cplex, the famous MIP solver.</p>
<p>There are a mailing list:</p>
<p><a href="http://groups.google.com/group/or-tools-discuss">http://groups.google.com/group/or-tools-discuss</a>
and a website:</p>
<p><a href="https://sites.google.com/site/ortoolssite/">https://sites.google.com/site/ortoolssite/</a>,</p>
<p>so I guess google also plans to maintain this library. Conclusion:
Good news for OR!</p>Mise à jour de TalkMyPhone2010-09-07T13:07:00+02:002010-09-07T13:07:00+02:00Toftag:blog.chmd.fr,2010-09-07:/mise-a-jour-de-talkmyphone.html<p>Salut planet-libre, J'ai mis à jour TalkMyPhone, mon application
android.</p>
<p>Pour ceux qui n'auraient pas suivi le lancement de l'application la
semaine dernière, TalkMyPhone est une application permettant de contrôler
son mobile à distance via xmpp, le protocole utilisé par jabber/gtalk. La
version beta supporte désormais:</p>
<ul>
<li>la réponse aux …</li></ul><p>Salut planet-libre, J'ai mis à jour TalkMyPhone, mon application
android.</p>
<p>Pour ceux qui n'auraient pas suivi le lancement de l'application la
semaine dernière, TalkMyPhone est une application permettant de contrôler
son mobile à distance via xmpp, le protocole utilisé par jabber/gtalk. La
version beta supporte désormais:</p>
<ul>
<li>la réponse aux sms</li>
<li>faire sonner le téléphone à distance (pour le retrouver)</li>
<li>demander la géolocalisation du téléphone</li>
</ul>
<p>Ça se passe ici:
<a href="https://code.google.com/p/talkmyphone/">https://code.google.com/p/talkmyphone/</a></p>
<p>Update: On en parle sur
<a href="http://www.frandroid.com/33622/talkmyphone-controlez-votre-telephone-a-distance/">frandroid</a>!</p>TalkMyPhone, une appli android pour recevoir des notifications de son téléphone2010-09-01T16:29:00+02:002010-09-01T16:29:00+02:00Toftag:blog.chmd.fr,2010-09-01:/talkmyphone-une-appli-android-pour-recevoir-des-notifications-de-son-telephone.html<p>Hello planet libre, J'ai codé une application android pour recevoir des
notifications de son téléphone.</p>
<p>Le principe est simple: vous créez un compte jabber pour votre appareil et
vous l'inscrivez dans vos amis gtalk (vérifiez que ça marche avec
pidgin/empathy en vous envoyant un message). Puis vous installez
l'application …</p><p>Hello planet libre, J'ai codé une application android pour recevoir des
notifications de son téléphone.</p>
<p>Le principe est simple: vous créez un compte jabber pour votre appareil et
vous l'inscrivez dans vos amis gtalk (vérifiez que ça marche avec
pidgin/empathy en vous envoyant un message). Puis vous installez
l'application sur votre appareil et vous la configurez comme il faut en
réglant les champs <code>login compte jabber téléphone</code>/<code>mot de passe compte
jabber téléphone</code>/<code>adresse gmail à notifier</code>. Vous démarrez alors le
service et votre téléphone vous transmet les sms qu'il reçoit et vous
notifie des appels de vos correspondants.</p>
<p>J'avoue que ça n'est pas d'une utilité fantastique, mais j'aime bien être
notifié de tout et n'importe quoi sur mon ordinateur, et ce genre de
notifications me manquait. Je prévois de rajouter de petites
fonctionnalités comme la possibilité de répondre aux sms quand j'aurai un
peu de temps.</p>
<p>Évidemment le code est libre (LGPL, même, puisque google code ne connait
pas la WTFPL ;) ). N'hésitez pas à me laisser des commentaires gentils.
L'url du projet:
<a href="https://code.google.com/p/talkmyphone/">https://code.google.com/p/talkmyphone/</a>
PS: Je ne garantis pas que ça marche sur votre téléphone. J'ai fait ça sur
mon temps libre, pour le fun, et je ne compte pas y passer des nuits
blanches. Mais je regarderai les rapports de bug s'il y en a...</p>De l'intérêt de détacher des programmes de la console (sans screen)2010-04-09T09:57:00+02:002010-04-09T09:57:00+02:00Toftag:blog.chmd.fr,2010-04-09:/de-linteret-de-detacher-des-programmes-de-la-console-sans-screen.html<p>Qui n'a jamais perdu par erreur une compilation, une session ssh ou
une fenêtre irssi en fermant une console par inadvertance, à cause
d'un lag réseau, ou bien à cause d'un redémarrage brutal de X11?</p>
<p>Les outils présentés ici permettent de vous affranchir de ce genre
de problème. dtach est …</p><p>Qui n'a jamais perdu par erreur une compilation, une session ssh ou
une fenêtre irssi en fermant une console par inadvertance, à cause
d'un lag réseau, ou bien à cause d'un redémarrage brutal de X11?</p>
<p>Les outils présentés ici permettent de vous affranchir de ce genre
de problème. dtach est un petit programme bien pratique qui sert à
détacher un programme de la console où celui-ci tourne. De manière
simple, ça veut dire que si on quitte le terminal dans lequel on a
lancé le programme détaché, on pourra par une courte commande
récupérer ce programme.</p>
<p>Exemple, la commande suivante permet de
lancer le programme irssi en détaché, sur le socket /tmp/irssi.sock
(qui sera créé par le programme), où, s'il est déjà lancé, de
récupérer ce programme.</p>
<div class="highlight"><pre><span></span><span class="err">dtach -A /tmp/irssi.sock /usr/bin/irssi</span>
</pre></div>
<p>J'en connais des tas qui ne jurent que par gnu screen. Mais à quoi
bon, si on peut se contenter d'un simple alias?</p>
<div class="highlight"><pre><span></span><span class="err">alias irssi='dtach -A /tmp/irssi.sock /usr/bin/irssi'`</span>
</pre></div>
<p>Jusque là, je me contentais de deux ou trois alias du genre, et j'avais
une petite fonction au début de mon .zshrc qui me permettait de toujours
lancer mon shell en détaché. Cependant, tout ceci manquant de souplesse,
je me suis intéressé à screen et à ses alternatives, et je dois dire que
je trouve tmux vraiment propre. Je mets de côté tous les aspects de
coupage d'écran en deux, onglets et tutti quanti, qui sont plus ou moins
inutiles quand on utilise <a href="http://awesome.naquadah.org/">un vrai window manager</a>.</p>
<p>Si screen et tmux peuvent tous deux ouvrir un nombre illimité de sessions
(screen pouvant, si j'ai bien compris, ouvrir jusqu'à 10 fenêtres au sein
de la même session), tmux offre un mécanisme pour alterner entre
différentes sessions que j'ai cherché en vain dans screen (je vois d'ici
les ardents défenseurs de leur programme favori venir me crucifier dans
les commentaires: tant pis, si ça existe, j'assume ma mauvaise lecture des
pages de manuel).</p>
<p>Dans tmux, avec la configuration par défaut, un simple CTRL-b suivi de s
montre une liste à choix des sessions ouvertes (attachées ou détachées) et
il suffit alors de selectionner une entrée pour que tmux se connecte à
ladite session (et si vous aimez couper l'écran en deux et mettre
plusieurs fenêtres dans la même session, vous pouvez, sans limitation de
nombre).</p>
<p>Voici quelques lignes que j'ai rajoutées au début de mon .zshrc: elles
garantissent qu'une nouvelle session tmux est toujours lancée avec le
shell. La fermeture de la session en cours entraine l'essai de connection
à une autre session, sauf s'il n'y a plus aucune session de lancée.</p>
<div class="highlight"><pre><span></span># TMUX
# if no session is started, start a new session
if test -z <span class="cp">${</span><span class="n">TMUX</span><span class="cp">}</span>; then
tmux
fi
# when quitting tmux, try to attach
while test -z <span class="cp">${</span><span class="n">TMUX</span><span class="cp">}</span>; do
tmux attach || break
done
</pre></div>
<p>Et désormais je lance irssi de la manière suivante:</p>
<div class="highlight"><pre><span></span><span class="err"># IRSSI IN TMUX</span>
<span class="err"># switch to irssi session (and if necessary starts this session before)</span>
<span class="err">irssi()</span>
<span class="err">{</span>
<span class="err"> if tmux has -t irssi >/dev/null; then</span>
<span class="err"> tmux switch -t irssi</span>
<span class="err"> else</span>
<span class="err"> TMUX="" tmux new -d -s irssi /usr/bin/irssi</span>
<span class="err"> tmux switch -t irssi</span>
<span class="err"> fi</span>
<span class="err">}</span>
</pre></div>
<p>Si vous utilisez zsh et/ou urxvt, et que vous souhaitez tenter l'essai, je
vous suggère de jeter un coup d'oeil à <a href="https://github.com/chmduquesne/dotfiles/">ma configuration</a> (les
problèmes de couleurs et de scrolling y sont réglés). À noter qu'il existe
d'autres alternatives à gnu screen, dont le très prometteur <a href="http://caca.zoy.org/wiki/neercs">neercs</a>,
qui permet entre autre de détacher des programmes qu'on avait oublié de
lancer dans neercs.</p>renaming files and variables from vim2010-03-26T01:10:00+01:002010-03-26T01:10:00+01:00Toftag:blog.chmd.fr,2010-03-26:/renaming-files-and-variables-from-vim.html<p>I just wrote a plugin that does it (thanks to cscope). Find it here:
<a href="http://www.vim.org/scripts/script.php?script_id=3028">http://www.vim.org/scripts/script.php?script_id=3028</a></p>Continuous background compilation within vim2010-03-14T16:36:00+01:002010-03-14T16:36:00+01:00Toftag:blog.chmd.fr,2010-03-14:/continuous-background-compilation-within-vim.html<p>You <em>can</em> do continuous background compilation within vim. The following
code snippet will compile your project with <code>make</code> each time you save the
current buffer:</p>
<div class="highlight"><pre><span></span><span class="err">augroup c++</span>
<span class="err"> autocmd BufWritePost *.{hpp,cpp}</span>
<span class="err"> \ silent execute ":!make > ~/.vim/cpperrors 2>&1 &" |</span>
<span class="err"> \ redraw! |</span>
<span class="err"> \ cgetfile ~/.vim/cpperrors</span>
<span class="err">augroup END</span>
</pre></div>
<p>Of course you could replace the …</p><p>You <em>can</em> do continuous background compilation within vim. The following
code snippet will compile your project with <code>make</code> each time you save the
current buffer:</p>
<div class="highlight"><pre><span></span><span class="err">augroup c++</span>
<span class="err"> autocmd BufWritePost *.{hpp,cpp}</span>
<span class="err"> \ silent execute ":!make > ~/.vim/cpperrors 2>&1 &" |</span>
<span class="err"> \ redraw! |</span>
<span class="err"> \ cgetfile ~/.vim/cpperrors</span>
<span class="err">augroup END</span>
</pre></div>
<p>Of course you could replace the make command with something more
complicated (for example calling some script that would run the
compilation on another machine, and getting the error file back in your
<code>~/.vim</code> directory).</p>Utilisons incron pour être notifiés des événements du système de fichiers2010-02-18T00:26:00+01:002010-02-18T00:26:00+01:00Toftag:blog.chmd.fr,2010-02-18:/utilisons-incron-pour-etre-notifies-des-evenements-du-systeme-de-fichiers.html<p><a href="http://incron.aiken.cz/">incron</a> est un programme fonctionnant sur
le même principe que cron, mais basé sur des événements dans le
système de fichiers plutôt que sur des moments de la journée. C'est
très propre: pour l'utiliser, on spécifie un ou des fichiers à
surveiller, un type d'action à détecter sur le(s …</p><p><a href="http://incron.aiken.cz/">incron</a> est un programme fonctionnant sur
le même principe que cron, mais basé sur des événements dans le
système de fichiers plutôt que sur des moments de la journée. C'est
très propre: pour l'utiliser, on spécifie un ou des fichiers à
surveiller, un type d'action à détecter sur le(s) fichier(s) en
question, et une commande à déclencher lorsque l'événement
survient. Je me suis dit que c'était l'occasion où jamais de mettre
à jour un vieux script que j'avais, qui me met au courant des
modifications sur mes logs (je tire l'idée de ce script
<a href="http://www.daemontux.org/?q=node/31">d'un ancien post sur le planet libre</a>).
Après avoir installé incron, j'édite ma table de configuration
incron:</p>
<div class="highlight"><pre><span></span><span class="err">incrontab -e</span>
</pre></div>
<p>Avec mon éditeur favori, je lui mets la ligne suivante:</p>
<div class="highlight"><pre><span></span><span class="err">/var/log/kernel.log IN_MODIFY sh /home/me/documents/scripts/popLog.sh /var/log/kernel.log</span>
</pre></div>
<p>popLog.sh est un script qui prend en argument un log, en extrait la
dernière ligne modifiée, la colorise avec `source-highlight`_ et
l'envoie en notification par le biais de `notify-send`_. Le but
de ce script est donc d'afficher le dernier log dans une bulle,
avec coloration syntaxique. Je fournis le script en question, et
j'ajoute quelques explications:</p>
<ul>
<li>source-highlight a besoin de parler un code couleurs compris
par les bulles de notifications. notification-daemon comprend des
couleurs de type <span color="couleur">mots à colorier</span>,
d'où le fichier supplémentaire awesome.outlang (que j'avais écrit à
l'origine pour naughty et donc compatible avec celui-ci, pour les
utilisateurs d'<a href="http://awesome.naquadah.org/">awesome wm</a> - à ce
propos il y a plusieurs entrées dans le wiki pour faire des choses
semblables).</li>
<li>incron ne comprend pas bien les variables d'environnement, il
vaut mieux les redéfinir dans le script, comme je l'ai fait.</li>
<li>faites attention à ne pas faire n'importe quoi avec incron, il
est facile de créer une boucle infinie en surveillant par exemple
/var/log/everything.log (vous notifiant du lancement de ce script,
et donc générant une nouvelle notification): IN_NO_LOOP est votre
ami.</li>
<li>incron prend des chemins absolus.</li>
</ul>
<p>Après tous ces avertissements, voici
/home/me/documents/scripts/popLog.sh:</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env bash</span>
<span class="c1"># Usage: popLog /var/log/yourlog</span>
<span class="c1"># pops a colored log with the last line of the log</span>
<span class="nb">export</span> <span class="nv">DISPLAY</span><span class="o">=</span><span class="s2">":0.0"</span>
<span class="nb">export</span> <span class="nv">HOME</span><span class="o">=</span><span class="s2">"/home/me"</span>
<span class="c1">#Urgency</span>
<span class="nv">infoUrgency</span><span class="o">=</span><span class="s1">'low'</span>
<span class="nv">warningUrgency</span><span class="o">=</span><span class="s1">'normal'</span>
<span class="nv">errorUrgency</span><span class="o">=</span><span class="s1">'critical'</span>
<span class="nv">securityUrgency</span><span class="o">=</span><span class="s1">'critical'</span>
<span class="c1">#Popup time</span>
<span class="nv">infoPopupTime</span><span class="o">=</span><span class="m">5000</span>
<span class="nv">warningPopupTime</span><span class="o">=</span><span class="m">8000</span>
<span class="nv">errorPopupTime</span><span class="o">=</span><span class="m">11000</span>
<span class="nv">securityPopupTime</span><span class="o">=</span><span class="m">11000</span>
<span class="c1">#Icons</span>
<span class="nv">infoIcon</span><span class="o">=</span><span class="s1">'/usr/share/icons/gnome/32x32/status/dialog-information.png'</span>
<span class="nv">warningIcon</span><span class="o">=</span><span class="s1">'/usr/share/icons/gnome/32x32/status/dialog-warning.png'</span>
<span class="nv">errorIcon</span><span class="o">=</span><span class="s1">'/usr/share/icons/gnome/32x32/status/dialog-error.png'</span>
<span class="nv">securityIcon</span><span class="o">=</span><span class="s1">'/usr/share/icons/gnome/32x32/status/security-medium.png'</span>
<span class="nv">coloredLog</span><span class="o">=</span><span class="k">$(</span>tail -n <span class="m">1</span> <span class="nv">$1</span> <span class="p">|</span> <span class="se">\</span>
source-highlight --failsafe <span class="se">\</span>
--src-lang<span class="o">=</span>log <span class="se">\</span>
--style-file<span class="o">=</span>default.style <span class="se">\</span>
--outlang-def<span class="o">=</span><span class="si">${</span><span class="nv">HOME</span><span class="si">}</span>/documents/scripts/awesome.outlang<span class="k">)</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$coloredLog</span>!<span class="o">=</span><span class="s1">''</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span><span class="nb">echo</span> <span class="nv">$1</span><span class="p">|</span>grep info<span class="k">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">messageType</span><span class="o">=</span><span class="s1">'info'</span><span class="p">;</span> <span class="k">fi</span>
<span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span><span class="nb">echo</span> <span class="nv">$1</span><span class="p">|</span>grep warn<span class="k">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">messageType</span><span class="o">=</span><span class="s1">'warning'</span><span class="p">;</span> <span class="k">fi</span>
<span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span><span class="nb">echo</span> <span class="nv">$1</span><span class="p">|</span>grep err<span class="k">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">messageType</span><span class="o">=</span><span class="s1">'error'</span><span class="p">;</span> <span class="k">fi</span>
<span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span><span class="nb">echo</span> <span class="nv">$1</span><span class="p">|</span>grep auth<span class="k">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">messageType</span><span class="o">=</span><span class="s1">'security'</span><span class="p">;</span> <span class="k">fi</span>
<span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span><span class="nb">echo</span> <span class="nv">$1</span><span class="p">|</span>grep access<span class="k">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">messageType</span><span class="o">=</span><span class="s1">'security'</span><span class="p">;</span><span class="k">fi</span>
<span class="k">if</span> <span class="o">[[</span> <span class="k">$(</span><span class="nb">echo</span> <span class="nv">$notification</span><span class="p">|</span>grep <span class="s1">'UFW BLOCK INPUT'</span><span class="k">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">messageType</span><span class="o">=</span><span class="s1">'security'</span><span class="p">;</span> <span class="k">fi</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$messageType</span> <span class="o">==</span> <span class="s1">''</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nv">messageType</span><span class="o">=</span><span class="s1">'info'</span><span class="p">;</span> <span class="k">fi</span>
<span class="k">case</span> <span class="nv">$messageType</span> in
info<span class="o">)</span>
<span class="nv">urgency</span><span class="o">=</span><span class="nv">$infoUrgency</span>
<span class="nv">icon</span><span class="o">=</span><span class="nv">$infoIcon</span>
<span class="nv">popupTime</span><span class="o">=</span><span class="nv">$infoPopupTime</span>
<span class="p">;;</span>
warning<span class="o">)</span>
<span class="nv">urgency</span><span class="o">=</span><span class="nv">$warningUrgency</span>
<span class="nv">icon</span><span class="o">=</span><span class="nv">$warningIcon</span>
<span class="nv">popupTime</span><span class="o">=</span><span class="nv">$warningPopupTime</span>
<span class="p">;;</span>
error<span class="o">)</span>
<span class="nv">urgency</span><span class="o">=</span><span class="nv">$errorUrgency</span>
<span class="nv">icon</span><span class="o">=</span><span class="nv">$errorIcon</span>
<span class="nv">popupTime</span><span class="o">=</span><span class="nv">$errorPopupTime</span>
<span class="p">;;</span>
security<span class="o">)</span>
<span class="nv">urgency</span><span class="o">=</span><span class="nv">$securityUrgency</span>
<span class="nv">icon</span><span class="o">=</span><span class="nv">$securityIcon</span>
<span class="nv">popupTime</span><span class="o">=</span><span class="nv">$securityPopupTime</span>
<span class="p">;;</span>
<span class="k">esac</span>
notify-send -u <span class="nv">$urgency</span> -t <span class="nv">$popupTime</span> -i <span class="s2">"</span><span class="nv">$icon</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$coloredLog</span><span class="s2">"</span>
<span class="k">fi</span>
</pre></div>
</td></tr></table>
<p>Et voici /home/me/documents/scripts/awesome.outlang:</p>
<div class="highlight"><pre><span></span>extension "awesome"
color "<span class="nt"><span</span> <span class="na">color=</span><span class="s">\"$style\"</span><span class="nt">></span>$text<span class="nt"></span></span>"
colormap
"green" "#33CC00"
"red" "#FF0000"
"darkred" "#990000"
"blue" "#0000FF"
"brown" "#9A1900"
"pink" "#CC33CC"
"yellow" "#FFCC00"
"cyan" "#66FFFF"
"purple" "#993399"
"orange" "#FF6600"
"brightorange" "#FF9900"
"brightgreen" "#33FF33"
"darkgreen" "#009900"
"black" "#000000"
"teal" "#008080"
"gray" "#808080"
"darkblue" "#000080"
default "#66FFFF"
end
</pre></div>
<p>Je vous laisse faire joujou, je suis sûr que vous allez trouver
plein d'idées.</p>La TODO liste du pauvre2009-12-20T22:08:00+01:002009-12-20T22:08:00+01:00Toftag:blog.chmd.fr,2009-12-20:/la-todo-liste-du-pauvre.html<p>Il y a des dizaines de logiciels permettant de gérer sa TODO liste.
Paradoxalement, si on cherche quelque chose de simple, on ne trouve
pas. Ce que je cherchais à faire est on ne peut plus simple à
décrire: quelque chose qui apparaisse une fois par heure.</p>
<p>En effet, le …</p><p>Il y a des dizaines de logiciels permettant de gérer sa TODO liste.
Paradoxalement, si on cherche quelque chose de simple, on ne trouve
pas. Ce que je cherchais à faire est on ne peut plus simple à
décrire: quelque chose qui apparaisse une fois par heure.</p>
<p>En effet, le problème des notes persistantes est que l'on finit par ne
plus les voir. Pour cela, j'ai opté pour les notifications. Le principe
est simple: on met sa TODO liste dans le fichier <code>~/TODO</code>. Une fois par
heure, le contenu de ce fichier est affiché dans une bulle de notification
qui dure 10 secondes. Une façon gentille de rappeler les choses à faire,
intrusive, certe, mais à la durée assez courte pour ne pas être ennuyeuse.
Ça se fait très facilement avec le script suivant:</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env bash</span>
<span class="c1"># pour que cron sache sur quel moniteur jouer la notification</span>
<span class="nv">DISPLAY</span><span class="o">=</span>:0.0
<span class="c1">#params</span>
<span class="nv">todofile</span><span class="o">=</span><span class="nv">$HOME</span>/TODO
<span class="nv">icon</span><span class="o">=</span><span class="s1">'/usr/share/icons/gnome/32x32/status/dialog-information.png'</span>
<span class="nv">popupTime</span><span class="o">=</span><span class="m">10000</span>
<span class="nv">urgency</span><span class="o">=</span><span class="s1">'low'</span>
<span class="k">if</span> <span class="nb">test</span> -f <span class="nv">$todofile</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">notification</span><span class="o">=</span><span class="sb">`</span>cat <span class="nv">$todofile</span><span class="sb">`</span>
notify-send -u <span class="nv">$urgency</span> -t <span class="nv">$popupTime</span> -i <span class="s2">"</span><span class="nv">$icon</span><span class="s2">"</span> TODO <span class="s2">"</span><span class="nv">$notification</span><span class="s2">"</span>
<span class="k">fi</span>
</pre></div>
</td></tr></table>
<p>Le script, que j'ai nommé todo.sh est à faire invoquer toutes les
heures par une tache cron:</p>
<div class="highlight"><pre><span></span>0 * * * * sh <span class="cp">${</span><span class="n">HOME</span><span class="cp">}</span>/documents/scripts/todo.sh
</pre></div>
<p>Simple comme bonjour, et efficace. Ça fait un moment que je
l'utilise, et j'en suis satisfait.</p>Gérer ses plugins vim avec :GetLatestVimScripts2009-11-05T18:52:00+01:002009-11-05T18:52:00+01:00Toftag:blog.chmd.fr,2009-11-05:/gerer-ses-plugins-vim-avec-getlatestvimscripts.html<p>J'ai envie d'attirer l'attention sur une fonctionnalité sympa de
vim, qui pourtant semble méconnue de pas mal de monde, même des
utilisateurs avancés: la commande <code>:GetLatestVimScripts</code>, ou son
alias <code>:GLVS</code>.</p>
<p>Le principe est simple: vous installez un script pour vim, et vous voulez
que ce script se maintienne à jour …</p><p>J'ai envie d'attirer l'attention sur une fonctionnalité sympa de
vim, qui pourtant semble méconnue de pas mal de monde, même des
utilisateurs avancés: la commande <code>:GetLatestVimScripts</code>, ou son
alias <code>:GLVS</code>.</p>
<p>Le principe est simple: vous installez un script pour vim, et vous voulez
que ce script se maintienne à jour (c'est à dire que vous voulez profiter
des versions successives du script par l'auteur). Au lieu de vous embêter
à vérifier si il y a des nouvelles versions périodiquement et d'avoir à
suivre un procédé d'installation qui differera selon que vous ayez affaire
à un vimscript, un vimball, ou une quelconque archive, vous pouvez tout
simplement dire à vim de gérer tous vos scripts d'un coup. Pour cela, il
vous suffit de maintenir à jour la liste des scripts qui vous intéressent
dans le fichier <code>~/.vim/GetLatest/GetLatestVimScripts.dat</code>. Le format de
ce fichier est simple:</p>
<div class="highlight"><pre><span></span><span class="err"><numéro du script> <numéro de version installée du script> :AutoInstall: <nom du script></span>
</pre></div>
<p>Le numéro du script est dans l'url sur sourceforge, donné par <code>scriptid</code>.
La version installée du script est maintenue directement par la commande
<code>:GLVS</code>. Si vous voulez être sûr que la mise à jour soit faite, mettez 1.</p>
<p>Maintenant, votre répertoire <code>~/.vim</code> est assez facile à transporter. J'ai
pour habitude d'en garder une copie "vide", avec une arborescence sous la
forme:</p>
<div class="highlight"><pre><span></span><span class="err">\.vim/</span>
<span class="err"> |-GetLatest/</span>
<span class="err"> |-GetLatestVimScripts.dat</span>
</pre></div>
<p><em>Un test?</em></p>
<p>Vous pouvez tester l'astuce assez simplement: Sauvez votre répertoire
<code>~/.vim</code> (si vous en avez un) en le bougeant sous un autre nom, et faites
en un nouveau ou vous recréerez l'arborescence décrite précedemment.
Insérez dans GetLatestVimScripts.dat les lignes suivantes:</p>
<div class="highlight"><pre><span></span><span class="gh">ScriptID SourceID Filename</span>
<span class="gh">--------------------------</span>
# Les lignes commençant par '#' sont des commentaires
# Les deux premières lignes sont nécessaires
#
# Script permettant d'avoir une complétion grâce à la touche <tab>
# le premier numéro a été obtenu dans l'url du script:
# http://www.vim.org/scripts/script.php?script_id=1643
1643 1 :AutoInstall: supertab.vim
</pre></div>
<ul>
<li>Ouvrez vim, tapez :GLVS. Le script va se mettre à jour de
lui-même.</li>
<li>Vous pouvez tester le script, assez sympa, qui permet de
compléter les mots que vous tapez avec la touche de tabulation
(pour savoir comment ça se paramètre, lisez le script, pour
l'instant sa doc est incluse en commentaire dans le code - j'ai
proposé au mainteneur un patch avec une vraie doc vim, accessible
par :help et j'ai bon espoir qu'il l'inclue dans une future
version)</li>
<li>Fin de la démo. Vous pouvez supprimer votre répertoire .vim et
remettre votre ancienne configuration (si vous en aviez une).</li>
</ul>
<p>Une petite explication supplémentaire s'impose. Le mot clé :AutoInstall:
dans la ligne que j'ai préconisée n'est pas obligatoire. Cela vient du
fait que tous les scripts ne sont pas installables automatiquement (mais
tous sont téléchargeables automatiquement). Cela dit, les scripts
sourceforge sont assez standards et la plupart seront autoinstallables
même si l'auteur du script ne connaissait pas la fonctionnalité. Si jamais
votre script ne s'installe pas correctement, vous pouvez écrire à son
auteur afin qu'il le modifie (ça marche, je l'ai fait <a href="http://slinky.imukuppi.org/2009/10/24/zenburn-v2-13/">récemment</a> avec
<a href="http://www.vim.org/scripts/script.php?script_id=415">zenburn</a> en aidant son auteur à le mettre sous forme de vimball) et en
attendant, retirer ce mot clé.</p>
<p>En espérant que ça serve... En bonus, voici la liste des plugins
que j'utilise. C'est très orienté C++. Mon conseil, c'est de vous
abonner au flux rss de vim.org, comme ça vous serez au courant des
plugins sympa qui sortent.</p>
<div class="highlight"><pre><span></span><span class="gh">ScriptID SourceID Filename</span>
<span class="gh">--------------------------</span>
39 1 :AutoInstall: matchit.zip
40 1 :AutoInstall: Drawit.vim
273 1 :AutoInstall: taglist.zip
294 1 :AutoInstall: Align.vim
302 1 :AutoInstall: AnsiEsc.vim
415 1 :AutoInstall: zenburn.vim
489 1 :AutoInstall: Manpageview.vim
610 1 :AutoInstall: ctags.vim
642 1 :AutoInstall: getscript.vim
1066 1 :AutoInstall: cecutil.vim
1075 1 :AutoInstall: netrw.vim
1116 1 :AutoInstall: maplesyrup.tar.gz
1195 1 :AutoInstall: vis.vba.gz
1502 1 :AutoInstall: vimball.vim
1506 1 :AutoInstall: LargeFile.vim
1520 1 :AutoInstall: omnicppcomplete.zip
1643 1 :AutoInstall: supertab.vim
1658 1 :AutoInstall: NERD_tree.zip
1697 1 :AutoInstall: surround.vim
2136 1 :AutoInstall: repeat.vim
2164 1 :AutoInstall: renamec.vim
2527 1 :AutoInstall: jpythonfold.vim
2540 1 :AutoInstall: snipMate.zip
2645 1 :AutoInstall: colourscheme_bandit.vim
2646 1 :AutoInstall: ctags_highlighting.vba
</pre></div>gdb 7.0 est sorti, c'est une merveille et vous ne le saviez pas.2009-10-06T19:19:00+02:002009-10-06T19:19:00+02:00Toftag:blog.chmd.fr,2009-10-06:/gdb-70-est-sorti-cest-une-merveille-et-vous-ne-le-saviez-pas.html<p>L'annonce vient de tomber sur la mailing liste : gdb vient de sortir dans
sa version 7.0! Vous vous dîtes: "Bof, gdb je connais, une nouvelle
version d'un débogueur qui sort, il n'y a pas de quoi fouetter un chat."
Détrompez-vous! Les progrès apportés sont tels que je n'allais pas …</p><p>L'annonce vient de tomber sur la mailing liste : gdb vient de sortir dans
sa version 7.0! Vous vous dîtes: "Bof, gdb je connais, une nouvelle
version d'un débogueur qui sort, il n'y a pas de quoi fouetter un chat."
Détrompez-vous! Les progrès apportés sont tels que je n'allais pas vous
laisser les ignorer. Je veux bien entendu parler du "reverse debugging".
Hein? C'est quoi? Bon, j'explique : normalement, dans un debugger (ou un
"débogueur", en bon français), on déroule le programme toujours dans le
même sens. Et ben maintenant, on a la possibilité de revenir en arrière!
Dans le concept, c'est un peu comme rembobiner un film, mais pour un
programme. Donc voilà, par exemple, on avait "c" pour "continue", on a
maintenant "rc" pour "reverse continue".</p>
<p>Bon, ça paye pas de mine, comme ça, mais à faire c'est probablement assez
compliqué. Ça fait tellement longtemps qu'on parle d'ajouter cela dans gdb
que ça justifie amplement le passage direct de 6.8 à 7.0 dans les numéros
de versions. Ça explique aussi pourquoi les développeurs la qualifiaient
d'avance de "major release".</p>
<p>Là, on marque une pause et on s'incline. Ceux qui savent comment
fonctionne un ordinateur se demandent comment ça peut bien marcher (allez
regarder le code source, les gars). On se rend compte de l'exploit
technique que ça doit représenter, on y ajoute une petite réflexion sur le
nombre d'architectures que le machin supporte, et on se dit que
décidemment il y a des gens très forts.</p>
<p>Je ne m'arrête pas en si bon chemin. Ceux qui ont tenté d'utiliser gdb ont
probablement aussi un assez mauvais souvenir de la maniabilité du
programme. C'est pas très, comment dire... "user friendly". Bon, pour
répondre à ces gens là je ne vous promets pas de miracle, mais sachez que
gdb est devenu scriptable en python. Ça promet d'améliorer sérieusement sa
souplesse, mais aussi, mon petit doigt me dit qu'on devrait probablement
voir de nouveaux front-end ultra souples voir le jour. Voilà pour mes
features préférées, mais il y en a d'autres. Je vous lie la fameuse
annonce, qui vaut son pesant de cacahuètes. Vivement que ma distribution
le package.</p>
<p><a href="http://www.gnu.org/software/gdb/download/ANNOUNCEMENT">L'annonce</a>
<a href="http://sourceware.org/gdb/download/onlinedocs/gdb_7.html#SEC51">La nouvelle doc sur le reverse debugging</a></p>autotools, doxygen, et génération conditionnelle2009-07-10T12:54:00+02:002009-07-10T12:54:00+02:00Toftag:blog.chmd.fr,2009-07-10:/autotools-doxygen-et-generation-conditionnelle.html<p>On m'a donné une astuce bien sympa pour générer de la documentation
de manière conditionnelle avec doxygen. J'utilise ça dans le projet
que je code au boulot, et je pense que ça vaut le coup de partager.
L'idée est de générer la documentation automatiquement à chaque
compilation de mon projet …</p><p>On m'a donné une astuce bien sympa pour générer de la documentation
de manière conditionnelle avec doxygen. J'utilise ça dans le projet
que je code au boulot, et je pense que ça vaut le coup de partager.
L'idée est de générer la documentation automatiquement à chaque
compilation de mon projet, en faisant appel aux features avancées
de doxygen en fonction des outils dont dispose l'utilisateur : dot,
htags, perl, etc... On va donc vérifier quels programmes sont
présents grâce au configure.ac, et on va générer le doxyfile en
fonction desquels sont présents. L'exemple que je donne n'est pas
complet, mais vous pouvez vous en inspirer: Fichier configure.ac</p>
<div class="highlight"><pre><span></span><span class="n">AC_CHECK_PROG</span><span class="p">(</span><span class="o">[</span><span class="n">DOT</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">dot</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">yes</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">no</span><span class="o">]</span><span class="p">)</span><span class="w"></span>
<span class="n">AC_CHECK_PROG</span><span class="p">(</span><span class="o">[</span><span class="n">HTAGS</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">htags</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">yes</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">no</span><span class="o">]</span><span class="p">)</span><span class="w"></span>
<span class="n">AC_PATH_PROG</span><span class="p">(</span><span class="o">[</span><span class="n">PERL</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">perl</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="err">[]</span><span class="p">)</span><span class="w"></span>
<span class="n">AM_CONDITIONAL</span><span class="p">(</span><span class="o">[</span><span class="n">DOXYGEN</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">test "x$doxygen_ok" = xyes</span><span class="o">]</span><span class="p">)</span><span class="w"></span>
<span class="n">AM_CONDITIONAL</span><span class="p">(</span><span class="o">[</span><span class="n">DOT</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">test "x$dot_ok" = xyes</span><span class="o">]</span><span class="p">)</span><span class="w"></span>
<span class="n">AC_CONFIG_FILES</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">doc</span><span class="o">/</span><span class="n">doxygen_html</span><span class="p">.</span><span class="n">cfg</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>
</pre></div>
<p>Ensuite, il suffit de glisser les bonnes références dans le fichier
doc/doxygen_html.cfg.in :</p>
<div class="highlight"><pre><span></span><span class="err">USE_HTAGS = @HTAGS@</span>
<span class="err">PERL_PATH = @PERL@</span>
<span class="err">HAVE_DOT = @DOT@</span>
</pre></div>
<p>Ainsi, après l'appel de ./configure, le fichier doxygen_html.cfg
va être généré, et les expressions entre @ vont y être remplacées
par les bonnes valeurs. Vous pourrez ensuite vous servir de ce
fichier pour véritablement générer la doc...</p>Mettre des couleurs un peu partout (gcc, diff, grep...)2009-06-19T21:31:00+02:002009-06-19T21:31:00+02:00Toftag:blog.chmd.fr,2009-06-19:/mettre-des-couleurs-un-peu-partout-gcc-diff-grep.html<p>Aujourd'hui, après avoir passé un bout de temps à déchiffrer la
sortie d'une compilation, je me suis mis en quête d'améliorer mon
quotidien et d'y mettre... des couleurs! Pour ce faire, on cherche
un peu ce qui existe déjà, et on tombe sur colorgcc. C'est
disponible sur pas mal de …</p><p>Aujourd'hui, après avoir passé un bout de temps à déchiffrer la
sortie d'une compilation, je me suis mis en quête d'améliorer mon
quotidien et d'y mettre... des couleurs! Pour ce faire, on cherche
un peu ce qui existe déjà, et on tombe sur colorgcc. C'est
disponible sur pas mal de distributions, c'est juste un script perl
à appeler à la place de gcc, et ça rajoute des couleurs. Pour en
profiter, il suffit de glisser dans vos Makefile</p>
<div class="highlight"><pre><span></span><span class="err">CXX=/usr/bin/colorgcc</span>
</pre></div>
<p>Avec les autotools, on peut régler ça à l'invocation du script
configure :</p>
<div class="highlight"><pre><span></span><span class="err">./configure CXX=/usr/bin/colorgcc</span>
</pre></div>
<p>Bon. Pas mal. Maintenant, les diff. Au boulot, je n'ai pas mieux
sous la main qu'un svn comme gestionnaire de version. Quand je me
tape des svn diff, j'aime bien que ça soit un peu lisible. Et si on
se mettait ça en couleurs? En lisant un peu la doc, on voit qu'il
suffit de se faire un script. Mettons diffwrap.sh.</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/bin/sh</span>
<span class="c1"># Configure your favorite diff program here.</span>
<span class="nv">DIFF</span><span class="o">=</span><span class="s2">"/usr/bin/colordiff"</span>
<span class="c1"># Subversion provides the paths we need as the sixth and seventh</span>
<span class="c1"># parameters.</span>
<span class="nv">LEFT</span><span class="o">=</span><span class="si">${</span><span class="nv">6</span><span class="si">}</span>
<span class="nv">RIGHT</span><span class="o">=</span><span class="si">${</span><span class="nv">7</span><span class="si">}</span>
<span class="c1"># Call the diff command</span>
<span class="nv">$DIFF</span> <span class="nv">$LEFT</span> <span class="nv">$RIGHT</span>
<span class="c1"># Return an errorcode of 0 if no differences were detected, 1 if some were.</span>
<span class="c1"># Any other errorcode will be treated as fatal.</span>
</pre></div>
</td></tr></table>
<p>J'ai installé colordiff pour faire le boulot. Il suffit après
d'éditer \~/.subversion/config, et d'ajouter, section [helpers]</p>
<div class="highlight"><pre><span></span><span class="err">diff-cmd = /path/to/diffwrap.sh</span>
</pre></div>
<p>Bon ok, mais quand je fais make, j'ai toujours beaucoup de sortie
Il n'y aurait pas moyen de se cantonner aux erreurs gcc lorsqu'il y
en a? Aller, on va baisser un peu ça avec un petit peu (le -j3 est
pour multithreader le make : j'ai un dual core, autant en
profiter).</p>
<div class="highlight"><pre><span></span><span class="err">alias make='make -j3 -s'</span>
</pre></div>
<p>Bien entendu, en tant qu'adepte de vim, j'utilise aussi beaucoup
:make. Dans le .vimrc, il peut s'avérer utile de glisser alors:</p>
<div class="highlight"><pre><span></span><span class="err">autocmd BufNewFile,BufRead,BufEnter *.cpp,*.hpp set makeprg=make\ -j3\ -s</span>
</pre></div>
<p>Au passage, j'espère que vous connaissiez
<a href="http://www.vim.org/scripts/script.php?script_id=1520">omnicppcomplete</a>,
qui va chez moi dans la même section du .vimrc:</p>
<div class="highlight"><pre><span></span><span class="err">autocmd BufNewFile,BufRead,BufEnter *.cpp,*.hpp set omnifunc=omni#cpp#complete#Main</span>
</pre></div>
<p>On combine tout ça à quelques alias assez connus, et on vit un peu
mieux dans sa console...</p>
<div class="highlight"><pre><span></span><span class="err"># SOME COLORS</span>
<span class="err">if [ -x /usr/bin/dircolors ]; then</span>
<span class="err"> eval "`dircolors -b`"</span>
<span class="err"> alias ls='ls --color=auto'</span>
<span class="err"> alias dir='dir --color=auto'</span>
<span class="err"> alias vdir='vdir --color=auto'</span>
<span class="err"> alias grep='grep --color=auto'</span>
<span class="err"> alias fgrep='fgrep --color=auto'</span>
<span class="err"> alias egrep='egrep --color=auto'</span>
<span class="err"> alias diff='colordiff'</span>
<span class="err"> alias less='less -R'</span>
<span class="err">fi</span>
</pre></div>
<p>Si vous avez des trucs utiles, n'hésitez pas! Je suis en
particulier à la recherche d'un script vim qui exploiterait un rien
les options 'errorformat' et 'QuickFixCmdPost' afin d'améliorer
encore la lisibilité des compilations dans la fenêtre quickfix.</p>vim+gdb=vimgdb2009-02-25T00:29:00+01:002009-02-25T00:29:00+01:00Toftag:blog.chmd.fr,2009-02-25:/vimgdbvimgdb.html<p>Ça faisait longtemps que je n'avais pas fait d'article, j'en profite donc
pour rendre hommage au méconnu <a href="http://clewn.sourceforge.net/">vimgdb</a>.
vimgdb est un patch pour vim qui permet de débogguer dans vim. On ne
vantera jamais assez les mérites d'un déboggeur (franchement, il y a un
stade où il faut arrêter les …</p><p>Ça faisait longtemps que je n'avais pas fait d'article, j'en profite donc
pour rendre hommage au méconnu <a href="http://clewn.sourceforge.net/">vimgdb</a>.
vimgdb est un patch pour vim qui permet de débogguer dans vim. On ne
vantera jamais assez les mérites d'un déboggeur (franchement, il y a un
stade où il faut arrêter les <code>fprintf(stdout, "kikoo")</code> et les <code>cout
<<"lol"</code>), que ce soit parce que c'est franchement plus élégant, que c'est
plus le pratique quand on maitrise, ou parce que c'est mille fois plus
puissant.</p>
<p>Alors, me direz-vous, chers adeptes de gvim, qu'il existe déjà un plugin
pour vim nommé <a href="http://clewn.sourceforge.net/">clewn</a> (ou voir mieux,
<a href="http://pyclewn.wiki.sourceforge.net/">pyclewn</a>) qui fait la même chose
sans se taper de recompilation intempestive de son éditeur favori. Eh bien
moi je vous répond: oui mais dans gvim on ne peut pas retrouver le shell
en tapant Ctrl-Z (ce qui met vim en arrière-plan) et c'est un sérieux
handicap pour les gens comme moi qui apprécient énormément cette feature
(au fait, fg est votre ami si vous découvrez en lisant l'article et que
vous ne savez pas comment revenir à vim).</p>
<p>Malheureusement, le paquet fait défaut sur la plupart des distrib (sauf
archlinux, où je me suis permis de l'ajouter dans
<a href="http://aur.archlinux.org/packages.php?O=0&K=vimgdb&do_Search=Go">AUR</a> --
si vous avez des suggestions pour améliorer le PKGBUILD, n'hésitez pas).
Vous pouvez donc vous inspirer dudit PKGBUILD pour <a href="http://clewn.sourceforge.net/install.html">compiler votre
version</a>, ou suivre les
indications du site (je vais pas vous dire comment compiler un programme,
quand même!). Après, en installant le plugin vim pour gdb (comme indiqué
dans la procédure du lien précédent), vous avez accès à tout un cas de
commandes sympa (<code>:help gdb</code> pour l'aide), qui permettent de voir vos
variables et de suivre le déroulement des opérations dans l'éditeur. Cool,
non? Preuve que c'est bien pensé, je n'ai eu à changer aucun des
raccourcis par défaut (J'ai juste changé un <code>where</code> en <code>where all</code> dans
.vim/macros/gdb_mappings.vim). Evidemment, il est aussi possible
d'ajouter ses propres mappings ou de modifier ceux qui sont fournis.</p>
<p>N'oubliez pas de rajouter run macros/gdb_mappings.vim dans votre .vimrc!
Je vous suggère aussi de vous renseigner sur gdb et de suivre le tuto de
<a href="http://dirac.org/linux/gdb/">Peter Jay Salzman</a>, qui m'a bien initié.
Pour ma part, je conserve aussi dans un coin <a href="http://www.unknownroad.com/rtfm/gdbtut/gdbtoc.html">un excellent
lien</a> qui me sert de
référence en cas de trou de mémoire... Bon déboggage! Si vous souhaitez
des screenshots, regardez <a href="http://sourceforge.net/project/screenshots.php?group_id=111038">par
là</a>...</p>
<p>PS: apparemment mon PKGBUILD a été marqué "out of date", je vais
corriger ça dès que possible...</p>l'UML automatisé et le libre : c'est pas gagné!2008-06-08T16:34:00+02:002008-06-08T16:34:00+02:00Toftag:blog.chmd.fr,2008-06-08:/luml-automatise-et-le-libre-cest-pas-gagne.html<p>Je recherche en ce moment des outils qui me permettraient
d'importer/exporter de l'<a href="http://fr.wikipedia.org/wiki/Unified_Modeling_Language">uml</a> pour un projet C++ que je vais faire cet
été. L'idée est la suivante : je souhaiterais que les modifications de mon
code soient répercutées sur un fichier contenant de l'uml sous un format
quelconque, et …</p><p>Je recherche en ce moment des outils qui me permettraient
d'importer/exporter de l'<a href="http://fr.wikipedia.org/wiki/Unified_Modeling_Language">uml</a> pour un projet C++ que je vais faire cet
été. L'idée est la suivante : je souhaiterais que les modifications de mon
code soient répercutées sur un fichier contenant de l'uml sous un format
quelconque, et je souhaiterais par ailleurs pouvoir générer du code à
partir de ce format. Idéalement, une règle dans le Makefile, appelée à
chaque génération du projet serait idéale pour ce genre de truc. À moins
que j'ai mal compris, Umbrello est bien capable de générer du code, mais
malheureusement l'import est une autre histoire : si celui-ci est bien
capable d'importer une classe à partir du C++, en revanche il ne génère
aucun diagramme (voir <a href="http://docs.kde.org/stable/en_GB/kdesdk/umbrello/code-import.html">la page consacrée de l'aide</a>):</p>
<blockquote>
<p>Note that Umbrello UML Modeller will not create any kind of Diagram
for showing your classes, they will only be imported into your
Model so that you can use them later in any diagram you want.</p>
</blockquote>
<p>J'ai aussi jeté un coup d'oeil du côté d'ArgoUml. Malheureusement,
de ce côté non plus c'est pas la panacée puisqu'ici on ne parle que
de java : moi, je veux du C++.</p>
<blockquote>
<p>What is ArgoUML?
~ [...] ArgoUML also has the ability to reverse engineer
compiling Java code and generate UML diagrams for it.
</p>
</blockquote>
<p>En allant inspecter les moteurs de recherche, j'ai fini par tomber
sur un outil intéressant:<a href="http://dia2code.sourceforge.net/index.html">dia2code</a>. Celui-ci
prend en entrée un schéma uml en dia, et génère du code dans le
langage choisi. J'ai regardé la section
<a href="http://dia2code.sourceforge.net/examples.html">examples</a> du site,
c'est assez convaincant. Pour ce schéma :</p>
<p><img alt="uml_dia.png" src="images/uml_dia.png"></p>
<p>Les fichiers suivants seront générés :</p>
<p>foowindow.cpp 1/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"foowindow.h"</span><span class="cp"></span>
<span class="kt">void</span> <span class="n">FooWindow</span><span class="o">::</span><span class="n">redraw</span> <span class="p">(</span> <span class="p">){</span>
<span class="p">}</span>
</pre></div>
<p>foowindow.h 2/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef FOOWINDOW_H</span>
<span class="cp">#define FOOWINDOW_H</span>
<span class="cp">#include</span> <span class="cpf">"window.h"</span><span class="cp"></span>
<span class="n">class</span> <span class="nl">FooWindow</span><span class="p">:</span> <span class="n">public</span> <span class="n">Window</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="c1">// Attributes</span>
<span class="c1">// Operations</span>
<span class="nl">public</span><span class="p">:</span>
<span class="kt">void</span> <span class="n">redraw</span> <span class="p">(</span> <span class="p">);</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>foowindowmanager.cpp 3/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"foowindowmanager.h"</span><span class="cp"></span>
</pre></div>
<p>foowindowmanager.h 4/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef FOOWINDOWMANAGER_H</span>
<span class="cp">#define FOOWINDOWMANAGER_H</span>
<span class="cp">#include</span> <span class="cpf">"windowmanager.h"</span><span class="cp"></span>
<span class="n">class</span> <span class="nl">FooWindowManager</span><span class="p">:</span> <span class="n">public</span> <span class="n">WindowManager</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="c1">// Attributes</span>
<span class="c1">// Operations</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>point.cpp 5/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"point.h"</span><span class="cp"></span>
<span class="n">Point</span><span class="o">::</span><span class="n">Point</span> <span class="p">(</span> <span class="kt">float</span> <span class="n">x</span><span class="p">,</span> <span class="kt">float</span> <span class="n">y</span> <span class="p">){</span>
<span class="p">}</span>
<span class="kt">float</span> <span class="n">Point</span><span class="o">::</span><span class="n">getX</span> <span class="p">(</span> <span class="p">){</span>
<span class="p">}</span>
<span class="kt">float</span> <span class="n">Point</span><span class="o">::</span><span class="n">getY</span> <span class="p">(</span> <span class="p">){</span>
<span class="p">}</span>
</pre></div>
<p>point.h 6/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef POINT_H</span>
<span class="cp">#define POINT_H</span>
<span class="n">class</span> <span class="n">Point</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="c1">// Attributes</span>
<span class="nl">private</span><span class="p">:</span>
<span class="kt">float</span> <span class="n">x</span><span class="p">;</span>
<span class="kt">float</span> <span class="n">y</span><span class="p">;</span>
<span class="c1">// Operations</span>
<span class="nl">public</span><span class="p">:</span>
<span class="n">Point</span> <span class="p">(</span> <span class="kt">float</span> <span class="n">x</span><span class="p">,</span> <span class="kt">float</span> <span class="n">y</span> <span class="p">);</span>
<span class="kt">float</span> <span class="nf">getX</span> <span class="p">(</span> <span class="p">);</span>
<span class="kt">float</span> <span class="nf">getY</span> <span class="p">(</span> <span class="p">);</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>rectangle.cpp 7/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"rectangle.h"</span><span class="cp"></span>
<span class="kt">float</span> <span class="n">Rectangle</span><span class="o">::</span><span class="n">getArea</span> <span class="p">(</span> <span class="p">){</span>
<span class="p">}</span>
</pre></div>
<p>rectangle.h 8/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef RECTANGLE_H</span>
<span class="cp">#define RECTANGLE_H</span>
<span class="cp">#include</span> <span class="cpf">"point.h"</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">"shape.h"</span><span class="cp"></span>
<span class="n">class</span> <span class="nl">Rectangle</span><span class="p">:</span> <span class="n">public</span> <span class="n">Shape</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="n">Point</span> <span class="n">points</span><span class="p">;</span>
<span class="c1">// Attributes</span>
<span class="c1">// Operations</span>
<span class="nl">public</span><span class="p">:</span>
<span class="kt">float</span> <span class="n">getArea</span> <span class="p">(</span> <span class="p">);</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>shape.cpp 9/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"shape.h"</span><span class="cp"></span>
</pre></div>
<p>shape.h 10/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef SHAPE_H</span>
<span class="cp">#define SHAPE_H</span>
<span class="n">class</span> <span class="n">Shape</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="c1">// Attributes</span>
<span class="c1">// Operations</span>
<span class="nl">public</span><span class="p">:</span>
<span class="n">virtual</span> <span class="kt">float</span> <span class="n">getArea</span> <span class="p">(</span> <span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>window.cpp 11/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"window.h"</span><span class="cp"></span>
</pre></div>
<p>window.h 12/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef WINDOW_H</span>
<span class="cp">#define WINDOW_H</span>
<span class="cp">#include</span> <span class="cpf">"shape.h"</span><span class="cp"></span>
<span class="n">class</span> <span class="n">Window</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="c1">// Attributes</span>
<span class="nl">private</span><span class="p">:</span>
<span class="n">Shape</span> <span class="n">visualrep</span><span class="p">;</span>
<span class="c1">// Operations</span>
<span class="nl">public</span><span class="p">:</span>
<span class="n">virtual</span> <span class="kt">void</span> <span class="n">redraw</span> <span class="p">(</span> <span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>windowmanager.cpp 13/14</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">"windowmanager.h"</span><span class="cp"></span>
</pre></div>
<p>windowmanager.h 14/14</p>
<div class="highlight"><pre><span></span><span class="cp">#ifndef WINDOWMANAGER_H</span>
<span class="cp">#define WINDOWMANAGER_H</span>
<span class="cp">#include</span> <span class="cpf">"window.h"</span><span class="cp"></span>
<span class="n">class</span> <span class="n">WindowManager</span> <span class="p">{</span>
<span class="c1">// Associations</span>
<span class="n">Window</span> <span class="n">windows</span><span class="p">;</span>
<span class="c1">// Attributes</span>
<span class="c1">// Operations</span>
<span class="p">};</span>
<span class="cp">#endif</span>
</pre></div>
<p>Pas mal. Il y a de l'idée. Maintenant, cherchons s'il existe le procédé
inverse. J'ai trouvé trois outils capables de générer de l'uml dia à
partir du C++ : <a href="http://cpp2dia.sourceforge.net/">cpp2dia</a>, <a href="http://www.aarontrevena.co.uk/opensource/autodia/index.html">autodia</a>, et <a href="http://medoosa.sourceforge.net/">medoosa</a>. Autant vous
dire tout de suite que rien de spécialement convaincant ne sort de ces
programmes.</p>
<ul>
<li>Le dernier de ces 3 à avoir été mis à jour semble être autodia
(2007). Autodia est un script perl qui peut parser plusieurs
langage, mais il semblerait que le module C++ soit buggué. D'abord,
la sortie est immonde et complètement enchevêtrée. Mais ça, ça
s'édite avec dia (du moment que les associations sont bonnes, moi
je suis content). Ensuite il prend mal les noms des classes
puisqu'il m'a embarqué l'accolade ouvrante à chaque génération de
classe (Je le soupçonne en fait d'avoir oublié de gérer les
namespaces). J'ai tout de même écrit à l'auteur pour lui signaler
le problème.</li>
<li>cpp2dia est celui qui n'a pas été mis à jour depuis le plus de
temps (mai 2003). Cependant, les
<a href="http://cpp2dia.sourceforge.net/screenshots.html">screenshots</a> ont
l'air sympa. C'est un script tcl que j'ai réussi à faire marcher,
mais qui ne m'a pas du tout donné le même genre de résultat que ce
qu'on peut voir sur le site. Pourtant, l'idée est intéressante : au
lieu de parser le programme lui-même, il se sert des ctags pour
récupérer ce qui l'intéresse, comptant ainsi sur un programme qui
marche assez bien et auquel on peut résolument faire confiance. Par
ailleurs, il utilise neato (qui fait partie de
<a href="http://www.graphviz.org/">graphviz</a>) pour organiser le tout, donc
la sortie est nettement plus lisible. Malheurleusement, j'ai eu
beau traffiquer mon \~/.cpp2diarc, dans tous les sens, pas de bol
pour moi, les attributs ne sont pas pris en compte (J'ai aussi
contacté l'auteur pour lui demander s'il avait une astuce).</li>
<li>Il reste medoosa, sans doute le plus élaboré des trois, mais
non véritablement mieux maintenu que cpp2dia (août 2003 pour la
dernière release). Ce programme a été écrit par un thésard, et sait
lui aussi produire des
<a href="http://medoosa.sourceforge.net/medoosa-model.ps">sorties</a> assez
sexy. L'idée originale est que celui-ci se sert de ccdoc, un
utilitaire de documentation à la doxygen, pour générer le graphe.
Malheureusement, il faut une vieille version de ccdoc (la 0.7a)
pour le faire marcher, et j'ai été incapable de trouver celle-ci en
téléchargement (encore une fois, j'ai contacté l'auteur pour lui
signaler ce problème, lui conseillant de s'arranger avec les
auteurs de ccdoc pour qu'ils remettent une vieille version en
ligne, car cela nuit à son programme).</li>
</ul>
<p>Conclusion: rien de bien convaincant pour l'instant. Cependant, je n'avais
pas encore regardé bouml et je viens de voir qu'ils mentionnaient le genre
de fonctionnalités que je recherche. Quelqu'un a testé? Ou bien dans le
cas général, connaissez-vous un quelque chose capable de faire mon
bonheur?</p>Les lecteurs de flux rss, en ligne, indépendants, libres (suite).2008-05-02T18:51:00+02:002008-05-02T18:51:00+02:00Toftag:blog.chmd.fr,2008-05-02:/les-lecteurs-de-flux-rss-en-ligne-independants-libres-suite.html<p>Hier, j'expliquais pourquoi je préférais de loin utiliser un
lecteur de flux rss en ligne et je donnais un petit panorama des
web-agregator libres que j'avais pu découvrir. J'ai fait ma petite
étude, et tiny tiny rss sort à mon avis grand gagnant. D'abord,
comme rien ne vaut un petit …</p><p>Hier, j'expliquais pourquoi je préférais de loin utiliser un
lecteur de flux rss en ligne et je donnais un petit panorama des
web-agregator libres que j'avais pu découvrir. J'ai fait ma petite
étude, et tiny tiny rss sort à mon avis grand gagnant. D'abord,
comme rien ne vaut un petit essai pour se faire une idée, voici des
liens vers les versions de démo que j'ai pu trouver :</p>
<p>Tiny tiny rss -> [<a href="http://tt-rss.org/trac/">site</a>]
[<a href="http://tt-rss.org/demo/tt-rss.php">démo</a>] :</p>
<ul>
<li>Sait aggréger plusieurs flux pour en former un seul dont vous
pourrez donner l'adresse à vos amis</li>
<li>Peut marcher sous PostgreSQL comme sur MySQL</li>
<li>Gestion des tags par des règles de filtrage très facile à
utiliser</li>
<li>Sait s'autentifier pour lire des flux protégés (autentification
simple, le https n'est pas encore supporté)</li>
<li>navigation clavier intuitive (vim-like, comme gmail)</li>
<li>bénéficie d'une
<a href="https://addons.mozilla.org/firefox/3342/">extension firefox pour les notifications</a></li>
<li>développement très actif</li>
<li>installation difficile chez free (bug dans l'importation
d'opml, voir les commentaires du billet précédent pour corriger ça,
et les tags ne marchent pas du tout)</li>
</ul>
<p>gregarius -> [<a href="http://tt-rss.org/trac/">site</a>]
[<a href="http://tt-rss.org/demo/tt-rss.php">démo</a>] :</p>
<ul>
<li>ne marche qu'avec mysql, mais par contre buggue moins</li>
<li>un énorme avantage : supporte des thèmes et des plugins divers
et variés</li>
<li>La navigation clavier est moins intuitive et moins complète</li>
<li>installation super facile</li>
<li>a aussi une bonne intégration avec firefox, mais pas de système
de notification.</li>
<li>développement moins actif</li>
</ul>
<p>Je n'ai pas trouvé de version de test disponible pour feed on feeds
->[<a href="http://tt-rss.org/trac/">site</a>]. Sachez que Feed on feeds est
assez vieux et que son développement est apparemment arrêté. Il a
donné lieu à deux projets : FoFredux
->[<a href="http://tt-rss.org/trac/">site</a>]
[<a href="http://tt-rss.org/demo/tt-rss.php">démo</a>] et à MonkeyChow
->[<a href="http://tt-rss.org/trac/">site</a>], pour lequel je dispose
simplement d'un <a href="http://www.shokk.com/mc.html">screencast</a> (en
flash, beurk). Je n'ai pas poussé beaucoup mes tests, car aucun
d'eux n'a vu de nouvelle version sortir depuis 2006, ce qui est
selon moi trop vieux pour espérer voir maintenus ces projets qui
semblent par ailleurs assez prometteurs. En résumé, je ne retiens
que deux projets : Tiny tiny rss et gregarius. Même si gregarius et
beaucoup plus facile à installer, plus stable et bénéficie d'un
très bon système de plugins, ma préférence se porte sur Tiny tiny
rss, qui a un développement plus dynamique, et surtout dont
l'interface se révèle bien plus agréable et rapide à utiliser : si
j'ai un lecteur de flux rss, c'est pour gagner en productivité.</p>Les lecteurs de flux rss en ligne libres2008-05-01T15:19:00+02:002008-05-01T15:19:00+02:00Toftag:blog.chmd.fr,2008-05-01:/les-lecteurs-de-flux-rss-en-ligne-libres.html<p>Aujourd'hui, Samuel Martin a fait <a href="http://blog.creaone.fr/post/2008/04/30/10-bonnes-raisons-dutiliser-Liferea-:-Lecteur-de-fils-rss/atom">un billet</a> que j'ai trouvé assez
intéressant sur les avantages de liferea. J'avoue qu'il y a de bons
arguments, notamment le contrôle sur les données personnelles qu'on a avec
un tel lecteur et qu'on n'a pas chez les fournisseurs de services en
ligne.</p>
<p>Cela ne …</p><p>Aujourd'hui, Samuel Martin a fait <a href="http://blog.creaone.fr/post/2008/04/30/10-bonnes-raisons-dutiliser-Liferea-:-Lecteur-de-fils-rss/atom">un billet</a> que j'ai trouvé assez
intéressant sur les avantages de liferea. J'avoue qu'il y a de bons
arguments, notamment le contrôle sur les données personnelles qu'on a avec
un tel lecteur et qu'on n'a pas chez les fournisseurs de services en
ligne.</p>
<p>Cela ne me fera pas pour autant passer à liferea, car le problème
majeur qu'il me pose est celui de son accessibilité dès qu'on utilise un
autre ordinateur. En effet, je consulte mes flux rss de beaucoup
d'endroits différents, comme par exemple les ordis de mon école. Or,
comme je n'ai pas les droits pour y installer exactement tout ce que je
veux. C'est dans ce genre de cas que j'apprécie de n'avoir besoin que d'un
navigateur web pour m'en tirer.</p>
<p>Cependant, sensible aux arguments sur la protection des données
personnelles, je me suis demandé s'il n'y avait pas un moyen de me
récupérer un autre lecteur de flux rss en ligne, qui n'utiliserait pas mes
informations personelles pour le profit d'une quelconque société (me
débarassant par la même occasion du cookie google qui traine dans le cache
de mon navigateur). J'ai donc fait des petites recherches sur les
solutions libres à héberger sur son propre serveur. J'en ai trouvé
plusieurs, que je partage avec vous. Il faut que je regarde si c'est
possible d'en utiliser une sur mon compte free.</p>
<p><a href="http://tt-rss.org/trac/">tiny tiny rss</a>
<a href="http://gregarius.net/">gregarius</a>
<a href="http://feedonfeeds.com/">feed on feeds</a> et ses petit frères
<a href="http://fofredux.sourceforge.net/">FoFredux</a> et
<a href="http://sourceforge.net/projects/monkeychow/">Monckeyshow</a></p>
<p>Si vous en connaissez d'autres, je suis preneur...</p>Couper une vidéo et extraire une scène d'un film2008-04-07T22:28:00+02:002008-04-07T22:28:00+02:00Toftag:blog.chmd.fr,2008-04-07:/couper-une-video-et-extraire-une-scene-dun-film.html<p>Comme promis dans le dernier billet, voici comment on fait pour
extraire une scène d'un film, par exemple pour en faire un fichier
.gif (cf post précédent)... Pour cela vous utiliserez mencoder :</p>
<div class="highlight"><pre><span></span><span class="err">sudo apt-get install mencoder</span>
</pre></div>
<p>Et la syntaxe est la suivante :</p>
<div class="highlight"><pre><span></span><span class="err">mencoder -ss h:mm:ss \</span>
<span class="err"> -endpos h:mm …</span></pre></div><p>Comme promis dans le dernier billet, voici comment on fait pour
extraire une scène d'un film, par exemple pour en faire un fichier
.gif (cf post précédent)... Pour cela vous utiliserez mencoder :</p>
<div class="highlight"><pre><span></span><span class="err">sudo apt-get install mencoder</span>
</pre></div>
<p>Et la syntaxe est la suivante :</p>
<div class="highlight"><pre><span></span><span class="err">mencoder -ss h:mm:ss \</span>
<span class="err"> -endpos h:mm:ss \</span>
<span class="err"> film_origine.avi \</span>
<span class="err"> -o extrait.avi \</span>
<span class="err"> -oac copy -ovc copy</span>
</pre></div>
<ul>
<li>L'argument de -ss est le temps à partir duquel commence la
scène à extraire.</li>
<li>celui de -endpos est la durée de la scène à extraire (oui, je
sais, c'est bizarre, j'aurais plutôt mis le temps où finit la
scène)</li>
</ul>
<p>En espérant que ça vous serve! PS : Ce billet est assez court, je
compte me rattraper en en faisant un plus substantiel bientôt...</p>Faire un gif animé à partir d'un film2008-04-06T21:29:00+02:002008-04-06T21:29:00+02:00Toftag:blog.chmd.fr,2008-04-06:/faire-un-gif-anime-a-partir-dun-film.html<p>J'ai souvent vu des gens poser cette question : comment fait-on un
gif animé à partir d'un film sous ubuntu? Avec ffmpeg, rien de plus
aisé. Sous gnome, avec nautilus-actions, il vous sera même possible
de faire clic droit>générer un gif animé à partir de cette vidéo.
Commencez-donc par installer …</p><p>J'ai souvent vu des gens poser cette question : comment fait-on un
gif animé à partir d'un film sous ubuntu? Avec ffmpeg, rien de plus
aisé. Sous gnome, avec nautilus-actions, il vous sera même possible
de faire clic droit>générer un gif animé à partir de cette vidéo.
Commencez-donc par installer ffmpeg et nautilus-actions.</p>
<div class="highlight"><pre><span></span><span class="err">sudo apt-get install ffmpeg nautilus-actions</span>
</pre></div>
<p>La syntaxe pour réaliser un gif animé à partir d'un film est</p>
<div class="highlight"><pre><span></span><span class="err">ffmpeg -i fichier_entree.avi -pix_fmt rgb24 \</span>
<span class="err"> -s 120x120\</span>
<span class="err"> -r 5\</span>
<span class="err"> fichier_sortie.gif</span>
</pre></div>
<ul>
<li>Vous pouvez régler la hauteur et la largeur du fichier de
sortie en touchant au paramètre '-s 120x120' (cependant 120x120 est
une taille raisonnable pour les forums).</li>
<li>Vous pouvez régler le nombre d'image par seconde prises dans le
film d'origine en touchant au paramètre '-r 5'.</li>
</ul>
<p>Bon, maintenant, offrons-nous la possibilité de gérer tout ça à
coup de clic droit. Sous Ubuntu, si vous avez bien installé
nautilus-actions, ça se passe dans
système>préférences>configuration des actions de nautilus. Faites
'Ajouter'. Configurez la nouvelle action comme suit :</p>
<p><img alt="nautilus-actions-1.png" src="images/nautilus-actions-1.png">
<img alt="nautilus-actions-2.png" src="images/nautilus-actions-2.png"></p>
<p>Ce qui est important, c'est le champ 'paramètres' :</p>
<div class="highlight"><pre><span></span><span class="err">-i %M -pix_fmt rgb24 -s 120x120 -r 5 %M.gif</span>
</pre></div>
<p>Vous pouvez désormais vous amuser à faire toute sorte de gif
animés. Le seul défaut : les fichiers produits ont le désavantage
de ne pas boucler. Heureusement, il est très facile d'y remédier
avec the gimp. Il suffit d'ouvrir le .gif, et de le ré-enregistrer
en laissant cochée l'option 'boucle infinie'... Dans un prochain
billet, je vous expliquerais comment couper votre vidéo pour
extraire une scène qui vous intéresse. Ainsi, il vous sera possible
de chainer les deux méthodes pour faire exactement le gif que vous
voulez.</p>