J’ai craqué !

Quand je dis ça, je suis un peu mélodramatique … quoique.

Enfin bref.

J’avais déja craqué, pour l’essentiel, en prenant un forfait téléphonique, certes limité (le fameux forfait free 2H/2€). Mais j’étais resté coincé avec un de ces fameux feature phones à clapets et sans applciations, ni gadgets de quelque ordre que ce soit. Un téléphone … pour téléphoner.

Mais là, j’ai craqué d’une autre façon en m’offrant un téléphone Android, avec un grand, beau, (et salissant) écran de 5" qui me rappelle mon Palm d’une autre époque, à un détail près : le Wiko Raimbow que je viens de m’acheter est bien moins cher, et français (enfin, vendu en France par des français, je ne doute pas qu’il soit fabriqué en Chine).

Le moment est donc venu d’apprendre à utiliser un autre OS que Windows ou Mac. Certaines choses sont diablement pratiques, d’autres moins. Mais dans l’ensemble, c’est assez plaisant, je trouve.

Et l’écran, même si il n’est aps reconnu comme exceptionnel, me paraît personnellement être déja une grande victoire.

Par contre, j’ai encore quelques soucis philosophiques de gestion de ma mp3thèque en synchronisation : j’utilisais auparavant iPod manager pour synchroniser mon iPod avec Foobar2000, mais là, je n’y arrive absolument pas. Et ça me paraît bien dommage … Parce que je vais devoir remplacer ça par une copie d’une sélection de mes MP3s préférés dans la carte SD, assortie de l’utilisation d’un podcatcher pour Android. Je ne suis pas très satsifait de ce découpage, mais il faut bien le tester, j’imagine.

 

Le voyage dans le temps, c’est possible sur internet

Notez bien que, dans le sens le plus général, c’est déja possible à travers des outils comme Internet Wayback Machine, mais c’est quand même assez peu pratique.

En revanche, là où ça devient pratique, c’est quand l’historique peut s’afficher directement dans le navigateur. Et ça, c’est ce que propose le protocole Memento. J’imagine qu’il doit y avoir un rapport avec le film, mais lequel … mystère (En passant, la construction en ping-pong marche avant/marche arrière de ce film est la même que celle du superbe roman de Iain M Banks nommé "L’usage des armes").

Enfin bref, memento, c’est une bonne idée.

Mais dans ce cas, pourquoi, POURQUOI, malgré la RFC, choisissent-ils de ne l’implémenter qu’avec Chrome en standard ? Hein ? Pourquoi. Heureusement pour moi, Firefox est open-source, et il existe une extension alternative curieusement nommée mementofox qui va me permettre de tester ce truc que j’imagine dément.

Cela dit, ce dont j’ai vraiment besoin (essentiellement pour le link rewriting dans le lifestream), c’est d’une librairie Java me fournissant l’équivalent de memento, pour pouvoir être sûr de montrer les liens tels qu’ils étaient à l’époque où je les ai sauvegardés. Ca doit pouvoir se trouver, non ? A priori, non, toutefois comme il existe un navigateur memento pour Android, j’imagine qu’il doit être possible d’en extraire le code métier pour faire des requêtes memento à la main …

Ca y est ! J’ai enfin terminé la migration de posterous !

Evidement, ça ne va pas intéresser grand monde … quoique.

Donc, vous vous souvenez de cet article "L’import de posterous, c’est quand même pas ça" ? J’y expliquai rapidement que les caractères non ASCII des articles que j’en importais étaient salement transformés. Au total, j’avais environ 600 articles contenant des accents, et donc contenant des saletés de "??". J’ai donc dû, quasi-manuellement, remplacer tous ces caractères par les vrais bon caractères accentués (merci d’ailleurs aux macros de Notepad++ qui m’ont bien facilité les choses). J’aurais bien aimé, dans l’idéal, pouvoir monter un partage WebDAV pour trouver plus rapidement tous ces articles à mettre à jour. Malheureusement, comme ce blog est hébergé gratuitement par WordPress.com (ce dont je les remercie), je ne peux pas installer de plugins, et je n’ai donc pas accès à mes articles facilement.

D’où cette terriblement longue phase de correction, qui a duré quand même 6 mois !

