Catégorie : développement

Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.

JavaScript : comment tester, et faire partager très rapidement son code

Supposons que vous vouliez montrer quelques exemples de code JavaScript, mais surtout, le partager rapidement.
C’est très simple : avec http://jsfiddle.net/, vous tapez votre exemple de code, et à la fin vous cliquez sur « sauver » et hop, une URL automatique est créée. Il vous suffit de copier colle le lien pour partager votre code exemple (ou votre code qui démontre qu’une librairie a un problème, par exemple).

ExtJs et variables locales – fonctions anonymes

J’ai eu à faire face à un problème.
Malgré le fait que j’aie l’impression que la variable soit accessible parce que c’est un accès à l’intérieur de la classe, ça ne fonctionnait pas et l’erreur ressortait systématiquement :
this.writerForm: variable unknown

J’ai mis en gras ci-dessous le code qui pose problème :

Ext.define('Writer.Panel', {
    extend: 'Ext.panel.Panel',

    initComponent: function(){
        this.writerForm = new Writer.Form({
            listeners: {
                create: function(form, data){
                    this.store.insert(0, data);
                }   
            }   
        }); 
        this.writerGrid = new Writer.Grid({
            store: this.store,
            listeners: {
                selectionchange: function(selModel, selected) {
                    this.writerForm.setActiveRecord(selected[0] || null);
                }   
            }   
        }); 
        Ext.apply(this, {
            layout:'border',
            items:[{
                region:'north',
                layout:'fit',
                items: [this.writerGrid]
            },{ 
                region:'center',
                layout:'fit',
                items: [this.writerForm]
            }]  
        }); 
        this.callParent();
    }   
});

La solution est simple : il semblerait que ça soit un hack ExtJs, mais ça fonctionne, et j’espère que je vais vous éviter de perdre autant de temps que moi. Il faut ajouter « scope: this » au code.
J’ai mis en gras ci-dessous le code qui a résolu problème :

Ext.define('Writer.Panel', {
    extend: 'Ext.panel.Panel',

    initComponent: function(){
        this.writerForm = new Writer.Form({
            listeners: {
                create: function(form, data){
                    this.store.insert(0, data);
                }   
            }   
        }); 
        this.writerGrid = new Writer.Grid({
            store: this.store,
            listeners: {
                /* super important pour les fonctions anonymes */
                scope: this,
                selectionchange: function(selModel, selected) {
                    this.writerForm.setActiveRecord(selected[0] || null);
                }   
            }   
        }); 
        Ext.apply(this, {
            layout:'border',
            items:[{
                region:'north',
                layout:'fit',
                items: [this.writerGrid]
            },{ 
                region:'center',
                layout:'fit',
                items: [this.writerForm]
            }]  
        }); 
        this.callParent();
    }   
});

ExtJS 4 et le MVC (modèle-vue-contrôleur) – howto

Ci suivent quelques notes que j’ai prises après toute une journée passée à créer en entier l’exemple qui fonctionne.
Vous pouvez télécharger, puis décompresser l’exemple en entier en cliquant ici.
Pour l’installer et le tester c’est très simple : le répertoire s’appele « siteinternet » et c’est là qu’est le site internet, il vous suffira d’afficher la page « http://localhost/intranet/gs.php ». Oui j’ai développé cet exemple dans un sous-répertoire « intranet » car ExtJS est destiné, pour ma part à faire uniquement de l’administration.

Voici ce qui fonctionne : la vision d’une liste :

Vision d'une liste avec ExtJS 4.x (juste la vision)

Et le mode édition :

Vision d'une liste avec ExtJS 4.x (mode édition d'une ligne)

Le plus intéressant c’est le modèle MVC.
Je vous laisse lire toute la documentation ici, ici et .

Maintenant je vous fais un résumé de ce que j’ai retenu :

L’architecture

Elle doit absolument suivre ce schéma :

`-- app
    |-- controller
    |-- data
    |-- model
    |-- store
    `-- view

———————
controller =
Ce qui assemble data + model + store + view En général les contrôleurs créent les vues et attendent des évenements pour agir en conséquence.

model =
Là où on définit les colonnes des ensembles de données. C’est là aussi où on définit en général où aller chercher les données par défaut (« proxy »).

store =
Là où on définit sur quels modèles on se base, et où on surcharge là où aller chercher les données (= redéfinition de « proxy »).

