/dev/blah

things i want to remember, things i want to share

Développeur Python et adepte Linux depuis 2005, passionné par beaucoup trop de choses. Profil Github

Kivy hackathon in paris

written by tshirtman, on 4/16/13 12:04 AM.

Last week saw the first 24h hackathon event entirely dedicated to Kivy happening, in Paris. It was initiated by a hightly motivated student of the Cifacom school in paris, David Scheck, and attended by 4 groups of students, each with 3 to 5 members. I was pleased to share the hard task to help students discover the technology with my colleague Julien Miotte, from Majerti during the event.

The student weren’t very familiar with Python, and totally new to kivy, so it was a really challenging situation for both the student and the framework, would they be able to achieve anything in the hard limit of 24 hours?

First, after the students brainstormed on their project ideas, we got them through the major concepts and important classes of Kivy, using the Getting started page, it’s hard to get the point of properties accross in 10 minutes to student that didn’t have experienced the need of them, but I tried to at least make them aware it would be useful. The kv language presentation at this point, even if rudimentary, was probably useful, as we will see later.

Then students went on to try to build their project, except for a few quickly solved issues with windows installation, the starting was smooth. Julien and I gave some more explanations about how to start building a basic App (the doc is there, but who reads the doc? ;)) and people started designing their interface, and build the core of their application.

Eat Smart

One of the most required feature was certainly the use of multiple screens in an application, to build menu, so the use of ScreenManager was explained to at least two groups. Most of the end results consisted of interfaces done mainly in Kv, and some internal logic to display data, most group had a quite ambitious target, using geolocalisation, databases, complex interactions, and I wasn’t very optimistic on the odds of seeing them completed. Although I was right in that, I was still happy of the good designs they came up with, applications were incomplete (to a notable exception, will come back to that soon), but some interfaces were beautiful, reactive and engaging, so it was nice to see the magic happen in such a short time.

Floor2be

One group had a very different objective of the others, and although they had a difficult start, it turns out they were probably the best at teamwork, and had chosen a target they could actually achieve, a game! These motivated coders/artists came up with a classic 2D sidescroller, when the main character has to avoid elements on her way. Simple, to the point, and a quite a good realisation in such a short time, the fact that they created original artworks and integrated them in their game, and that the general theme had a nice touch of humour in the current political events in France certainly hearned them points, on top of having a completed project. They even could test it on Android during the competition time, and it was running perfectly. Their hard work earned them the right to run in a bigger international competition in the near future the angel hack in paris, next month, congratulation! I can only hope they’ll chose kivy as their secret weapon in this competion too.

The BoutinRun team at work

I would love to have better pictures, but i didn’t think much of taking them during the event, I should have better ones soon.

Tip me if you like this :)

Mutt + offlineimap + notmuch + nottoomuch

written by tshirtman, on 3/17/13 4:00 PM.

Some time ago, I got tired of various bugs and the general slowness of thunderbird, and decided to try to go back to a more sensible setup. I’m a big CLI user, and trying mutt again made sense, even if my first experience with it two years ago had been inconclusive, I decided to do things right this time.

After some research, I concluded what I did wrong last time was to give to much responsibility to mutt itself, and that I should use it only for what it’s good at, displaying mails. So I went on to complete the various pieces of the puzzle.

Getting mails

For various reasons, even though my computer is always connected to the internet, I think it’s good idea to have a local copy of my mails, one of them is that although my ubiquitous mail provider has a “don’t be evil” moto, such a big company can still screw up, and some people have been trapped out of their mail in the past, if it happens to me, at least I have a backup.

So I set up offlineimap, as a way to retrieve emails to a local MailDir. Setting up offlineimap is not complex, you edit the .offlineimaprc file to declare your accounts, and it gets your mail each time you start it.

Here is the general structure of the file

[general]
# list of the configured accounts
accounts = Personal, Professional
fsync = False 

[Account Personal]
localrepository = Local
remoterepository = Remote
#autorefresh = 10 # no autorefresh, i run it one-shot each time
quick = 30
status_backend = sqlite
maxage = 900

[Repository Local]
type = Maildir
localfolders = /media/gabriel/stockage/Mail/Personal

[Repository Remote]
type = Gmail
remoteuser = example@gmail.com
realdelete = no
# google app-specific password
remotepass = 
ssl = yes
maxconnections = 5
holdconnectionopen = yes
sslcacertfile = /etc/ssl/certs/ca-certificates.crt
postsynchook = notmuch new