Du coup, évidement, je suis très content d’en avoir fini avec cet enfer, parce que je peux maintenant passer à des choses plus intéressantes, comme par exemple des améliorations du lifestream.

La première chose à faire, c’est finir d’implémenter le support de WordPress, ce qui me permettra de proposer ce support à l’auteur de JBake …

La deuxième, ce sera sans doute de détecter automatiquement les liens morts. Parce que dans WordPress, comme dans Shaarli, les liens périssent. Et pour l’instant, je ne le détecte pas et c’est bien dommage. Mais je sais que ça viendra !

La liste des plugins que j’utilise avec foobar2000

Parce que je viens de jeter un oeil au site de foobar2000 et que mon retard de version est … très important. Et comme foobar2000 ne gère pas lui-même ses plugions installés (ou alors je suis mal renseigné), je devrais les réinstaller après la mise à jour.

Alors effectivement, j’avais déja fait une liste dans un article subtilement nommé "foobar2000, de plus en plus dingue". Mais je ne suis pas sûr qu’elle soit à jour. Donc allons-y …

Et avec ça, je pourrais faire ma mise à jour rapidement, j’espère.

Allez on reprend proprement …

Bon, suite à la sortie de wisdom 0.6.1, j’ai décidé de reprendre les choses proprement.

Parce que j’ai réfléchi, et j’ai constaté plusieurs erreurs bêtes :

  • J’avais pensé créer un repository Git, mais il ne m’a finalement servi à rien. C’est idiot.
  • D’accord il n’y a pas de tests avec karma, mais je peux utiliser fluentlenium, non ?

Donc cette fois-ci, je vais essayer de faire les choses proprement, avec un repository git bien taggé, avec des tests d’interface, avec les archétypes qui vont bioen, et je vais essayer aussi de parler un peu d’angular.

Donc, reprenons du début …

Pour commencer, je crée le projet facilement puisque Eclipse me permet d’utiliser les archétypes, et que wisdom en propose maintenant un chouette. Donc je mets les bons paramètres, je clique dans le wizard d’Eclipse sur Finish … et c’est parti, j’ai mon application angular-google-shop que vous retrouverez rapidement dans Github (ce point bien précis est dans le tag 01_-_Après_l'appel_de_l'archétype_maven).

Et là, c’est évidement le moment du premier appel à mvn wisdom:run …

Histoire de ne pas reproduire le pataquès précédent, je vais tout de suite me créer un autre contrôleur (un collègue me soufflait d’ailleurs que ce serait bien cool d’avoir des outils de scaffolding comme dans Grails … pas bête).

Donc on y va pour le tutorial angular …. Sans passer par la case Bootstrapping, puisque j’ai déja fait mon projet.

Je la remplace gaillardement par la création d’un autre contrôleur, que j’appelle GoogleShopController, et dont le contenu est à peu près ça

@Controller
public class GoogleShopController extends DefaultController {
}

Maintenant, je vais le remplir … Ce que j’ai déja fait dans Un peu de wisdom, ça fera du bien

Créons donc un template statique  1 – Static Template

Donc, dans mon contrôleur, je crée une View et une méthode pour l’afficher :

    /**
     * Ici "list" est le nom du fichier du template, sans l'extension thl.html
     */
    @View("list")
    Template list;

    /**
     * Et donc quand on va aller sur http://localhost:9000/list, ça va afficher le template {@link #list}
     */
    @Route(method = HttpMethod.GET, uri = "/list")
    public Result todoList() {
        return ok(render(list));
    }

Et le fichier .thl.html qui va bien … Parce que je l’avais pas fait au début, heureusement j’ai eu droit à une belle exception lors de l’affichage, qui m’a poussé à aller voir le monitoring, qui m’a indiqué cette chouette erreur :

Wisdom Monitor __ Controllers_2014-07-08_15-07-00C’est clair, non ?

Bien, j’en suis donc arrivé à la fin de l’étape 1 du tutoriel, et le résultat est dans le tag 01_-_Etape_01_du_tutoriel_Angular_JS_avec_template_statique.

Et voilà les templates  2 – Angular Templates