Règles de syntaxe à respecter :

store = noms au pluriel :
app/store/Stations.js
model = noms au singulier :
app/model/Station.js

Notation :

  • au début, de type « bosse de chameau »,
  • au milieu tout en minuscules,
  • à la fin, de type « bosse de chameau » :

MonApplication.model.UserList
MonApp.view.user.List
MonApp.view.user.User
Panda.view.NewStation
Panda.view.SongControls

Arbre complet des fichiers de l’exemple ici :

gs
|-- app
|   |-- controller
|   |   `-- Users.js
|   |-- data
|   |   |-- users.json
|   |   `-- usersUpdate.json
|   |-- model
|   |   `-- User.js
|   |-- store
|   |   `-- Users.js
|   `-- view
|       `-- user
|           |-- Edit.js
|           `-- List.js
`-- app.js

A partir de là, à vous de jouer.

Au début, ce n’est pas simple, mais au final, c’est extrêmement évolutif et on gagne énormément de temps. Un peu comme d’apprendre vim :).

Awstats et activation de plugins

Lorsque vous installez awstats (un outil pour faire des jolies statistiques de fréquentation), certains plugins sont désactivés par défaut :

  • decodeutfkeys
  • ipv6

(entre autres).

L’astuce est extrêmement simple :

Il suffit de lire les commentaires dans le fichier et de lire les modules requis :

Cherchez # REQUIRED MODULES

Respectivement, pour les deux modules :

  • Encode and URI::Escape
  • Net::IP and Net::DNS

En gros il faut installer ces « plugins Perl » Encode, URI::Escape, Net::IP et Net::DNS.

Les ordres à taper sont hyper simples : il vous suffit, en ligne de commande, de :

  • lancer la console d’outils Perl
    (ce n’est peut-être pas exactement cela, mais je le vois comme ça) : tapez
    cpan
  • puis tapez install "nom du module"
  • install Encode
  • install URI::Escape
  • install Net::IP
  • install Net::DNS

Et à chaque ordre, lorsque vous validez par la touche entrée, toute une liste de modules s’installent, et à la fin… tout fonctionne comme par magie !

ExtJS et PhoneGap : une nouvelle façon de voir les choses

Comme je l’ai toujours dit, ExtJS est une librairie JavaScript extrêmement puissante.
Le seul problème c’est qu’elle est dure à maitriser… mais les résultats obtenus sont incroyablement beaux par rapport au temps de développement.

La même société, Sencha, qui n’est constituée – apparemment – que de personnes très compétentes, a développé le même système, mais pour téléphones portables : le Sencha Touch.

Et ils se sont penchés sur ce que j’appellerai le site du moment : PhoneGap.

Ils ont fait un tutoriel qui vous permet de combiner la puissance de PhoneGap et de Sencha Touch :

http://www.sencha.com/learn/a-sencha-touch-mvc-application-with-phonegap

J’expliquerai plus en détail dans un prochain article comment fonctionne PhoneGap, mais à mon avis, c’est l’avenir pour des développeurs comme moi qui n’ont pas le temps de se pencher sur les plateformes mobiles spécifiques : je n’ai pas le temps d’apprendre tout iOS et je n’ai pas le temps d’apprendre Android. Par contre je connais bien JavaScript, je commence à bien connaitre HTML5, et grâce à PhoneGap, on peut aller loin, très loin 😉

YSlow : Utiliser des domaines sans Cookie : traduction

Je viens de traduire un gros morceau du texte ici.

Lorsque le navigateur fait une requête pour une image statique, il envoie tout de même les cookies dans la requête. Le serveur ne se sert absolument pas de ces cookies. Ils créent donc un traffic supplémentaire totalement inutile. Il faut s’assurer que tous les composants statiques tels que les images sont récupérés sur des domaines sans cookie. Par exemple, il suffit de créer un sous-domaine static, et d’y mettre les composants adéquats.
Par exemple, si le domaine est www.example.org, il suffit de mettre les composants statiques sur static.example.org. Néanmoins, si vous avez déjà mis en place des requêtes sur le domaine de plus haut niveau, soit example.org, alors les cookies suivront tout de même sur static.example.org. Une solution est d’acheter un nom de domaine dédié.
Par exemple, Yahoo! utilise yimg.com, Youtube utilise ytimg.com et Amazon utilise images-amazon.com.
Un autre bénéfice concerne les proxies : certains proxies refusent de mettre en cache des composants qui ont été demandés avec des cookies. Pour la note, si vous vous demandez s’il vaut mieux utiliser example.org ou www.example.org pour votre page de base, pensez à l’impact des cookies. Le fait de supprimer www ne vous laissera pas d’autre choix que d’écrire des cookies qui seront tous diffusés sur *.example.org.
Donc, pour des raisons de performance, c’est mieux d’utiliser le sous domaine « www » et d’écrire les cookies pour ce sous-domaine.


