tag:blogger.com,1999:blog-277736482024-03-19T07:27:30.424+01:00m8t's blogSee my <small>not-too-long-not-too-short-hacky-tricky-things</small>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.comBlogger88125tag:blogger.com,1999:blog-27773648.post-68101556411618422752014-01-05T16:45:00.000+01:002014-01-05T17:11:04.111+01:00Remote notificationsThis post explains how to get notifications (libnotify) from a remote system. Typically this is useful with an IRC client accessible through SSH.<br />
<br />
Prerequisites:<br />
<ul>
<li>A notification daemon! (dunst, xfce4-notifyd, etc.)</li>
<li><tt>socat</tt></li>
<li><tt>notify-send</tt></li>
</ul>
<pre>apt-get install socat libnotify-bin</pre>
<br />
On the client, modify the SSH configuration to introduce two elements:<br />
<ul>
<li>forward a TCP port,</li>
<li>execute a local command.</li>
</ul>
<br />
Example entry for <tt>~/.ssh/config</tt>:<br />
<pre>Host remote-host
Hostname remote-host.gandi.net
RemoteForward 12000 localhost:12000
PermitLocalCommand yes
LocalCommand socat -u tcp4-listen:12000,reuseaddr,fork,bind=127.0.0.1 exec:$HOME/.local/bin/notify-remote.sh 2>/dev/null &
</pre>
The fowarded TCP port will be used to <tt>netcat</tt> notification messages to the local system.<br />
<br />
<tt>socat</tt> is used to bind a port on the local system, it will take the notifcation messages, and write them to the executed shell script <tt>notify-remote.sh</tt>.<br />
<br />
The shell script will then simply call <tt>notify-send</tt> to display a notification with the default notification daemon.<br />
<br />
<tt>notify-remote.sh</tt>:<br />
<pre>#!/bin/sh
delay="5000"
read line
summary="$line"
read line
msg="$line"
read line
if [ "$line" = "" ] && [ "$summary" != "" ]; then
[ -x "$(which notify-send)" ] && notify-send -u critical -t "$delay" -- "$summary" "$msg"
fi
</pre>
<br />
Now it is possible to connect to the remote host and "write" notifications:<br />
<pre>local$ ssh remote-host
remote-host$ echo -e 'Summary\nBody\n\n' | nc 127.0.0.1 12000
</pre>
<br />
<h3>Integrate into irssi</h3>
<br />
Copy the irssi script available bellow to get notifications from hilights, and private messages.<br />
<br />
Once the script is copied, execute <tt>/script load rnotify.pl</tt> inside irssi.<br />
<br />
<tt>~/.irssi/scripts/autorun/rnotify.pl</tt>:<br />
<pre>
# shamelessly copied from http://git.esaurito.net/?p=godog/bin.git;a=blob;f=rnotify.pl
use strict;
use Irssi;
use HTML::Entities;
use vars qw($VERSION %IRSSI);
$VERSION = "0.01";
%IRSSI = (
authors => 'Luke Macken, Paul W. Frields',
contact => 'lewk@csh.rit.edu, stickster@gmail.com',
name => 'rnotify',
description => 'Use libnotify to alert user to hilighted messages',
license => 'GNU General Public License',
url => 'http://lewk.org/log/code/irssi-notify',
);
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_port', '12000');
Irssi::settings_add_bool('misc', $IRSSI{'name'} . '_if_away', 0);
sub is_port_owner {
my ($port, $uid) = @_;
my $wanted = sprintf("0100007F:%04X", $port);
# XXX linux-specific
open HANDLE, "< /proc/net/tcp" || return 0;
while(<HANDLE>){
# sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
my @splitted = split /\s+/;
my $local = $splitted[2];
my $remote = $splitted[3];
my $uid = $splitted[8];
return 1 if $local eq $wanted and $uid == $<;
}
close HANDLE;
return 0;
}
sub notify {
my ($server, $summary, $message) = @_;
$message = HTML::Entities::encode($message);
$summary = HTML::Entities::encode($summary);
# echo \ escaping
$message =~ s/\\/\\\\/g;
$summary =~ s/\\/\\\\/g;
my $port = Irssi::settings_get_str($IRSSI{'name'} . '_port');
return if ! is_port_owner($port, $<);
# check for being away in every server?
return if $server->{usermode_away} &&
(Irssi::settings_get_bool($IRSSI{'name'} . '_if_away') == 0);
# XXX test for other means of doing TCP
#print("echo '$summary\n$message\n\n' | /bin/nc 127.0.0.1 $port");
system("echo '$summary\n$message\n\n' | /bin/nc 127.0.0.1 $port &");
#my $pid = open(FH, "|-");
#if( $pid ){
# print FH "$summary\n$message\n\n";
# close(FH) || warn "exited $?";
#}else{
# exec("/bin/nc 127.0.0.1 $port") || warn "can't exec $!";
#}
}
sub print_text_notify {
my ($dest, $text, $stripped) = @_;
my $server = $dest->{server};
return if (!$server || !($dest->{level} & MSGLEVEL_HILIGHT));
my $sender = $stripped;
$sender =~ s/^\<.([^\>]+)\>.+/\1/ ;
$stripped =~ s/^\<.[^\>]+\>.// ;
my $summary = "Message on $dest->{target}";
notify($server, $summary, $stripped);
}
sub message_private_notify {
my ($server, $msg, $nick, $address) = @_;
return if (!$server);
notify($server, "Private message from ".$nick, $msg);
}
sub dcc_request_notify {
my ($dcc, $sendaddr) = @_;
my $server = $dcc->{server};
return if (!$dcc);
notify($server, "DCC ".$dcc->{type}." request", $dcc->{nick});
}
Irssi::signal_add('print text', 'print_text_notify');
Irssi::signal_add('message private', 'message_private_notify');
Irssi::signal_add('dcc request', 'dcc_request_notify');
# vim: et
</pre>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com1tag:blogger.com,1999:blog-27773648.post-14384986332759634672013-08-15T10:59:00.002+02:002013-08-15T10:59:54.471+02:00rndc retransfer failed: not foundI came accross the dummy error <i><b>rndc: 'retranfer' failed: not found</b></i>, with many unhelpful articles. If you run a <i>rndc retranfer</i> command, and get this error, make sure there is an entry for the zone on the slave, it may be helpful…Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com4tag:blogger.com,1999:blog-27773648.post-41416029142159051802013-07-02T21:40:00.001+02:002013-08-15T10:32:33.847+02:00Reorder network devices set by udevIn order to reorder network devices (e.g. swap eth1 with eth2), the persistent-net rules from udev can be edited. Usually there is a file at the following location:
<br />
<pre>/etc/udev/rules.d/70-persistent-net.rules</pre>
The file contains several rules, for example:
<br />
<pre>SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="3c:ab:cd:00:ab:cd", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="3c:ab:cd:00:ab:ce", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth3"</pre>
By editing this file it is possible to change the NAME of each rule. After that, to reload the rules, simply issue this command:
<br />
<pre>udevadm control --reload-rules</pre>
<strong>Edit:</strong> you need to unload the modules first (modprobe -r e1000e for example), ensure the udev rules are reloaded, and load the modules back in. If the network drivers are built into the kernel, you need to reboot.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com3tag:blogger.com,1999:blog-27773648.post-58819300404477824562013-05-18T20:20:00.000+02:002013-05-18T20:20:03.692+02:00Making use of custom actions with Xfce AppfinderOne addition in the latest versions of Appfinder was the custom actions. I never used it until after I started typing several times twitter which didn't work (a habit from the web browser url bar).<br />
<br />
The custom actions can be useful for anything, and it's really quick to run it.<br />
<br />
Examples of custom actions:<br />
<ul>
<li>twitter: <i>xdg-open https://twitter.com/</i></li>
<li>us: <i>setxkbmap us</i></li>
</ul>
It can be very handy, check the <a href="http://docs.xfce.org/xfce/xfce4-appfinder/preferences#actions" target="_blank">online documention</a> for a quick setup. There are also <a href="http://docs.xfce.org/xfce/xfce4-appfinder/examples" target="_blank">online examples</a>, don't mind to leave a comment or to fill the bugtracker if you have clever ideas, I can add them, I just did with the <i>setxkbmap us</i> example ;-)Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com1tag:blogger.com,1999:blog-27773648.post-35899523256118799922013-03-14T18:58:00.000+01:002013-03-14T18:58:37.041+01:00Moving from Unique to GtkApplicationA new class has been introduced in GTK+3 that is <a href="https://developer.gnome.org/gtk3/stable/GtkApplication.html" target="_blank">GtkApplication</a>, and <a href="https://developer.gnome.org/gio/stable/GApplication.html" target="_blank">GApplication</a> with GIO 2.28. A common use case is to have a single window present every time the same application or command line is run, that is also known as process uniqueness. This is already possible with <a href="https://live.gnome.org/LibUnique" target="_blank">Unique</a> that was especially developed for single instance applications. This very basic post will show an example in C with Unique, and also how to do it with GtkApplication, where you will see that GtkApplication makes things even easier.<br />
<br />
First of all, the documentation available from the GIO source code doesn't give a concrete example for process uniqueness with GApplication. There are mainly examples about <a href="http://gapplication-example-actions/" target="_blank">using GApplication with GSimpleAction</a>, that is pretty cool since it lets you easily define actions to run on the primary instance outside of the process, either with the same program or a different one.
<br />
<h4>
Single window with Unique</h4>
In the following example, a UniqueApp class is instantiated, then it's checked against another running instance. If not, a window is created and a handle is connected to the UniqueApp object to react on received messages. Otherwise a message is sent, and the existing instance will execute the connected handle and put the window in front.
<br />
<pre>#include <unique/unique.h>
#include <gtk/gtk.h>
static UniqueResponse
cb_unique_app (UniqueApp *app,
gint command,
UniqueMessageData *message_data,
guint time_,
gpointer user_data)
{
GtkWidget *window = user_data;
if (command != UNIQUE_ACTIVATE)
{
return UNIQUE_RESPONSE_PASSTHROUGH;
}
gtk_window_present (GTK_WINDOW (window));
return UNIQUE_RESPONSE_OK;
}
gint main (gint argc, gchar *argv[])
{
GtkWidget *window;
UniqueApp *app;
gtk_init (&argc, &argv);
app = unique_app_new ("info.mmassonnet.UniqueExample", NULL);
if (unique_app_is_running (app))
{
if (unique_app_send_message (app, UNIQUE_ACTIVATE, NULL) == UNIQUE_RESPONSE_OK)
{
g_object_unref (app);
return 0;
}
}
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
gtk_main ();
return 0;
}
</pre>
<h4>
Single window with GtkApplication</h4>
In this example, a GtkApplication class is instantiated. This one is then registered, and a check is done to know if the running process is the primary one or a remote one. Just like in the previous example, either the process is the main one and a window is created and shown, otherwise a signal is sent and the connected handle will put the window in front. The handle used here is directly a GTK function that presents the window which spares the need to write a custom handler.
<br />
<pre>#include <gtk/gtk.h>
gint main (gint argc, gchar *argv[])
{
GtkWidget *window;
GtkApplication *app;
GError *error = NULL;
gtk_init (&argc, &argv);
app = gtk_application_new ("info.mmassonnet.GtkExample", 0);
g_application_register (G_APPLICATION (app), NULL, &error);
if (error != NULL)
{
g_warning ("Unable to register GApplication: %s", error->message);
g_error_free (error);
error = NULL;
}
if (g_application_get_is_remote (G_APPLICATION (app)))
{
g_application_activate (G_APPLICATION (app));
g_object_unref (app);
return 0;
}
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
g_signal_connect_swapped (app, "activate", G_CALLBACK (gtk_window_present), dialog);
gtk_main ();
return 0;
}
</pre>
In both examples there is just one difference, it is how the primary process is seen. With Unique there is a function to know if another instance is running, while with GtkApplication there is a function to know if the current process is not the primary one e.g. a remote instance. I prefer the second approach, since with Unique if there is only one instance running, the is_running property will tell you false but the primary instance is running, isn't it? But anyhow, as you can see, it is possible to implement painlessly what is done by Unique with GtkApplication.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com1tag:blogger.com,1999:blog-27773648.post-50756365601717592802012-12-23T12:23:00.002+01:002012-12-23T12:23:40.417+01:00Apache restart with Vim autocmdIn order to execute a command right after saving a file in Vim, you can use the <a href="http://vimdoc.sourceforge.net/htmldoc/autocmd.html" rel="nofollow" target="_blank"><i>:autocmd</i></a> command. Here is a quick example how it can be useful with Apache files.<br />
<br />
NB: on my system, Debian in this case, an Apache file is automatically recognized as <i>filetype=apache</i>.<br />
<br />
<pre>augroup apache
autocmd BufWritePost */sites-enabled/* !/etc/init.d/apache2 restart
augroup END</pre>
Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com1tag:blogger.com,1999:blog-27773648.post-85866259857484338612012-07-30T23:04:00.002+02:002012-10-25T01:42:29.850+02:00Vim and ValaI once wrote a <a href="http://blog.mmassonnet.info/2009/03/vala-notes-plugin.html">quick note</a> about <a href="https://live.gnome.org/Vala/" target="_blank">Vala</a> and <a href="http://www.vim.org/" target="_blank">Vim</a> (or Vim and Vala) and the use of the <a href="http://vim-taglist.sourceforge.net/" target="_blank">Tag List plugin</a>. Here is a clean post about these two beasts.<br />
<br />
Vim — probably the best editor out there, at least always after trying out different editors I end up with Vim — has great plugins. However there is a lack of support for the Vala language. So here are two basic add-ins to include in the Vim editor.<br />
<h4>
Vala syntax</h4>
First there is no syntax color for this language. A quick fix is to use the C# syntax with the command <span style="font-family: 'Courier New', Courier, monospace;">:set filetype=cs</span>. That works but is not ideal, ideal is to install a <span style="font-family: 'Courier New', Courier, monospace;">vala.syntax</span> file, and there is one available on <a href="https://live.gnome.org/Vala/Vim" target="_blank">this GNOME Live! page</a>.<br />
<br />
First download the file from <a href="https://live.gnome.org/Vala/Vim?action=AttachFile&do=view&target=vala.vim" target="_blank">this page</a> and save it under <span style="font-family: 'Courier New', Courier, monospace;">~/.vim/syntax/</span>. Next add the following lines to your <span style="font-family: 'Courier New', Courier, monospace;">~/.vimrc</span> file:<br />
<pre>" Filetypes
augroup filetypedetect
au! BufRead,BufNewFile *.vala,*.vapi setfiletype vala
augroup END
augroup vala
autocmd BufRead *.vala,*.vapi set tw=100 efm=%f:%1.%c-%[%^:]%#:\ %t%[%^:]%#:\ %m
augroup END
</pre>
<h4>
Tag List</h4>
Tag List is a powerful plugin that lets you explore classes or functions from a source file, also called a source code browser. The <a href="http://vim-taglist.sourceforge.net/installation.html" target="_blank">installation steps</a> are simple, they are also available bellow, and again to get it working with Vala there is a small hack to include inside the <span style="font-family: 'Courier New', Courier, monospace;">~/.vimrc</span> file.<br />
<br />
First download the latest version of taglist from <a href="http://vim.sourceforge.net/scripts/script.php?script_id=273" target="_blank">this page</a>. Then uncompress the archive with, for example, the command line:
<br />
<pre>unzip -x taglist_45.zip -d $HOME/.vim/</pre>
Then go inside <span style="font-family: 'Courier New', Courier, monospace;">~/.vim/doc</span>, run Vim and inside Vim execute the command <span style="font-family: 'Courier New', Courier, monospace;">:helptags .</span>:
<br />
<pre>cd ~/.vim/doc
vim
:helptags .
</pre>
Finally add the following lines inside <span style="font-family: 'Courier New', Courier, monospace;">~/.vimrc</span>:
<br />
<pre>" Work-around Tag List for Vala
let tlist_vala_settings='c#;d:macro;t:typedef;n:namespace;c:class;'.
\ 'E:event;g:enum;s:struct;i:interface;'.
\ 'p:properties;m:method'
</pre>
<br />
Now Vim is ready for Vala, and it's possible to browse source code by typing the command <span style="font-family: 'Courier New', Courier, monospace;">:TlistToggle</span>.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlJ-ckSTLTrPQEKRZDM4wpHLenN5NWwibWpEGF4sNutDUVL6wA8oSJRP91g3bSmvjr7OoDH_FOKnY7IGtShwdbUSGckBazim9hOX7c2-WtlZrsl9EGf8_WvIOQXhchu43scvCa/s1600/vim-vala-taglist.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Screenshot of Vim Vala Tag List" border="0" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlJ-ckSTLTrPQEKRZDM4wpHLenN5NWwibWpEGF4sNutDUVL6wA8oSJRP91g3bSmvjr7OoDH_FOKnY7IGtShwdbUSGckBazim9hOX7c2-WtlZrsl9EGf8_WvIOQXhchu43scvCa/s400/vim-vala-taglist.png" title="Screenshot of Vim Vala Tag List" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Vim Vala Tag List</td></tr>
</tbody></table>
Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com3tag:blogger.com,1999:blog-27773648.post-22447236193315052882012-01-22T11:20:00.002+01:002012-01-22T11:20:20.706+01:00.screenrcSo I pimped up my <i>.<a href="http://ddg.gg/?q=man+screen" target="_blank">screenrc</a></i>, and since it's been a long time I didn't care about my hardstatus I keep the content here just in case I need it again in a few years...<br />
<br />
<pre>defscrollback 2048
startup_message off
caption always "%{= Wk}%-w%{= KW}%f%n %t%{-}%+w"
hardstatus off
hardstatus alwayslastline
hardstatus string "%{= ky}[ %H %l ]%=%{= kg}%{+b}[ %n %t ]%-=%{= ky}[ %D %d.%m.%Y %0c ]"
screen -t irssi 0
screen -t mutt 1
screen -t bubbie 2</pre>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com0tag:blogger.com,1999:blog-27773648.post-84254995387072625442011-08-21T18:22:00.000+02:002011-08-21T18:22:42.205+02:00Xfce 4.8 with ConkyI have been following a short discussion on the IRC channel <a href="irc://irc.freenode.net/#xfce">#xfce</a> regarding an issue with the use of <a href="http://conky.sourceforge.net/">Conky</a> and transparency. I didn't use Conky for a very long time, but since I knew it was possible to have Conky perfectly running, I gave it a shot again and since I did a fresh reinitialization of Xfce on my workstation, I tweaked the configuration file to my need. Now I have it running in the background and I'll most probably keep it.<br />
<br />
The configuration I was able to get for a good working Conky window with transparency is bellow. Of course I could tell you which combination doesn't work, with the why, but since there are so many of them I simply put a working one.
<br />
<pre><b>own_window yes</b> <i># create a separate XWindow over the one from Xfdesktop</i>
<b>own_window_type desktop</b> <i># the window cannot be moved or resized</i>
<b>own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager</b> <i># make it behave like it belongs to the desktop</i>
<b>own_window_argb_visual yes</b> <i># true transparency, a compositor has to be active</i>
<b>own_window_argb_value 100</b> <i># make the background semi-transparent</i>
<b>double_buffer yes</b> <i># avoid flickering</i>
</pre>
<br />
Here is a screenshot of the desktop with Conky in the bottom right corner, I made sure there is some I/O activity going on :-)<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOvXwZW-Q_Nv1Y7XNuwdqXOqlxWO_hh0KEFQNuMNtXff6_DurKZmYLjes4wtKTp1jrTFtcW3efG-k1D_KKzfbKBNKloZqJbZzIHtECTRoZC2Jrq36YOwP92Ofey8mkLw6iYcP3/s1600/Xfce+with+Conky+2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOvXwZW-Q_Nv1Y7XNuwdqXOqlxWO_hh0KEFQNuMNtXff6_DurKZmYLjes4wtKTp1jrTFtcW3efG-k1D_KKzfbKBNKloZqJbZzIHtECTRoZC2Jrq36YOwP92Ofey8mkLw6iYcP3/s400/Xfce+with+Conky+2.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Xfce with Conky</td></tr>
</tbody></table>
Now if you want you can steal my <a href="http://bubbie.mmassonnet.info/~mike/public/.conkyrc">.conkyrc</a> file.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com65tag:blogger.com,1999:blog-27773648.post-32956788507027399562011-07-16T15:02:00.000+02:002011-07-16T15:02:41.000+02:00Analysing a phishing emailI've been hit by several <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Phishing">phishing</a> emails in a short time the last week. Having time this morning I took the initiative to look at the headers from one email and the phishing location.<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>The hosting server</b></span><br />
The domains DNS zone is hosted on a particular network just like its website. Two different servers actually, but behind it seems to be a lucrative webhosting service where you can get your domain registered although it's not a registrar. All of this is hosted in Texas.<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>The email server</b></span><br />
The email is originating from Italy. The FROM address is set up to show a truthful email (usually where you put the surname) with an inexistant email address behind that. The email address' domain name exists however and is hosted in France, but has no relation to the scam, at least the owner of this domain can't do anything about it.<br />
<br />
The Return-Path shows a real email address with a different domain name but same network anyway. The domain name shows a dummy webpage "Under construction".<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>Who to contact?</b></span><br />
All of them if you care, otherwise just let it go, because phishing pages are set up and down daily...<br />
<br />
To contact the webhosting or email server, request the <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Whois">Whois</a> information of the IP address and contact the abuse department, there is always an abuse section in the Whois of an IP address. You can also contact the domain name holder and/or look if the registrar or webhosting sevice has a dedicated abuse website page.<br />
<br />
Of course it happens that an abuse email address forwards everything to the trash can. In order to have a chance to stop the scam, it is good to contact as many services as possible.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com0tag:blogger.com,1999:blog-27773648.post-73422703768135702432011-05-27T08:11:00.001+02:002011-05-27T19:22:08.214+02:00Changing PolicyKit settings per userI have been hit twice by a required authentication on my workstation after the Wifi connection got lost and it is clearly irritating, especially when you are not around. The authentication requests are handled by PolicyKit (polkit for short) and can be tweaked.<br />
<br />
The message by which I was hit was the following: "<i>System policy prevents modification of network settings for all users</i>."<br />
<br />
Before you get started, the system wide configuration files that contain the default values reside inside the <i>/usr/share/polkit-1/actions/</i> directory. In this directory resides the file <i>org.freedesktop.NetworkManager.policy</i> which contains all the default actions. It does also contain the message about the network settings for which the action id is "<i>org.freedesktop.NetworkManager.settings.modify.system</i>." At this point I was still clueless of what I was supposed to do.<br />
<br />
After having search the web for information about PolicyKit I have found one <a href="http://skvidal.wordpress.com/2009/11/18/polkit-and-package-kit-and-changing-settings/">interesting article</a> that helped me getting done with my issue and learning more about this authorization framework. This action being very seldom to perform, I'm summing up everything here.<br />
<br />
There are two useful commands to perform tests with PolicyKit, <b>pkcheck</b> and <b>pkaction</b>.<br />
<br />
The first interesting command to use is <b>pkcheck</b>. It will trigger an authorization request and prompt you to type in a password, simply return true if no authorization is required otherwise false. For example:<br />
<pre>pkcheck --action-id org.freedesktop.NetworkManager.settings.modify.system \
--process `pidof gnome-session` -u `id -u`</pre>You have to adapt the process and user parameters of course.<br />
<br />
<div class="separator" style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY7HTjMMbLEMv9zz8JDg6lO5TL2MGYu-4CUNwYHd_L0p1B54FZhBtMf-dhoBPb_Au0Rk4jO2fTrrvkhNoaytr2ErMLcubUZBwBF9BDknwwJTqQMPVyST7vrSb7T2XI8hllsQfI/s1600/authentication-request.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY7HTjMMbLEMv9zz8JDg6lO5TL2MGYu-4CUNwYHd_L0p1B54FZhBtMf-dhoBPb_Au0Rk4jO2fTrrvkhNoaytr2ErMLcubUZBwBF9BDknwwJTqQMPVyST7vrSb7T2XI8hllsQfI/s400/authentication-request.jpg" width="400" /></a></div><br />
<br />
Next the command <b>pkaction</b> can be used to print the default system values, for example:<br />
<pre>pkaction --action-id org.freedesktop.NetworkManager.settings.modify.system \
--verbose</pre>Now to have a custom setting for your user, what has to be done is to create a <i>PolicyKit Local Authority</i> file inside the directory <i>/var/lib/polkit-1/localauthority/</i>. Here is an example:<br />
<pre>[Let user mike modify system settings for network]
Identity=unix-user:mike
Action=org.freedesktop.NetworkManager.settings.modify.system
ResultAny=no
ResultInactive=no
ResultActive=yes</pre>I have saved this file under <i>/var/lib/polkit-1/localauthority/50-local.d/10-network-manager.pkla</i>.<br />
<br />
There are three main values you can pass to <i>ResultActive</i> that are <i>no</i>, <i>auth_admin</i> or <i>yes</i>. Respectively it will deny the authorization, ask for a password, and give access. For further information about the possible values check the <a href="http://hal.freedesktop.org/docs/polkit/polkit.8.html">polkit manpage</a>, also don't miss the <a href="http://hal.freedesktop.org/docs/polkit/pklocalauthority.8.html">pklocalauthority manpage</a> to read more about the <i>localauthority</i> tree structure.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com11tag:blogger.com,1999:blog-27773648.post-21595471571860687482011-01-23T10:20:00.001+01:002011-01-23T10:21:53.459+01:00Update the GeoIP database<a href="http://www.maxmind.com/app/ip-location">GeoIP</a> is a proprietary technology provided by <a href="http://www.maxmind.com/">MaxMind </a>that allows the geolocalization of IPs. It provides databases as both free and paid solutions with IP records matching the country and the city. The <a href="http://www.maxmind.com/app/geolitecountry">GeoLite Country</a> database can be downloaded for free and is updated about once a month.<br />
<br />
The database can be used with the command line tool <i>geoiplookup <ip></ip></i>. By calling it, it will check for the default database, but you can specify another one through a command line option.<br />
<br />
First download and install the <a href="http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz">latest database</a> and <a href="http://geolite.maxmind.com/download/geoip/database/LICENSE.txt">license</a> under your home directory, for example <i>~/.local/share/GeoIP/</i>. Make sure to decompress the database with <i>gunzip</i>. The directory has to contain these files:<br />
<pre>GeoIP.dat
LICENSE.txt</pre>Next create an alias for the command <i>geoiplookup</i>, for example through your <i>~/.bashrc</i> script put the following line:<br />
<pre>alias geoiplookup='geoiplookup -d $HOME/.local/share/GeoIP/'</pre><br />
And done! But why all the hassle? Because your system may not provide the updates on a regular basis. Of course you can set up a scheduled task to download the database right into your home directory.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com1tag:blogger.com,1999:blog-27773648.post-26217004145100422382010-11-28T15:31:00.002+01:002010-12-02T20:01:02.961+01:00SPAM-ips.rbI'm sharing a small script that allows to scan IPs against Whois and GeoIP databases. It allows to quickly retrieve the geolocation of the IPs and print statistics, so that you know from where the connections are originating from. The Whois information is stored inside text files named whois.xxx.yyy.zzz.bbb.<br />
<br />
You can download the script <a href="http://dl.dropbox.com/u/2670286/scripts/spam-ips.rb">here</a>.<br />
<br />
Example:<br />
<pre><em> • Usage</em>
<strong>$ spam-ips.rb --help</strong>
Usage: /home/mike/.local/bin/spam-ips.rb ip|filename [[ip|filename] ...]
<em> • First we retrieve some IPs</em>
<strong>$ awk '{print $6}' /var/log/httpd/access.log > /tmp/ip-list.txt</strong>
<em> • Now we run the script with the list of IPs inside the text file</em>
<strong>$ cd /tmp</strong>
<strong>$ spam-ips.rb ip-list.txt</strong>
Scanning 18 IPs... done.
xxx.zzz.yyy.bbb GeoIP Country Edition: IP Address not found
xxx.zzz.yyy.bbb GeoIP Country Edition: BR, Brazil
xxx.zzz.yyy.bbb GeoIP Country Edition: AR, Argentina
xxx.zzz.yyy.bbb GeoIP Country Edition: SE, Sweden
xxx.zzz.yyy.bbb GeoIP Country Edition: CA, Canada
xxx.zzz.yyy.bbb GeoIP Country Edition: US, United States
xxx.zzz.yyy.bbb GeoIP Country Edition: DE, Germany
xxx.zzz.yyy.bbb GeoIP Country Edition: BE, Belgium
xxx.zzz.yyy.bbb GeoIP Country Edition: FR, France
xxx.zzz.yyy.bbb GeoIP Country Edition: NL, Netherlands
xxx.zzz.yyy.bbb GeoIP Country Edition: NO, Norway
xxx.zzz.yyy.bbb GeoIP Country Edition: FI, Finland
xxx.zzz.yyy.bbb GeoIP Country Edition: DE, Germany
xxx.zzz.yyy.bbb GeoIP Country Edition: FR, France
xxx.zzz.yyy.bbb GeoIP Country Edition: FR, France
xxx.zzz.yyy.bbb GeoIP Country Edition: DE, Germany
xxx.zzz.yyy.bbb GeoIP Country Edition: RU, Russian Federation
xxx.zzz.yyy.bbb GeoIP Country Edition: RU, Russian Federation
3 FR, France
3 DE, Germany
2 RU, Russian Federation
1 US, United States
1 NL, Netherlands
1 IP Address not found
1 NO, Norway
1 FI, Finland
1 SE, Sweden
1 CA, Canada
1 BR, Brazil
1 BE, Belgium
1 AR, Argentina
Total: 18
</pre><br />
I wrote this script when I noticed Wiki SPAM and concluded that SPAM originated from a single Bot master but of course I was unable to figure out which one. The script can still be useful from times to times.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com0tag:blogger.com,1999:blog-27773648.post-48486056267200138772010-10-23T10:43:00.000+02:002010-10-23T10:43:26.571+02:00XTerm as root-tailThe idea behind this title is to use XTerm as a log viewer over the desktop, just like <a href="http://oldhome.schmorp.de/marc/root-tail.html" title="http://oldhome.schmorp.de/marc/root-tail.html" rel="nofollow">root-tail</a> works. The tool root-tail paints text on the root window by default or any other XWindow when used with the <code>-id</code> parameter.<br />
<br />
Using XTerm comes with little advantage, it is possible to scroll into the “backlog” and make text selections. On a downside, it won't let you click through into the desktop, therefore it is rather useful for people without desktop icons for example.<br />
<br />
We will proceed with a first simple example, by writing a Shell script that will use the combo <a class="urlextern" href="http://live.gnome.org/DevilsPie" rel="nofollow" title="http://live.gnome.org/DevilsPie">DevilsPie</a> and XTerm. The terminals will all be kept in the background below other windows and never take the focus thanks to DevilsPie. DevilsPie is a tool watching the creation of new windows and applies special rules over them.<br />
<br />
Obviously, you need to install the command line tool <code>devilspie</code>. It's a command to run in the background as a daemon. Configuration files with a <code>.ds</code> extensions contain matches for windows and rules that are put within the <code>~/.devilspie</code> directory.<br />
<br />
<h4>First example</h4>The first example shows how to match only one specific XTerm window.<br />
<br />
The DevilsPie configuration:<br />
<dl class="code"><dt><a class="mediafile mf_ds" href="http://wiki.xfce.org/_export/code/howto/xterm-as-root-tail?codeblock=0" title="Download Snippet">DesktopLog.ds</a></dt>
<dd><pre class="code lisp"><span class="br0">(</span><span class="kw1">if</span>
<span class="br0">(</span>is <span class="br0">(</span>window_class<span class="br0">)</span> <span class="st0">"DesktopLog"</span><span class="br0">)</span>
<span class="br0">(</span>begin
<span class="br0">(</span>wintype <span class="st0">"dock"</span><span class="br0">)</span>
<span class="br0">(</span>geometry <span class="st0">"+20+45"</span><span class="br0">)</span>
<span class="br0">(</span>below<span class="br0">)</span>
<span class="br0">(</span>undecorate<span class="br0">)</span>
<span class="br0">(</span>skip_pager<span class="br0">)</span>
<span class="br0">(</span>opacity <span class="nu0">80</span><span class="br0">)</span>
<span class="br0">)</span>
<span class="br0">)</span></pre></dd></dl>The Shell script making sure <code>devilspie</code> is running, and spawning a single <code>xterm</code> process:<br />
<dl class="code"><dt><a class="mediafile mf_sh" href="http://wiki.xfce.org/_export/code/howto/xterm-as-root-tail?codeblock=1" title="Download Snippet">desktop-log.sh</a></dt>
<dd><pre class="code bash"><span class="co0">#!/bin/sh</span>
<span class="kw3">test</span> <span class="sy0">`</span><span class="kw2">pidof</span> devilspie<span class="sy0">`</span> <span class="sy0">||</span> devilspie <span class="sy0">&</span>
xterm <span class="re5">-geometry</span> 164x73 <span class="re5">-uc</span> <span class="re5">-class</span> DesktopLog <span class="re5">-T</span> daemon.log <span class="re5">-e</span> <span class="kw2">sudo</span> <span class="kw2">tail</span> <span class="re5">-f</span> <span class="sy0">/</span>var<span class="sy0">/</span>log<span class="sy0">/</span>daemon.log <span class="sy0">&</span></pre></dd></dl><strong>NB:</strong> You can notice the size of the XTerm window is set through the Shell script while the position is set through the DevilsPie rules file, and there is a simple reason for this. By default XTerm has a size of 80 columns and 24 lines and text with too long lines will be wrapped on the next line. If afterwards you resize the window the wrapped text won't move up and the result will be ugly. Therefore it's better to set the initial size of the terminal correctly.<br />
<br />
To try the example, save the DevilsPie snippet inside the directory <code>~/.devilspie</code>, and download and execute the Shell script. Make sure to quit any previous DevilsPie process whenever you modify or install a new <code>.ds</code> file.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZQUPvouXAwF8uHGAoa6JBv9xSnb76PCCls_xaZlwIdEpF-H0RQbN-HiocRfRUfV9eZQVDhMnHnH0c-IhqsAQ7gfESJ4BMp7TNC8SzynLpz9k0N7fqNvqsbHb7jSev2OKtLWMA/s1600/desktop-log-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZQUPvouXAwF8uHGAoa6JBv9xSnb76PCCls_xaZlwIdEpF-H0RQbN-HiocRfRUfV9eZQVDhMnHnH0c-IhqsAQ7gfESJ4BMp7TNC8SzynLpz9k0N7fqNvqsbHb7jSev2OKtLWMA/s400/desktop-log-1.png" width="400" /></a></div><br />
<h4>Second example</h4>The second example is a little more complete, it starts three terminals of which one is coloured in black.<br />
<dl class="code"><dt><a class="mediafile mf_ds" href="http://wiki.xfce.org/_export/code/howto/xterm-as-root-tail?codeblock=2" title="Download Snippet">DesktopLog.ds</a></dt>
<dd><pre class="code lisp"><span class="br0">(</span><span class="kw1">if</span>
<span class="br0">(</span>matches <span class="br0">(</span>window_class<span class="br0">)</span> <span class="st0">"DesktopLog[0-9]+"</span><span class="br0">)</span>
<span class="br0">(</span>begin
<span class="br0">(</span>wintype <span class="st0">"dock"</span><span class="br0">)</span>
<span class="br0">(</span>below<span class="br0">)</span>
<span class="br0">(</span>undecorate<span class="br0">)</span>
<span class="br0">(</span>skip_pager<span class="br0">)</span>
<span class="br0">(</span>opacity 80<span class="br0">)</span>
<span class="br0">)</span>
<span class="br0">)</span>
<span class="br0">(</span><span class="kw1">if</span>
<span class="br0">(</span>is <span class="br0">(</span>window_class<span class="br0">)</span> <span class="st0">"DesktopLog1"</span><span class="br0">)</span>
<span class="br0">(</span>geometry <span class="st0">"+480+20"</span><span class="br0">)</span>
<span class="br0">)</span>
<span class="br0">(</span><span class="kw1">if</span>
<span class="br0">(</span>is <span class="br0">(</span>window_class<span class="br0">)</span> <span class="st0">"DesktopLog2"</span><span class="br0">)</span>
<span class="br0">(</span>geometry <span class="st0">"+20+20"</span><span class="br0">)</span>
<span class="br0">)</span>
<span class="br0">(</span><span class="kw1">if</span>
<span class="br0">(</span>is <span class="br0">(</span>window_class<span class="br0">)</span> <span class="st0">"DesktopLog3"</span><span class="br0">)</span>
<span class="br0">(</span>geometry <span class="st0">"+20+330"</span><span class="br0">)</span>
<span class="br0">)</span></pre></dd></dl><dl class="code"><dt><a class="mediafile mf_sh" href="http://wiki.xfce.org/_export/code/howto/xterm-as-root-tail?codeblock=3" title="Download Snippet">desktop-log.sh</a></dt>
<dd><pre class="code bash"><span class="co0">#!/bin/sh</span>
<span class="kw3">test</span> <span class="sy0">`</span><span class="kw2">pidof</span> devilspie<span class="sy0">`</span> <span class="sy0">||</span> devilspie <span class="sy0">&</span>
xterm <span class="re5">-geometry</span> 88x40 <span class="re5">-uc</span> <span class="re5">-class</span> DesktopLog1 <span class="re5">-T</span> daemon.log <span class="re5">-e</span> <span class="kw2">sudo</span> <span class="re5">-s</span> <span class="kw2">tail</span> <span class="re5">-f</span> <span class="sy0">/</span>var<span class="sy0">/</span>log<span class="sy0">/</span>daemon.log <span class="sy0">&</span>
xterm <span class="re5">-geometry</span> 70x20 <span class="re5">-uc</span> <span class="re5">-class</span> DesktopLog2 <span class="re5">-T</span> auth.log <span class="re5">-e</span> <span class="kw2">sudo</span> <span class="re5">-s</span> <span class="kw2">tail</span> <span class="re5">-f</span> <span class="sy0">/</span>var<span class="sy0">/</span>log<span class="sy0">/</span>auth.log <span class="sy0">&</span>
xterm <span class="re5">-fg</span> grey <span class="re5">-bg</span> black <span class="re5">-geometry</span> 70x16 <span class="re5">-uc</span> <span class="re5">-class</span> DesktopLog3 <span class="re5">-T</span> pacman.log <span class="re5">-e</span> <span class="kw2">sudo</span> <span class="re5">-s</span> <span class="kw2">tail</span> <span class="re5">-f</span> <span class="sy0">/</span>var<span class="sy0">/</span>log<span class="sy0">/</span>pacman.log <span class="sy0">&</span></pre></dd></dl><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG-36OwlG9NCYZm1BHywOh4wZCQsZYMHkPfKg08e_UD8PEow-koSbHVIRkf1T7cKSXkbt3ACIdFKDqKQAwdBTOll39Zu21O3tqU81BXGMrYh_POh3EFMuOXqQoYQT8LKO6jVDc/s1600/desktop-log-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG-36OwlG9NCYZm1BHywOh4wZCQsZYMHkPfKg08e_UD8PEow-koSbHVIRkf1T7cKSXkbt3ACIdFKDqKQAwdBTOll39Zu21O3tqU81BXGMrYh_POh3EFMuOXqQoYQT8LKO6jVDc/s400/desktop-log-2.png" width="400" /></a></div><br />
<br />
<strong>NB:</strong> You will probably notice that setting the geometry is awkward, specially since position and size are in two different files, getting it right needs several tweakings.<br />
<br />
<em>This blog post was cross-posted to the <a href="http://wiki.xfce.org/howto/xterm-as-root-tail">Xfce Wiki</a>.</em>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com2tag:blogger.com,1999:blog-27773648.post-69752364748607635102010-09-19T15:14:00.000+02:002010-09-19T15:14:44.622+02:00CLI tool to review PO filesIf there is something annoying about reviewing PO files is that it is <i>impossible</i>. When there are two hundred messages in a PO file, how are you going to know which messages changed? Well, that's the way it works currently for <a href="http://transifex.org/">Transifex </a>but there are very good news, first a review board is already available which is a good step forward but second it is going to get some good kick to make it awesome. But until this happens, I have written two scripts to make such a review.<br />
<h4>A shell script <em>msgdiff.sh</em></h4><u>Pros</u>: tools available on every system<br />
<u>Cons</u>: ugly output, needs template file<br />
<br />
<pre>#!/bin/sh
PO_ORIG=$1
PO_REVIEW=$2
PO_TEMPL=$3
MSGMERGE=msgmerge
DIFF=diff
PAGER=more
RM=/bin/rm
MKTEMP=mktemp
# Usage
if test "$1" = "" -o "$2" = "" -o "$3" = ""; then
echo Usage: $0 orig.po review.po template.pot
exit 1
fi
# Merge
TMP_ORIG=`$MKTEMP po-orig.XXX`
TMP_REVIEW=`$MKTEMP po-review.XXX`
$MSGMERGE $PO_ORIG $PO_TEMPL > $TMP_ORIG 2> /dev/null
$MSGMERGE $PO_REVIEW $PO_TEMPL > $TMP_REVIEW 2> /dev/null
# Diff
$DIFF -u $TMP_ORIG $TMP_REVIEW | $PAGER
# Clean up files
$RM $TMP_ORIG $TMP_REVIEW
</pre><br />
Example:<br />
<pre>$ ./msgdiff.sh fr.po fr.review.po thunar.pot
[...]
#: ../thunar-vcs-plugin/tvp-git-action.c:265
-#, fuzzy
msgid "Menu|Bisect"
-msgstr "Différences détaillées"
+msgstr "Menu|Couper en deux"
#: ../thunar-vcs-plugin/tvp-git-action.c:265
msgid "Bisect"
-msgstr ""
+msgstr "Couper en deux"
[...]
</pre><br />
<h4>A Python script <em>podiff.py</em></h4><div><u>Pros</u>: programmable output</div><div><u>Cons</u>: external dependency</div><br />
The script depends on <a href="http://pypi.python.org/pypi/polib/">polib</a> that can be installed with the <em>setuptools</em> scripts. Make sure <em>setuptools</em> is installed and than run the command <code>sudo easy_install polib</code>.<br />
<br />
<pre>#!/usr/bin/env python
import polib
def podiff(path_po_orig, path_po_review):
po_orig = polib.pofile(path_po_orig)
po_review = polib.pofile(path_po_review)
po_diff = polib.POFile()
po_diff.header = "PO Diff Header"
for entry in po_review:
orig_entry = po_orig.find(entry.msgid)
if not entry.obsolete and (orig_entry.msgstr != entry.msgstr \
or ("fuzzy" in orig_entry.flags) != ("fuzzy" in entry.flags)):
po_diff.append(entry)
return po_diff
if __name__ == "__main__":
import sys
import os.path
# Usage
if len(sys.argv) != 3 \
or not os.path.isfile(sys.argv[1]) \
or not os.path.isfile(sys.argv[2]):
print "Usage: %s orig.po review.po" % sys.argv[0]
sys.exit(1)
# Retrieve diff
path_po_orig = sys.argv[1]
path_po_review = sys.argv[2]
po_diff = podiff(path_po_orig, path_po_review)
# Print out orig v. review messages
po = polib.pofile(path_po_orig)
for entry in po_diff:
orig_entry = po.find(entry.msgid)
orig_fuzzy = review_fuzzy = "fuzzy"
if "fuzzy" not in orig_entry.flags:
orig_fuzzy = "not fuzzy"
if "fuzzy" not in entry.flags:
review_fuzzy = "not fuzzy"
print "'%s' was %s is %s\n\tOriginal => '%s'\n\tReviewed => '%s'\n" % (entry.msgid, orig_fuzzy, review_fuzzy, orig_entry.msgstr, entry.msgstr)
</pre><br />
Example:<br />
<pre>$ ./podiff.py fr.po fr.review.po
'Menu|Bisect' was fuzzy is not fuzzy
Original => 'Différences détaillées'
Reviewed => 'Menu|Couper en deux'
'Bisect' was not fuzzy is not fuzzy
Original => ''
Reviewed => 'Couper en deux'
[...]
</pre>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com3tag:blogger.com,1999:blog-27773648.post-66347086362598796622010-09-06T21:31:00.002+02:002010-09-06T21:49:22.865+02:00Benchmarking Compression ToolsComparison of several compression tools: lzop, gzip, bzip2, 7zip, and xz.<br />
<ul><li><b>Lzop</b>: small and very fast yet good compression.</li>
<li><b>Gzip</b>: fast and good compression.</li>
<li><b>Bzip2</b>: slow for both compression and decompression although very good compression.</li>
<li><b>7-Zip</b>: LZMA algorithm, slower than Bzip2 for compression but very good compression.</li>
<li><b>Xz</b>: LZMA2, evolution of LZMA algorithm.</li>
</ul><h4>Preparation</h4><ul><li><i>Be skeptic about compression tools and wanna promote <b>the</b> compression tool</i></li>
<li><i>Compare quickly old and new compression tools and find interesting results</i></li>
</ul><div>So much for the spirit, what you really need is to write a <b>script</b> (Bash, Ruby, Perl, anything will do) because you will want to generate the benchmark data automatically. I picked up Ruby as it's nowadays the language of my choice when it comes to any kind of Shell-like scripts. By choosing Ruby I have a large panel of classes to process benchmarking data, for instance I have a Benchmark class (wonderful), I have a CSV class (awfully documented, redundant), and I have a zillion of Gems for any kind of tasks I would need to do (although I always avoid them).</div><br />
I first focused on retrieving the data I was interested into (memory, cpu time and file size) and saving it in the <b>CSV</b> format. By doing so I am able to produce <b>charts</b> easily with existing applications, and I was thinking maybe it was possible to use <a href="http://code.google.com/p/googlecl/">GoogleCL</a> to generate charts from the command line with Google Docs but it isn't supported (maybe it will maybe it won't, it's up to <a href="http://code.google.com/p/gdata-python-client/"><span class="Apple-style-span" style="font-family: inherit;"><i>gdata-python-client</i></span></a>). However there is an actual Google tool to generate charts, it is the <a href="http://code.google.com/apis/chart/docs/making_charts.html"><b>Google Chart API</b></a> that works by providing a URI to get an image. The <a href="http://imagecharteditor.appspot.com/">Google Image Chart Editor</a> website helps you to generate the chart you want in a friendly WYSIWYG mode, after that it is just a matter of computing the data into shape for the URI. But well while focusing on the charts I found the Ruby Gem <a href="http://googlecharts.rubyforge.org/"><i>googlecharts</i></a> that makes it friendly to pass the data and save the image.<br />
<h4>Ruby Script</h4>The Ruby script needs the following:<br />
<ul><li>It was written with Ruby 1.9</li>
<li>Linux/Procfs for reading the status of processes</li>
<li><a href="http://googlecharts.rubyforge.org/">Googlecharts</a>: <i>gem install googlecharts</i></li>
<li>ImageMagick for the command line tool <i>convert</i> (optional)</li>
</ul>The Ruby script takes a path as argument, with which it creates a tarball inside a tmpfs directory in order to avoid I/O latencies from a hard-drive. Next it runs a number of commands over the tarball from which it collects benchmark data. The benchmark data is then saved inside CSV files that are reusable within spreadsheet applications. The data is also reused to retrieve charts from the Google Chart API and finally it calls the ImageMagick tool ''convert'' to collect the charts inside a single image. The summary displayed on the standard output is also saved inside a text file.<br />
<br />
The script is a bit long for being pasted here (more or less 300 lines) so you can <a href="http://mmassonnet.info/~mike/benchmark-compression.rb">download</a> it from my workstation. If the link doesn't work make sure the web browser doesn't encode ~ (f.e. to "<i>%257E</i>"), I've seen this happening with Safari (inside my logs)! If really you are out of luck, it is available on <a href="http://pastebin.com/nWR1GWy8">Pastebin</a>.<br />
<h4>Benchmarks</h4>The benchmarks are available for three kinds of data. Compressed media files, raw media files (image and sound, remember that the compression is lossless), and text files from an open source project.<br />
<h5>Media Files</h5>Does it make sense at all to compress already compressed data. Obviously not! Let's take a look at what happens anyway.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZuDXNM8telgw6bAKE0GmpudwoyyabZuznxyuAR0KZo4LQ5bADpzSN3IhNaXUQfeuHiBCQY55Mhipmel8PxavF1LAgfkaxXNclK22MFjvkX5ylvfSPjTZl1AvTF8EU5ZSqlMLa/s1600/medias-3charts.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZuDXNM8telgw6bAKE0GmpudwoyyabZuznxyuAR0KZo4LQ5bADpzSN3IhNaXUQfeuHiBCQY55Mhipmel8PxavF1LAgfkaxXNclK22MFjvkX5ylvfSPjTZl1AvTF8EU5ZSqlMLa/s400/medias-3charts.png" width="400" /></a></div><br />
As you see, compression tools with focus on speed don't fail, they still do the job quick while gaining a few hundred kilo bytes. However the other tools simply waste a lot of time for no gain at all.<br />
<br />
So always make sure to use a backup application without compression over media files or the CPU will be heating up for nothing.<br />
<h5>Raw Media Files</h5>Will it make sense to compress raw data? Not really. Here are the results:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRvLQkt3F0Ucyx0RcLisKGFxN_6ZlsQU6uGcCQJ5mlZk82Gsg_8fiefJWA9GZ5qf-Wml_gOEslxpE8i2HqZ2ySIZPJsIWJK4VXvhfm4gempxGYCWGg2Eo230vR-yaXOp8v_SNY/s1600/medias-raw-3charts.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRvLQkt3F0Ucyx0RcLisKGFxN_6ZlsQU6uGcCQJ5mlZk82Gsg_8fiefJWA9GZ5qf-Wml_gOEslxpE8i2HqZ2ySIZPJsIWJK4VXvhfm4gempxGYCWGg2Eo230vR-yaXOp8v_SNY/s400/medias-raw-3charts.png" width="400" /></a></div><br />
There is some gain in the order of mega bytes now, but the process is still the same and for that reason it is simply unadapted. For media files there are existing formats that will compress the data lossless with a higher ratio and a lot faster.<br />
<br />
Let's compare lossless compression of a sound file. The initial WAV source file has a size of <i>44MB</i> and lasts <i>4m20s</i>. Compressing this file with <i>xz</i> takes about <i>90s</i>, this is very long while it reduced the size to <i>36MB</i>. Now if you choose the format FLAC, which is doing lossless compression for audio, you will have a record. The file is compressed in about <i>5s</i> to a size of <i>24MB</i>! The good thing about FLAC is that media players will decode it without any CPU cost.<br />
<br />
The same happens with images, but I lack knowledge about photo formats so your mileage may vary. Anyway, except the Windows bitmap format, I'm not able to say that you will find images uncompressed just like you won't find videos uncompressed... <a href="http://en.wikipedia.org/wiki/Tagged_Image_File_Format">TIFF</a> or <a href="http://en.wikipedia.org/wiki/Raw_image_format">RAW</a> is the format provided by many reflex cameras, it has lossless compression capabilities and contains many information about image colors and so on, this makes it the perfect format for photographers as the photo itself doesn't contain any modifications. You can also choose the <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">PNG</a> format but only for simple images.<br />
<h5>Text Files</h5>We get to the point where we can compare interesting results. Here we are compressing data that is the most commonly distributed over the Internet.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMjxL_IUHq1LDSAWO4zvbYW2HEqZPfYwHUTkRwdwerqG9NPTwkvz4d9YJNZ2NKWkJozfrChizYoDSCTRJpFhtbDwe6LfLJprXrU9XWDdT3MrMvc1XyPhF-4Pz0Vxgpjra3KU0L/s1600/text-3charts.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMjxL_IUHq1LDSAWO4zvbYW2HEqZPfYwHUTkRwdwerqG9NPTwkvz4d9YJNZ2NKWkJozfrChizYoDSCTRJpFhtbDwe6LfLJprXrU9XWDdT3MrMvc1XyPhF-4Pz0Vxgpjra3KU0L/s400/text-3charts.png" width="400" /></a></div><br />
Lzop and Gzip perform fast and have a good ratio. Bzip2 has a better ratio, and both LZMA and LZMA2 algorithms even better. We can use an initial archive of 10MB, 100MB, or 400MB, the charts will always look alike the one above. When choosing a compression format it will either be good compression or speed, but it will definitely never ever be both, you must choose between this two constraints.<br />
<h4>Conclusion</h4>I never heard about the <b>LZO</b> format until I wanted to write this blog post. It looks like a good choice for end-devices where CPU cost is crucial. The compression will always be extremely fast, even for giga bytes of data, with a fairly good ratio. While <b>Gzip</b> is the most distributed compression format, it works just like Lzop, by focusing by default on speed with good compression. But it can't beat Lzop in speed, even when compressing in level 1 it will be fairly slower in matter of seconds, although it still beats it in the final size. When compressing with Lzop in level 9, the speed is getting ridiculously slow and the final size doesn't beat Gzip with its default level where Gzip is doing the job faster anyway.<br />
<br />
<b>Bzip2</b> is noise between LZMA and Gzip. It is very distributed as default format nowadays because it beats Gzip in term of compression ratio. It is of course slower for compression, but easily spottable is the decompression time, it is the worst amongst all in all cases.<br />
<br />
Both <b>LZMA</b> and <b>LZMA2</b> perform almost with an identical behavior. They are using dynamic memory allocation, unlike the other formats, where the higher the input data the more the memory is allocated. We can see the evolution of LZMA is using less memory but has on the other hand a higher cost on CPU time. And we can see they have excellent decompression time, although Lzop and Gzip have the best scores but then again there can't be excellent compression ratio and compression time. The difference between the compression ratio of the two formats is in the order of hundred of kilo bytes, well after all it is an evolution and not a revolution.<br />
<br />
On a last note, I ran the benchmarks on an Intel Atom N270 that has two cores at 1.6GHz but I made sure to run the compression tools with only one core.<br />
<br />
A few interesting links:<br />
<ul><li><a href="http://www.glasslantern.com/RAWpository/">RAWpository</a>: a collection of RAW images</li>
<li><a href="http://www.thegeekstuff.com/2010/06/lzma-better-compression-than-bzip2-on-unix-linux/">LZMA vs Bzip2 at TheGeekStuff</a> from 2010-06-04</li>
<li><a href="http://stephane.lesimple.fr/wiki/blog/lzop_vs_compress_vs_gzip_vs_bzip2_vs_lzma_vs_lzma2-xz_benchmark_reloaded">Benchmarks by Stéphane Lesimple</a> with different levels from 2010-03-09</li>
<li><a href="http://www.advogato.org/person/badger/diary/80.html">Benchmarks by Advogato</a> also with different levels from 2009-09-25</li>
</ul>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com4tag:blogger.com,1999:blog-27773648.post-34927686470177112632010-07-15T22:25:00.001+02:002010-07-15T22:26:50.729+02:00Don't produce Gzipped tarballsA quick note so I can delete it from my desktop. In order to produce only a Bzip2 tarball with the Autotools, specially when running <i>make distcheck</i>, set the automake init call with these parameters:<br />
<br />
<b>AM_INIT_AUTOMAKE([no-dist-gzip dist-bzip2])</b><br />
<br />
By the way I wonder if it's worth dumping bzip2 against <a href="http://tukaani.org/xz/">xz</a>.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com4tag:blogger.com,1999:blog-27773648.post-89827379369432032572010-06-14T17:01:00.000+02:002010-06-14T17:01:44.091+02:00Major changes in the Xfce Task Manager going 1.0It's done. The task manager application available in Xfce for quite some years is now available with major changes. It has been rewritten from scratch, with GtkBuilder UI definitions and GObjects, everything is fresh and clean. The application has support for Linux, OpenBSD, FreeBSD and OpenSolaris.<br />
<br />
Let's start by visual changes:<br />
<ul><li>The buttons at the bottom are gone, the progress bars at the top are vanished, say hello to a <b>toolbar</b> with buttons and <b>monitors</b>.</li>
<li>You read well, monitors are in, they show a graph of the CPU and memory usage by time.</li>
<li>A <b>status bar</b> is visible at the bottom, it displays a general information about the system usage.</li>
<li><b>Icons</b> are displayed beneath the task names.</li>
</ul><br />
Let's continue with less visual:<br />
<ul><li>Tasks that start are displayed with a <b>green background</b> for a short delay and tasks that terminate with a <b>red background</b>.</li>
<li>Tasks which state is changing are temporarily displayed with a <b>yellow background</b>. This covers tasks changing their state from <i>idle</i> to <i>running</i>, vice versa and etc.</li>
<li>The tree views context menu contains the same actions as before, sending signals to the task and changing the priority. They have been polished however, for example the <i>continue</i> and <i>stop</i> signals aren't shown altogether anymore, and there are only five priorities to set ranging from <i>Very low</i> to <i>Very high</i>.</li>
<li>The tree view columns can be <b>reordered</b> as you wish.</li>
<li>An optional <b>status icon</b> can be activated allowing you to hide the application.</li>
<li>It is possible to display percentage values with <b>more precision</b>.</li>
<li>And finally, the default <b>refresh rate</b> is 750ms and it can be switched from 500ms up to 10s.</li>
</ul><br />
And the result is as follows:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXrPkepOR3xehqPbkvL_bjC9LvhHByV3VIgU9Gjv9BUvAc61bRH2kMWNzt9UpqAWIfLKZJ9kE_-8wkd9bsvNIeU_z_YFgCz0QTvW8NkDv8wrPvZ9DRK-hxdy2QfwwxEtn-8Ycw/s1600/xfce4-taskmanager-1.0.0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="233" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXrPkepOR3xehqPbkvL_bjC9LvhHByV3VIgU9Gjv9BUvAc61bRH2kMWNzt9UpqAWIfLKZJ9kE_-8wkd9bsvNIeU_z_YFgCz0QTvW8NkDv8wrPvZ9DRK-hxdy2QfwwxEtn-8Ycw/s400/xfce4-taskmanager-1.0.0.png" width="400" /></a></div><br />
The application is fully translated into fifteen <a href="https://translations.xfce.org/projects/p/xfce4-taskmanager/c/master/">languages</a>!<br />
<br />
Go to <b><a href="http://goodies.xfce.org/projects/applications/xfce4-taskmanager">project webpage</a></b>.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com12tag:blogger.com,1999:blog-27773648.post-31383703861906738632010-05-30T21:59:00.006+02:002010-05-31T00:39:14.087+02:00Meego installation on a USB stickThis post wouldn't be if the hard-drive from my Acer Aspire One didn't die. I have a fresh backup of the disk (a full 'dd' plus a separate one for just the home partition) so if I need something back, and I know I don't I care but backups are important, I can always mount it in a loopback and copy files.<br />
<br />
The hard-drive is actually, what I want to call it, a cheap and fake SSD. It's a PATA SSD that I'm sure I will never find a replacement for. Look:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENFY-87e6wQLhhjfmve1CGIZ4xPxAtKtZdejtmcnfMVt6zjz7jSUMfMOvyhyphenhyphenclLdTp3e0D7BwKN2oPQupllD2dOvexlkAcm8bDPKJ_ge0IEjjM0Z9PRdj-eKVec6J26ciV7Nv/s1600/aa-one-pata-ssd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENFY-87e6wQLhhjfmve1CGIZ4xPxAtKtZdejtmcnfMVt6zjz7jSUMfMOvyhyphenhyphenclLdTp3e0D7BwKN2oPQupllD2dOvexlkAcm8bDPKJ_ge0IEjjM0Z9PRdj-eKVec6J26ciV7Nv/s320/aa-one-pata-ssd.jpg" /></a></div><br />
Now the dilemma was easy, or I threw the netbook to trash, or I found something to boot on. I started to look for a solution and <a href="http://meego.com/">Meego</a> just got released, this is crazy timing. I downloaded the boot image and tried it out, and guess what, it is getting better and better. It's definitely more beautiful, it is getting faster, it has better dialogs for customization, well just try it out if you didn't yet, you wont be disappointed but surprised.<br />
<br />
So in the end, installing a system on a USB stick is the only solution I can come up with. I ordered an extra USB stick, but <i>mini</i> please, a <a href="http://www.kingston.com/ukroot/flash/dtm10.asp">Kingston DTmini10</a>! Now when I tell people this is my actual hard-drive, they are like “<i>say-whaaat.”</i><br />
<br />
The installation of Meego didn't went that fluently. I have two USB sticks, one with the boot image, another serving as target device for installation. The installation worked fine without any modification, it boots but ends on a black screen with the CAPS del blinking. Boo, kernel panic, or something else <i>ungroovy</i>. I also tried an installation with the file-system ext3, the default is btrfs, but then the grub installer fails and the Meego installer is knocked out in a waiting sequence. So I did a default installation again, sigh. After a search I tried out some parameters for the kernel command line and adding “<i>rootdelay=8</i>” did the trick. In fact, the USB stick boots without problem, but past that there is some delay for the kernel to discover the USB device, you can then see the following message:<br />
<br />
<i> sd 11:0:0:0: [sdx] Assuming drive cache: write through</i><br />
<br />
If there is no rootdelay parameter there is no root device found, and booting just ain't gonna work out. End of story. There are some tiny tweaks to be done afterwards. The kernel command line must point to the right root device, just like for the fstab file. The kernel command line can be edited in the file <i>/boot/extlinux/extlinux.conf</i>. Everything else works out just fine. Booting time, except the rootdelay, is acceptable, but shutting down seems to be endless, and precisely when I want the netbook to turn off I want it to be really fast. I'm going to send it to sleep more often than usual, by closing and opening the lid, which is the fastest “boot” sequence one can get ;-)<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpd_jT-elCrRutUCSOiQYtEghPHvS6Bv4jsWGm3AgiL9XTUeWlO997c4E_1W1Dq_KbGzOLFhZOl4bkv8UIpUeuWtFl4YK3-LiyymNT_YRuPKbWietwpwiU0iCXN2wQDYWGrAgd/s1600/aa-one-dtm10.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpd_jT-elCrRutUCSOiQYtEghPHvS6Bv4jsWGm3AgiL9XTUeWlO997c4E_1W1Dq_KbGzOLFhZOl4bkv8UIpUeuWtFl4YK3-LiyymNT_YRuPKbWietwpwiU0iCXN2wQDYWGrAgd/s320/aa-one-dtm10.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: left;"><b>Update</b>: I've been wrong stating the shutdown process is taking ages, I just did a shutdown and this time it went quick, so something must have been be unlucky and the disk synced something around and around.</div><div class="separator" style="clear: both; text-align: center;"></div>Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com9tag:blogger.com,1999:blog-27773648.post-79127365384221632072010-04-30T22:27:00.001+02:002010-05-30T20:37:18.232+02:00Moblin blazing fastI updated my netbook to give it a new look. I switched the Xfce Panel against <a href="http://code.google.com/p/bmpanel2/">bmpanel2</a> and changed the background (the previous definitelly lasted very long.) Not much changes, but I topped a cold boot of about six seconds, always faster baby :-P And the window manager is <a href="http://openbox.org/">OpenBox</a> by the way.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvw6KRD52uyIauX2-Gx8-gnzlyWlXRQfxa47WiVKREnMFaaq-Zgn-ydA5mX3NlzHfc4JUKAGcNNtqqV2vGYdX6pKfxobBon-nv5JF8gq5dqMv5Z2ES7SG6xQ4qBPvvAMKXK9pr/s1600/Moblin-openbox-bmpanel2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvw6KRD52uyIauX2-Gx8-gnzlyWlXRQfxa47WiVKREnMFaaq-Zgn-ydA5mX3NlzHfc4JUKAGcNNtqqV2vGYdX6pKfxobBon-nv5JF8gq5dqMv5Z2ES7SG6xQ4qBPvvAMKXK9pr/s400/Moblin-openbox-bmpanel2.png" width="400" /></a></div><br />
The only real useful entry missing in this panel is a battery monitor. At least I have an indicator over the keyboard that starts blinking when there is about three percents left. What I like about this panel is the cool themes that it is provided with, however the configuration is set through a hand-written configuration file which sucks but what do you want, it is extremely lightweight on the other hand.<br />
<br />
<b>Update</b>: Should I mention I totally forgot about the Xfce power manager? Well I did, and it is provided with a notification icon displaying the battery status :-) However I had to fix the default ACPI script related to the lid, since HAL doesn't list it, in order to get the netbook to go into sleep.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com4tag:blogger.com,1999:blog-27773648.post-124351004912744382010-04-04T23:37:00.003+02:002010-04-10T15:32:21.525+02:00VLC with GTK+ look-n-feelTo get Qt applications to look like GTK+ applications run <b>qtconfig</b> and in <b>Select GUI Style</b> choose <b>GTK+</b>. Next click in the menu bar <b>File > Save</b>.<br />
<br />
Something is still puzzling me, why does GNOME run VLC automatically with native GTK+ look-n-feel and not Xfce?<br />
<br />
<b>Update</b>: Thanks to the power of tig and grep, I figured the Qt library (qt_init function) defines the desktop environment as GNOME for Xfce (this results in GTK+ theming, GNOME like Open dialogues, etc) by retrieving an X11 atom on the root window and compares it to “xfce4” <strike>but it seems that this doesn't work nowadays (at least it didn't work within an Xfce 4.7 desktop session)</strike>. I'm looking forward for sending patches.<br />
<br />
<b>Update2</b>: The latest version Qt 4.6.2 doesn't include the code for checking the X11 atom (it's in git), which explains why it doesn't work.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com2tag:blogger.com,1999:blog-27773648.post-2104759296738158902010-03-27T09:48:00.001+01:002010-04-09T21:58:17.628+02:00New notes plugin release 1.7.3Three months since the last release, and three months since it is available as a separate standalone application running in the notification area. This has made it a lot easier to test and debug, as before I had to build the plugin, install the plugin, restart the panel or remove/readd the plugin in the panel, now I just have to run <i>./xfce4-notes</i> from the source directory.<br />
<br />
This new release has seen some structural tree changes to save time during compilation. Now everything is in <i>src/</i> and <i>lib/</i>, where <i>lib/</i> contains code to build an <i>XnpHypertextView</i>, an <i>XnpNote </i>(a composite-widget that embeds a <i>GtkScrolledWindow </i>with an <i>XnpHypertextView </i>and sends “save” signals on changes), an <i>XnpWindow </i>with the custom made navigation and title bars and the right click menu on the title bar, and finally an <i>XnpApplication</i> class that is the heart of everything, it handles creations/deletions of notes, loads/saves the data, etc. The <i>src/</i> directory contains the main files for the panel plugin, the status icon, the popup command and the settings dialogue.<br />
<br />
The new stuff is mostly eye-candy as stated in the <a href="http://mmassonnet.blogspot.com/2010/03/include-custom-gtk-rc-style.html">previous blog entry</a>. The GTK+ RC style has been pimped up with custom made scrollbars and the source code contains a self-drawn close button. The stuff about GTK+ scrollbars theming is grossly explained on <a href="http://live.gnome.org/GnomeArt/Tutorials/GtkEngines/PixmapEngine">live.gnome.org</a> but I opened the <a href="https://launchpad.net/dusttheme">GTK+ Dust theme</a> files which was, to me, more understandable :-) Also it was because of this particular theme I took a look at customizing the scrollbars, see below the before/after screenshots. The older article about <a href="http://www.gnomejournal.org/article/34/writing-a-widget-using-cairo-and-gtk28">writing a Widget with Cairo</a> helped me getting started from scratch with an empty “close button” widget to replace the simple <i>GtkButton</i> with label. As I liked very much the time passed on these changes I contributed a tutorial “<a href="http://dl.dropbox.com/u/2670286/Monochrome-icon.pdf">Monochrome icon</a>” available only in PDF as of today which I hope to be useful for Vala beginners but also a nice update of the article about Cairo but with Vala language.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9zeWStmNo72CnELTB9VnKZa90CiECjos0O-sbh1smQZQ3ICLn4s_Sbvd1FENpcg6ocMfqiTqrULMX1vUSe3GbE73KEfMzOzWydI_VnnHc0HI0XXH3fuCT1ZKaLstD3GEipTR/s1600/notes-before.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9zeWStmNo72CnELTB9VnKZa90CiECjos0O-sbh1smQZQ3ICLn4s_Sbvd1FENpcg6ocMfqiTqrULMX1vUSe3GbE73KEfMzOzWydI_VnnHc0HI0XXH3fuCT1ZKaLstD3GEipTR/s200/notes-before.png" width="176" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNex4anQte7aRkS6fPep2EyxYGWTBGUMev1kj0CnBCZkKrrof9NmEjP9OLN1uraxR5wuCUas4QR2gJUIbuRtXKDtuhUlfzqUzPq4puKiIogMAL3SiBInw1SqwZc0oYTipN8kpk/s1600/notes-after.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNex4anQte7aRkS6fPep2EyxYGWTBGUMev1kj0CnBCZkKrrof9NmEjP9OLN1uraxR5wuCUas4QR2gJUIbuRtXKDtuhUlfzqUzPq4puKiIogMAL3SiBInw1SqwZc0oYTipN8kpk/s200/notes-after.png" width="176" /></a></div><br />
The fixes included in this release are the following: correctly restore sticky-window and keep-above states after some race conditions, and restore tab label orientation after renaming a note. And last but definitely not least the undo feature was not working because an internal timeout wasn't reset to zero which made the code think a snapshot was needed and thus the undo/redo buffers ended with the same content after the timeout elapsed. Thanks to Christian (the developer behind <a href="http://www.twotoasts.de/index.php?/pages/midori_summary.html">Midori</a>) otherwise I would still not have taken a look around this!<br />
<br />
The forthcoming features I have in mind would be a search dialogue and per-note options for activating a stripped down “markdown” syntax, an orthographic corrector and wrapping words which is the default for the moment.<br />
<br />
The release is available at <a href="http://archive.xfce.org/src/panel-plugins/xfce4-notes-plugin/1.7/">archive.xfce.org</a>.<br />
<br />
Thanks for the feedbacks and reports you sent and will send back.<br />
<br />
<b>Update</b>: The tutorial is now also available on the <a href="http://wiki.xfce.org/howto/monochrome-icon">Xfce wiki</a>.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com16tag:blogger.com,1999:blog-27773648.post-7326209425146613672010-03-08T16:46:00.002+01:002010-03-27T21:51:35.113+01:00Include custom GTK+ RC styleI've been using a custom GTK+ RC style for the notes plugin since the version 1.4.0, right now it is at version 1.7.2. I have been playing with GTK+ theming again these last two hours, and I've get custom scrollbars, a gradient for the custom-made “title bar”, and better colours for the notebook to get the current tab stand out from the crowd.<br />
<br />
While experimenting on a test-case code I found out a better way to parse a gtkrc file in the program. The first time I was fighting with the existing gtk_rc related functions, I gave up on a solution I partially dislike that is to include a line to the custom gtkrc file within ~/.gtkrc-2.0.<br />
<br />
Today I understood how <b><a href="http://library.gnome.org/devel/gtk/unstable/gtk-Resource-Files.html#gtk-rc-parse">gtk_rc_parse</a>(filename)</b> behaves. You have to call this function at the beginning of the program before building any widgets, it will work even if the file doesn't exist yet. Next, while the program is running, you can modify the file, create it, delete it, truncate it, whatever, and call <b><a href="http://library.gnome.org/devel/gtk/unstable/gtk-Resource-Files.html#gtk-rc-reparse-all">gtk_rc_reparse_all</a>()</b> to get the style refreshed in the GUI. It's hard to believe that such easy things are sometimes a PITA :-)<br />
<br />
Be prepared for a 1.7.3 notes plugin with nicer <span style="background-color: #fff2cc; color: #7f6000;">c</span><span style="background-color: #ffd966; color: #bf9000;">o</span><span style="background-color: #7f6000; color: #f1c232;">l</span><span style="background-color: #bf9000; color: #fff2cc;">o</span><span style="background-color: #f1c232; color: #ffe599;">u</span><span style="background-color: #bf9000; color: #fff2cc;">r</span><span style="background-color: #7f6000; color: yellow;">s</span>.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com0tag:blogger.com,1999:blog-27773648.post-42318540657562189542010-03-01T01:02:00.001+01:002010-03-27T21:51:35.113+01:00Show/hide functionality from notification areaWhen using a status icon within the notification area it is common to use the left-click action to show/hide the main window. Obviously this is often done in different ways. So here is my tip on how to do it right :-)<br />
<br />
What I believe to me the most sense-full way is to:<br />
<ol><li>Check if the application is invisible and show it,</li>
<li>Otherwise check if the window is inactive and present it,</li>
<li>Otherwise hide it.</li>
</ol>In C language it looks like this:<br />
<pre><i>/* Show the window */</i>
<span style="color: purple;">if</span> (!(<span style="color: red;">GTK_WIDGET_VISIBLE</span>(<span style="color: #999999;">window</span>))) {
<span style="color: red;">gtk_widget_show</span>(<span style="color: #999999;">window</span>);
}
<i>/* Present the window */</i>
<span style="color: purple;">else if</span> (!<span style="color: red;">gtk_window_is_active</span>(GTK_WINDOW(<span style="color: #999999;">window</span>))) {
<span style="color: red;">gtk_window_present</span>(GTK_WINDOW(<span style="color: #999999;">window</span>));
}
<i>/* Hide the window */</i>
<span style="color: purple;">else</span> {
int <span style="color: #999999;">winx</span>, <span style="color: #999999;">winy</span>;
<span style="color: red;">gtk_window_get_position</span>(GTK_WINDOW(<span style="color: #999999;">window</span>), &<span style="color: #999999;">winx</span>, &<span style="color: #999999;">winy</span>);
<span style="color: red;">gtk_widget_hide</span>(<span style="color: #999999;">window</span>);
<span style="color: red;">gtk_window_move</span>(GTK_WINDOW(<span style="color: #999999;">window</span>), <span style="color: #999999;">winx</span>, <span style="color: #999999;">winy</span>);
}</pre>I have been doing this for quite a long time inside the Xfce Notes plugin, except a little different with multiple windows.<br />
<br />
Some remarks, the <a href="http://live.gnome.org/GTK%2B/3.0/PendingSealings">PendingSealings</a> proposes <b>gtk_widget_get_visible</b> instead of its analogous MACRO. And as you may also notice when the window is hidden it gets moved just after, this is important as otherwise the window would be repositioned by its initial value once shown again (e.g. centre of screen or dynamically by the window manager).Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com0tag:blogger.com,1999:blog-27773648.post-36281859790037049592010-02-13T23:18:00.005+01:002010-09-04T21:17:10.896+02:00Eatmonkey 0.1.3 benchmarkingEatmonkey has now been <a href="http://foo-projects.org/pipermail/xfce/2010-February/026765.html">released</a> for the 4th time and I started to use it to download <a href="http://video.fosdem.org/2010/">videos</a> from FOSDEM2010 by drag-n-dropping the links from the web page to the manager :-)<br />
<br />
I downloaded four files and while they were running I had a close look at <b>top</b> and <b>iftop</b> to monitor the CPU usage and the bandwidth usage between the client/server (the connection between eatmonkey and the aria2 XML-RPC server running on the localhost interface).<br />
<br />
I had unexpected results and was surprised by the CPU usage. It is very high currently which means I have a new task for the next milestone, getting the CPU footprint low. The bandwidth comes without surprises, but since the milestone will target performance where possible I will fine down the number of requests made to the server. This problem is also noticeable in the GUI in that it tends to micro-freeze during the updates of each download. So the more active downloads will be running the more the client will be freezing.<br />
<br />
Some results as it will speak more than words:<br />
<table><tbody>
<tr><th>Number of active downloads</th><th>Reception</th><th>Emission</th><th>CPU%</th></tr>
<tr><td>4 downloads</td><td>144Kbps</td><td>18Kbps</td><td>30%</td></tr>
<tr><td>3 downloads</td><td>108Kbps</td><td>14Kbps</td><td>26%</td></tr>
<tr><td>2 downloads</td><td>73Kbps</td><td>11Kbps</td><td>18%</td></tr>
</tbody></table><br />
I will start by running benchmarks on the code itself, and thanks to Ruby there is built-in support for Benchmarking and Profiling. It comes with at least three different useful modules: <b>benchmark</b>, <b>profile</b> and <b>profiler</b>. The first measures the time that the code necessitated to be executed on the system. It is useful to measure different kind of loops like <b>for</b>, <b>while</b> or <b>do...while</b>, or for example to see if a string is best to be compared through a dummy compare function or via a compiled regular expression. The second simply needs to be included at the top of a Ruby script and it will print a summary of the time passed within each method/function call. The third does the same except it is possible to run the Profiler around distinctive blocks of code. So much for the presentation, below are some samples.<br />
<br />
File <code>benchmark.rb</code>:<br />
<pre>#!/usr/bin/ruby -w
require "benchmark"
require "pp"
integers = (1..10000).to_a
pp Benchmark.measure { integers.map { |i| i * i } }
Benchmark.bm(10) do |b|
b.report("simple") { 50000.times { 1 + 2 } }
b.report("complex") { 50000.times { 1 + 2 - 6 + 5 * 4 / 2 + 4 } }
b.report("stupid") { 50000.times { "1".to_i + "3".to_i * "4".to_i - "2".to_i } }
end
words = IO.readlines("/usr/share/dict/words")
Benchmark.bm(10) do |b|
b.report("include") { words.each { |w| next if w.include?("abe") } }
b.report("regexp") { words.each { |w| next if w =~ /abe/ } }
end
</pre><br />
File <code>profile.rb</code>:<br />
<pre>#!/usr/bin/ruby -w
require "profile"
def factorial(n)
n > 1 ? n * factorial(n - 1) : 1;
end
factorial(627)
</pre><br />
File <code>profiler.rb</code>:<br />
<pre>#!/usr/bin/ruby -w
require "profiler"
def factorial(n)
(2..n).to_a.inject(1) { |product, i| product * i }
end
Profiler__.start_profile
factorial(627)
Profiler__.stop_profile
Profiler__.print_profile($stdout)
</pre><b>Update</b>: The profiling showed that during a status request 65% of the time is consumed by the XML parser. The REXML class is written 100% in Ruby, and that gives a good hint that the same request done with a parser written in C may present a real boost. On another hand, the requests are now only run once periodically and cached inside the pooler. This means that the emission bitrate is always the same and that the reception bitrate grows as there are more downloads running. And as a side-effect there is less XML parsing done thus less CPU time used.Mike Massonnethttp://www.blogger.com/profile/00582966565407297350noreply@blogger.com4