jeudi 29 octobre 2009

Traffic on Google Map

Moi aussi j'y avait pensé... mais peut être un an ou deux trop tard!

Regular expression en Python

Voici deux très bonnes références pour l'utilisation d'expression régulière en Python.
Utiliser des raw string avec les regular expression
Pour facilité l'écriture des regular expressions, il est préférable d'utiliser les raw string de Python.
Les raw strings sont précédées d'un r et informe le compilateur que le caractère  "\" dans la string n'initie pas une séquence d'échappement Python.
# avec raw string
if re.search(r'\tok', item)>0

# sans raw string
if re.search('\\tok', item)>0
Sans raw string, il est nécessaire de doubler le \ (ce qui donne \\) pour que Python interprète la séquence d'échappement \\ (soit \+\) comme un simple \ qu'il envoi alors au module d'expression régulière.
L'utilisation des raw strings dans les régulars expressions permet de s'émanciper d'une situation communément dénommée "The Back Slash Hell".

Plus d'information
Voir le site de documentation  docs.python.org
A voir également: la section string services de docs.python.org abordant les strings sous toutes leurs formes (StringIO, Codes, Regular expression, template, formattage, etc)

Lecture de fichier et streaming d'objets en Python

Voici quelques notes et exemples rudimentaires de lecture de fichier texte.

Lecture séquentielle
>>> def readFile( sFilename ):
    file = open( sFilename )
    while 1:
        line = file.readline()
        if not line:
            break
        print( line )
    file.close()
>>> readFile( 'c:\\dcu\\test.txt' )
***
Plus d'information sur la lecture de fichier dans cet article "Reading Text Files".

fichiers et séquences

Qui n'a pas un jour eu le besoin de charger le contenu d'un fichier dans une liste ou une séquence?
Voici un petit script permettant de charger le contenu d'un fichier dans une séquence en quelques lignes.
>>> filename = 'c:/Source/MySoft/fileset2'
>>> _file = open( filename, 'r' )
>>> fileset2 = _file.readlines()
>>> _file.close()
>>> fileset2 
['acl.pas\n', 'Action.pas\n', 'Address.pas\n', 'Check.pas\n', 'Template.pas\n', 'listStuff.pas\n', 'ruine.pas\n', 'Cassandre.pas\n', 'ptoleme.pas\n', 'Codes.pas\n', 'BCV.pas\n', 'DisplayModule.pas\n', 'DocumentTemplate.pas\n' ]

plus d'info sur la manipulation de fichier sur l'article "Introduction to Python: File I/O".

