Science-fiction et anachronismes #2

Il y a quelques années à la lecture du roman de science-fiction Les menhirs de glace (Icehenge an VO) de Kim Stanley Robinson, j’avais été frappé par certains éléments qui me semblaient particulièrement anachroniques dans le futur qu’il nous proposait au point d’en faire un article.

Cette fois-ci c’est le visionnage de deux séries de Star Trek : d’abord Enterprise (2001-2005), puis Deep Space Nine (1993-1999) dont je viens de finir la saison 2 qui m’ont fait tiquer sur certains points.

Je ne vais pas parler de la facilité qu’ils ont à traduire les langues ou d’autres éléments qui ont évidemment pour source le besoin d’éviter les longueurs dans la série. On n’est pas dupe une seconde sur le réalisme mais il y a une justification pratique : l’ensemble de la série perdrait de sa fluidité sans cela, ça fait partie des choses qu’il faut admettre (on est dans une fiction, pas dans un documentaire).

Mais il y a d’autres points qui ne sont pas nécessaires au bon fonctionnement de la série en général et me semblent juste relever d’anachronismes injustifiés.

Attention : ces séries étant anciennes, je vais donner des éléments du déroulement de certains épisodes sans masquage ou gros messages d’alerte. Vous êtes prévenus.

Les outils de communication

Dans Deep Space Nine, chacun des officiers de la station dispose de son « combadge ». Mes souvenirs de la série d’origine sont très vagues mais d’après Wikipédia, ils remplacent les « communicateurs » de l’époque.

On est donc sur des appareils qui ne permettent que le la communication audio (pas d’images notamment) plus certaines données comme la localisation. On est donc bien sur des versions diminuées de nos ordiphones actuels. Quelque part, on peut considérer que ça ne tapait pas trop à côté puisqu’on est effectivement allé dans cette direction (même si dans la pratique on est allé bien plus loin et plus vite qu’ils ne l’envisageaient).

Mais là où ça commence à vraiment être bizarre c’est dans Enterprise qui se passe un siècle avant la série d’origine et deux avant Deep Space Nine. Là la communication dans le vaisseau est assurée par un réseau de bornes murales qui relaient les messages vocaux auxquels on peut répondre après avoir pressé un bouton…

J’imagine que l’idée était de caser un système moins évolué que les communicateurs et combadges des séries chronologiquement postérieures et en cela ça se tient. Cependant ce n’est vraiment pas très crédible par rapport à la réalité de ce qui s’est passé entre temps et qui était déjà bien engagé à l’époque où a été tournée Enterprise (2001-2005) : le téléphone portable puis l’ordiphone se sont rapidement généralisés.

Du coup imaginer qu’on revienne en arrière avec un réseau fixe dans le vaisseau parait assez difficile. Surtout avec tous les petits appareils qu’ils trimbalent et permettant de magiquement tout analyser ou traduire des milliers de langues en temps réel… Qu’ils n’aient pas intégré un appareil de communication sous une forme ou une autre est des plus bizarres et ne s’explique que parce qu’ils ont dû se retrouver piégés entre ce qui avait déjà été fait dans les autres séries (chronologiquement postérieures et donc technologiquement plus avancées) et ce qui s’est passé entre temps dans la réalité.

L’irréfutabilité de l’enregistrement

La bascule ne s’est pas encore faite dans notre époque actuelle mais elle s’annonce de plus en plus : comment peut-ont imaginer s’assurer qu’un enregistrement est véridique ? Pour une communication en temps réel c’est plus simple, on peut imaginer des signatures authentifiant les interlocuteurs comme on le fait actuellement avec les mails quand on veut certifier leur émetteur et la non-altération du contenu. Mais on ne certifie en aucun cas l’honnêteté de l’interlocuteur, juste de la transmission.

Dans l’épisode 13 de la seconde saison de Deep Space Nine (Annihilation en VF, Armageddon Game en VO), les représentant d’une race extra-terrestre rapportent un enregistrement vidéo censé relater la mort de deux membre de la station. Cet enregistrement est accueilli comme évidemment vrai par le commandant.

La seule à le mettre en doute est la femme de l’un des deux supposés morts qui croit déceler une incohérence dans le comportement de son mari (qui ironiquement s’avère en plus faux à la fin de l’épisode). À aucun moment les responsables de la station ne remettent en cause la véracité de l’enregistrement. Ils remettent fréquemment en cause les témoignages oraux mais pas les enregistrements. Notamment ils se fient aveuglément à un élément pourtant facilement falsifiable : l’horaire indiqué dans l’enregistrement.