Rien de bien sorcier là-dedans, mis à part évidement l’ajout des webjars :

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>angularjs</artifactId>
            <version>${angular.version}</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>${bootstrap.version}</version>
        </dependency>

C’est vraiment cool, je l’ai déja dit.

Bien, au passage, j’avais oublié d’ajouter la CSS de Bootstrap.

Et, encore une fois au passage, Wisdom intègre maintenant un chouette gadget pour ne pas trop s’emmerder avec les chemins des assets :

        <link th:href="${#routes.asset('css/bootstrap.css')}" rel="stylesheet"/>

Vous voyez la "fonction" thymeleaf #routes.asset('..') ? Eh bien elle convertit le chemin côté serveur en un chemin utilisable côté client, en s’occupant de toutes ces histoires de transformation de chemin. Bien joué ! D’ailleurs, elle plante joliment sur le chemin que j’ai entré pour angular, preuve que je n’arrive décidément pas à mettre la main dessus …

Ah, ça y est, j’ai trouvé :

        <script th:src="${#routes.asset('angular.js')}"></script>

Dingue, non ?

Tiens, au passage, une petite observation sur Angular …

Dans cette étape, on utilise pour la première fois ng-repeat="...". Un truc me trouble avec ce bidule : j’ai pas l’impression que ce soit du javascript qui y est écrit …je me trompe ? Eh bien non, ng-repeat utilise une "expression". Alors ça c’est bizarre …

Et c’est là qu’arrivent les tests jasmine/karma … pour lesquels je dois écrire un Watcher … A moins bien sûr que je ne décide de faire un test Fluentlenium qui accède à la page HTML de tests Jasmine pour les exécuter … Mouais, je vais plutôt faire ça, tiens …
Bon, j’ai pas été au bout, en revanche, l’approche est tellement bonne que je vais en discuter avec la liste wisdom. En fait c’est assez simple : il faut faire un bout d’application qui déclare un contrôleur JasmineRunner. Ce contrôleur définit une route qui cahrge la page de tests de Jasmine et qui utilise cette page pour produire les résultats des tests. Vous pouvez regardez dans le tag qui va bien 02_-_Etape_02_du_tutoriel_avec_templates_Angular_et_tests_Jasmine.

Filtrons 3 – Filtering Repeaters

Ca va aller vite …

Mis à part que protractor se traduit évidement par un vrai test Fluentlenium :-)

Et là, c’est le drame : je n’arrive pas à trouver la bonne syntaxe pour que ce test marche. En bonus, la syntaxe de Protractor n’a que peu de rapport avec celle de Fluentlenium. Pour tout dire, Protractor me donne l’impression d’un outil très spécifique à Angular, que je trouve de fait d’un intérêt assez faible.

Grmbl ..

Bon, après quelques heures de recherche, il s’est avéré que le test ne marchait pas parce que le driver Selenium par défaut ne supporte pas trop bien la syntaxe Angular.

Et donc, maintenant que j’ai un test Fluentlenium, je peux dire que l’étape 3 est accomplie ! Ce qui donne donc le tag 03_-_Après_l'ajout_du_filtrage.

Trions 4 – Two-way Data Binding

Là aussi, c’est assez rapide puisque je sais déja ce qu’il y a à faire, en fait plus rien de compliqué puisque toute l’infrastructure existe !

En revanche, définitivement, je préfère la syntaxe Fluentlenium. En effet, comme on n’y utilise que le HTML, on "bloque" l’interface dans une forme donnée, sans trop se préoccuper de ce qui est ait au niveau Angular, alors que Protractor fait tout le contraire.

Et du coup, encore un joli tag : 04_-_Après_l'ajout_du_tri.

Bon, comme les étapes suivantes sont du même accabit, je vais accélérer un peu, hein …

5 – XHRs & Dependency Injection

Rien de bien compliqué, juste une copie de fichiers "au bon endroit".

Il y a toutefois un truc malin dans le mock du service HTTP : le fait de flusher à la main la requête permet d’avoir un contrôle très fin sur ce qui se passe. C’est bien vu !

Bon, par contre, ne pas indiquer dans le tutorial que les tests end-to-end peuvent ne plus marcher, c’est pas très sympa … Mais j’ai quand même le tag 05_-_XHR