Pickling
Ou le "streaming d'objets" !
Apparemment, le pickling est une méthode permettant de transformer un object en sa représentation texte compacte afin d'en permettre facilement le transport (par reseau, fichier, etc).
Le module pickle contient la fonction "dumps" permettant de transformer un objet en sa représentation texte.
>>> pickled = pickle.dumps( Mike ) # Mike est un objet de type Student
>>> print( pickled )
Fournira le résultat suivant:
(i__main__
Student
p0
(dp1
S'school'
p2
S'UIUC'
p3
sS'year'
p4
S'Senior'
p5
sS'name'
p6
S'Mike'
p7
sS'gpa'
p8
F0.59999999999999998
sS'major'
p9
S'CS'
p10
sb.

La fonction loads du module pickle permet quant a elle de recréer une instance de la classe.
>>> # La création d'un nouvel objet depuis le pickle
>>> Mike2 = pickle.loads(pickled)

Le streaming
Il est également possible d'écrire l'état d'un objet dans un fichier... voir l'exemple suivant:
>>> f = open( 'c:/pickle.dat', 'w' )
>>> P = pickle.Pickler( f )
>>> P.dump( Mike ) # Mike est un objet de type Student
>>> f.close()

Plus d'info voir l'article "Introduction to Python: File I/O".

mercredi 28 octobre 2009

Embedded File System en Delphi

Les articles "Writing an embedded file system" et "GpStructuredStorage internals" de Primoz Gabrijelcic (créateur de GpTools et GpSynch) explique comment implémenter, à l'aide de Delphi, un système de fichier avec répertoires dans un seul fichier physique.
L'implémentation de  GpStructuredStorage tire encore une fois parti des avantages offerts par l'implémentation d'interface. Le code utilisant GpStructuredStorage est d'une grande lisibilité.

L'utilisation de cette technique permet par exemple:
  1. De maintenir les nombreuses données de configurations d'un logiciel dans un seul fichier physique.
  2. D'organiser des fichiers de données les plus variés au sein d'un seul fichier physique.
  3. Mettre en place une pseudo base de donnée (basée sur un système de fichier).

Télécharger les sources de GpStructuredStorage.

mardi 27 octobre 2009

Data Liberation: Exportez et Importez vos données Google

C'est un peu par hasard que je croise le chemin de l'initiative Data Liberation de Google.
Data Libération fut initié en 2007 par quelques ingénieurs de Google et visait à permettre l'exportation et l'importation de données personnelles depuis et vers les services de Google.
C'est ainsi qu'il est possible d'exporter ses e-mail GMail, ses contacts, ses documents Google Doc, ses articles de Blog, App Engine, etc.
Data Liberation centralise toutes les informations nécessaires à ces processus d'importation et exportation.

Comme résultat de cette initiative, il est maintenant possible de convertir, zipper et exporter toute une série de documents Google Doc.
Pour plus d'information, voir l'article Liberate Your Google Docs with convert, Zip and Download du blog officiel de Google et le blog de Data Liberation.

jeudi 22 octobre 2009

200 articles publiés



Commencé comme une simple curiosité, ce Blog est vite devenu mon indispensable carnet de notes.
C'est ainsi que j'ai finalement dépassé la barre des 200 publications avec mon dernier article "Comprehension list, itérateurs et générateurs (Yield) en python".

Entre ma vie professionnelle et mes centres d'intérêts (quasi uniquement professionnels) ce blog ne cesse de gonfler très régulièrement. C'est qu'en plus d'être prolifique (je crois), je prends également énormément de plaisir à partager mon savoir.
Et depuis la découverte du moteur de recherche personnalisé  de Google, il m'est même devenu facile d'y retrouver mes propres informations.

Mon seul regret c'est que Blogger n'offre pas de fonctionnalités avancées pour l'écriture d'articles techniques.
Par exemple, l'ajout de code dans un article nécessite quelques manipulations en html. J'espère qu'un jour Google se décidera à ajouter un système de plug-in pour son éditeur html.

mercredi 21 octobre 2009

Comprehension list, itérateurs et générateurs (Yield) en python

List Comprehension
Les list comprehensions sont est une syntaxe particulière permettant de construire facilement et rapidement des listes.

La syntaxe est les suivantes:
[ expression-manipulation for expression in sequence ]
[ expression-manipulation for expression in sequence if test]

>>> [word.upper() for word in "c est une phrase".split() ]
['C', 'EST', 'UNE', 'PHRASE']

# ou code equivalent mais plus long

>>> myList = []
>>> for word in "c est une phrase".split():
...     myList.append( word.upper() )
... 
>>> myList
['C', 'EST', 'UNE', 'PHRASE']

# Autre exemple de list comprehension
>>> [ i * 3 for i in range(10) if i%2==0]
[0, 6, 12, 18, 24]

Les itérateurs
L'iteration est un mecanisme permettant de passer en revue le contenu d'une liste en utilisant le principe d'iteration.
Un itérateur implemente la fonction next() qui retourne la prochaine valeur (ou l'exception StopIteration quand il n'y a plus d'élément).
Les itérateurs sont utilisés de façon transparente dans les syntaxes tel que "for item in sequence:".
Il est également possible d'obtenir un itérateur (implémentant la fonction next) en utilisant la primitive iter( anObjectExposingIteratorFunction ).
On appele ensuite la fonction next() de l'iterateur pour retrouver les différents élements.

L'exemple suivant est disponible dans le fichier testIterator.py .
>>> def UseIterator():
     """ l exemple suivant démontre l'utilisation
         explicite d'un itérateur. Pour information, 
  l'instruction for fait un usage implicite de 
         L'itérateur """
     mySequence = ['a', 'b', 5 ,7 ,9 ,'tz']
     _iterator = iter( mySequence )
     try:
             while True:
                     _value = _iterator.next()
                     print( _value )
     except StopIteration:
             print( '--- End of iteration ---' )
>>> testIterator.UseIterator()
a
b
5
7
9
tz
--- End of iteration ---

Définir son propre itérateur
Il est possible de definir un iterateur pour ses propres classes.
Dans ce cas, il est nécessaire d'implémenter la fonction __iter__ retournant une référence vers un object implémentant la methode next().
NB: la fonction __iter__ peut être utilisée pour retourner une référence vers l'objet lui-même si ce dernier implémente la fonction next(). Ce sera le cas de l'exemple ci-dessous aussi disponible dans  le fichier testIterator.py .

import random

def UseIterator():
     mySequence = ['a', 'b', 5 ,7 ,9 ,'tz']
     _iterator = iter( mySequence )
     try:
             while True:
                     _value = _iterator.next()
                     print( _value )
     except StopIteration:
             print( '--- End of iteration ---' )

class myIterableClass(object):
 """ class contenant une liste d'élément iterable.

     Attention: Ceci est un exemple pour faciliter la 
  compréhension.
                Cette classe ne sais produire qu'un
  seul iterateur à la fois car elle implémente 
  elle meme son propre itérateur et par conséquent
                l'index est reseter a chaque obtention de 
                l'itérateur (via __iter__).
                La solution a ce problème est d'implémenter une
                classe d'iteration indépendante. """
 _list = []
 _index = 0 # cursor for iteration

    # Constructor
 def __init__( self ):
  # prepare a random list of items
  for i in range( 1, random.randint(1,25) ):
   self._list.append( 'Value %s is %s ' % (i, 
    random.randint(1,1000) ) )
 # Iterable primitive 
  def __iter__( self ):
  self._index = 0;
  return self
 # Iteration function
 def next( self ):
  self._index += 1
  if self._index-1 >= len( self._list ):
   raise StopIteration()
  return self._list[self._index-1]

>>> # Utilisation de la classe iterable
>>> #
>>> obj = myIterableClass()
>>> for theValue in obj:
...     print( theValue )
... 
Value 1 is 687 
Value 2 is 3 
Value 3 is 427 
Value 4 is 954 


>>> # Utilisation de la classe iterable 
>>> #   via la declaration d'un iterateur
>>> it = iter( obj )
>>> it.next()
'Value 1 is 687 '
>>> it.next()
'Value 2 is 3 '
>>> it.next()
'Value 3 is 427 '
>>> it.next()
'Value 4 is 954 '
>>> it.next()

Les générateurs (Yield)
Yield est un mot clé permettant de retourner un contenu énumerable.
Dans le monde Python, la syntaxe utilisant le mot clé "yield" correspond au concept de "générateur" (generator).
L'interpréteur utilise le générateur qui mémorisera l'état de la fonction appelée. Comme précisé par Tarek Ziadé, "la directive yield constituant en quelque sorte un return avec point de sauvegarde de l'état des variables locales et de l'endroit où le code de la fonction à quitté." (Source: Programmation Python seconde Edt., Page 149, ISBN 9782-212-12483-5)

L'exemple suivant issu du script testIterator.py démontre l'usage du mot clé yield.
class YieldedItem( object ):
 """ Classe de demonstration démontrant l'utilité du mot 
            clé "yield". Voir les fonctions TestYielded et 
            BuildYielded """   
 _value = -1
 def __init__(self):
  self._value = random.randint(1,25)
 def __getValue( self ):
  return self._value
 value = property( __getValue, None, None )

def BuildYielded():
 """ Cette fonction génère une série d'objects
     de type YieldedItem() et retourne les 
            références à l'aide du mot clé "yield".
     Les objects ainsi crées seront énumerables """
 for i in range( 10 ):
  print( 'BuildYielded(): Create YieldedItem() object #%s' 
   % (i) )
  yield YieldedItem()

def TestYielded():
 """ Cette fonction démontre l'utilité du mot
     clé "yield". En effet, la fonction BuildYielded()
     retourne une série d'objet à l'aide du mot clé "yield".
     Par conséquent, les différents objets sont stockés 
     dans un générateur qui lui est énumérable. """

 # Exemple démontrant l'usage du générateur
 print( 'La fonction BuildYielded() retourne un générateur.' )
  print( 'Notez que la fonction BuildYielded() n\'est pas exécutée!')
 print( BuildYielded() )
 
 # Exemple démontrant le caractère énumérable
 print( 'Le resultat de la fonction peut être facilement énuméré.' )
 print( 'Notez l\'entrelas des appels entre TestYielded() et ' +    
               'BuildYielded()' ) 
        for item in BuildYielded():
  print( 'TestYielded(): Valeur stockée dans l\'objet #%s est %s' % (id(item),item.value) )

 # Exemple stockant la référence du générateur
 print( ' ' );
 print( 'Autre exemple en stockant la référence du générateur' )
 gen = BuildYielded();
 for item in gen:
  print( 'TestYielded(): Valeur stockée est %s' % (
   item.value) )

Le code précédent produissant le résultat ci-dessous.
Notez l'entrelas des appels entre les fonctions BuildYielded() et TestYielded()! Les générateurs sont plus particulièrement approprié lors de la manipulation de grands ensembles/set d'objets (voir l'exemple du point suivant concernant les générateurs et les listes de compréhension).

>>> TestYielded()
La fonction BuildYielded() retourne un générateur.
Notez que la fonction BuildYielded() n'est pas exécutée!
<generator object at 0x839086c>
Le resultat de la fonction peut être facilement énuméré.
Notez l'entrelas des appels entre TestYielded() et BuildYielded()
BuildYielded(): Create YieldedItem() object #0
TestYielded(): Valeur stockée dans l'objet #137953772 est 4
BuildYielded(): Create YieldedItem() object #1
TestYielded(): Valeur stockée dans l'objet #137955468 est 6
BuildYielded(): Create YieldedItem() object #2
TestYielded(): Valeur stockée dans l'objet #137953772 est 7
BuildYielded(): Create YieldedItem() object #3
TestYielded(): Valeur stockée dans l'objet #137955468 est 9
BuildYielded(): Create YieldedItem() object #4
TestYielded(): Valeur stockée dans l'objet #137953772 est 8
BuildYielded(): Create YieldedItem() object #5
TestYielded(): Valeur stockée dans l'objet #137955468 est 20
BuildYielded(): Create YieldedItem() object #6
TestYielded(): Valeur stockée dans l'objet #137953772 est 11
BuildYielded(): Create YieldedItem() object #7
TestYielded(): Valeur stockée dans l'objet #137955468 est 18
BuildYielded(): Create YieldedItem() object #8
TestYielded(): Valeur stockée dans l'objet #137953772 est 1
BuildYielded(): Create YieldedItem() object #9
TestYielded(): Valeur stockée dans l'objet #137955468 est 20
 
Autre exemple en stockant la référence du générateur
BuildYielded(): Create YieldedItem() object #0
TestYielded(): Valeur stockée est 3
BuildYielded(): Create YieldedItem() object #1
TestYielded(): Valeur stockée est 18
BuildYielded(): Create YieldedItem() object #2
TestYielded(): Valeur stockée est 19
BuildYielded(): Create YieldedItem() object #3
TestYielded(): Valeur stockée est 9
BuildYielded(): Create YieldedItem() object #4
TestYielded(): Valeur stockée est 15
BuildYielded(): Create YieldedItem() object #5
TestYielded(): Valeur stockée est 3
BuildYielded(): Create YieldedItem() object #6
TestYielded(): Valeur stockée est 4
BuildYielded(): Create YieldedItem() object #7
TestYielded(): Valeur stockée est 22
BuildYielded(): Create YieldedItem() object #8
TestYielded(): Valeur stockée est 6
BuildYielded(): Create YieldedItem() object #9
TestYielded(): Valeur stockée est 9
Les générateurs et comprehension list
Finalement, il est également possible d'associer les générateurs et les compréhensions lists (décrit en début d'article). le résultat étant appelé un "Generator Expression"!
Pour créer une générateur sur base d'une compréhension list, l'on utilise la syntaxe suivante où les parenthèses remplacent les crochets.

aGenerator = ( expression-manipulation for expression in sequence if test)

Un cas typique de son utilisation serait l'exécution de l'expression de manipulation (expression-manupilation) que lorsque l'on extrait l'information du generateur. Cela peut devenir utile si le processus est grand consommateur de ressource (comme des accès DB).
A Contrario, toutes les expressions de manipulation sont exécutées immédiatement lors de la création d'une expression list.

Voici un exemple extrait du module GenVsExpList.py .

""" Ce module d'exemple sert a mettre en évidence la différence de fonctionnement entre un Generator et une Comprehension List """

def transformIntForGen( iValue ):
 """Cette fonction de transformation est appelée pour
 transformer les valeurs d'un générateur d'expression.
 Grace à la trace, il est possible de déterminer le 
 mode de fonctionnement."""
 print( '%s: pour la value %s' % (
   'transforme for Generator', iValue) )
 return 100-iValue

def transformIntForCompList( iValue ):
 """Cette fonction de transformation est appelée pour
 transformer les valeurs d'une comprehension list.
 Grace à la trace, il est possible de déterminer le 
 mode de fonctionnement."""
 print( '%s: pour la value %s' % (
   'transform ComprehensionList', iValue) )
 return 100-iValue

def compareGenVsCompList():
 """Fonction de comparaison d'execution de generateur 
  et comprehension list"""
 print( '--- Comprehension List execution ---' )
 print( '1) prepare comprehension list' )
  _list = [ transformIntForCompList(i) for i in range(25) if i%3==0 ]
 print( '2) display comprehension list content' )
 for index in range( len(_list) ):
  print( 'Comprehension List value #%s : %s' % (
   index, _list[index]) )

 print( '--- Generator expression execution ---' )
 print( '1) prepare generator' )
  _gen = ( transformIntForGen(i) for i in range(25) if i%3==0 )
 print( '2) display generator expression content' )
 # Dans le cas d'un générayeur, il faut malheureusement
 #   gérer l'index soit même. 
 _idx = 0 
 for item in _gen: 
  print( 'Generator expression value #%s : %s' % (
   _idx, item) )
  _idx += 1

Le résultat démontre bien que dans le cas d'un generator expression, l'expression de transformation n'est appelée qu'au moment de l'extraction de la valeur!

>>> compareGenVsCompList()
--- Comprehension List execution ---
1) prepare comprehension list
transform ComprehensionList: pour la value 0
transform ComprehensionList: pour la value 3
transform ComprehensionList: pour la value 6
transform ComprehensionList: pour la value 9
transform ComprehensionList: pour la value 12
transform ComprehensionList: pour la value 15
transform ComprehensionList: pour la value 18
transform ComprehensionList: pour la value 21
transform ComprehensionList: pour la value 24
2) display comprehension list content
Comprehension List value #0 : 100
Comprehension List value #1 : 97
Comprehension List value #2 : 94
Comprehension List value #3 : 91
Comprehension List value #4 : 88
Comprehension List value #5 : 85
Comprehension List value #6 : 82
Comprehension List value #7 : 79
Comprehension List value #8 : 76
--- Generator expression execution ---
1) prepare generator
2) display generator expression content
transforme for Generator: pour la value 0
Generator expression value #0 : 100
transforme for Generator: pour la value 3
Generator expression value #1 : 97
transforme for Generator: pour la value 6
Generator expression value #2 : 94
transforme for Generator: pour la value 9
Generator expression value #3 : 91
transforme for Generator: pour la value 12
Generator expression value #4 : 88
transforme for Generator: pour la value 15
Generator expression value #5 : 85
transforme for Generator: pour la value 18
Generator expression value #6 : 82
transforme for Generator: pour la value 21
Generator expression value #7 : 79
transforme for Generator: pour la value 24
Generator expression value #8 : 76