Déjà actuellement, l’authentification des preuves que ce soient des enregistrement vidéo ou vocaux ou plus généralement des documents numériques est de plus en plus difficile. De nombreuses manipulations peuvent être faites de façons de plus en plus indétectable : changer une métadonnée comme la date est généralement assez simple et difficilement détectable.

On imagine donc bien qu’au 23e siècle, tandis que l’humanité parcourt la galaxie, les techniques de manipulation d’image ont nécessairement progressé également. Si à notre époque les premières résurrections d’acteurs décédés par images de synthèses restent perfectibles, on imagine bien que 3 siècles plus tard ce sera plus vrai que nature.

Il parait donc plus qu’étrange que la question de la falsification ne se pose même pas avant l’intervention de l’épouse. Certes les extra-terrestres en question sont bien censés être plus ou moins des alliés mais bon quand on vous annonce que deux de vos experts sont morts (suite à une erreur de manipulation de l’un d’eux en plus) alors qu’ils étaient sur le point de finir une mission sans danger il semble naturel de se poser des questions. Et là rien : l’enregistrement est une preuve évidente. Point.

L’impasse de la biométrie

Dans l’épisode 25 de la seconde saison de Deep Space Nine (Tribunal aussi bien en VO qu’en VF), Miles O’Brien est accusé d’avoir volé des armes. Notamment l’ordinateur relève que c’est lui qui est le dernier à être entré dans le dépôt. La preuve ? C’est sa voix qui a commandé l’ouverture de la porte.

Bon là au moins la preuve est mise en doute et rapidement ils remarquent en analysant l’enregistrement que la voix a été trafiquée. Ou plutôt que la phrase prononcée est un montage réalisé à partir de mots distincts enregistrés.

Mais un système de sécurité authentifiant les gens à leur voix ? Vraiment ? C’est tellement évidemment facile à abuser, que ce soit en rejouant un enregistrement véridique ou en en construisant un, que même de nos jours on n’essaie pas d’utiliser un truc aussi faible.

Intrinsèquement la biométrie est peu fiable pour de l’authentification et ce pour deux raisons principales : d’une part les données biométriques sont publiques ou récupérables assez facilement et d’autre part elles sont non-modifiables (enfin y a toujours moyen de recourrir à la chirugie pour certaines d’entre elles mais c’est assez lourd pour une donnée fuitée dont la remplaçante sera de nouveau facilement accessible).

Même actuellement quand on met en avant la biométrie pour de l’authentification on a la décence de prendre un truc un peu moins facile à falsifier que la voix (genre l’iris ou les empreintes digitales).

Là on est censé avoir fait des progrès énormes mais on reste sur de l’authentification vocale pour protéger l’accès à un dépôt d’armes… Ça laisse songeur.


Carte Magic perso : Troisième main

On continue la série de republications de cartes Magic perso avec une carte orientée humour qui aurait plutôt sa place dans une extension type Unglued. Elle aussi était une participation à un jeu FC mais je n'ai pas retrouvé le thème.

Troisième main
Troisième main

Bon, j'avoue c'est loin d'être ma plus réussie mais bon, je la poste quand même parce que bon, l'idée de base me plait bien :p

Réalisation

Comme d'hab : GIMP + le xcf de NorthNikko (un peu retouché par moi à force). L'illustration n'est pas idéale mais après une heure de recherches infructueuses, j'ai fini par me rabattre l'illustration OOOK par Berilia. Enfin, la texture : il s'agit de pramos03 par Lwsypher.

Rien de transcendant dans la réalisation mais à force de chercher désespérément une illustration qui convienne, j'avais plus le courage de faire un truc recherché pour le reste :tired: J'envisageais de lui coller des cartes dans une main et le pied visible mais j'ai pas eu le courage... peut-être un jour je prendrai le temps de le faire, un jour où je me sentirai plus motivé qu'hier ^^

Idée

L'idée m'est venue comme ça qu'on pouvait faire un truc marrant avec les pieds :D On a donc là une carte fun qui, si l'on est agile de ses pieds permet de piocher 7 nouvelles cartes ne comptant pas dans la limite de cartes en main (normal, elles ne sont pas dans la main mais dans le pied :smile:).