# then nearly the same thing for Professional and its 
# repositories

It’s easy, the general section reference to the account sections, and the account sections reference the repository sections, the local is where you store the files, the remote is where they are on the mail provider. If you use gmail (there, i said it) and 2factors authentication (which i recommend you to do) you can use an app-specific password here.

As there is a few gigs of mails, I decided to put them out of my home directory, you can put them wherever you want, as long as it’s mounted when offlineimap is started (heh).

Also, we tell it to export the mailbox names for mutt to be able to display them:

[mbnames]
enabled = yes
filename = ~/.mutt/mailboxes
header = "mailboxes "
peritem = "+%(accountname)s/%(foldername)s"
sep = " "
footer = "\n"

This works to show gmail’s tags.

I use cron to run offlineimap with the desired granularity

0 * * * * offlineimap

Displaying mails

This is mutt’s job, first we need to tell it where the mails are:

in muttrc

set mbox_type=Maildir
set folder=/media/gabriel/stockage/Mail

I tried to cut most configuration in separate files by usage:

source $HOME/.mutt/mailboxes
source $HOME/.mutt/folder_hooks
source $HOME/.mutt/macros
source $HOME/.mutt/colors
source $HOME/.mutt/sidebar
source $HOME/.mutt/statusbar
source $HOME/.mutt/pager
    source $HOME/.mutt/query

We’ll see them later (except mailboxes, which is generated by offlineimap as seen before).

Customize index view:

set index_format="%Z %{%a %d %b %Y} %3M %-15.15L │%s"

Then a few general options.

set realname = "Gabriel Pettier"

# initial box
set spoolfile=+Personal/INBOX

set header_cache =~/.mutt/cache/headers
set message_cachedir =~/.mutt/cache/bodies
set certificate_file =~/.mutt/certificates
set mailcap_path = $HOME/.mutt/mailcap

set move = no  #Stop asking to "move read messages to mbox"!

ignore headers *
unignore headers from to subject date cc

set sendmail_wait=-1
set wait_key = no        # shut up, mutt
set timeout = 3          # idle time before scanning
set mail_check = 0       # minimum time between scans
unset move               # gmail does that
set delete               # don't ask, just do
unset confirmappend      # don't ask, just do!
set quit                 # don't ask, just do!!
unset mark_old           # read/new is good enough for me
set smart_wrap

I can delete mails from INBOX, they are still in “All mails” (here “tous les messages”), so the effect is exactly the same as archiving them.

foder_hooks

folder-hook . 'unset trash'
folder-hook Personal source $HOME/.mutt/accounts/personnal
folder-hook Professional source $HOME/.mutt/accounts/Professional

both of these files being modified copies of accounts/dummy

unset from;
unset signature;
set from="Gabriel Pettier <gabriel.pettier@gmail.com>";
set smtp_url = "smtp://gabriel.pettier@smtp.gmail.com:587/"
set smtp_pass = ""
set trash="=[Gmail].Corbeille";
set mbox="=[Gmail].Tous les messages";
set postponed="=[Gmail].Brouillons"'
set signature="";

This is mostly for having the correct sending address and signature based on which mail box I’m in.

macros

    bind editor <Tab> complete-query
bind editor ^T complete

This is to have contact completion in to/cc/bcc inputs

macro index,pager c "<change-folder>?<toggle-mailboxes>" "open a 
different folder"

macro index p "<enter-command>set pager_index_lines=30"
macro index P "<enter-command>set pager_index_lines=0"

Using mutt with the sidebar patch, i don’t use these much.

bind index gg       first-entry
bind index G        last-entry

Faster vim-like navigation

bind index R        group-reply
bind index u        sync-mailbox
bind index <space>  collapse-thread
bind index _        collapse-all

bind compose p postpone-message

macro index,pager d "<save-message>=[Gmail].Corbeille<enter>"           "move message to the trash"
macro index,pager S "<save-message>=/[Gmail].Spam<enter>"                "mark message as spam"

Manage draft/trash/spam folders

colors

I kept things simple on this one

color header brightred default subject
color hdrdefault cyan default
color quoted green default
color status cyan default
color indicator red default
color normal white default
color tree cyan default

sidebar