lundi 19 octobre 2009

Exception en Python

Mécanisme standard d'exception
Ce mécanisme n'est pas différent des autres environnements évolués. En voici la notation en Python.
try:
    try:
            # Création d'une exception !
            4/0
    except:
            print('except')
            raise
finally:
    print( 'finally' )

# ou encore
try:
  4/0
except:
  print('except')
  raise
finally:
  print( 'finally' )
Résultat:
except
finally
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
ZeroDivisionError: integer division or modulo by zero
Créer une classe d'exception
Python requière l'usage de classes dans les mécanismes d'exception. Cette dernière servira à l'identification du type d'exception ainsi qu'au transport des arguments/details de l'exception. Bien que toutes les classes soient acceptées,il est préférable d'utiliser un descendant d'Exception... cela permet de faire un casting d'erreur efficace. Encore une fois, rien de différent par rapport aux autres langages évolués.
class myError(Exception):
    pass

def doAnError():
    raise myError()

doAnError()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in doAnError
__main__.myError: <__main__.myError instance at 0xb7d0804c>

Casting d'exception
Le casting d'exception s'obtient en placant la classe après le mot clé "except". Dans ce cas, seule les exceptions de ce type (et dérivés) seront interceptées.
try:
  8/0
except ArithmeticError:
  print( 'Oups!' )