Vous ne voyez pas que je suis en train de pleurer ? J’ai tout faux sur la plupart des sites Internet que j’ai crée. Bon, aujourd’hui c’est nettement moins problématique que si nous étions dix ans en arrière, mais c’est très agaçant de savoir que tout le travail mis en place est à revoir (règles de réécriture, traducteur, etc)… et le discours que je tenais qui va avec (pas la peine des www). On en apprend tous les jours !

Delphi Embarcadero et RxLib : comment installer les composants

Il risque de vous afficher un problème de SizeOf :
Il vous faut juste préciser que c’est le SizeOf de l’unité Systems, donc :

System.SizeOf()

Puis ouvrez le fichier RxConst.pas :

Il manque simplement le define 220 : ajoutez après tous les define jusqu’au 210 :

{$IFDEF VER220}
const
SDelphiKey = 'Software\Embarcadero\BDS\8.0';
{$ENDIF}

Et vous pourrez compiler puis installer les composants.
Ce sont deux petites astuces simples, mais si je les avais eues, j’aurais gagné… deux heures 😉

Python, débutant et jeu : Soko-ban version geek

Avez-vous déjà entendu parler de Sokoban, le jeu ?
J’ai eu la formidable idée (c’est de l’humour…) de le coder en Python, et encore mieux (c’est encore de l’humour…) de le coder pour pouvoir y jouer en mode console.

\o/

J’ai commencé à développer pour qu’il soit international, donc les commentaires sont pour la plupart en anglais.

La première chose que je voulais faire c’est pouvoir faire des affichages différents. Donc, selon que votre console le supporte ou pas, vous pourrez changer l’affichage :

# Different drawings:
glob_tab_chars = \
[
    # Ground / GroundStoneDest / Wall / Player / Stone
    [ ' ', '.', '█', '☺', '☻', '○','♦' ],
    [ ' ', '.', '#', '@', '+', '$','*' ],
    [ ' ', '.', '░', '☺', '☻', '○','◙' ]
]

Voici l’écran de base :

Copie d'écran de PySoko

Voici l’écran, si on veut changer les graphismes (en cliquant sur « + » ou sur « -« ) :
Copie d'écran de PySoko

Voici l’écran, si on veut encore changer les graphismes (en cliquant sur « + » ou sur « -« ) :
Copie d'écran de PySoko

Le code orienté objet

Les classes de base

Et ensuite le plus important à mon sens : le code orienté objet. J’ai voulu apprendre l’orienté objet de python. J’ai donc crée des classes qui correspondent aux objets de base (dans l’ordre, classe du Sol sans rien, classe du Sol où il faut ranger une pierre, classe Mur, et classe Joueur) :

# Different drawings:
class Ground(object):
    def __init__(self):
        super(Ground,self).__init__() # Parent call:

class GroundStoneDest(object):
    def __init__(self):
        super(GroundStoneDest,self).__init__() # Parent call:

class Wall(object):
    def __init__(self):
        super(Wall,self).__init__() # Parent call:

class Player(object):
    def __init__(self):
        super(Player,self).__init__() # Parent call:

Classe Level

Et de la même façon j’ai crée la classe Level qui est la plus complexe, et qui contient les fonctions les plus utilisées :

  • apply_drawings_set()
    Calculer les motifs pour dessiner le tableau (oui, oui c’est plus complexe que ça n’en a l’air) ;
  • draw()
    Dessiner les motifs en cours à l’écran ;
  • register_player_move()
    Se souvenir des mouvements du joueur, soit pour pouvoir faire un « undo » (pas implémenté), soit pour pouvoir les sauver pour les rejouer (pas implémenté non plus) ;
  • move()
    Essai de déplacer un objet situé en (x,y) du décalage (add_x, add_y), sachant que le décalage peut être négatif ;
  • solved()
    Test si toutes les pierres sont bien rangées.