This is only useful if you use the sidebar patch of mutt (mutt-sidebar on ubuntu).

# set up the sidebar, default visible
set sidebar_width=43
set sidebar_visible=yes
set sidebar_delim   = '  │'

# color of folders with new mail
color sidebar_new yellow default

# up/down to select next, prev folder
# right to open selected folder
bind index,pager <up> sidebar-prev
bind index,pager <down> sidebar-next
bind index,pager <right> sidebar-open

# I don't need these.  just for documentation purposes.  See below.
# sidebar-scroll-up
# sidebar-scroll-down

# b toggles sidebar visibility
macro index b '<enter-command>toggle sidebar_visible<enter>'
macro pager b '<enter-command>toggle sidebar_visible<enter>'

statusbar

I customized the status bar (at the bottom of the pager), to display more information.

set status_chars  = " *%A"
set status_format = "───[ Folder: %f ]─%V──[%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]───%>─%?p?( %p postponed )?─── %l|%L"

%V shows if we currently have a filter (l) on the view, and %l/%L display the file size of the box, I’m not sure of the difference between both values, they are usually equal for me.

pager

This manage the display/navigation when a mail is open for reading.

set pager_index_lines = 10 # number of index lines to show
set pager_context = 3      # number of context lines to show
set pager_stop             # don't go to next message automatically
set menu_scroll            # scroll in menus
set tilde                  # show tildes like in vim
unset markers              # no ugly plus signs

set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+"
alternative_order text/plain text/enriched text/html

bind pager R  group-reply

# View attachments properly.
bind attach <return> view-mailcap

Also, the viewing of attachment files is managed using mailcap preferences.

query

This is to hook with nottoomuch-addresses and fixing the output format

set query_command="$HOME/.mutt/ntmw.sh %s"
set query_format="%t %-25.24n %a %e"

We’ll see the ntmw.sh script later, info on the query_format can be found here (took me quite some time to find how to fix the stupid column default width).

mailcap

#MS office documents
application/excel; $HOME/.mutt/mutt_bgrun libreoffice %s
application/ms-exc; $HOME/.mutt/mutt_bgrun libreoffice %s
application/msword; $HOME/.mutt/mutt_bgrun libreoffice %s
application/vnd.ms-exc; $HOME/.mutt/mutt_bgrun libreoffice %s
application/vnd.ms-excel; $HOME/.mutt/mutt_bgrun libreoffice %s
application/x-msexcel; $HOME/.mutt/mutt_bgrun libreoffice %s

I don’t get these often, but still nice to be able to open them

# Images
image/*; $HOME/.mutt/mutt_bgrun eog %s

# PDFs
application/pdf; $HOME/.mutt/mutt_bgrun evince %s

# HTML
text/html; $HOME/.mutt/mutt_bgrun firefox %s

text/*; vim %s

# Unidentified files
application/octet-stream; $HOME/.mutt/mutt_bgrun xdg-open %s

multipart/alternative; less %s

As you can see, I use the mutt_bgrun script so opening gui applications to display a file doesn’t block mutt, I found this script here, and it works well.

searching

Searching through mails is done using notmuch, notmuch is mainly an interface to the xapian search engine, it’s fast and reliable, you just need it configured and bound to a key in mutt to start a search.

Configuration (~/.notmuch-config):

[database]
path=/media/gabriel/stockage/Mail

[user]
name=Gabriel Pettier
primary_email=gabriel.pettier@gmail.com

[new]
tags=unread;inbox;
ignore=

[search]
exclude_tags=deleted;spam;

[maildir]
synchronize_flags=true

As configured before, offlineimap will start it after sync, so not much more to do (the first import will take some time, the next ones will be really fast).

Install notmuch-mutt (’apt-get install notmuch-mutt’ on ubuntu), this adds the F8 and F9 macros to search through your mails using a simple syntax (do F8 then help to get started), and then return the result as a pseudo mailbox you can manipulate as any mailbox, F9 allows you to get the entire thread the selected mail comes from. I usually use the sidebar to get back to the mailbox I’m interested in after.

Contacts completion

I didn’t have much success with the goobook script, so i searched more, and fund that there was a way to use notmuch to provide me all the addresses I know about, there are various scripts to do that, but nottoomuch-addresses.sh was hailed as the fastest one, so I gave it a try.

Get it from here and run it with –update to get your addresses list generated (again, first import will take some time, next ones much less).

However, it’s more designed to be used with emacs than with mutt, thus integration is not perfect, so I did a small wrapper:

ntmw.sh

#!/usr/bin/env sh
# nottoomuch-addresses.sh wrapper

$HOME/.mutt/nottoomuch-addresses.sh "$1" \
    |sed -s 's/\(.*\) \(<.*\)/\2\   \1/'\
    |sed -s 's/\"//g'\
    |sed -s '/buzz+.*/d'\