Il est également possible de récupérer une référence vers l'objet d'exception en déclarant un second paramètre après le mot clé except.
class anError( Exception ):
    pass

try:
    raise anError()
except Exception, errObj:
    print( id(errObj) )
    dir( errObj )
    print( errObj )
    print( '--- End of Exception ---' )
Resultat:
3080090404
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__str__', '__weakref__', 'args', 'message']

--- End of Exception ---

Classes d'exception de base
Exception
Classe de base de toutes les exceptions. Le constructeur prend en plusieurs paramètres qui sont stockés dans l'attribut args. Lors de l'affichage par l'interpreteur, le function __str__() est appelée pour afficher les informations de l'exception. Dans le cas de Exception, __str__() affiche le contenu de l'attribut args.

StandardError
class StandardError( Exception )
Classe de base de presque toutes les exceptions en Python.

ArithmeticError
class ArithmeticError( StandardError )
Pour toutes les erreurs. On retrouve en descendant ZeroDivisionError, OverflowError (dépassement de capacité), FloatingPointError (erreur en calcul flottant)

LookupError
class LookupError( StandardError )
Utilisé lors de l'utilisation d'un index est incorrect sur une liste ou lors de l'utilisation d'une clé incorrecte dans un mapping.

EnvironmentError
class EnvironmentError( StandardError )
Utilisé comme classe de base pour les erreurs de type système (lecture fichier, appel API, etc).
Ce type d'erreur accepte un "Numéro d'erreur" et un message (les No d'erreur étant très courant en programmation système).
Voir attibut "errno".
Parmis les descendant, l'on retrouve IOError et OSError

