<rss version="2.0"><channel><title>D'oh! pabluk's blog</title><link>http://pabloseminario.com</link><description>A weblog about my projects, free and open source software, internet and sometimes about real life ;)</description><item><title>Building a serverless Telegram bot</title><link>https://seminar.io/2018/09/03/building-serverless-telegram-bot/</link><description>&lt;p&gt;With the arrival of &lt;a href="https://en.wikipedia.org/wiki/Function_as_a_service"&gt;FaaS&lt;/a&gt; and all the serverless infrastructure providers (AWS, Google Cloud, Azure, etc) now is easy to deploy our own Telegram bot.&lt;/p&gt;
&lt;p&gt;A Webhook-based bot it's the perfect use case for serverless computing, using for example Google Cloud Functions we'll have all these advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our function will be associated to a public endpoint (IPv4 and IPv6) over HTTPS (using a valid certificate provided by Google)&lt;/li&gt;
&lt;li&gt;Pay only for function invocations and its compute resources consumption, so it could be cheaper than paying for a server powered on all the time&lt;/li&gt;
&lt;li&gt;No server management&lt;/li&gt;
&lt;li&gt;Scales automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Requirements&lt;/h4&gt;
&lt;p&gt;Before start building your bot you'll need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Register a new bot following these instructions &lt;a href="https://core.telegram.org/bots#3-how-do-i-create-a-bot"&gt;core.telegram.org/bots&lt;/a&gt; in order to get an API token&lt;/li&gt;
&lt;li&gt;Using a Google Cloud account, register a new project, enable the Cloud Functions API and install the Cloud SDK following &lt;a href="https://cloud.google.com/functions/docs/quickstart"&gt;the official quickstart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Code&lt;/h4&gt;
&lt;p&gt;In a few lines of Python you can code a simple echo bot that will reply with the same message that it receives:&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# main.py&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;telegram&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;telegram&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TELEGRAM_TOKEN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;telegram&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;de_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;chat_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
        &lt;span class="c1"&gt;# Reply with the same message&lt;/span&gt;
        &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;chat_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The only dependency needed is the amazing &lt;a href="https://python-telegram-bot.org/"&gt;python-telegram-bot&lt;/a&gt; library:&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;# requirements.txt 