This reverses order of mail address and real name in the answer, and separates them with a tab (so mutt’s query-menu put them in different columns), it also removes “ caracters, as mutt adds some on its own, finally, I added a small filter to remove old adresses i won’t care about ever (generated by now-defunct google buzz).

So now when I type in a to/cc/bcc input, i get a list of all the addresses containing the typed input, I can select a few different ones with ‘t’ or just type enter to have the selected one inserted, the only issue i have with it is to insert multiple different addresses, once you have inserted an address, the search doesn’t work, the solution is to go to the beggining of the line again (home key), and to insert the new name, the search will now work, so you just have to do your additions in reverse order.

Conclusion

This may be not the perfect setup (yet), but it works great for me, I’m confident my mails are secure and easy to search, I have great (and fast!) contact completion, and can type my mails in vim. Finally, adding a new mailbox (for work or whatever) is easy thanks to offlineimap. I still go to gmail interface to setup filters, as I prefer these things to be server side, and i don’t see how to do these configuration from anything client-side, but it’s not an everyday operation, so no hurry with that.

Tip me if you like this :)

Debugging python-for-android with gdb

written by tshirtman, on 11/13/12 1:55 AM.

So i’ve been sinking a lot of time in trying to make python-for-android support multiprocessing, and for various reasons, it turns out to be a bad idea®, but in doing that, i had to go to great extents to understand more about python-for-android, about gdb, and about android itself. So, if it can save some trouble to others, i’ll try to document here the things i found how to do in this situation.

So the first thing to do is to get python-for-android compiled with debug symbols, so you can feed gdb with them, i found android-ndk-r8b to work much better after (well, to work at all), so it’s good to start with it, i put my changes in a branch of python-for-android repository, aptly called `debug` but they are not that big in fact, it’s mostly removing stripping in places, and adding -g in others.

With those changes, one can build a python-for-android distribution usable for debugging.

./distribute.sh -f -m 'kivy' -d debug

then, build your to-be-debugged application with this distribution, and install it, from then, you need a shell access to your android terminal (i use ssh, because adb over wifi is flacky but that’s another story, adb shell is good), you must then check if your terminal has the gdbserver command, if not, you can push it from the ndk to the terminal, and give it execution rights.

adb push ~/android-ndk-r8b/prebuilt/android-arm/gdbserver
adb shell
chmod 755 gdbserver

now, you can start your test program (from the UI), and tell gdbserver to attach to it,

ps | grep python
gdbserver :5050 --attach $pid

obviously using the pid found using the command, i use a shortcut though

./gdbserver :5050 --attach $(ps | grep python | tail -n 1 | tr -s " " " "| cut -d" " -f2)

This will tell gdbserver to listen on port 5050 (you can chose about any number between 1024 and 65536) and then the fun part begins

using the gdb in the ndk, load the pymodules.so file

$ ~/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb\
 ~/python-for-android/dist/debug/private/libpymodules.so

of course, this path (and the following ones) will need to be adapted to your system!

once in gdb, you’ll want to attach to the gdbserver on your device, i assume you are on the same wifi network as your device, but if not, you can do a port redirection through adb link i think

(gdb) target remote transformer:5050

If everything went fine, you should get a message a bit like this

Remote debugging using transformer:5051
warning: while parsing target library list (at line 2): No segment defined for com.showgen.processcraft.freemium:python
warning: Could not load shared library symbols for 87 libraries, e.g. /system/bin/linker.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0x400b9384 in ?? ()

as the helpful message put it, we need to tell gdb where it can load the shared libs with debug symbols. Personnaly i found this setting of `solib-search-path`to work well:

(gdb) set solib-search-path \
/home/gabriel/python-for-android/src/obj/local/armeabi/:\
/home/gabriel/python-for-android/dist/debug/private/lib/python2.7/lib-dynload/:\
/home/gabriel/python-for-android/dist/debug/libs/armeabi/