Après pour habiller un peu le tout, je l'ai tournée en références aux singes, dont les pieds sont habiles que les nôtres et qui renforçaient l'ambiance fun de la carte :p C'est pour ça que j'ai collé une touche de vert en plus du bleu, même si la capacité n'y fait pas des masses référence.

Pour le texte d'ambiance, en bon fan l'œuvre de de Terry Pratchett, j'ai hésité un moment à mettre juste "Ook !" mais bon finalement j'ai fait un peu plus long ^^

Bon après y a un gros point noir à ma carte (comme à certaines autres participations d'ailleurs) : le pied n'est pas à proprement parler un permanent, du coup c'est pas complètement dans le thème, mais bon j'avais pas d'autre idée... :-/

Voilà voilà :o


Moteur de recherche dans un site Jekyll

La problématique

Dernier des gros points noirs relevés lors de ma bascule sur Jekyll : l’absence de moteur de recherche.

Forcément quand le site est statique, c’est plus compliqué de mettre en place un moteur de recherche. Il y a plusieurs approches possibles :

  • faire une partie dynamique côté serveur pour la recherche : bof, le but c’est d’avoir maintenance côté serveur, donc non
  • faire appel à une API tierce qui ferait l’indexation puis la recherche : bof aussi, ça permet certes de rester statique côté serveur mais délocaliser la chose n’est pas mieux (en plus ça veut dire maintenance sur l’utilisation de l’API) donc non
  • déléguer complètement à un moteur externe type Google Search : ça existe sur certains sites (quoique ça fait un moment que je l’ai plus vu) sous la forme d’un formulaire de recherche redirigeant sur Google avec une recherche de type site:monsite.com ...… c’est mieux côté maintenance mais pire côté délocalisation puisqu’on quitte carrément le site, donc non

Reste la dernière : faire la recherche directement dans le navigateur en JS à partir d’un index fourni, solution finalement retenue.

Bon, c’est loin d’être parfait comme concept : ça ne passe évidemment pas à l’échelle notamment mais ce site reste un blog perso donc la volumétrie de devrait pas exploser…

L’index fait environ 500ko avec mes 156 articles actuels (représentant un peu plus de 10 ans) donc ça reste jouable, même si j’ai augmenté mon rythme ces derniers temps (notamment à cause des republications). Dans tous les cas on reste loin des pages d’accueil avec des gros carrousels d’images à 2Mo chacune qu’on trouve sur certains sites (notamment e-commerce) et ce n’est de toutes façons chargé que sur la page de recherche.

Donc c’est réaliste dans mon cas et vous pouvez le tester via le champ de recherche dans la colonne de droite.

Solution existante et adaptations

Je suis parti de cet article proposant une solution basée sur la bibliothèque Lunr mais comme souvent c’était loin d’être satisfaisant de base :

  • forcément c’est en anglais, donc fallait au moins traduire
  • ça ne permet pas de placer le champ de recherche sur toutes les pages (à moins d’inclure le code de recherche sur toutes les pages aussi, ce qui est exclus)
  • visuellement le rendu ne me convenait pas du tout
  • toutes les pages sont indexées, y compris les pages de catégories par exemple qui ne sont que des regroupements d’articles

Du coup j’ai réorganisé les choses différemment en :

  • séparant l’index dans un fichier JS à part
  • modifiant le formulaire pour qu’il fasse un simple GET vers une page dédiée au résultat de recherche
  • modifiant le JS pour que le terme à rechercher soit cherché dans l’URL
  • ajoutant dans l’en-tête des pages devant être indexées un paramètre searchable: true

La section suivante détaille la marche à suivre pour intégrer tout ça sur votre site.

Mise en œuvre

La bibliothèque Lunr

À récupérer ici et à ajouter dans le dossier assets/js.

Le code JS utilisant Lunr

Dans un fichier assets/js/search.js :

(function (window) {
	window.onload = function () {
		var idx = lunr(function () {
			this.ref('id');
			this.field('title');
			this.field('body');

			window.searchIndex.forEach(function (doc) {
				this.add(doc)
			}, this)
		});

		var resultsElement = document.getElementById('search-results');
		var HTML = '';
		var term = getQueryString('q');
		if (term) {
			document.getElementById('search-field').value = term;
			var results = idx.search(term);
			if (results.length > 0) {
				var plural = results.length > 1;
				HTML += '<p>' + results.length + ' résultat' + (plural ? 's' : '') + ' trouvé' + (plural ? 's' : '') + ' pour la recherche « ' + term + ' » :</p> <ul>';
				for (var i = 0; i < results.length; i++) {
					var result = window.searchIndex[results[i]['ref']];
					var url = result['url'];
					var title = result['title'];
					var date = result['date'];
					var body = result['body'].substring(0,160) + '...';
					var type = result.type === 'post' ? 'Article' : 'Page';

					HTML += '<li class="search-result"><p class="metadata"><a href="' + url + '" class="title">' + title + '</a>';
					HTML += ' <span class="type">' + type + '</span>';
					if (date) {
						HTML += ' <span class="date">publié le ' + date + '</span>';
					}
					HTML += '</p><p class="summary">' + body + '</p></li>';
				}
				HTML += '</ul>';
			}
			else {
				HTML += '<p>Aucun résultat trouvé poru la recherche « ' + term + ' ».</p>';
			}
		}
		else {
			HTML += '<p>Aucun terme à rechercher.</p>';
		}
		resultsElement.innerHTML = HTML;
	};

	/**
	 * Get the value of a query string.
	 * @param {string} field The field to get the value of
	 * @param {string=} url The URL to get the value from (optional)
	 * @return {string} The field value
	 */
	var getQueryString = function (field, url) {
		var href = url ? url : window.location.href;
		var reg = new RegExp( '[?&]' + field + '=([^&#]*)', 'i' );
		var string = reg.exec(href);
		return string ? string[1] : null;
	};
})(window);

Je n’ai pas cherché à extraire le rendu HTML du résultat de recherche, donc il faudra directement modifier ce fichier pour l’arranger.

Le fichier d’index : search-index.js

Dans un fichier search-index.html à la racine du projet :

---
layout: null
permalink: search-index.js
---

(function (window) {
  {%- assign counter = 0 %}
  window.searchIndex = [{% for page in site.pages %}{% if page.searchable %}{
    "id": {{ counter }},
    "url": "{{ site.url }}{{ page.url }}",
    "type": "page",
    "title": "{{ page.title | replace: '"', ' ' }}",
    "body": "{{ page.content | markdownify | replace: '.', '. ' | replace: '</h2>', ': ' | replace: '</h3>', ': ' | replace: '</h4>', ': ' | replace: '</p>', ' ' | strip_html | strip_newlines | replace: '  ', ' ' | replace: '"', ' ' }}"{% assign counter = counter | plus: 1 %}
  }, {% endif %}{% endfor %}{% for page in site.posts %}{
    "id": {{ counter }},
    "url": "{{ site.url }}{{ page.url }}",
    "type": "post",
    "date": "{{ page.date | date: '%d/%m/%Y à %R' }}",
    "title": "{{ page.title | replace: '"', ' ' }}",
    "body": "{{ page.content | markdownify | replace: '.', '. ' | replace: '</h2>', ': ' | replace: '</h3>', ': ' | replace: '</h4>', ': ' | replace: '</p>', ' ' | strip_html | strip_newlines | replace: '  ', ' ' | replace: '"', ' ' }}"{% assign counter = counter | plus: 1 %}
  }{% if forloop.last %}{% else %}, {% endif %}{% endfor %}];
})(window);

Il est possible de modifier ce fichier si vous voulez ajouter des informations à l’index (par exemple des données complémentaires pour l’affichage des résultats).

La page de résultat de recherche

Dans un fichier search.md à la racine du projet :

---
layout: page
title: Recherche
---

<script src="/assets/js/lunr.js?v={{ site.time | date: '%s' }}" type="application/javascript" async="async"></script>
<script src="/assets/js/search.js?v={{ site.time | date: '%s' }}" type="application/javascript" async="async"></script>
<script src="/search-index.js?v={{ site.time | date: '%s' }}" type="application/javascript" async="async"></script>

<div id="search-results">Recherche en cours...</div>

L’entrée layout est à adapter en fonction de ce que vous avez défini sur votre site.

Le formulaire de recherche

Il reste à intégrer le formulaire de recherche là où vous souhaitez de voir apparaitre :

<form action="/search.html" method="get" class="search-form">
  <p>
    <input id="search-field" type="text" name="q" maxlength="255" value="" />
    <button type="submit" title="Lancer la recherche"><img src="/assets/img/search.svg" alt="Lancer la recherche" /></button>
  </p>
</form>

Pages indexables

En l’état seuls les articles seront indexés. Il reste donc à ajouter searchable: true dans l’en-tête de chaque page que vous souhaitez indexer.


Cartes Magic perso : Cycle Demwen

On continue la série de republications de cartes Magic perso avec cette fois un cycle de 5 cartes réalisées à l'époque dans le cadre d'un jeu FC sur l'Assemblée de Funomanciens (je n'ai plus retrouvé le sujet exact du défi mais il fallait qu'on propose un extrait d'histoire qui justifie la ou les cartes), avec leur commentaire d'origine. L'ensemble a été finalisé à l'époque de façon un peu précipitée sans que je le retravaille ensuite, contrairement à d'autres cartes, ce qui explique certains passages du commentaire. De même l'histoire mériterait sans doute d'être un peu retravaillée.