6 – Templating Links & Images

Bon là il y a un peu de modification de chemins, mais rien de grave … Quelques modifications dans les tests, aussi, mais vraiment rien de grave. Et le tag est 06_-_Liens_et_images.

7 – Routing & Multiple Views

Alors là, je l’ai déja dit, mais globalement, quand ils disent dans le tutorial

The routing functionality added by this step is provided by angular in the ngRoute module, which is distributed separately from the core Angular framework.

Ca veut juste dire d’ajouter le bon script :

<script th:src="${#routes.asset('angular-route.js')}"></script>

Bon il y a aussi un peu de code à modifier, mais rien d’insurmontable … dans le tag 07_-_avec_deux_routes.

8 – More Templating

Dans le tag 08_-_avec_un_beau_template_pour_les_détails. Je dois juste à l’honnêteté de dire que j’ai réutilisé le test d el’étape 7, parce qu’il y avait franchement une répétition.

9 – Filters

Ca donne un joli tag de plus 09_-_avec_des_filtres_de_rendu … Et l’envie certaine d’intégrer les tests Jasmine dans le build.

10 – Event Handlers

Trop facile ! Y compris le test Fluentlenium qui va bien. D’où le tag 10_-_avec_des_événements.

11 – REST and Custom Services

Là, comme pour les routes, il faut ajouter un module dans bower, c’est-à-dire que c’est déja fait avec webjars … Bon, le mauvais point de mon runner Jasmine actuel, je dois le dire, c’est qu’il n’arrive pas à récupérer les scripts utilisés dans list.thl.html, et c’est dommage. Mais j’imagine qu’un peu de lecture de thymeleaf m’y aiderait …

Ah, petite blague : Angular a écrit son tutorial avec Jasmine 1.3, et ne l’a pas mis à jour. Mais jasmine 2.0 change le style d’écriture des custom matchers, d’où un beforeEach un peu différent de la version fournie avec angular (que je n’ai par ailleurs aps réussi à faire marcher de façon satisfaisante).

J’en ai aussi profité pour m’assurer que je compilais bien en 1.7 …

Et j’ai donc créé le tag 11_-_avec_un_service_REST.

12 – Applying Animations

Bon, il y a le traditionnel ajout d’un module angular …

 <script th:src="${#routes.asset('angular-animate.js')}"></script>

Et l’ajout de …jQuery ? WTF ?!#
Ah, au fait, notez bien qu’à cause d’un "bug" Wisdom, si vous ajoutez un webjar, il faut relancer wisdom:run à la main pour l’instant … Bref …

Revenons-en à nos animations. C’est pas compliqué compliqué, je trouve juste bizarre d’avoir une animation jQuery alors que le tutorial dit bien

jQuery isn’t required to do JavaScript animations with AngularJS, but we’re going to use it because writing your own JavaScript animation library is beyond the scope of this tutorial

Est-ce que c’est pas une façon déguisée de dire que les animations avec jQuery sont quand même plus simples qu’avec angular ?

Cela dit, j’ai mon tag 12_-_avec_des_animations. Et j’ai fini le tutorial !

Conclusion

J’espère vous avoir convaincu, malgré le côté un peu expérimental de cette histoire, de l’intérêt d’utiliser wisdom. Pourquoi ?

  • Parce que le packaging javascript utilisant les webjars est bien plus simple
  • Parce que les tests Fluentlenium sont eux aussi bien plus simples à écrire que les tests protractor
  • Parce que je n’ai pas parlé des optimisations des images, de l’utilisation de LESS, de Typescript, ou d’autres fonctionnalités encore plus chouettes
  • Et enfin parce que lorsqu’on package une application wisdom, on package un tout : client et serveur, bénéficiant à la fois de la facilité de Javascript, et de l’écosystèpme serveur Java.

La suite ?

Je pourrais, dans une version ultérieure, faire un peu de code serveur : générer le phones.json à aprtir d’une servlet quelconque, gérer la sécurité, faire du push via websockets, … Mais pour ça, on verra plus tard.

 

Encore un peu de wisdom ?