You can check the result of this by using the command `info sharedlibrary` (or `i sh` for the lazy) to see if symbols have been found, the interresting part for me is:

0x56d31348  0x56d5c148  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl.so
0x579b5400  0x579d5798  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_image.so
0x579fa428  0x57a2c1f8  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_ttf.so
0x56a5a6b0  0x56a69c20  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_mixer.so
0x5b985570  0x5bbc9e90  Yes         /home/gabriel/python-for-android/dist/billing/libs/armeabi/libpython2.7.so
0x56a79a1c  0x56a79c04  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libapplication.so
0x56dee534  0x56dee5e8  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_main.so
0x57604450  0x5761ed40  Yes         /home/gabriel/python-for-android/dist/billing/private/lib/python2.7/lib-dynload/_io.so
0x57a7426c  0x57a77630  Yes         /home/gabriel/python-for-android/dist/billing/private/lib/python2.7/lib-dynload/unicodedata.so
0x57b5b058  0x57b97d00  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsqlite3.so

Interrestingly, it seems the command is only useful after connecting to the target, doing it in reverse order doesn’t seem to bring any result, so the `search` is probably done only once, whet the search-patch is set.
Now, you can use the command `continue` or set breakpoints, or other rather common usage of gdb there. There are quite some resources out there about gdb usage :)

It’s not perfect, but i found it helping to be able to backtrace things on the tablet, in the nasty case you get a crash, or some weird “OSError”, with an unhelpful message, comming from the C side of things.

For the story, my error was likely caused by memory corruption due to the way we tried to reimplement the multiprocessing use of semaphore (sem_open being not implemented in android), and there is apparently no good way to do it. So i’ll look into android services instead when i have time, and try to give an API in python for that.

Tip me if you like this :)

[Kivy] android-like pulldown menu

written by tshirtman, on 10/22/12 9:29 PM.

kivy all the things

As someone asked how to do such thing in kivy, i spent some time writting it, and as i (sadly) don’t blog on kivy often (if ever?), and since i think this example is quite telling about how kivy make such things quite easy, let’s talk a bit about this code.

To put things in context, what we want is the bar at the top of the android phones, that one can pull down to see notifications, this one is semi transparent and goes over the normal screen.

So, here is the code. first the kv part:

FloatLayout:
    FloatLayout:
        # placeholder for the "normal screen"
        Label:
            center: root.center
            text: 'test content'
            size_hint: None, None
            size: self.texture_size

    ScrollView:
        # container for the "notifications"
        y: dg.top # let's stick it to the top
        x: root.x # and to the left
        size_hint_y: None
        do_scroll_x: False # only vertical scrolling
        do_scroll_y: True
        
        # most of the magic is there, auto adjust size to follow the draggable label
        height: root.top - dg.y

        # let's put a nearly opaque black background
        canvas:
            Color:
                rgba: 0, 0, 0, .8
            Rectangle:
                pos: self.pos
                size: self.size
        
        # the actual notification container, with placeholder content
        BoxLayout:
            size_hint_y: None
            height: 1000
            orientation: 'vertical'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'

    # the draggable label, which behaviour is defined in python file
    DraggableLabel:
        # some decoration behind the text
        canvas.before:
            Color:
                rgba: 0, 0, 0, 1
            Rectangle:
                pos: self.pos
                size: self.size
            Color:
                rgba: .5, .5, .5, 1
            Rectangle:
                pos: self.pos
                size: self.width, 1

        size_hint_y: None
        top: root.top
        # assign its id to "dg" so we can reference it elsewhere
        id: dg
        height: '20pt'
        text: 'drag me'

then the python part

from kivy.app import App 
from kivy.uix.label import Label
from kivy.animation import Animation


class DraggableLabel(Label):
    '''A label you can drag upside-down'''
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            # assure ourselves we will get the updates of this motion
            touch.grab(self)
            return True

        return super(DraggableLabel, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch.grab_current is self:
            # really straightforward...
            self.y = touch.y
            return True

        return super(DraggableLabel, self).on_touch_move(touch)

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            # check if the movement direction was up or down
            if touch.dy < 0:
                a = Animation(y=0) # down? put the bar all the way down
            else:
                a = Animation(top=self.parent.top) # up? put it at the top

            a.start(self) # actually start the animation
            return True

        return super(DraggableLabel, self).on_touch_up(touch)


class TabApp(App):
    pass


TabApp().run()

 

I think it doesn’t really need more explanations, the DraggableLabel is looking for touch events that are for it, first if they are on it, then if they are grabbed by itself, and move accordingly, and the kv auto adjust the size of the ScrollView to take all the distance between top of the screen and top of the DraggableLabel.

Of course, if things are not clear, feel free to ask questions :)