Demwen, fillette captive Demwen, enfant sauvage Demwen, adolescente ardente Demwen, femme cruelle Demwen, esprit apaisé
Demwen, fillette captive (HD) / Demwen, enfant sauvage (HD) / Demwen, adolescente ardente (HD) / Demwen, femme cruelle (HD) / Demwen, esprit apaisé (HD)

En cherchant des illustrations, l'idée m'est venue de faire un cycle reprenant les étapes de la vie d'un personnage (chose qui n'existe pas encore à ce jour dans les cartes officielles il me semble). Les deux première illustrations collaient plutôt bien à l'idée et trainaient dans ma sélection sur deviantART depuis un bout de temps, c'était donc l'occasion de les exploiter ^^

On a donc l'histoire d'un ange, Demwen. Comme souvent quand je manque d'inspiration pour un nom, j'ai pioché dans le vocabulaire elfique élaboré par Tolkien (le Sindarin en l’occurrence). On a donc dem qui signifie triste et le suffixe -wen signifiant fille, vierge, jeune fille d'après le dictionnaire proposé par le site Ambar Eldaron. Vous l'aurez compris, notre amie Demwen va bien entendu jouir d'une vie heureuse et dans la joie et l'allégresse.

Ou pas.

Durant les premières années de sa vie, Demwen fut prisonnière, enchaînée, ses ailes entravées. N'apercevant le jour qu'à travers les barreaux de sa cellules, elle rêvait du jour où, enfin libérée, elle parcourrait les cieux. Priant Serra, la divinité angélique d'un lointain passé dont les légendes louaient la bonté et la perfection, elle savourait chaque nouvelle aube comme un nouvel espoir. Mais chaque jour avait également son crépuscule et les années passèrent, lui semblant une éternité.