ValueError
Class ValueError( StandardError )
Utiliser pour indiqué une valeur d'argument inappropriée (de type incorrecte).

UnicodeError
class UnicodeError( ValueError )
Classe de base pour les erreur de conversion unicode.
Parmis les descendant l'on retrouve UnicodeEncodeError, UnicodeDecodeError.

AttributeError
class AttributeError( StandardError )
Indique un attribut manquant.

NameError
class NameError( StandardError )
Indique un nom qui, globalement, ne peut pas être résolu.

Notes en vrac
Passage d'arguments à la classe d'Exception
def doSomeStuffWithError():
    try:
            4/0
    except:
            raise Exception('Un message d\'erreur', 'un brol', -12 )

doSomeStuffWithError()
print( '-----------------------' )
try:
    doSomeStuffWithError()
except Exception, errObj:
    print( errObj.args ) 
avec pour résultat:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in doSomeStuffWithError
Exception: ("Un message d'erreur", 'un brol', -12)
-----------------------
("Un message d'erreur", 'un brol', -12)


Casting multiples
try:
  doStuffWithError()
except ArithmeticError:
  print( 'Damned!! A math error!' )
# Matching a list of exception class
except (AttributeError, IOError ):
  print( 'Oups!' )

mardi 13 octobre 2009