Tip me if you like this :)

Gödel, Escher, Bach

written by tshirtman, on 9/27/12 2:50 PM.

Je regarde depuis quelques jours la série de cours magistraux du MIT donné sur ce bouquin en 2007, disponible sur youtube, c’est fascinant, non seulement les sujets abordé, mais je trouve toujours impressionnant comment les profs du MIT arrivent à aborder des notions complexes, en supposant que vous n’y connaissez rien et expliquer très rapidement les concepts.

Ce cours est très orienté philosophie, en fait, les maths y sont juste un support d’étude de l’univers, des concepts étudiés (qu’est ce que le langage, qu’est ce que le sens, la conscience…). Le cours touche vraiment à beaucoup d’aspect fondamentaux du monde et de notre conception de celui ci à travers les ages, au travers de notre évolution de la compréhension des mathématique et de la physique, mais le niveau requis en mathématique n’est pas très elèvé, le prof semble désolé quand il écrit une formule avec un sinus dedans, ou pire, une dérivée.

Un seul regret, cependant, les parties de lecture du livres ont systématiquement été coupé au montage, et je n’ai pas le livre (et pas sur d’avoir le temps de le lire, c’est pour ça que je regarde le cours, ça va plus vite), donc on loupe bien sur une partie du cours, et à forciori, du sens du livre, ça m’apprendra à être pressé, mais qui sait, peut être que ça excitera assez ma curiosité pour que je me procure le livre :).


Tip me if you like this :)

Hacking tablette carrefour CT705

written by tshirtman, on 9/20/12 10:38 PM.

Carrefour a fait pas mal de pub sur une tablette 7″ android 4.0 à 77€, ça avait pas l’air trop mal dedans, alors pour le prix, j’en ai commandé une.

C’est pas mal, mais de base, on peut pas faire grand chose avec… J’ai vu qu’on pouvait installer cyanogenmod dessus, mais tout ne marche pas encore, donc j’ai préféré résoudre les problèmes un par un.

Installation du market:

Oui, par défaut, il n’y a pas google play… il y a un market alternatif très limité, «getjar», j’ai trouvé une procédure pour installer le market et ses dépendances à la main, en cliquant les apk, mais ça n’a jamais voulu marcher, j’avais toujours une «server error» en lançant le market, ou pire, un crash.

J’ai finit par rooter la tablette, en utilisant ce script, que j’ai trouvé sur un coins du net, et convertis de batch à bash: https://gist.github.com/3758061 (les fichiers associés sont )

Sauf que… adb ne voyait pas la tablette, ça a faillit me rendre fou… la solution, ça a été de faire :

android update adb
echo "0x2207" > ~/.android/adb_usb.ini
adb kill-server
adb root
adb start-server

La tablette est ensuite correctement visible, et `adb shell` marche (le numéro magique, 0x2207, vient d’une doc sur une tablette archos basé sur la même archi, c’était un peu du pifometre, mais ça a marché, alors…) (edit: cette solution ne marche pas tout le temps, je n’ai pas encore bien compris, un conseil, une fois que vous avez réussis et rooté, installez un serveur ssh, dropbear ssh server est très bien).

Une fois, donc, la tablette rooté, j’ai pushé buildroid-gapps-ics-20120317-signed.tgz, remonté /system en rw, et extrait le contenus dans /, puis redémarré… (procédure et archive trouvé )

Changement de DPI:

Je trouve la résolution un peu faiblarde, j’ai vu qu’on pouvait changer le DPI pour caser plus de choses dans l’interface, il y a des applications pour ça, mais celle que j’ai crashait par ce que la bonne clée n’était pas dans le fichier de conf, j’ai donc fait les changement à la main.

su
mount -o remount,rw /system
vi /system/build.prop
# ajouter "ro.sf.lcd_density=120" dans le fichier
mount -o remount,ro
reboot

J’aurais bien mis moins, mais ça faisait crasher le launcher (une division par 0, pour ce que m’ont dit les logs… huhu)