Puis le jour vint ou ses prières furent exhaussées. Dans le fracas des combats d'une guerre dont elle ne savait rien, les chaines qui l'emprisonnaient furent brisées et le mur de sa triste geôle s'effondra. Terrifiée par les combats, Demwen prit la fuite, se réfugiant dans la forêt. Perdue dans ce monde étranger, ses ailes atrophiées par la captivité ne pouvant la porter bien longtemps, la jeune évadée resta dans cette forêt sombre et hostile.

Elle regorgeait de prédateurs mais la fillette apprit à éviter leur pièges et à lutter pour survivre. Le temps passa et l'ancienne captive, devenue enfant sauvage, grandit. Devenant plus forte, de gibier elle devint prédateur. Ses ailes s'étaient renforcées et étaient devenues un atout, même dans cette forêt emplie d'obstacles.

Puis revint à nouveau la guerre. La forêt fut dévorée par les flammes mais l'adolescente survécut une fois de plus, apprivoisant le feu, s'en faisant une nouvelle arme. Mais il ne restait rien de ce qui était devenue sa maison et Demwen prit son envol parcourant Ulgrotha, recherchant un nouveau lieu où vivre.

Elle finit par échouer dans la sombre baronnie de la famille Sengir. Où elle défit le bras droit du maitre des lieux en combat singulier qui périt brûlé vif. Le Baron, impressionné par ses aptitudes la prit sous son aile et elle intégra les troupes sengiennes, en lieu et place du lieutenant déchu. Les années passèrent ainsi et la jeune femme qu'elle était devenue sombrait toujours plus dans la noirceur et la cruauté.