Quelques distributions Linux

Issus d'un article parut sur TooLinux, voici quelques distributions Linux pouvant présenter un quelconque intérêt (selon les circonstances).

Tiny Core Linux 
Une distribution Linux compacte (10Mo). Avec cette taille réduit, Tiny Core s'offre même le luxe d'un environnement graphique!
Plus d'information sur le site Tiny Core Linux (screenshots ici).

Easy Peasy 
Distribution destinée aux Netbooks et basée sur Ubuntu.
La vidéo ci-dessous montre d'ailleurs cette distribution en fonctionnement sur un Eee PC d'Asus 900.
Plus d'information sur Easy Peasy ici (screenshots) ou encore sur la Home Page du projet.





Ultimate Edition
Une version Linux spécialement dédiée aux jeux.
Plus d'information et téléchargement sur le site Ultimate Edition



Les incontournables
Voici quelques incontournables comme Puppy (screenshots et intro ici) qui n'a besoin que de 64Mb ou encore SystemRescueCd.

Une liste complète de distributions
Voir cette article sur TooLinux.
On y retrouvera des distribution couteaux Suisse pour le dépannage, le partionning des disques, l'analyse réseau.

lundi 12 octobre 2009

Les pics de grippe selon Google

Google évalue l'évolution des pics de grippe dans différents pays sur base de données collectées via la net.
Ces données misent en regard avec les données d'années précédentes permettent de se faire une idée de l'évolution mois par mois.