Ben oui, après le message de la semaine dernière, vous ne vous attendiez tout de même pas à ce que ça s’arrête aussi vite ! Surtout que l’équipe de wisdom a sorti une version 0.6 (ce serait d’ailleurs bien d’avoir une page différente par release, parce que là, c’est pas super pratique), que je me suis empressé d’installer, et qui fournit un monitor que je trouve très bien (surtout parce qu’il liste les routes utilisables).

Donc, j’ai mis à jour, j’ai lancé mon application, toujours sur les traces du tutorial angular, et je suis passé à la page où on ajoute du javascript. Et j’ai remarqué plusieurs choses …

D’abord, évidement, que je pouvais appeler angular avec la bonne déclaration HTML :

<script src="/libs/angular.js"/>

Ensuite, et ça n’est pas évident pour moi, les tests Java ne sont pas relancés quand on redéploie l’application. J’ai bien l’impression que si l’équipe de wisdom regardait ce que fait par exemple Infinitest (je dis infinitest, mais je crois qu’il y a au moins un autre outil de test du même style. Sinon, reflections doit être capable de trouver les références à une classe Java dans tout un projet, je pense), ils pourraient facilement exécuter les tests "intéressants" au redéploiement.

Dans le même ordre d’idées, je sais bien que wisdom encapsule une instance node. Donc, quand angular me dit de faire un test Javascript, j’imagine que je dois pouvoir le faire quelque part … mais où ? La doc de wisdom ne me semble pas indiquer ça. Tiens, et ils annoncent en bonus

Angular developers prefer the syntax of Jasmine’s Behavior-driven Development (BDD) framework when writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in this tutorial in Jasmine v1.3. You can learn about Jasmine on the Jasmine home page and at the Jasmine docs.

The angular-seed project is pre-configured to run unit tests using Karma but you will need to ensure that Karma and its necessary plugins are installed. You can do this by running npm install.

OK, mais moi, dans mon projet, je n’ai pas de dépendance qui s’appelle karma ou Jasmine. j’imagine donc qu’il s’agit plus ou moins d’une forme de webjar … Ah, oui, jasmine est un webjar. Mais karma ? D’après la doc, il semble que je doive développer une extension de watcher (ou tout au moins un mojo) pour pouvoir l’utilser … C’est pas un peu beaucoup, là ?

J’imagine que je vais pouvoir commencer une FAQ officieuse pour wisdom avec toutes les réponses que je glane en les tanant par mail :-)

Bon, c’est assez de frustration pour aujourd’hui, je crois :-) Ce qu’il faut toutefois comprendre, c’est qu’il s’agit de frustrations somme toute mineures : je pourrais tout à fait faire une application pure Java, avec des pages HTML statiques. Là, je me complique un peu la vie parce que je creuse les détails de l’intégration client/serveur. Et je suis quand même franchement admiratif du boulot fourni sur Wisdom. J’imagine que je peux dire "à la semaine prochaine pour un autre épisode".

Mojo Executor

Admettons que vous deviez écrire un Mojo maven. ou, pire encore, un cycle de vie personnalisé. Vous allez sans doute faire des trucs déja implémentés par d’autres plugins maven. Et vous vous en voudrez.

Eh bien pour que vous ne vous en vouliez plus, n’éhsitez pas à appeler ces cibles directement avec Mojo-Executor.

Allez voir sur le site, c’est vraiment très très pratique dès qu’on veut reprendre un truc déja disponible dans un plugin du build. Et par vraiment, j’euphémise à mort. En fait, ça change tout.

Bon, il y a juste un truc qui me chiffone un peu, c’est qu’il faut lui passer un Plugin complet (c’est-à-dire avec une version valide). or, dans le code java, la version, on ne la connaît pas forcément, d’autant plus que le projet peut déja utiliser ce plugin et que, dans ce cas-là, sa version est déja connue des composants Maven. D’où cette petite méthode qui facilite bien la vie :

Ah, et si ça ne suffit pas, ajoutez-y ces petites méthodes qui facilitent l’ajout d’attributs (très pratique quand on fait de l’ant-exec)

Avec tout ça, votre prochain mojo sera vraiment facile à écrire.