Jusqu'au jour où, au gré des combats, elle se retrouva face à face à l'une de ses sœurs de race. L'ange était pure autan que Demwen était souillée et leur duel fut violent et sanglant. Les deux championnes périrent, entrainant avec elles une grande partie de leurs alliés.

Mais si son corps fut détruit, l'esprit de l'ancienne captive survécut. Absorbant les restes de l'âme déchirée de son adversaire, elle put se défaire de la souillure qui envahissait la sienne, retrouvant la pureté angélique que sa dure existence lui avait enlevée. Sous son influence protectrice, l'ancien champ de bataille devint un havre, un refuge pour les voyageurs égarés.

Jusqu'au jour où un arpenteur échoua en Ulgrotha. Comme c'est trop souvent le cas avec ces magiciens voyageurs des plans, il était avide de nouveau pouvoir et, à l'aide d'un puissant sortilège, il s'appropria les pouvoirs de Demwen. Mais cette nouvelle puissance qu'il venait d'acquérir était liée elle. Si son âme s'éteignait, elle s'éteindrait avec elle. Il lui fallait un corps pour lui permettre de se régénérer. La privant de ses souvenirs, il la plaça dans le corps d'une enfant, l'enchaîna et l'enferma dans une prison où elle vivrait captive mais protégée.

Donc voilà voilà, que du bonheur, comme on dit sur TF1.

On a donc les cinq étapes de l'existence de Demwen, avec à chaque fois une capacité permettant de passer à l'étape suivante (en sacrifiant l'actuelle et en cherchant la suivante dans sa bibliothèque), conditionnée par un critère en restreignant l'usage. Chaque version est un ange et a donc le vol, comme tous les anges de Magic me semble-t-il. Elle a également une deuxième capacité à mot-clé correspondant à cette étape, ainsi qu'une capacité déclenchée lorsqu'elle meurt, liée à la condition de déclenchement du changement d'étape précédent.

Les cinq étapes sont les suivantes :

  • la fillette captive ne peut logiquement pas attaquer, d'où le défenseur. La carte piochée représente les possibilités offertes par la liberté quelle acquiert et la condition de passage (une créature de force 3 ou plus) symbolise la créature qui, dans le feu de l'action et sans le faire exprès, l'a libérée de la sa prison
  • l'enfant sauvage non seulement peut attaquer mais a le contact mortel : la proie des bêtes sauvages est devenue chasseresse. Le boostage fourni en quittant le champ de bataille représente le regain d'énergie gagné en apprivoisant le feu et la condition de passage représente l'attaque de la forêt qui a déclenché le changement
  • l'adolescente ardente a est une voyageuse rapide et féroce, d'où la célérité. Les trois blessures infligées en quittant le champ de bataille rappellent le lieutenant du Baron, brûlé vif et la condition de passage à l'étape suivante représente la mort du lieutenant et de deux autre soldats qui étaient au mauvais endroit au mauvais moment (bon OK, me rattrape aux branches basses mais il est déjà presque 22h30 et j'ai la flemme de reprendre ma storyline pour introduire cet élément oublié :p)
  • la femme cruelle est donc la nouvelle championne du Baron. Intégrant l'armée d'un comte vampire, c'est fort logiquement qu'elle acquiert donc la soif de sang. La destruction de trois créature ciblées (notons qu'il n'y a pas le choix : si l'adversaire n'a pas de créatures à tuer, il faut tuer les siennes) représente les dégât occasionnés par le duel, tandis que la condition d'activation fait écho à l’absorption de l'âme de son adversaire (oui bon, d'accord, j'ai brodé les détails de ma storyline bien après avoir finalisé les cartes, donc y a deux-trois petits problèmes de chronologie :oops:)
  • enfin l'esprit apaisé est puissant et protège le lieu de la bataille qui lui a coûté la vie et ce lieu la renforce et la protège en retour, d'où la défense talismanique. Les points de vie gagnés représentent le pouvoir acquis par l'arpenteur et les trois cartes en main les trois sortilèges qu'il lance pour lui prendre son pouvoir, lui donner son nouveau corps et priver de ses souvenirs en la scellant dans sa nouvelle prison

Et voilà que la boucle est bouclée.