Changer le laucher (justement).

Je trouvais le launcher un peu lourdingue, donc j’ai installé trebuchet, celui de CyanogenMod. trouvé .

Le soucis, c’est qu’on ne peut pas installer l’apk normalement, enfin si, mais il ne marche pas bien, certaines permissions ne sont pas accessibles aux applications non «système», il faut donc l’installer dans /system

adb push Trebuchet.apk /sdcard/
adb shell
su mount -o remount,rw /system
cp /sdcard/Trebuchet.apk /system/app/
mount -o remount,ro
reboot

on peut maintenant reprendre la procédure précédente, et passer la DPI à 96, ça marche… il faut juste ensuite aller dans les options et passer le texte en “gros” ou “très gros”, par ce que sinon il n’est pas affiché… je pense que “très gros” est le plus raisonnable, ça reste un peu petit, sérieusement, mais je pense que c’est bien comme ça, on a bien plus de place qu’avant…

Conclusion:

Pour le prix… je suis pas déçus, on peut faire pas mal avec cette tablette, y’a un peu de bricolage pour en tirer le meilleur partis, mais c’est faisable…

Ah, et vu que c’était le but, quand même, les applications kivy marchent très bien dessus… (mais ne profitent pas du changement de dpi, elles comptent en pixels, Mathieu Virbel travaille la dessus, ça devrait arriver dans quelques temps).

Tip me if you like this :)

PyJNIus mailing list

written by tshirtman, on 9/6/12 3:43 PM.

Since there are some questions/discussions that doesn’t perfectly fit as github issues, i just created a google group to discuss PyJNIus development, i hope this will make collaboration easier.

https://groups.google.com/forum/#!forum/pyjnius-dev

pyjnius-dev@googlegroups.com

Tip me if you like this :)

Pyjnius

written by tshirtman, on 8/20/12 4:46 PM.

J’ai bossé ces derniers jours avec Tito (oui, enfin, il a fait 90% du code ^^) sur une petite lib pour manipuler des objects java de façon transparente depuis python, à l’origine prévus pour le project python-for-android, mais c’est finalement utilisable sur desktop aussi, ça marche vraiment pas mal, et ça peut sans doute intéresser des gens, on a parfois besoin de bosser avec un système java depuis python, et cette lib fournis une interface je pense très agréable pour le faire.

Présentation sur le blog de Tito avec un peu plus de détails.

Le project est hébergé sur github.

Get it while it’s hot ! :)

Tip me if you like this :)

Announcing PythonAR

written by tshirtman, on 8/7/12 9:56 PM.

Some time ago, doing heavy-client dev (with kivy, check it out, it’s great!), i got bored with the save/run/quit/edit workflow, and having used flask and other tools with “–reload” like options, i wondered if there was something more generalistic.

I didn’t find anything, thought i didn’t search a lot, but i decided to scratch that itch, and to build a solution usable for about anything.

So after a few hours of hacking, i got a first version of an app reloader, using the watchdog lib, and some subprocess hacking. However the application was stealing the focus everytime it was started, wich made it a bit less fun to use. Another problem was there are a lot of events when you edit files (temporary files), and even when you save, a file editor as vim can produce as much as 8 events for only one save action. So a few options were added, and i think it’s now very usable.

For clarity, pythonar will use colors if possible (using the termcolor module if installed, and using colorama for windows compatibility if installed). So you should easily distinguish the events that trigger reloading of your app.

So here is a little presentation of what i called PythonAR, for Python Auto Reloader (althought it can be used for any apps, not just python ones):

Assume you are editing a few files with vim, and want to restart your python app when you save any file, the base configuration for that would be :

reload python my_app.py

or

reload ./my_app.py

But you’ll run into a few issues, first, vim will create swapfiles, that will be changed after about everytime you touch your keyboard, let’s ignore those files.

reload -i *.sw* ./my_app.py

Now, when your app will start, it will often create .pyc or .pyo files, we can ignore them too :

reload -i *.sw* *.py. ./my_app.py

We’ll soon discover it’s not enought, thought, what happens when vim save a file is not a single operation, first vim test if it can write in the folder, creating a file named “4913″, and delete it, then it moves the files it want to save to a backup, create a new file, modify it, and delete the backup. That would trigger way to much restarts to be comfortable with. Filtering with -i, as we did before can only lower that to two restarts, because two events are happening on the real filename we want, so another option is needed.

