Blog Programmes About

Nerd pastime

+

dots

+

nerd

=

This one is made from 1000 (careful, 4.2mo, prefer download) pic. 100 for this one.

Then, looking for way to make this look funnier I discover that cooler graph already exist.

Script.

An experiment.

This is the next xkcd I will reproduce.

pytestator, un script vim pour gérer ses tests unitaires plus facilement

J’ai (enfin) releasé un petit script vim pour rendre plus agréable l’utilisations de tests untaires pour python dans vim.

Le principe est assez simple, ce script vous introduit plusieurs nouveaux raccourcis dont voici les deux plus intéressants:

  • ,s qui vous fais passer du fichier de tests au fichier testé et vice versa (s pour swap)
  • ,tr qui lance le fichier de tests correspondant au fichier que vous êtes en train d’éditer, que vous soyez dans ce fichier ou dans le fichier de test (tr pour test run)

La page du script avec un peu plus d’informations et du mauvais anglais: http://www.vim.org/scripts/script.php?script_id=3151

Sinon des mappings que j’aime bien pour écrire mes tests unitaires:

imap ,ar self.assertRaises()<left>
imap ,ae self.assertEqual()<left>
imap ,at self.assertTrue()<left>
imap ,af self.assertFalse()<left>

Mes maps git pour vim

Un poste rapide pour vous donner mes maping pour git dans vim. J’ai beau avoir regardé tous les plugins vim pour git, aucun ne m’a plus, je me suis donc contenté de faire plein de maps pour pouvoir utiliser git dans vim et ce le plus rapidement possible.

Le principe est très simple et surtout facile à retenir: les maps commencent tous par “,” (comme tous mes maps ou presque) puis par “g” (comme git), après je rajoute une lettre qui est le début de la commande et je la mets parfois en majuscule quand c’est la même commande avec des options différentes. C’est tout bête mais ça permet de ne taper que 3 char pour faire n’importe quelle commande (qui est beaucoup plus longue à écrire), je me retrouve même à ouvrir vim pour utiliser git maintenant -_-“

map ,ga :!git add -p<cr>
map ,gA :!git add %<cr>
map ,gf :!git add
map ,gs :!git status<cr>
map ,gc :!git commit -m “”<left>
map ,gC :!git add %<cr>:!git commit -m “”<left>
map ,gd :!git diff<cr>
map ,gD :!git diff —cached<cr>
map ,gp :!git push<cr>
map ,gP :!git pull<cr>
map ,gb :!git branch<cr>
map ,gB :!git branch
map ,gh :!git checkout
map ,gi :!git init<cr>
map ,gt :!tig<cr>
map ,gl :!git log<cr>

WD12, WD29, la scission du PE sur internet

Remarque: désolé, ce poste est assez technique sur l’activisme contre ACTA, je suis trop fatigué pour tout vulgariser.

J’ai reçu aujourd’hui la liste des signataires de la déclaration écrite 29, qui sous couvert de protéger les gens nenfants, est en réalité un cheval de troi pour la data retention. Comme pour la déclaration écrite 12, contre ACTA, sûr laquelle je fais des graphes et des listes pour aider La Quadrature du net, je me suis amusé à faire des joulies graphiques.

Ce qu’il faut bien comprendre c’est que la déclaration écrite 12 est signé par les gens « pour » internet et la 29 par ceux « contre » (et ceux qui se sont fait avoir par le message manipulateur). Autant je m’attendais à des différences de résultat mais pas à un symétrie aussi flagrante, je vous laisse admirer.

(WD == written declaration == déclaration écrite)

Le résultat parle de lui même, la majorité des pays pour la wd29 ne soutiennent pas la wd12 et vice versa.

Continuant sur ma lancée, après des bidouillages dégueux et de l’édition de svg à la main et du bon gros scripting que j’oserais montrer à personne tellement il est moche, j’ai réussit à faire ces jolies cartes et je suis surpris de voir que même géographiquement on constate une symétrie. (En rouge la wd29 et en vert la wd12).