Comme ce cycle doit être joué ensemble pour exploiter tout son potentiel, j'avais le choix entre utiliser peu de mana coloré et cette autre solution que j'ai retenue de donner le choix entre du mana coloré et le double de mana générique, ce qui me semblait un bon compromis : on peut garder des coûts raisonnables en coloré et laisser un peu de souplesse en autorisant un paiement dans une autre couleur (moyennant une rallonge budgétaire).

Reste à parler un peu de la réalisation :

  • comme toujours, la carte est réalisée sous GIMP avec le XCF de Sovelis et NorthNikko, rien de nouveau sous le soleil.
  • la texture est réalisée sous Photoshop Elements et se base sur celle-ci, complétée de plumes... qu'on ne voit plus du tout sur le résultat final. Pas plus qu'on ne voit que les textures des 5 cartes n'en forment qu'une seule... mais bon, tant pis :o
  • les illustrations des 5 cartes sont respectivement les suivantes :

Quelques trucs sur Jekyll #2

Lisibilité des erreurs

Par défaut, le serveur de développement de Jekyll remonte des erreurs assez sommaires en ne précisant que le template concerné. C’est inutilisable quand on débugue un template (même si un numéro de ligne ne serait pas du luxe) mais quand l’erreur vient d’un plugin c’est plutôt limité.

Pour un affichage un peu plus détaillé avec une trace d’exécution permettant de déterminer quelle ligne de quel plugin est en cause, il faut utiliser l’option --trace ou -t.

bundle exec jekyll serve --drafts -t

Fichiers sitemap.xml et robots.txt

Il existe un plugin pour générer le fichier sitemap.xml, par contre je n’ai rien trouvé pour gérer son intégration au fichier robots.txt. On peut certes faire un fichier robots.txt à la main mais le lien est censé être absolu, donc ce n’est pas super propre de le mettre en dur.

Finalement je m’en suis sorti en ajoutant un fichier robots.html avec le contenu suivant :

---
layout: null
permalink: robots.txt
---

Sitemap: {{ site.url }}/sitemap.xml

La directive permalink: robots.txt permet de forcer le bon nom de fichier, layout: null dit que le contenu ne doit pas du tout être habillé et comme on est dans une page normale on a accès aux variables globales, notamment site.url.

Éviter la profusion d’espaces dans les pages

Le moteur de template de Jekyll fonctionne en ajoutant des pseudo balises dans le code HTML notamment pour indiquer les structures de contrôles, boucles, affectations de variables, etc.

Pour que le code reste lisible on fait des retours à la ligne entre ces différentes balises et on indente. Ceci aboutit à de très nombreuses lignes uniquement peuplées d’espaces (ceux de l’indentation).

Exemple :

<h2>Catégories</h2>
{% assign groupedCategories = site.categories | group_categories %}
{% for group in groupedCategories %}
  <h3>{{ group[0] }}</h3>
  <ul>
    {% assign categories = group[1] | sort_by_keys %}
    {% for category in categories %}
      <li><a href="/categories/{{ category[0]|slugify:'latin' }}/">{{ category[0] }}</a> ({{ category[1].size }})</li>
    {% endfor %}
  </ul>
{% endfor %}

Il est possible d’y remédier en utilisant un caractère - dans les balises. Chaque - suivant une ouverture de balise ({% devient {%-) indique que les espaces précédents doivent être ignorés et sur les fermetures ( (%} devient -%})) que les espaces suivants doivent être ignorés.

L’exemple précédent devient alors :

<h2>Catégories</h2>
{%- assign groupedCategories = site.categories | group_categories -%}
{% for group in groupedCategories %}
  <h3>{{ group[0] }}</h3>
  <ul>
    {%- assign categories = group[1] | sort_by_keys -%}
    {% for category in categories %}
      <li><a href="/categories/{{ category[0]|slugify:'latin' }}/">{{ category[0] }}</a> ({{ category[1].size }})</li>
    {%- endfor %}
  </ul>
{% endfor %}

C’est la même syntaxe que l’on retrouve dans d’autres moteurs de templates comme Twig pour PHP (la plupart des syntaxes sont assez proches en fait entre ces deux moteurs).

Remarque : cette syntaxe semble ne pas bien fonctionner avec le tag endraw, en effet j’ai des erreurs dès que je place un tiret un en début de ce tag (alors qu’à la fin et sur le tag raw ça marche)…