Ainsi, l'on apprendra:
  • Que la Belgique dispose d'un pic de grippe ciblé et donc une période relativement courte de risque de contamination (a comparer avec l'Allemagne et le Canada par exemple).
  • Que cette année, la Belgique présente un niveau de contamination un peu plus élevé (entre basse et moyenne) que les autres années. A cette période le taux de contamination est habituellement minimal.
    C'est une bonne nouvelle, les conditions sont assez bonnes :-)
  • Que le pic de grippe est très étalé au Canada et en Allemagne (bien plus qu'en Belgique).
    Ces deux pays présentant taux moyen de contamination plus important et plus longtemps.
  • Que la Suède et la Norvège (ayant un modèle de pic Janvier-Février -- similaire à la Belgique) sont en avance. Leurs pics ayant eu le maxima mi-aout par rapport aux autres années.
  • Que la Russie connait ses pics aux alentours de février-mars (donc après nous).
Quelques recommandations pour se protéger (et protéger les autres) de la grippe:
  • Éternuer et tousser dans un mouchoir (sa manche ou ses mains) pour éviter les prolifération.
  • Se laver les mains souvent.
  • Rester chez soi en cas de grippe déclarée.
Grippe: la maladie des mains
Saviez-vous que la grippe est assez communément dénommée la "maladie des mains".
Les mains sont un excellent vecteur de contamination... On éternue dans les mains, on touche son matériel... des poignées de portes ainsi que divers endroits où l'on dépose alors ses "petits microbes".
Ces mêmes poignées de portes, ustensiles et endroits touchés par vos congénères, amis et membres de votre famille.
Ces pauvres congénères qui se frottent les yeux, le nez, la bouche... des gestes simplement naturel au quotidien.
C'est la raison pour laquelle il est important d'avoir une hygiène des mains irréprochable.
Dans le milieu de travail, le simple prêt d'un stylo à bille peut devenir un vecteur de contamination si l'hygiène n'est pas correcte.
Il n'est pas nécessaire de devenir parano... quelques règles de bon sens et un peu d'hygiène feront l'affaire :-) 

jeudi 8 octobre 2009

Delphi 2009 Handbook

Marco Cantù propose son ouvrage "Delphi 2009 Handbook" sur Lulu.com (aussi disponible via Amazon).


Ce livre consacre une partie de son contenu à l'implémentation Unicode maintenant devenu le type par défaut des strings et chars (les anciens types 8 bits étant devenu AnsiChar et AnsiString).
Pour information, le standard de transformation en Delphi est UTF-16.
Hormis le côté Unicode, ce livre se consacre également aux points suivants:
  • Type génériques
  • Méthodes anonymes.
  • Support COM en Delphi 2009.
  • DataSnap 2009
  • DBExpress
Quelques vidéos consacrées à l'implémentation Unicode sont également disponibles.
Plus d'information ici sur le site de Marco Cantù.

Note:
Le site de Marco Cantù référence également un article intéressant comparant les langages OOP.

Définition des propriétés en Python

Petit exemple montrant la définition des propriétés dans les classes Pyhton (les classes New-Styles dérivant explicitement de "object")

>>> class Car(object):
      def __init__(self):
         self._im = '%s' % id(self)
         self._changed = False
      def _getim( self ):
         return self._im
      def _setim( self, value ):
         if value != self._im:
            self._im = value
            self._changed = True
      def _getchanged( self ):
         return self._changed
      immatriculation = property( _getim, _setim, None )
      hasChanged = property( _getchanged, None, None )
>>> Cars = dict()
>>> Cars['domeu']= Car()
>>> Cars['frc']= Car()
>>> # can also be written as follow
>>> # Cars = dict( (('domeu', Car()), ('frc', Car())) )
>>> for key, value in Cars.items():
      print( 'Car of %s with immatriculation "%s". Changed? %s.' % (key,value.immatriculation, value.hasChanged) )

Car of frc with immatriculation "18698568". Changed? False.
Car of domeu with immatriculation "18511832". Changed? False.
>>> 
>>> Cars['domeu'].immatriculation = 'XYZ 103'
>>> for key, value in Cars.items():
      print( 'Car of %s with immatriculation "%s". Changed? %s.' % (key,value.immatriculation, value.hasChanged) )


Car of frc with immatriculation "18668880". Changed? False.
Car of domeu with immatriculation "XYZ 103". Changed? True. 

mercredi 7 octobre 2009

Enumérer les méthodes d'une classe (en Run-Time)

L'article "Class RTTI" offre une introduction intéressante à l'utilisation des informations RTTI, HostScripting et de l'invocation automatique des méthodes depuis les WebSnap.

L'utilisation de {$METHODINFO ON} avec l'unité DetailedRtti.pas de David Glassborrow permet d'envisager l'extraction et l'utilisation des informations RTTI en RunTime pour faire des appels dynamiques.
Fournit sous forme de Class  Helper et Record Helper, DetailedRtti.pas permet, par exemple, d'extraire la définition des méthodes/fields/etc d'une classe.

L'exemple ci-dessous énumère toutes les méthodes d'un object.
type 
    {$METHODINFO ON}
  TFRM_Main = class(TForm)
    SBB_Button1: TButton;
    ...

procedure TFRM_Main.Button1Click(Sender: TObject);
begin
  Log( self.RTTIMethodsAsString );
end;


L'énumération des méthodes peuvent s'avérée utile lors de l'invocation sur à la volée (par exemple à l'aide de MethodAddress).
type   TTestProc = procedure of object;
  {$METHODINFO ON}
  TForm1 = class(TForm)
        SBB_DoTesting: TButton;
    ...
  published
    procedure Proc_TestMe;
    procedure Proc_TestMeAlso;
  end;
  ...