J’ai vraiment l’impression de voir 2 Europes de l’internet se distinguer (en tout cas dans le Parlement Européen), c’est assez surprenant. Je serais curieux de voir les conclusions d’un spécialiste du sujet (au hasard, La Quadrature sortira peut être un CP ou un dossier sur ce sujet).

Lifelogging, un script pour faciliter la tache

Tout a commencé quand j’ai lu un poste de blog que je n’arrive plus à retrouver, il parlait du lifelogging, la pratique de loger (noter, journaliser) toute une série d’informations sur sa propre vie. Cela permet pas mal de choses, des plus inutiles, comme de savoir que l’on a bu 1546 tasses de cafés depuis 16 mois, et des plus intéressantes tel que la découvertes de patterns (ie: quand je pratique tel type d’activités je me sens globalement mieux, quand je mange comme une merde ben je dors super mal etc …).

Toujours intrigué par cette pratique (et probablement pas son côté nerd) j’avais fait une première tentative dans un tableau openoffice. Constat: en quelques jours, voulant trop en (tout) faire, je me suis retrouvé avec 15 milles colonnes pas du tout pertinentes, un truc pénible et lourd à entretenir, à remplir plusieurs fois par jours. J’ai vite arrêté tout simplement parce que c’était chiant et que je n’ai rien réussit à en tirer.

J’ai récemment eu envie de m’y remettre (merveilleux blocus) et cette fois si, j’ai décidé de changer d’approche pour éviter ce qui était arrivé.

  • Ne le faire qu’une seule fois le lendemain matin
  • Cela doit prendre le moins de temps possible
  • Limiter la collecte d’informations à seulement celles qui sont pertinentes
  • Automatiser la tache, en tout cas le rappel
  • Et avoir des informations ayant le même format pour pouvoir comparer facilement

Résultat, je me suis fait un formulaire à remplir sur une page web en locale, la page ne contient que des radio et un petit champ texte pour mettre un commentaires.

Comme le résultat est assez personnel et surtout adapter à mon style de vie, je vais vous donner des bouts de code à compléter vous même si vous voulez reproduire la chose. Le code est, oh surprise, bien dégueux, j’ai simplement adapté l’exemple sur la page d’accueil de werkzeug en rajoutant un peu de SQLObjects dedans pour pouvoir entrer les informations dans une base de données en vu d’un traitement futur (des joulies graphiques quoi). Je vous conseil de quand même pas mal réfléchir à ce que vous allez loger et dans quelle forme, les changements de structure demandant une modification de la DB.

Pour l’automatisation je me suis simplement fait une tache cron qui m’envoi un mail tous les jours vers 5h du matin avec l’adresse de la page.

Le code html, à mettre dans un répertoire templates là où est le script python:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd“>
<html xmlns=http://www.w3.org/1999/xhtml xml:lang=“fr”>
<head>
    <title>Loglife v0.0</title>
    <meta http-equiv=“Content-Type” content=“text/html; charset=Utf-8” />
</head>
    <body>
        <center>
            <h1>Loglife V ${version}</h1>
        % if not already_fill:
            % if missing:
                <h2>Thoses informations are missing:</h2>
                <ul>
                % for i in missing:
                    <li>${i}</li>
                % endfor
                </ul>
            % endif
        <form action=“.” method=POST accept-charset=“utf-8”>
            <label>Ma première question</label><br />
            <input type=“radio” name=“ma_première_clef” value=“5” id=“1”/> Choix 6<br />
            <input type=“radio” name=“ma_première_clef” value=“4” id=“2”/> Choix 5<br />
            <input type=“radio” name=“ma_première_clef” value=“3” id=“3”/> Choix 4<br />
            <input type=“radio” name=“ma_première_clef” value=“2” id=“4”/> Choix 3<br />
            <input type=“radio” name=“ma_première_clef” value=“1” id=“5”/> Choix 2<br />
            <input type=“radio” name=“ma_première_clef” value=“0” id=“6”/> Choix 1<br />
            <p>Remarque, il est intéressant d’inverser l’ordre des choix parfois.</p>
            <p>Ma deuxième question.</p>
            <input type=“radio” name=“etudes” value=“0” checked=“checked” /> Choix 1<br />

            …

            <p>Commentaire:</p>
            <input type=“text” name=“commentaire” />
            <br />
            <br />
            <input type=“submit” name=“submit” value=“Envoyer” />
        </form>
        % else:
            % if success:
                <p>Grand succès !</p>
            % else:
                <p>Data already enter for yesterday, come back tomorrow !</p>
            % endif
        % endif
        </center>
    </body>