python-telegram-bot==11.1.0
&lt;/pre&gt;&lt;/div&gt;</description><guid>building-serverless-telegram-bot</guid><pubDate>Mon, 03 Sep 2018 18:48:00 </pubDate></item><item><title>Notes about Android and IPsec on Linux</title><link>https://seminar.io/2016/04/23/notes-about-android-and-ipsec-on-linux/</link><description>&lt;p&gt;Here's some personal notes about the excellent Jeff Sharkey's article &lt;a href="http://jsharkey.org/blog/2012/09/22/deploying-a-pure-ipsec-pki-vpn-server-for-android-devices/"&gt;Deploying a pure-IPsec PKI VPN server for Android devices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My setup is a little bit different to that of Jeff, I have a 1Gbps fiber plan, a Linux server natted behind my ISP's router and my IPsec VPN server is running on a Linux container (LXC), so this container doesn't have a public IP address. The OS used in all the servers is Ubuntu Trusty 14.04.
On the VPN client side I'm using Android 6.0 Mashmallow.&lt;/p&gt;
&lt;h4&gt;Server configuration&lt;/h4&gt;
&lt;p&gt;In addition to installing the packages&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo apt-get install ipsec-tools racoon
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;I also installed the following packages&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo apt-get install iptables openssl tcpdump
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;When installing the Debian &lt;code&gt;racoon&lt;/code&gt; package, you have to chose the type of configuration, in my case I chose the &lt;code&gt;direct&lt;/code&gt; mode.&lt;/p&gt;
&lt;p&gt;I had to add 2 new port forwarding rules on my ISP's router to sent the traffic UDP on the ports 500 and 4500 to my Linux server, and on it I had to the same thing using &lt;code&gt;iptables&lt;/code&gt;&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo iptables -t nat -I PREROUTING -p udp -m udp --dport &lt;span class="m"&gt;4500&lt;/span&gt; -j DNAT --to-destination &lt;span class="m"&gt;10&lt;/span&gt;.0.3.91:4500
$ sudo iptables -t nat -I PREROUTING -p udp -m udp --dport  &lt;span class="m"&gt;500&lt;/span&gt; -j DNAT --to-destination &lt;span class="m"&gt;10&lt;/span&gt;.0.3.91:500
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here the IP address &lt;code&gt;10.0.3.91&lt;/code&gt; is assigned to the container running the IPsec VPN server.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;/etc/racoon/racoon.conf&lt;/code&gt; file I had to change the public IP address used by Jeff by the container's private IP address:&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;listen {
    isakmp 10.0.3.91[500];
    isakmp_natt 10.0.3.91[4500];
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;`
For more details about the configuration options you can see the &lt;a href="http://manpages.ubuntu.com/manpages/trusty/en/man5/racoon.conf.5.html"&gt;racoon.conf&lt;/a&gt;'s man page.&lt;/p&gt;
&lt;p&gt;About the RSA keys, don't forget to convert your server's private key into RSA format using&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ openssl rsa -in myserver.key -out myserver-rsa.key
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As the documentation says &lt;a href="http://manpages.ubuntu.com/manpages/xenial/en/man1/rsa.1ssl.html#contenttoc3"&gt;the output filename should not be the same as the input filename&lt;/a&gt;, so you also need to change it in your &lt;code&gt;/etc/racoon/racoon.conf&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Android configuration&lt;/h4&gt;
&lt;p&gt;Here some details when configuring your VPN profile on your phone:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don't need to install the &lt;code&gt;adb&lt;/code&gt; tool to push your &lt;code&gt;.p12&lt;/code&gt; certificate file, you can download it from an URL, Android will detect the format and it will install it using the Android's certificate installer.&lt;/li&gt;
&lt;li&gt;If you want to use the &lt;a href="https://support.google.com/nexus/answer/2819573?hl=en"&gt;Always-on VPN&lt;/a&gt; option, you need to specify a server's public IP address (instead of its fqdn) and you also must specify an IP address for the DNS servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Troubleshooting&lt;/h4&gt;
&lt;p&gt;If you find some problems, you can always take a look at the &lt;code&gt;/var/log/syslog&lt;/code&gt; file and use &lt;code&gt;tcpdump&lt;/code&gt; to inspect your network traffic.&lt;/p&gt;
&lt;p&gt;It's also highly recommended to read the &lt;a href="http://www.ipsec-howto.org/x202.html"&gt;Section 2 of the IPsec HOWTO&lt;/a&gt; to understand the theory behind IPsec and its Linux Kernel implementation.&lt;/p&gt;</description><guid>notes-about-android-and-ipsec-on-linux</guid><pubDate>Sat, 23 Apr 2016 21:35:00 </pubDate></item><item><title>You Build It, You Run It</title><link>https://seminar.io/2015/04/05/you-build-it-you-run-it/</link><description>&lt;a href="http://shop.oreilly.com/product/0636920013228.do"&gt;You Build It, You Run It&lt;/a&gt;&lt;br&gt;&lt;blockquote&gt;
&lt;p&gt;Giving developers operational responsibilities has greatly enhanced the quality of the services, both from a customer and a technology point of view. The traditional model is that you take your software to the wall that separates development and operations, and throw it over and then forget about it. Not at Amazon. You build it, you run it. This brings developers into contact with the day-to-day operation of their software. It also brings them into day-to-day contact with the customer. This customer feedback loop is essential for improving the quality of the service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;source: Werner Vogel, CTO at Amazon.com from Programming Amazon EC2&lt;/em&gt;&lt;/p&gt;</description><guid>you-build-it-you-run-it</guid><pubDate>Sun, 05 Apr 2015 20:38:00 </pubDate></item><item><title>8-bit art in Paris</title><link>https://seminar.io/2015/03/29/8-bit-art-in-paris/</link><description>&lt;img src="https://seminar.io/media/photos/IMG_20150328_181622709-medium.jpg" alt="The 8-bit Mona Lisa"/&gt;&lt;br/&gt;The 8-bit version of Mona Lisa at &lt;a href="https://a.tiles.mapbox.com/v4/pabluk.ljd1plga/page.html?access_token=pk.eyJ1IjoicGFibHVrIiwiYSI6IjI4V18xWjgifQ.1UTnViq5-eXQSs0B85LJ4A#16/48.8613/2.3418" target="_blank"&gt;20 Rue du Louvre, Paris&lt;/a&gt;.</description><guid>8-bit-art-in-paris</guid><pubDate>Sun, 29 Mar 2015 20:33:00 </pubDate></item><item><title>DNS resolution for LXC in Ubuntu 14.04</title><link>https://seminar.io/2014/07/27/dns-resolution-for-lxc-in-ubuntu-trusty/</link><description>&lt;p&gt;Working with &lt;a href="https://linuxcontainers.org/"&gt;LXC&lt;/a&gt; (Linux containers) in Ubuntu
is very easy but by default you need to know the IP address of new containers
to connect to services (ssh, database, webserver, etc.) running on them.&lt;/p&gt;
&lt;p&gt;With some minor configuration you can connect to your containers using a domain
name like that&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo lxc-create --name container1
$ sudo lxc-start --name container1 --daemon
$ ssh ubuntu@container1.lxc
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In Ubuntu 14.04 Trusty Tahr, &lt;code&gt;lxc-create&lt;/code&gt; use by default the Ubuntu template
and it will create a user called &lt;code&gt;ubuntu&lt;/code&gt;, to change it take a look at the
template options with &lt;code&gt;lxc-create -t ubuntu -h&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To set up the internal DNS resolution on your machine, you must edit
&lt;code&gt;/etc/default/lxc-net&lt;/code&gt; and uncomment the line&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;LXC_DOMAIN=&amp;quot;lxc&amp;quot;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Also you need to create the file &lt;code&gt;/etc/NetworkManager/dnsmasq.d/lxc.conf&lt;/code&gt;
with the following content&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;server=/lxc/10.0.3.1
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will redirect DNS queries for &lt;code&gt;*.lxc&lt;/code&gt; hosts to the &lt;code&gt;dnsmasq&lt;/code&gt; instance
running on &lt;code&gt;10.0.3.1&lt;/code&gt; that manage DHCP and DNS for containers.&lt;/p&gt;
&lt;p&gt;After that restart networking related services&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo service lxc-net stop
$ sudo service lxc-net start
$ sudo service network-manager restart
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For the &lt;code&gt;lxc-net&lt;/code&gt; service you can't use the &lt;code&gt;restart&lt;/code&gt; command, you must use
the &lt;code&gt;stop&lt;/code&gt;/&lt;code&gt;start&lt;/code&gt; commands to reload the configuration.&lt;/p&gt;
&lt;p&gt;If you had some containers running, do not forget to restart them&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ sudo lxc-stop --name container1
$ sudo lxc-start --name container1 --daemon
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Finally to check that everything works you can use, for example, the &lt;code&gt;ping&lt;/code&gt;
command and you must see something like this&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ ping -c &lt;span class="m"&gt;3&lt;/span&gt; container1.lxc
PING container1.lxc &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.0.3.8&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="m"&gt;56&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; bytes of data.
&lt;span class="m"&gt;64&lt;/span&gt; bytes from &lt;span class="m"&gt;10&lt;/span&gt;.0.3.8: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt; &lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.072 ms
&lt;span class="m"&gt;64&lt;/span&gt; bytes from &lt;span class="m"&gt;10&lt;/span&gt;.0.3.8: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt; &lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.125 ms
&lt;span class="m"&gt;64&lt;/span&gt; bytes from &lt;span class="m"&gt;10&lt;/span&gt;.0.3.8: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt; &lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.113 ms

--- psql.lxc ping statistics ---
&lt;span class="m"&gt;3&lt;/span&gt; packets transmitted, &lt;span class="m"&gt;3&lt;/span&gt; received, &lt;span class="m"&gt;0&lt;/span&gt;% packet loss, &lt;span class="nb"&gt;time&lt;/span&gt; 2000ms
rtt min/avg/max/mdev &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;.072/0.103/0.125/0.024 ms
&lt;/pre&gt;&lt;/div&gt;</description><guid>dns-resolution-for-lxc-in-ubuntu-trusty</guid><pubDate>Sun, 27 Jul 2014 15:28:00 </pubDate></item><item><title>Comment utiliser les photographies a&#233;riennes de Nantes avec Leaflet</title><link>https://seminar.io/2014/01/04/photographies-aeriennes-de-nantes-avec-leafletjs/</link><description>&lt;p&gt;&lt;img alt="Screenshot d'une carte interactive" src="/media/photographies-aeriennes-de-nantes-avec-leafletjs.jpg" /&gt;
Ce mini post explique comment on peut utiliser les &lt;a href="http://data.paysdelaloire.fr/donnees/detail/photographies-aeriennes-de-la-loire-atlantique/"&gt;Photographies a&#233;riennes de la Loire-Atlantique&lt;/a&gt; pour cr&#233;er des cartes interactives avec &lt;a href="http://leafletjs.com/"&gt;Leafletjs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Les &lt;a href="http://data.paysdelaloire.fr/donnees/detail/photographies-aeriennes-de-la-loire-atlantique/"&gt;Photographies a&#233;riennes de la Loire-Atlantique&lt;/a&gt; font partie des jeux de donn&#233;es Open Data de la r&#233;gion des Pays de la Loire et pour utiliser et acc&#233;der aux donn&#233;es il faut acepter leur licence.&lt;/p&gt;
&lt;p&gt;Pour acc&#233;der aux images le site &lt;a href="http://vuduciel.loire-atlantique.fr/"&gt;vuduciel.loire-atlantique.fr&lt;/a&gt; d&#233;livre un flux WMS (Web Map Service) qui peut &#234;tre int&#233;gr&#233; facilement avec Leaflet en utilisant une &lt;code&gt;TileLayer.WMS&lt;/code&gt;.
Par exemple avec quelques lignes de HTML on peut g&#233;n&#233;rer une carte et ajouter un marqueur :&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://cdn.leafletjs.com/leaflet-0.7.1/leaflet.css&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;480&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;map&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://cdn.leafletjs.com/leaflet-0.7.1/leaflet.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;map&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;setView&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;47.2162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.5492&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;laURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;http://services.vuduciel.loire-atlantique.fr/geoserver/ows/&amp;quot;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;loireAtlantique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tileLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;laURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ORTHO44:jp2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;image/jpeg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;attribution&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Open Data D\u00e9partement de Loire-Atlantique&amp;quot;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;marker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;47.2162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.5492&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindPopup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Ch&amp;amp;acirc;teau des ducs de Bretagne&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;openPopup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nx"&gt;loireAtlantique&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;voici le &lt;a href="/examples/nantes-leafletjs.html"&gt;r&#233;sultat&lt;/a&gt; avec le code de l'exemple. &lt;/p&gt;
&lt;p&gt;Si on a besoin de modifier les images livr&#233;es par le WMS ou de servir les images depuis notre propre serveur web de fa&#231;on statique on peut utiliser par exemple &lt;a href="https://github.com/makinacorpus/landez"&gt;landez&lt;/a&gt; qui permet de t&#233;l&#233;charger les images (tiles) d'une zone particuli&#232;re de la carte, les modifier et les h&#233;berger dans un r&#233;pertoire de notre serveur web.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer :&lt;/strong&gt; ma langue maternelle est l'espagnol, donc n'h&#233;sitez pas &#224; me corriger s'il y a des fautes d'orthographe :)&lt;/p&gt;</description><guid>photographies-aeriennes-de-nantes-avec-leafletjs</guid><pubDate>Sat, 04 Jan 2014 01:15:00 </pubDate></item><item><title>Do not program defensively</title><link>https://seminar.io/2013/12/19/do-not-program-defensively/</link><description>&lt;a href="http://www.erlang.se/doc/programming_rules.shtml#HDR11"&gt;Do not program defensively&lt;/a&gt;&lt;br&gt;&lt;blockquote&gt;
&lt;p&gt;Most of the code in the system should be written with the assumption that the input data to the function in question is correct. Only a small part of the code should actually perform any checking of the data. This is usually done when data &lt;strong&gt;enters&lt;/strong&gt; the system for the first time, once data has been checked as it enters the system it should thereafter be assumed correct.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;source: Program Development Using Erlang&lt;/em&gt;&lt;/p&gt;</description><guid>do-not-program-defensively</guid><pubDate>Thu, 19 Dec 2013 08:49:00 </pubDate></item><item><title>Testing your REST client in Python</title><link>https://seminar.io/2013/09/27/testing-your-rest-client-in-python/</link><description>&lt;p&gt;When you start to write a client for a REST API in Python at beginning it's easy to test it using a Python interactive session,
but at some point you'll have to write tests, at that moment you'll see that it's not easy to test your code against live data from the RESTful web API.
You may encounter various problems, for example, you can have network problems when tests run, the web server may be temporarily down or tests become slow due to network latency.&lt;/p&gt;
&lt;p&gt;A solution to this problem is to use Mock objects, they simulate the behavior of your real objects in a controlled way,
so in this case a mock object may simulate the behavior of the &lt;code&gt;urlopen&lt;/code&gt; function (from the &lt;code&gt;urllib2&lt;/code&gt; module) and return &lt;em&gt;something&lt;/em&gt; like an HTTP response (a file-like object) without hit the real REST API. The file-like object returned may map a RESTful resource to a file which contains a pre-saved response from the real web server.&lt;/p&gt;
&lt;p&gt;To show the idea I wrote a simple REST client for the &lt;a href="http://developer.github.com/v3/"&gt;Github API&lt;/a&gt;. Here's what the directory structure looks like&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ tree project
project
&#9500;&#9472;&#9472; client.py
&#9492;&#9472;&#9472; tests/
    &#9500;&#9472;&#9472; test_client.py
    &#9492;&#9472;&#9472; resources/
        &#9492;&#9472;&#9472; users/
            &#9492;&#9472;&#9472; test_user

&lt;span class="m"&gt;3&lt;/span&gt; directories, &lt;span class="m"&gt;3&lt;/span&gt; files
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;I use &lt;a href="https://nose.readthedocs.org/"&gt;nose&lt;/a&gt; as test runner and &lt;a href="http://www.voidspace.org.uk/python/mock/"&gt;Foord's Mock&lt;/a&gt; library to create mock objects. You can install them into a virtualenv by typing&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ pip install nose mock
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here's the content of the &lt;code&gt;client.py&lt;/code&gt; file&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;urllib2&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlopen&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClientAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://api.github.com/users/&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As you can see, it calls &lt;code&gt;urlopen&lt;/code&gt;, parse the JSON data from the HTTP response and return a Python dictionary.&lt;/p&gt;</description><guid>testing-your-rest-client-in-python</guid><pubDate>Fri, 27 Sep 2013 12:38:00 </pubDate></item><item><title>All links are created equal</title><link>https://seminar.io/2013/09/10/all-links-are-created-equal/</link><description>&lt;blockquote&gt;&amp;ldquo;On an open Internet, where all links are created equal, good ideas win. Anyone, anywhere can share an idea that can be seen by millions.&amp;rdquo;&lt;br&gt;&amp;mdash;Alexis Ohanian, Reddit co-founder&lt;/blockquote&gt;</description><guid>all-links-are-created-equal</guid><pubDate>Tue, 10 Sep 2013 13:11:00 </pubDate></item><item><title>8-bit art in Nantes II</title><link>https://seminar.io/2013/08/18/8-bit-art-in-nantes-2/</link><description>&lt;img src="https://seminar.io/media/photos/IMG_20111002_185341-medium.jpg" alt="Mario Bros in Nantes"/&gt;&lt;br/&gt;Mario Bros in the streets of Nantes. Can you guess where I found it?</description><guid>8-bit-art-in-nantes-2</guid><pubDate>Sun, 18 Aug 2013 20:07:00 </pubDate></item><item><title>How to use the Percolate API with Python</title><link>https://seminar.io/2013/07/19/how-to-use-the-percolate-api-with-python/</link><description>&lt;p&gt;Recently, I've been working on migrate a Django project from &lt;a href="http://lucene.apache.org/solr/features.html"&gt;Solr&lt;/a&gt; to &lt;a href="http://www.elasticsearch.org/overview/"&gt;Elasticsearch&lt;/a&gt;, both of them are great search servers based on Apache Lucene, but Elasticsearch has an interesting feature called Percolate, that's missing on Solr.&lt;/p&gt;
&lt;p&gt;Percolate is the reverse operation of indexing and then searching. Instead of sending docs, indexing them, and then running queries. One sends queries, registers them, and then sends docs and finds out which queries match that doc.&lt;/p&gt;
&lt;p&gt;So, here an example of percolation from the &lt;a href="http://www.elasticsearch.org/guide/reference/api/percolate/"&gt;Percolate API documentation&lt;/a&gt; with Python. See the &lt;a href="http://www.elasticsearch.org/guide/reference/setup/"&gt;setup&lt;/a&gt; section to known how to setup Elasticsearch and get it running.&lt;/p&gt;
&lt;p&gt;First, you'll want to install &lt;a href="https://github.com/rhec/pyelasticsearch"&gt;pyelasticsearch&lt;/a&gt;&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ pip install pyelasticsearch
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Open a terminal and type &lt;code&gt;python&lt;/code&gt; to use the Python interactive console&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyelasticsearch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElasticSearch&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;es&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElasticSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://localhost:9200&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You need create a new index, named &lt;code&gt;test&lt;/code&gt;&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;acknowledged&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, you must specify a query to index. As the &lt;code&gt;_percolator&lt;/code&gt; index is also an index, we use the &lt;code&gt;index&lt;/code&gt; method to index it, &lt;code&gt;doc_type&lt;/code&gt; is the name of the index created before (&lt;code&gt;test&lt;/code&gt;) and &lt;code&gt;kuku&lt;/code&gt; is our query &lt;code&gt;id&lt;/code&gt;&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;query&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;term&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;field1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;value1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_percolator&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kuku&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kuku&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_version&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_index&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_percolator&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Finally to test a percolate request we need call the &lt;code&gt;percolate&lt;/code&gt; method with a document&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;doc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;field1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;value1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;percolate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;matches&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kuku&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We can see that &lt;code&gt;kuku&lt;/code&gt; matches with our document.&lt;/p&gt;
&lt;p&gt;For more details see the &lt;a href="http://www.elasticsearch.org/guide/reference/api/"&gt;Elasticsearch's reference API&lt;/a&gt; and the documentation of &lt;a href="http://pyelasticsearch.readthedocs.org/en/latest/api/#pyelasticsearch.ElasticSearch.percolate"&gt;pyelasticsearch&lt;/a&gt;.&lt;/p&gt;</description><guid>how-to-use-the-percolate-api-with-python</guid><pubDate>Fri, 19 Jul 2013 08:21:00 </pubDate></item><item><title>The value of breaking the law</title><link>https://seminar.io/2013/07/17/the-value-of-breaking-the-law/</link><description>&lt;a href="http://www.schneier.com/blog/archives/2013/07/the_value_of_br.html"&gt;The value of breaking the law&lt;/a&gt;&lt;br&gt;&lt;p&gt;Interesting post and essay about the value and the ability to break the law.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;source: &lt;a href="http://www.schneier.com/"&gt;Bruce Schneier's blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description><guid>the-value-of-breaking-the-law</guid><pubDate>Wed, 17 Jul 2013 08:20:00 </pubDate></item><item><title>8-bit art in Nantes</title><link>https://seminar.io/2013/07/11/8-bit-art-in-nantes/</link><description>&lt;img src="https://seminar.io/media/photos/1362486306334-medium.jpg" alt="Pac-Man Ghosts in Nantes"/&gt;&lt;br/&gt;One of the ghosts from the Pac-Man video game that I discover in the streets of Nantes.</description><guid>8-bit-art-in-nantes</guid><pubDate>Thu, 11 Jul 2013 12:12:00 </pubDate></item><item><title>Running Scrapy on Amazon EC2</title><link>https://seminar.io/2013/03/26/running-scrapy-on-amazon-ec2/</link><description>&lt;p&gt;Sometimes can be useful to crawl sites with &lt;a href="http://scrapy.org/"&gt;Scrapy&lt;/a&gt; using temporary
resources on the cloud, and Amazon EC2 is perfect for this task.
You can launch an Ubuntu OS instance and schedule your spiders using the Scrapyd API.
With &lt;a href="http://boto.readthedocs.org/"&gt;boto&lt;/a&gt;, a python interface to Amazon Web Services,
you can launch instances and install the scrapy daemon using the user data feature to run a script on boot.&lt;/p&gt;
&lt;p&gt;First, you need an AWS account with your access keys, a EC2 security group
accepting TCP connections on port 6800 and a key pair for the selected region.
After that you must choose an Ubuntu EC2 image, here you can find a list
of &lt;a href="http://cloud-images.ubuntu.com/locator/ec2/"&gt;Ubuntu AMIs&lt;/a&gt;.&lt;/p&gt;</description><guid>running-scrapy-on-amazon-ec2</guid><pubDate>Tue, 26 Mar 2013 16:21:00 </pubDate></item><item><title>Ubatar and the Ubuntu App Showdown</title><link>https://seminar.io/2012/07/08/ubatar-and-the-ubuntu-app-showdown/</link><description>&lt;p&gt;The last 3 weeks I was working on developing an application to participate in
a contest called &lt;a href="http://developer.ubuntu.com/showdown/"&gt;Ubuntu App Showdown&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My application is called &lt;a href="https://launchpad.net/ubatar/"&gt;Ubatar&lt;/a&gt; and its main
objective is to provide a solution to this &lt;a href="http://brainstorm.ubuntu.com/idea/25833/"&gt;idea&lt;/a&gt;.
Here you can see some videos of the latest version of Ubatar fulfilling its purpose.&lt;/p&gt;
&lt;iframe width="853" height="480" src="//www.youtube.com/embed/Kn05Isb7lwE?list=PL66E4F18CC99EB82C" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;During these 3 weeks I learned many things, reading a lot of source code, looking
for &lt;a href="http://nullege.com/"&gt;examples&lt;/a&gt;
and &lt;a href="http://askubuntu.com/questions/tagged/application-development"&gt;discussing&lt;/a&gt; with other developers.
I can only say that I really enjoyed and was an incredible experience.
Thanks to all the Ubuntu development team and the community at large.&lt;/p&gt;
&lt;p&gt;And this is not the end of the project, there are still many things to improve,
if you want to help please contact me via this &lt;a href="https://launchpad.net/~pabluk/+contactuser"&gt;form&lt;/a&gt;.
Also any questions or suggestions can be sent to
&lt;a href="https://answers.launchpad.net/ubatar"&gt;Questions for Ubatar&lt;/a&gt; in Launchpad.&lt;/p&gt;</description><guid>ubatar-and-the-ubuntu-app-showdown</guid><pubDate>Sun, 08 Jul 2012 20:11:00 </pubDate></item><item><title>World IPv6 day</title><link>https://seminar.io/2012/06/06/world-ipv6-day/</link><description>&lt;p&gt;To celebrate the &lt;a href="http://www.worldipv6launch.org/"&gt;world IPv6 day&lt;/a&gt;
I decided to activate IPv6 on this blog.
Now you can visit my site with native IPv6 connectivity.&lt;/p&gt;
&lt;p&gt;If you want to know more about IPv6 you can start reading this
&lt;a href="http://www.google.com/intl/en/ipv6/"&gt;overview&lt;/a&gt;.&lt;/p&gt;</description><guid>world-ipv6-day</guid><pubDate>Wed, 06 Jun 2012 21:53:00 </pubDate></item><item><title>Installing Solr on Debian 6.0</title><link>https://seminar.io/2011/02/22/installing-solr-on-debian-6-0/</link><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; this is an old blog post, Solr is now included in Debian since 7.0, it can be installed through apt-get by calling &lt;code&gt;apt-get install solr-tomcat&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Recently I've been working on a Django project that uses the
&lt;a href="http://haystacksearch.org/"&gt;Haystack&lt;/a&gt; search API and the
&lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; search engine to perform full text
searching on indexed data.&lt;/p&gt;
&lt;p&gt;This project was initially deployed on a Debian 5.0 (Lenny) server with some
issues with Tomcat, but using the latest stable release of Debian (code named
&lt;a href="http://www.debian.org/releases/squeeze/"&gt;Squeeze&lt;/a&gt;) install Tomcat 6 and Solr is
very easy.&lt;/p&gt;
&lt;p&gt;Just run the following&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;apt-get install tomcat6 tomcat6-admin
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;download and install the latest version of
&lt;a href="http://www.apache.org/dyn/closer.cgi/lucene/solr/"&gt;Solr&lt;/a&gt;&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;wget http://apache.cict.fr//lucene/solr/1.4.1/apache-solr-1.4.1.tgz
tar xvfz apache-solr-1.4.1.tgz
&lt;span class="nb"&gt;cd&lt;/span&gt; apache-solr-1.4.1
cp dist/apache-solr-1.4.1.war /var/lib/tomcat6/webapps/solr.war
cp -fr example/solr /var/lib/tomcat6/
chown -R tomcat6:tomcat6 /var/lib/tomcat6/solr
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;after install Solr you need to restart the tomcat6 service&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;/etc/init.d/tomcat6 restart
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And voil&#224;, Solr is running. Point your browser to
http://localhost:8080/solr/admin this should show the Solr Admin interface.&lt;/p&gt;</description><guid>installing-solr-on-debian-6-0</guid><pubDate>Tue, 22 Feb 2011 19:29:00 </pubDate></item><item><title>Screenkey 0.2 released!</title><link>https://seminar.io/2010/06/16/screenkey-0-2-released/</link><description>&lt;p&gt;A few days ago I released the first version of &lt;a href="/projects/screenkey/"&gt;Screenkey&lt;/a&gt;
which was reviewed positively by &lt;a href="http://www.omgubuntu.co.uk/2010/06/screenkey-desktop-recording-tool.html"&gt;OMG! Ubuntu!&lt;/a&gt;,
&lt;a href="http://www.korben.info/screenkey-le-logiciel-de-screencast-pour-ubuntu-qui-affiche-les-touches-tapees-au-clavier.html"&gt;Korben&lt;/a&gt;
and &lt;a href="http://linuxundich.de/de/ubuntu/screenkey-eingaben-screencasts-visualisieren/"&gt;Linux und Ich&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, I'm happy to announce the release of Screenkey 0.2. This release includes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A preferences dialog to adjust size and position&lt;/li&gt;
&lt;li&gt;Two keyboard modes (normal and raw)&lt;/li&gt;
&lt;li&gt;Command line options (see &lt;code&gt;--help&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Some &lt;a href="https://bugs.launchpad.net/screenkey/+bugs?field.status:list=FIXRELEASED"&gt;bug fixes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next release will include support for Launchpad translations, save session to file and more keyboard modes (specific vim and emacs key bindings).&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="http://www.sparsebrain.com/"&gt;Ivan Makfinsky&lt;/a&gt; for Fedora packaging and thanks to everyone who reported problems and made suggestions for improvement!&lt;/p&gt;</description><guid>screenkey-0-2-released</guid><pubDate>Wed, 16 Jun 2010 11:02:00 </pubDate></item><item><title>Le greffon OpenSubtitles de Totem</title><link>https://seminar.io/2010/05/25/le-greffon-opensubtitles-de-totem/</link><description>&lt;p&gt;Si vous n'avez pas encore mis &#224; jour votre syst&#232;me Ubuntu vers la derni&#232;re version 10.04 &lt;em&gt;Lucid Lynx&lt;/em&gt; et si vous utilisez le greffon de t&#233;l&#233;chargement de sous-titres du lecteur vid&#233;o Totem, vous remarquerez que le greffon ne marche plus.
Cela est d&#251; &#224; un changement de l'&lt;a href="http://trac.opensubtitles.org/projects/opensubtitles/wiki/XMLRPC"&gt;API XML-RPC&lt;/a&gt; du site &lt;a href="http://www.opensubtitles.org"&gt;opensubtitles.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mais bon pour le corriger, sans mettre &#224; jour votre syst&#232;me &lt;em&gt;Ubuntu 9.10&lt;/em&gt;, vous pouvez ouvrir un terminal et lancez la commande suivante&lt;/p&gt;
&lt;div class="pygments"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/lib/totem/plugins/opensubtitles/
sudo sed -i &lt;span class="s1"&gt;&amp;#39;s/www/api/&amp;#39;&lt;/span&gt; opensubtitles.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Ainsi, vous pouvez continuer &#224; t&#233;l&#233;charger vos sous-titres sans probl&#232;mes.&lt;/p&gt;</description><guid>le-greffon-opensubtitles-de-totem</guid><pubDate>Tue, 25 May 2010 22:18:00 </pubDate></item><item><title>Another Counter... and J2ME</title><link>https://seminar.io/2010/04/08/another-counter-and-j2me/</link><description>&lt;p&gt;Just to try Java Wireless Toolkit, also know as J2ME, on my Samsung C3050 mobile phone I wrote a silly and simple application called Another Counter, wich as its name says is used to count things, like a tally counter, then you can count people, events, measure traffic, etc.&lt;/p&gt;
&lt;p&gt;A version of the toolkit for Linux can be downloaded from &lt;a href="http://java.sun.com/products/sjwtoolkit/download.html"&gt;here&lt;/a&gt;, it includes build tools, utilities, examples, &#160;and a device emulator. With some knowledge of Java programming and reading the &lt;a href="http://java.sun.com/javame/reference/apis/jsr118/"&gt;API&lt;/a&gt; is easy to write small applications like this.&lt;/p&gt;</description><guid>another-counter-and-j2me</guid><pubDate>Thu, 08 Apr 2010 23:28:00 </pubDate></item></channel></rss>