Classe LevelsReader

De la même façon, j’ai crée la classe LevelsReader qui lit un niveau, et l’analyse pour voir s’il est un minimum cohérent. Pas la peine d’entrer dans le détail, les fonctions sont suffisamment explicites je pense.

Bibliothèque curses

Et pour terminer, la fonction de la boucle principale qui concerne l’unité curses : def curses_main(stdscr, code). C’est ici qu’on affiche le menu, qu’on attend qu’on tape sur une touche, etc.

Notez bien : le code n’est pas terminé. C’est un début de code, relativement correctement fait. J’ai passé à peine deux jours dessus pour réussir à faire cela, donc ne m’en voulez pas trop, il n’est pas peaufiné, mais il fonctionne.

Si jamais vous l’améliorez, ce serait gentil de me faire parvenir la nouvelle version 🙂

Le lien que tout le monde attend avec impatience, la bave aux lèvres :

Cliquez ici : pysoko.tar.bz2

Windows Vista / Seven : fichier hosts introuvable : la solution

Vous n’arrivez pas à ouvrir le fichier hosts pour y rajouter ce que vous voulez ?
Très simple pourtant… quand on connait l’astuce !

Tout d’abord, si vous essayez d’ouvrir le fichier hosts, il faut aller dans le dossier
[disque:][répertoire windows]\system32\drivers\etc
en général, comme pour moi c’est :
C:\Windows\system32\drivers\etc
Mais si vous essayez d’ouvrir, vous allez voir que le répertoire n’existe pas !
En fait il est caché, il est invisible :
Windows dossier etc invisible

Il vous suffit juste de taper à la main « etc », comme si vous saviez qu’il était la :
Windows dossier etc invisible et il faut taper etc

Et de la même façon, le fichier hosts est invisible :
Windows fichiers hosts invisible

Il vous suffit juste de taper à la main « hosts », comme si vous saviez qu’il était la :
Windows fichier hosts invisible et il faut taper hosts

Ensuite, une fois que vous l’aurez ouvert dans votre éditeur favori (beaucoup utilisent Notepad++, moi c’est Pspad, mais c’est la même chose dirons-nous), vous ne pourrez pas sauvegarder tant que vous n’aurez pas modifié les autorisations. Comment faire ? C’est très simple, le résumé en image :

Windows comment modifier les autorisations du fichier hosts

Explication : il faut cliquer avec le bouton droit sur le fichier, choisir « propriétés », puis changer les autorisations, et mettre « contrôle total » pour tous les utilisateurs.

Attention, c’est assez dangereux, cela signifie que tout le monde peut écrire dedans, et si vous installez un virus, il pourra écrire dedans, comme tout le monde.

A vous de voir, mais je n’ai jamais eu, en 17 ans de développement, de virus… enfin il faut dire que j’utilise Linux 50 % du temps aussi !

Comme d’habitude, j’espère avoir apporté un peu de savoir à la communauté et que je vous aurai évité de perdre du temps dans des choses inutiles !

Python : comment détecter des noms de fichiers qui ne sont pas présents dans un fichier ?

Voilà, je viens de me donner un défi. Je l’expliquerai après.
Top chrono : 16:34 – Fini : 16:43
Voici mon problème : j’ai un fichier « index.htm » qui utilise plein de fichiers images. Seulement, tous ces fichiers « images » sont mélangés dans un seul et même répertoire, avec d’autres fichiers qui ne sont pas présents. Je voulais un listing des fichiers présents, et des fichiers pas présents.
9 minutes en python.
Voici mon script, qui n’est pas fabuleux, mais qui fonctionne bien :

  1 #!/usr/bin/python
  2 # -*- coding: utf-8 -*-
  3
  4 import os
  5
  6 path = './img'
  7 f = open('./index.htm', 'r')
  8 s = f.read()
  9 for nom in os.listdir(path):
 10     if s.find(nom)>=0:
 11         print "Présent - "+nom
 12
 13 for nom in os.listdir(path):
 14     if s.find(nom)<0:  15         print "Absent - "+nom

Bien sûr, il y aurait possibilité de faire ça en shell / bash, mais en python c'est tellement plus sympa 😉
Si ça peut éventuellement aider la communauté, j'en fais un article.