the “-s” (or “–sleep”) option, will prevent any event to trigger a reload for the number of seconds. That will resolve this problem.

reload -i *.sw* *.py. -s 1 ./my_app.py

For graphical applications, most window managers will pass the focus to the newly created window each time it is restarted, this can be a serious distraction. The solution here is not perfect, and probably won’t work out of Linux (patches welcome, thought ^^). The “-f” (or “–focus”) option, will prevent the wm from changing the focused application for at least a few seconds, effectively preventing the new window to steal the focus. Unfortulatly, this depend on “xdotool“ an utility based on the xlib, so only useful on X. Any solution for window or OSx appreciated.

reload -i *.sw* *.py. -s 1 -f 3 ./my_app.py

Whatsmore, the -p (”–path”) allow to monitor a different folder than the current one. And the “-a” (or “–action”) is reserved for potential future actions, the default and currently only available value is “restart”.

Yeah, that’s quite a lot of options, i think the next useful addition would be some config parser use, to save options for a project in a simple ini file.

That’s it :) i hope it will be useful to people. The project is hosted on Github, as most of the stuff i do nowadays :).

Tip me if you like this :)

Pourquoi ne pas utiliser de modulo pour les fonctions aléatoires.

written by tshirtman, on 5/9/12 6:37 PM.

Beaucoup de tutoriaux de développements conseillent d’utiliser l’opération modulo (%) pour tirer un nombre entre 0 et n.

C’est une aberration, et il n’est pas difficile de faire mieux.

Le problème de la génération de nombres aléatoires en informatique est complexe, en effet, si on veut pouvoir avoir n’importe quel nombre entre 0 et n, on veut aussi (edit: en général, oui grim :))  que tous aient une probablilité égale de sortir, on appelle ça une distribution uniforme. Les gens ont passé beaucoup de temps à travailler des formules permettant à de sortir des nombres bien distribués, alors ce serait dommage de casser tout ce beau travail bêtement (en effet, la génération de nombre aléatoire est une chose trop sérieuse pour être laissée au hasard).

En C, la fonction rand() fournis un nombre entier entre 0 et RAND_MAX, certains vous conseillerons donc de faire:

	x = rand() % n

ce qui  vous fournis effectivement un nombre entre 0 et n.

Mais, car il y a un mais, il faut bien comprendre quel est le résultat de cette opération, en effet, la fonction modulo, renvoit le reste de la division euclidienne par n:

supposons N entre 0 et RAND_MAX

	0<------------------------------------N------------->RAND_MAX

Après application de % N au résultat, on obtiens la distribution suivante:

	0<------------------------------------N
	------------->RAND_MAX % N

Que constate t’on ? que les nombres entre 0 et RAND_MAX % N ont deux fois plus de chances de sortir que les nombres entre RAND_MAX % N et N. Imaginez que vous avez décidé que vos enemies seront placés sur le tableau par une telle opération, et vous avez statistiquement (bon, pas vraiment, les matheux vont me taper) deux fois plus d’entre eux dans le premier tiers du tableau que dans le reste, ça fait quand même tâche non?

Donc, la solution, si votre N n’est pas trop grand, est de multiplier rand() par N puis de diviser par RAND_MAX, vous obtiendrez bien une distribution uniforme.

	x = (rand() * N)/RAND_MAX

On multiplie notre nombre aléatoire par N pour obtenir un nombre entre 0 et RAND_MAX * N, et l’on divise par RAND_MAX, on obtiens bien un entier entre 0 et N.

Cependant si N * RAND_MAX est supérieur à MAX_INT, vous risquez l’integer overflow, et votre distribution est à nouveau toute cassée (pour la même raison, MAX_INT faisant office de modulo), on peut alors faire:

	x = int((float rand()) / RAND_MAX) * N

On convertis notre nombre aléatoire en flottant et on le divise par RAND_MAX, pour obtenir un nombre entre 0 et 1, et on multiplie par N pour obtenir un nombre entre 0 et N.

ce qui est probablement plus couteux, mais plus sécurisé.

Voilà voilà. En espérant que ça serve un peu, beaucoup de débutants semblent tomber dans ce piège, très répendus dans les tutoriaux qui leurs sont destinés.

Tip me if you like this :)