Au passage, il semble que le même type ait écrit un maven-cli-plugin, actuellement difficile à trouver, pour éviter la perte de temps du démarrage de maven (ce qui ne m’intéresse pas professionnellement, puisque notre build prend 20 mns à s’exécuter).

Un peu de wisdom, ça fera du bien

Bon, cet après-midi, j’ai un peu de temps, donc je vais vous live-blogger une expérimentation.

L’expérimentation,, en l’occurence, est l’utilisation de wisdom-framework pour créer l’exemple canonique d’AngularJS : une liste de tâches mises à jour de façon "moderne". L’objectif est d’arriver avant la find e la journée à une application web qui enregistre les TODOs dans un fichier au format todo.txt.

EDIT : cet objectif n’a pas été atteint, parce que j’ai perdu un peu de temps sur l’install, et surtout parce que le fameux exemple de todo avec angular ne semble pas exister … bizarre.

Ah, mais vous ne connaissez pas wisdom ? C’est normal, c’est assez jeune, mais pourtant porteur d’innombrables promesses (et j’exagère à peine en disant ça). C’est donc un framework pour applications web basé sur la modularité et le dynamisme.

La modularité, grâce à OSGi, permet de découper une application web en paquets de tout petits blocs faciles à modifier, faciles à faire évoluer à peu près indépendament, mais pourtant utilisant des ressources communes.

Le dynamisme permet, encore grâce à OSGi, mais aussi grâce à maven, de développer aussi vite qu’avec une application pure Javascript, tout en bénéficiant de l’écosystème et des capacités de typage de Java. Enfin bon, vous allez voir avec moi.

Créer le projet

Facile, c’est documenté (la doc de wisdom me paraît d’ailleurs dans l’ensemble fort bien fichue – de toute façon, il suffit d’aller sur GitHub ou dans le Google Group pour poser des questions …). Donc allons-y :

mvn org.wisdom-framework:wisdom-maven-plugin:0.5.1:create -DgroupId=fr.fot.java.wisdom -DartifactId=wisdomTodo -Dversion=0.0.1-SNAPSHOT

Et normalement, c’est bon … sauf qu’entre ma version de maven incorrecte (3.0.4), mon Java incorrect (1.6.0_40), ça ne marche pas en ligne de commande et, de la même manière, créer le projet à partir de l’archétype dans Eclipse échoue lamentablement avec un message … cryptique :

Unable to create project from archetype [org.wisdom-framework:wisdom-maven-plugin:0.5.1 -> ]
The desired archetype does not exist (org.wisdom-framework:wisdom-maven-plugin:0.5.1)

Ca fait bizarre … Bon, je crée le projet à la main et je reviens …

Et pour créer le projet à la main, histoire que vous ne perdiez pas autant de temps que moi, si vous êtes dans Eclipse, la commande d’au-dessus se traduit sous la forme

Run Configurations_2014-06-20_16-03-09

A lancer dans un "Base directory" vide pour que ça se passe bien.

Et donc, une fois que c’est fait, je tape mvn wisdom:run, je vais sur http://localhost:9000 (ne craignez rien, ces instructions sont, encore une fois, indiquées dans la doc), et j’ai droit à une très jolie page m’indiquant que faire après …

Une page fournie par le WelcomeController. Le meilleur étant évidement que, quand je renomme le package de ce contrpoleur, je vois la console wisdom s’agiter un moment, puisque l’application est rechargée dans le dos d’Eclipse (c’est bon ça Clément !).

Ajouter une route à l’application

Donc maintenant, pour ajouter une nouvelle page (oui, je vais ajouter ma page avant de remplacer la @Route par défaut dans le contrôleur), ça me paraît assez facile :

    /**
     * Ici todo est le nom du fichier du template, sans l'extension thl.html
     */
    @View("todo")
    Template todoList;

    /**
     * Et donc quand on va aller sur http://localhost:9000/list, ça va afficher le template #todoList qui n'existe pas encore ... d'où une erreur.
     * @return
     */
    @Route(method = HttpMethod.GET, uri = "/list")
    public Result todoList() {
    	return ok(render(todoList));
    }

Et quand j’essaye de taper http://localhost:9000/list dans mon navigateur j’ai droit … évidement à une belle page d’erreur, puisque le tempalte n’existe pas ! Donc je le crée avec un contenu … quelconque.