procedure TForm1.RunThis(aProcedureName: String);
var
  pProc : TTestProc;
begin
  ShowInfo( 'Executer la méthode '+aProcedureName );
  TMethod(pProc).Data := Self;
  TMethod(pProc).Code := MethodAddress( 'proc_'+aProcedureName);

  try
    if not Assigned(TMethod(pProc).Code) then
      raise Exception.Create( 'Failed to locate test "proc_'+aProcedureName+'" method address' );
    pProc();
  except
    on e:Exception do
      ShowError( E.Message+' ('+E.ClassName+')' );
  end;
end;
... 
procedure TForm1.SBB_DoTestingClick(Sender: TObject);
begin
  // Exemple d'appel dynamique (à partir du nom de la méthode) 

  RunThis( 'TestMe' );
  RunThis( 'TestMeAlso' );
end;
...

mardi 6 octobre 2009

Inclure une DLL dans les ressource d'un logiciel

Voici une recette de cuisine trouvée sur LinkedIn permettant d'inclure une DLL directement dans les ressources d'un éxécutable.

1. Inclure la DLL dans une RAW section du fichier ressource. Ainsi, il sera linker dans l'exe au moment de la compilation.

2a) Ajouter un bout code au programme qui extrait la DLL des ressources et la stocker sur le disque avant de la charger avec un loadLibrary.

2b) Une autre option est de copier directement en mémoire la DLL disponible en ressource . Ensuite créer des liens dynamiques permettant au programme d'appeler les procédures de la DLL (demande un effort de programmation plus poussé).

Le composant TFakeDll (disponible sur uinC/Underground INformation Center) permet d'inclure des DLL en ressources.
Bien qu'ils datent un peu, uinC contient également d'autre code sources Delphi comme des KeyLogger, Password Cracker, etc... toujours intéressant pour assouvir sa curiosité.

samedi 3 octobre 2009

L'univers de la sience - Isaac Asimov

Quelle chance, le week-end dernier j'ai découvert mon premier ouvrage de vulgarisation issu de la plume d'Isaac Asimov au pêle-mêle de Waterloo.
En plus d'être un grand écrivain de science fiction, Isaac Asimov était également un excellent vulgarisateur scientifique et historique. A sa mort, Isaac Asimov comptabilisait pas moins de 400 oeuvres.

C'est avec un grand plaisir que je me lance dans la lecture de "l'Univers de la science" (1986, interEditions, Paris), une belle brique de 900 pages.
En voici d'ailleurs un extrait consacré à la curiosité comme le moteur du "désir de savoir", ce désir faisant avancer la science par les découvertes qui en découlent.

Le cerveau humain est le morceau de matière le plus merveilleusement organisé de l'Univers connu, et sa capacité de recevoir, de classer et d'enregistrer l'information dépasse très largement les besoins ordinaires de la vie. On a estimé que, au cours de sa vie, un être humain pouvaient emmagasiner 15000 milliards d'informations.
C'est à cette disponibilité que nous devons d'être vulnérables à une maladie très pénible, l'ennui. Un être humain, placé dans une situation où il n'a aucune occasion d'utiliser son cerveau si ce n'est pour assurer sa survie, ressentira une quantité croissante de symptômes inquiétants, jusqu'à connaître de graves troubles mentaux. Le fait est que l'être humain normal possède une curiosité intense et irrésistible. S'il n'a pas la possibilité de la satisfaire d'une façon immédiatement utile, il la satisfera par d'autres moyen - y compris des moyens regrettables, qui sont à l'origine d'expressions courantes comme "melez-vous de vos affaires" ou "la curiosité est un vilain défaut".
L'univers de la science, Isaac Asimov, Page 4.
Edt InterEditions (Paris), ISBN 2-7296-0141-4
Trad: Françoise Balibar, Claude Guthmann, Alain Laverne et Jean-Pierre Maury.