</html>

Le code python à complêter vous même (il ne marchera pas du premier coup):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ugly code is ugly

from os import path
from werkzeug import Request, Response
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
from mako.lookup import TemplateLookup

from sqlobject import *

from datetime import date, timedelta

__version__ = “0.1”

# calculate the path of the folder this file is in, the application will
# look for templates in that path
root_path = path.abspath(path.dirname(__file__))

# create a mako template loader for that folder and set the default input
# encoding to utf-8
template_lookup = TemplateLookup(directories=[path.join(root_path, ‘templates’)],
                                 input_encoding=‘utf-8’)

# here we can create the URL map.  Some sort of internal two-way
# mod rewrite :-)  The endpoints of those URLs are the names of the
# templates without the .html suffix we will render in the `dispatch_request`
# function.
url_map = Map([
    Rule(‘/’, endpoint=‘loglife’),
])

# TODO à remplir suivant (j’ai utilisé une bdd mysql) http://www.sqlobject.org/SQLObject.html#declaring-a-connection
sqlhub.processConnection = connectionForURI(“mysql://loglife:logtamère@localhost/loglife”)

# TODO à adapter aux questions suivant http://www.sqlobject.org/SQLObject.html#column-types
class Log(SQLObject):
    date = DateCol()
    premier_question = IntCol()
    # TODO
    commentaire = UnicodeCol()

# remarque, si vous modifiez la structure du précédent objet, n’oubliez pas
# d’adapter la table dans votre base de donnée
Log.createTable(ifNotExists=True)

@Request.application
def application(request):
    “”“A simple dispatch function that is the complete WSGI application
    that does the template rendering and error handling.
    ”“”
    # first we bind the url map to the current request
    adapter = url_map.bind_to_environ(request.environ)
    # then we wrap all the calls in a try/except for HTTP exceptions
    try:
        missing = []
        already_fill = False
        success = False
        today = date.today()
        yesterday = date.today() — timedelta(1)
        query = Log.select(Log.q.date == yesterday)

        if query.count() == 1:
            already_fill = True
        elif request.method == POST:
            # TODO
            clefs = [“L’ensemble des clefs que vous jugez obligatoire”]

            for i in clefs:
                if not request.form.get(i):
                    missing.append(i)

            if not missing:
                Log(date = yesterday,
                    premiere_question = int(request.form.get(“premiere_question”)),
                    # TODO complêter suivant les questions
                    commentaire = request.form.get(“commentaire”)
                    )

                success = True
                already_fill = True


        # get the endpoint and the values (variable or parts)
        # of the adapter.  If the match fails it raises a NotFound
        # exception which is a HTTPException which we catch
        endpoint, values = adapter.match()
        # now create an empty response object with the correct mimetype.
        response = Response(mimetype=‘text/html’)
        # now get the template and render it.  Pass some useful stuff
        # into the template (request and response objects, the current
        # url endpoint, the url values and a url_for function which can
        # be used to generate urls)
        template = template_lookup.get_template(endpoint + ‘.html’)
        # c’est là qu’on rajoute les variables à passer au template
        response.data = template.render_unicode(
            request=request,
            response=response,
            endpoint=endpoint,
            url_for=lambda e, **v: adapter.build(e, v),
            url_values=values,
            version = __version__,
            missing = missing,
            already_fill = already_fill,
            success = success
        )
        # now return the response
        return response
    except HTTPException, e:
        # if an http exception is catched we can return it as response
        # because those exceptions render standard error messages when
        # called as wsgi application
        return e


# if the script is called from the command line start the application
# with the development server on localhost:4000
if __name__ == ‘__main__’:
    from werkzeug import run_simple
    run_simple(‘localhost’, 4000, application)

ULR, url list reader ou mon viewer pour newsbeuter

MAJ: j’ai déjà reçu mon premier patch (gloire) par taziden qui permet d’ajouter l’url courante dans un fichier “bookmarks” (touche B) donc le code qui suit n’est plus à jours.

Situation: j’utilise newsbeuter pour lire mes RSS. C’est véritablement le meilleur lecteur de RSS sur lequel j’ai pu mettre la main, en plus il est en console. Sauf que, pour une fois la console me fait chier. En effet je lis plein de blog bayday et autre webcomics idiot et tout ce joli petit tointoin est rempli d’images ce qui ne fonctionne pas très bien en console. Surtout que j’ai une queryfeed avec des centaines d’éléments.

Dans l’ordre, voici les solutions qui s’offraient à moi:

  • utiliser la fonction intégré à newsbeuter pour ouvrir l’url dans mon naviguateur oueb. Ça va un moment, mais c’est lent et vraiment pas efficace.
  • histoire d’automatiser un peu le tout je me suis fait des macro super bourrin qui ouvre 10 20 30 40 80 120 élément dans mon browser. ça marche pas mal, sauf que Ça fait souvent péter firefox, faut attendre que tout est chargé, c’est pénible.

Puis finalement j’en ai eu marre et j’ai décidé de coder ma propre solution et voilà l’arrivé de ULR (vous remarquerez le subtile jeux de mot), un naviguateur web ultra minimaliste.

Le principe est simple: vous rajoutez des urls dans un fichier (ou lui passé en argument, il les rajoutera lui même). Puis vous le lancez le browser qui naviguera dans cette liste d’urls.

C’est du python, ça utilise webkit (le machin pour utiliser gecko était vraiment pourri en comparaison), c’est minimaliste, sans interface, juste des raccourcis clavier. J’aurais pu faire ça avec UZBL mais je n’ai pas eu le courage de chercher à comprendre comment le faire même si cela ne doit pas être bien difficile et puis quand je vois que cela tien sur moins de 200 lignes de python.

Un jouli screenshot:

url screenshot preview

Et parce que c’est toujours pratique pour l’utilisation, les raccourcis:

  • esc/q: quitter sans modifier la liste
  • n/espace: passe à l’url suivante (espace fait baisser l’écran aussi, j’ai eu la flemme de corriger ce bug)
  • r: fait un refresh de la page courante
  • s: sauve l’avancement dans la liste des urls (en gros supprime du fichier urls les urls déjà vu)
  • S: pareil puis quitte
  • y: copie l’url courante dans le clipboard de X (il faut avoir xclip installé)
  • f: envoie l’url vers firefox (il faut bien entendu qu’il soit installé)

Pour choper le code, un petit git clone git://git.worlddomination.be/python/ulr.git

EDIT: Le code qui suit ne correspond plus au master.

Et parce qu’il n’est pas très long mais bien dégeux (je n’avais aucun intérêt à le faire propre), voici le code:

#!/usr/bin/python
# -*- coding:Utf-8 -*-

import gtk
import os
import sys

import webkit
import gobject

class Browser:
    def delete_event(self, widget, event, data=None):
        return False

    def destroy(self, widget, data=None):
        gtk.main_quit()

    def open_list(self):
        self.urls = open(“urls”, “r”).readlines()
        if len(self.urls) == 0:
            print “List empty, fill list before launching”
            sys.exit(0)
        print len(self.urls), self.urls

    def __init__(self):
        gobject.threads_init()
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_resizable(True)
        self.window.connect(“delete_event”, self.delete_event)
        self.window.connect(“destroy”, self.destroy)
        self.window.connect(“key-press-event”, self.keyboard_cb)

        self.open_list()

        self.position = 0

        #webkit.WebView allows us to embed a webkit browser
        #it takes care of going backwards/fowards/reloading
        #it even handles flash
        self.web_view = webkit.WebView()
        self.web_view.open(self.urls[0][:-1])

        #entry bar for typing in and display URLs, when they type in a site
        #and hit enter the on_active function is called
        self.url_bar = gtk.Entry()
        self.url_bar.connect(“activate”, self.on_active)

        self.bar = gtk.Label()
        self.bar.set_single_line_mode(True)
        self.bar.set_text(self.urls[0][:-1] + “               “ + %i/%i % (self.position + 1, len(self.urls)))

        #anytime a site is loaded the update_buttons will be called
        self.web_view.connect(“load_committed”, self.update_buttons)

        scroll_window = gtk.ScrolledWindow(None, None)
        scroll_window.add(self.web_view)


        vbox = gtk.VBox(False, 0)
        vbox.pack_start(self.bar, False, True, 0)
        vbox.add(scroll_window)

        self.window.add(vbox)
        self.window.show_all()

    def on_active(self, widge, data=None):
        ”’When the user enters an address in the bar, we check to make
           sure they added the http://, if not we add it for them.  Once
           the url is correct, we just ask webkit to open that site.”’
        url = self.url_bar.get_text()
        try:
            url.index(“://”)
        except:
            url = http://+url
        self.url_bar.set_text(url)
        self.web_view.open(url)

    def go_back(self, widget, data=None):
        ”’Webkit will remember the links and this will allow us to go
           backwards.”’
        self.web_view.go_back()

    def go_forward(self, widget, data=None):
        ”’Webkit will remember the links and this will allow us to go
           forwards.”’
        self.web_view.go_forward()

    def refresh(self, widget, data=None):
        ”’Simple makes webkit reload the current back.”’
        self.web_view.reload()

    def update_buttons(self, widget, data=None):
        ”’Gets the current url entry and puts that into the url bar.
           It then checks to see if we can go back, if we can it makes the
           back button clickable.  Then it does the same for the foward
           button.”’
        self.url_bar.set_text( widget.get_main_frame().get_uri() )

    def main(self):
        gtk.main()

    def keyboard_cb(self, widget, event, data=None):
        #print “event:”, event
        keyname = gtk.gdk.keyval_name(event.keyval)
        print keyname
        if keyname == “Escape” or keyname == “q”:
            print “call deleting”
            self.destroy(widget)
        elif keyname == “space” or keyname == “n”:
            print “next”
            self.next()
        elif keyname == “r” or keyname == “R”:
            print “reload”
            self.refresh(“widget”)
        elif keyname == “b” or keyname == “p” or keyname == “Backspace”:
            print “previous”
            self.previous()
        elif keyname == “s”:
            print “saving”
            self.save()
        elif keyname == “S”:
            print “saving”
            self.save()
            print “destroying”
            self.destroy(“widget”)
        elif keyname == “y”:
            print “copy to clipboard”
            if os.system(‘echo -n “%s” | xclip -i’ % self.web_view.get_main_frame().get_uri()):
                print “#fail”
        elif keyname == “f”:
            print “go to firefox”
            if os.system(“firefox %s % self.web_view.get_main_frame().get_uri()):
                print “#fail”

    def save(self):
        urls = open(“urls”, “w”)
        for i in self.urls[self.position + 1:]:
            urls.write(i)

    def next(self):
        print “was:”, self.position
        if self.position < len(self.urls) — 1:
            print “go forwarf”, self.position + 1
            self.position += 1
            print “loading:”, self.urls[self.position][:-1]
            self.web_view.open(self.urls[self.position][:-1])
            self.bar.set_text(self.urls[self.position][:-1] + “               “ + %i/%i % (self.position + 1, len(self.urls)))
        elif self.position == len(self.urls) — 1:
            print “show finish”, self.position + 1
            data = ‘<html><head><title>Hello</title></head><body><center><h1>Finish</h1><h3>One more step forward and the browser will quit and empty the list</h3></center></body></html>’
            self.web_view.load_string(data, ‘text/html’, “utf-8”, “about”)
            self.position += 1

        else:
            print “end ? saving ? destroy”
            self.save()
            self.destroy(“widget”)

    def previous(self):
        print “was:”, self.position
        if self.position > 0:
            print “go back”, self.position — 1
            self.position -= 1
            self.web_view.open(self.urls[self.position][:-1])
            self.bar.set_text(self.urls[self.position][:-1] + “               “ + %i/%i % (self.position + 1, len(self.urls)))
        elif self.position == 0:
            self.position -= 1
            print “show begin”
            data = ‘<html><head><title>Hello</title></head><body><center><h1>Begin</h1></center></body></html>’
            self.web_view.load_string(data, ‘text/html’, “utf-8”, “about”)

if __name__ == “__main__”:
    if len(sys.argv) > 1:
        __dir__ = os.path.dirname(os.path.abspath(__file__))
        open(os.path.join(__dir__, “urls”), “a”).write(sys.argv[1] + \n)
    else:
        browser = Browser()
        browser.main()

Remarque: rien ne vous empêche de combiner ULR avec rsstail ou n’importe quel autre script ou programme.

Feel free to send patchs

Pour le configurer dans newsbeur, rajouter le simplement en browser, cela ne le lancera mais rajoutera l’url dans la liste des urls à lire, puis pour lire cette liste d’url il faudra lancer ulr manuellement.

Si vous trouvez l’ajout de fichiers lents via ulr.py, rien ne vous empêche de créer un script bash qui fait un echo $1 >> /path/vers/le/fichier/urls

Un petit souvenir de prague

Trouvé dans un ascenseur.

Edit: non je ne l’ai pas contacté rolala /o\

Vrac 1

Ne débordant pas de temps et surtout d’énergie à consacrer à l’écriture d’un poste plus fourni je vous livre une petite série de liens et d’astuces collectés dernièrement. Une bonne partie ne sont pas récente mais comme je les ressors souvent autant les remettre:

  • Ompload, une fonction bash pour envoyer le fichier en argument sur omploader.org, un chouette site qui support plein de formats de fichiers
  • ompload()
    {
        curl -# -F file1=@$1 http://omploader.org/upload|awk /Info:|File:|Thumbnail:|BBCode:/{gsub(/<[^<]*?\/?>/,”“);$1=$1;print};
    }
  • Conworld, un livre en ligne sur comment créer un univers fictif, je cherchais ça depuis longtemps donc je partage.
  • wordreference, le site pour traduire des mots, chaque options de recherches peut être rajoutées en moteur de recherche rapide pour firefox. Si vous utilisez vimperator n’hésitez pas à définir des mots clef pour ces moteurs de recherche.
    Par exemple: nf pour anglais ? français et fn pour français ? anglais.
  • Une vidéo qui montre comment très simplement préparer une grosse série de commandes shell à exécuter. Un must, ça m’a fait économiser énormément de temps à ne pas avoir à faire des boucles à la con et pour peut que vous maitrisiez les macro, :s et autre cela permet plein de choses sympa.
  • Imagemagick est un outil en CLI permettant de faire des modifications sur des images. Par exemple la commande pour redimensionner une image en gardant le ratio taille-largeur et en spécifiant une hauteur maximal est:
    convert image.png -resize 64x64\> image_small.png
    Les autres commandes de redimensionnement (imagemagick permet bien plus que ça).
  • Bartab, un super addon pour firefox qui permet de « décharger » (wééé !) un onglet pour économiser de la mémoire et plein d’autres joyeusetés comme ne par charger automatiquement les onglets au redémarrage de firefox pour pas attendre 50 ans que tout se charge.
  • Comment installer Gimp pour Ubuntu pour utiliser le mode mono fenêtre (infiniment plus agréable que le mode pop-ups). Pour les autres distributions il faut se procurer la version 2.7, comment activer le mode est décrit dans le lien.
  • Il est sympa le moteur de crysis quand même
  • Down for everyone or just me” un grand classique, ce site très pratique permet de tester sur un autre site internet est mourru.

C’est tout pour aujourd’hui.

Hello World

Ouverture prochaine ici même. Vu que c’est un journal personnel il y aura un peu tout et n’importe quoi qui m’intéresse, généralement nappé d’un fort côté geek (qui a dit nerd ?) et d’un brin d’humour (se prend au sérieux saimal).

Il me reste encore plein de petits trucs à changer, un design à faire et d’autres. Hésitez pas à me signaler les incohérences que vous remarquerez.

Un grand merci à Hobbestigrou sans qui à l’heure actuelle je n’aurais plus de cheveux et ce journal ne marcherait toujours pas.

A très bientôt o/