Et devinez quoi ? Eh bien évidement, ça marche !

Bon, je n’ai plus qu’à rempalcer ce contenu par celui de l’exemple d’Angular JS  … qui a malheureusement été remplacé par exemple commercial. Pas grave, on peut le trouver ailleurs (la deuxième version est bien plus simple pour un noob comme moi).

Et là c’est le drame : les attributs ng-app d’Angular viennent foutre le bazar dans le parsing XML :

Caused by: org.thymeleaf.exceptions.TemplateInputException: Exception parsing document: template="bundle://58.11:0/templates/todo.thl.html", line 13 - column 13
	at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.parseTemplateUsingPool(AbstractNonValidatingSAXTemplateParser.java:167) ~[na:na]
	at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.parseTemplate(AbstractNonValidatingSAXTemplateParser.java:117) ~[na:na]
	at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:277) ~[na:na]
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1104) ~[na:na]
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060) ~[na:na]
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011) ~[na:na]
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:955) ~[na:na]
	at org.wisdom.template.thymeleaf.impl.WisdomTemplateEngine.process(WisdomTemplateEngine.java:85) ~[na:na]
	at org.wisdom.template.thymeleaf.impl.ThymeLeafTemplateImplementation.render(ThymeLeafTemplateImplementation.java:120) ~[na:na]
	at org.wisdom.api.templates.Template$$Proxy.render(Unknown Source) ~[na:na]
	at org.wisdom.api.DefaultController.render(DefaultController.java:188) ~[wisdom-api-0.5.1.jar:na]
	at fr.fot.java.wisdom.todo.WelcomeController.__M_todoList(WelcomeController.java:65) ~[na:na]
	at fr.fot.java.wisdom.todo.WelcomeController.todoList(WelcomeController.java) ~[na:na]
	... 33 common frames omitted
Caused by: org.xml.sax.SAXParseException: Le nom d'attribut "ng-app" associ� � un type d'�l�ment "html" doit �tre suivi du caract�re '='.
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:441) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1375) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanAttribute(XMLDocumentFragmentScannerImpl.java:1489) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1279) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2715) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:488) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568) ~[na:1.7.0]
	at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:302) ~[na:1.7.0]
	at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.doParse(AbstractNonValidatingSAXTemplateParser.java:210) ~[na:na]
	at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.parseTemplateUsingPool(AbstractNonValidatingSAXTemplateParser.java:134) ~[na:na]
	... 45 common frames omitted

En même temps, je sais que c’est ça essentiellement grâce à une très bonne remontée d’erreur (c’est un avantage certain). Du coup je replonge dans la doc de wisdom pour voir comment angular et thymeleaf peuvent vivre ensemble … Ah en fait ça n’est pas dans la doc de Wisdom, mais sur la ML de Thymeleaf.

Bon, et du coup, une fois que j’ai modifié l’entête pour

<!doctype html>
<html data-ng-app="">

que j’ai fermé les différents tags mal fermés et corrigé deux ou trois boulettes, ma page s’affiche … mochement, je dois dire :-)

Je peux donc y ajouter le contrôleur pour angular, que je copie-colle également sans m’embêter. Mais avant ça, je vais d’abord ajouter les webjars demandés (quelle chouette idée, ces dépendances javascript utilisables facilement) …

Mais ça, ce sera pour une autre fois.

Parce que les mecs d’angular semblent avoir décidé de changer leur exemple (que j’ai pourtant vu des dizaines de fois) et que, n’ayant plus de tutoriel parfaitement clair, je ne peux même plus tenter d’adapter ce que je vois à ce que wisdom me fournit (parce que figurez-vous que je ne connais malheureusement pas encore l’outil).

Bon, bref. J’y reviendrai sans doute la semaine prochaine. En tout cas, je suis plutôt séduit par la facilité avec laquelle wisdom s’installe, s’adapte, et se met à jour quand on change du code.

Comme quoi l’apprentissage n’est pas toujours un chemin facile. Surtout quand on se met soi-même des bâtons dans les roues.

Et alors elles en sont où ces photos ?

Hein ?

Parce que bon, c’est bien beau d’annoncer des scripts et des bidules et des machins pour trier les photos. Mais depuis que j’en parle, ça devrait être fini, non ? Eh bien non !

En fait j’ai rencontré sur cet ensemble de projets un certain nombres de … difficultés. En effet, mon dernier plan était,

  1. Tagger mes photos via iView Media Pro (et son descendant de chez Microsoft)
  2. Renommer les photos avec  XnView
  3. Et enfin créer à partir de ces images un ensemble de dossiers reprenant des éléments clés

J’avais réussi. J’avais même dans ma branche de MiniGalNano, un script (habilement nommé reload.php) qui créait des paquets de dossiers à partir des images de ma bibliothèque.

Hélas, c’est parti en sucette à cause d’une histoire débile : autant mon NAS, sur lequel tourne ce script, est lamentablement lent pour créer des vignettes de mes images (dont la résolution native est quelque chose du genre 3600×2400 pixels). J’ai même dû arrêter d’utiliser ce script tellement c’était pathétiquement lent.

Du coup, j’ai réfléchi. Réfléchi longtemps. En gros, j’avais l’outil pour héberger les fichiers, mais je n’avais pas la puissance de calcul … Ou alors, je l’avais peut-être … partiellement.

Vous savez peut-être que j’ai un iBook G4 qui traîne dans ma cave. Alors qu’est-ce qui m’empêche de mettre en place un démarrage planifié de cet iBook, pour qu’il fasse des vignettes de mes photos et les uploade ? Hein, qu’est-ce qui m’en empêche ? Rien d’autre que le temps que ça va prendre. Cela dit, ça risque d’aller vite :

  • Je peux utiliser fuse pour monter mon NAS en SFTP
  • Et je peux utiliser phatch pour faire le redimenssionement. (et comme c’est du Python, j’imagine sans problème que ça va marcher sur l’iBook).
  • Par contre, pour démarrer/arrêter automatiquement l’iBook, je ne sais pas trop comment faire … Et surtout comment faire pour que l’iBook s’arrête dès qu’il a fini de bosser.

L’extension vidéo via UPnP ?

Depuis longtemps, je trouve les écrans dont je dispose trop petits. C’est maladif chez moi. Par exemple, au bureau, j’ai deux écrans Full HD, eh bien ça n’est pas assez (à ma décharge, je dois y lancer Eclipse, Flash Builder, Indesign, et quelques autres gros consomateurs d’esapce).

A la maison, c’est encore pire : mon beau tout-en-un n’a (contrairement à un chouette modèle MSI très récent) ni entrée ni sortie HDMI et est donc une île de vidéo au milieu d’un beau mur blanc. Or j’adorerais pouvoir balancer son image sur la télé ou ailleurs.

Oh, ne croyez pas que je n’ai pas cherché. je sais par exemple que ZoneScreen permet d’abuser VNC pour étendre un bureau sur une machine voisine. Mais la solution me semble un peu crapuleuse. Et en plus il n’est rgatuit que pour une utilisation domestique. Et il faut un logiciel sur le serveur (celui qui porte le clavier) et sur le client (celui qui reçoit l’image).

Bon, mes réflexions étaient un peu coincées, quand j’ai lu cet article de Lifehacker expliquant que DLNA/UPnP, c’est la meilleure solution pour qui veut dupliquer l’affichage de son smartphone.

Et là, j’ai eu un flash !

Je me suis dit que, si le mec de ZoneScreen était capable d’écrire un driver Windows envoyant l’image à travers VNC, pourquoi ne pas faire un driver envoyant l’image vers un lecteur UPnP ?

Evidement, je croyais que c’était une idée originale … pauvre fou que j’étais.

Cela dit, je note bien qu’aucun de ces sites ne détient de réponse claire, alors qu’il me semble qu’en aprtant du code de ZoneScreen, il soit possible d’écrire "le bon driver" : celui qui, quand un novueau client UPnP s’y connecte, crée un écran plug’n’play virtuel des bonnes dimensions pour y afficher du contenu provenant de la machine source.

Enfin bon, il faudrait pour ça que j’écrire un driver Windows … ce qui n’est pas actuellement dans mes cordes.