grimboite/index.json

1126 lines
409 KiB
JSON

{
"articles": [
{
"category": "au-coin-du-feu",
"content": "Borderlands\n===========\n\nBorderlands, c'est un peu le mi-chemin entre Diablo, Fallout, saupoudr\u00e9 d'un zeste de XIII, avec une pinc\u00e9e de Crysis et un soup\u00e7on de Portal. Un peu le cas typique d'un western post-apocalyptique. On ne se prend pas la t\u00eate, on fonce dans le tas, tout en enchainant les missions et en esquivant les ennemis un peu trop forts pour notre niveau actuel. \u00c7a, c'est pour le cot\u00e9 Diablo. On dirige le perso dans un monde compl\u00e8tement d\u00e9vast\u00e9, en faisant deux trois missions \u00e0 droite \u00e0 gauche avant de se farcir le gros monstre qui nous fait regretter de ne pas avoir tra\u00een\u00e9 entre deux qu\u00eates pour passer un niveau ou pour choper une arme un peu plus bal\u00e8ze. Vous l'aurez compris, on se trouve dans un gros hack and slash primaire pour d\u00e9zinguer de la grosse bestiole et devenir plus puissant.\n\nPrimaire ?\n\nBah oui. Primaire. On s'en sort avec tout au plus une dizaine de touches du clavier (souris comprise) et pour peu qu'on ait un peu l'habitude de se d\u00e9placer dans un environnement 3D, le jeu ne devrait pas poser trop de probl\u00e8mes. Pour la strat\u00e9gie, il faudra repasser. Les personnages, au nombre de quatre, proposent chacun un arbre de comp\u00e9tences particulier qui nous donne une \u00e9volution un chouia diff\u00e9rente suivant la progression choisie. Ceci dit, ne vous y trompez pas, ce ne sont pas les comp\u00e9tences qui guideront votre avanc\u00e9e mais les gros guns que vous d\u00e9nicherez sur les cadavres encore fumants de vos ennemis. Et oui, Borderlands, c'est crad'. Sachez que chaque ennemi a un point faible, et qu'exploiter ce point faible le m\u00e8nera beaucoup plus rapidement vers une mort atroce (pour les fans de Fallout 2, prenez la comp\u00e9tence \u00ab Brute \u00bb et savourez le r\u00e9sultat). C'est gore, violent, chaotique, mais suffisamment \"frais\" que pour ne pas choquer tout le monde: les graphismes \u00e9tant en cell shading, cela donne un cot\u00e9 cartoon au jeu, qui nous ram\u00e8ne du coup dans une autre dimension (\"la dimension o\u00f9 qu'on peut tout faire sans que \u00e7a ne tue de vrais personnes\"). On est loin d'un Call Of Duty 6, suffisamment bien script\u00e9 que pour avoir \u00e0 faire avec une vraie immersion. Ici, tout est permis, et d'ailleurs, tout le monde est mauvais (et ne manquera pas de vous le faire remarquer), \u00e0 part les ClapTraps, ce qui facilitera un peu les liaisons d'amiti\u00e9 : si \u00e7a bouge, c'est qu'on peut le tuer.\n\nAu niveau du jeu donc, on a \u00e9videmment une trame sc\u00e9naristique \u00e0 suivre, entrecoup\u00e9e de gros monstres bien bal\u00e8zes et pr\u00e9sent\u00e9s dignement, selon les pr\u00e9ceptes Tarentinien, ponctu\u00e9s d'un humour \u00e0 vif de circonstance. La progression du joueur est au final assez lin\u00e9aire. Seul l'attrait pour de nouveaux \u00e9quipements vous poussera \u00e0 continuer. Certaines zones valent \u00e9galement le d\u00e9tour, soit pour la diversit\u00e9 de ses gros monstres, soit pour la topologie des lieux qui vous permettra des heures (bon allez : des quarts d'heure) de jouissance en sniper, gr\u00e2ce au nouveau flingue x3 en dommage corrosifs que vous venez d'acqu\u00e9rir. Ouaip, au final, il n'y a que tr\u00e8s peu de zones \u00ab cloisonn\u00e9es \u00bb et vous pourrez vous y donner \u00e0 c\u0153ur joie pendant des heures. Seul b\u00e9mol : l'IA des ennemis n'est pas terrible : ils auront souvent tendance \u00e0 se diriger simplement vers vous, la hache \u00e0 la main et la bave \u00e0 la bouche. Autant pour certains, c'est compr\u00e9hensible (QI de 15 au niveau le plus \u00e9lev\u00e9, ok, c'est tol\u00e9rable). D'autres par contre resteront \u00e0 distance \u00e0 tenter le sniper au lance-roquettes. Niveau strat\u00e9gie, y'a mieux.\n\nAu niveau des qu\u00eates, certains passages sont parfois un peu creux : on passe beaucoup de temps \u00e0 faire quelques allers-retours entre plusieurs zones, or, si \u00e0 l'arriv\u00e9e dans une zone, cela peut repr\u00e9senter un certain challenge (nouveaux ennemis, nouvelles tactiques, nouveaux lieux, nouvelles armes, nouveaux bidules, barrez les trucs inutiles), apr\u00e8s 3 passages, les ennemis ne pr\u00e9sentent finalement plus d'int\u00e9r\u00eats et quelques clics de souris suffiront \u00e0 s'en d\u00e9barrasser. Heureusement les gros m\u00e9chants sont l\u00e0 pour soutenir un peu le rythme qui s'en prend quand m\u00eame plein la gueule \u00e0 un moment du jeu (aux alentours du niveau 25 ' 26, quand on d\u00e9barque tant qu'on n'a pas pass\u00e9 le canyon de Krom). De plus, les ennemis sont finalement assez peu vari\u00e9s : le point faible n'est donc jamais un gros probl\u00e8me, puisqu'il est toujours identique pour les ennemis de m\u00eame \u00ab race \u00bb (la gueule pour les skags, la t\u00eate pour les humains, le dard pour les araign\u00e9es, '). M'en fous de donner la solution, puisqu'au final, \u00e7a sera votre habilit\u00e9 \u00e0 manier la souris et les diff\u00e9rentes armes qui vous permettront de cibler ces points faibles.\n\nToujours au niveau des armes, on se retrouve un peu dans l'univers de Fallout (les deux premiers hein, pas le semi-Oblivion-marketing que f\u00fbt le troisi\u00e8me) : les terrains sont parsem\u00e9s de pubs en tout genre, simulant une certaine \u00ab \u00e2me \u00bb \u00e0 chacun des objets trouv\u00e9s (oui, \u00e7a devient assez mystique l\u00e0. D\u00e9sol\u00e9). Toujours pour le rapprocher de Fallout, le monde qu'on explorera est gore, bourr\u00e9 de grosses bestioles pas accueillantes qui ne voudront qu'une chose : vous bouffer. Oh joie cependant, chaque bestiole rapportera sont lot de loot, allant du \u00ab cadeau \u00bb commun \u00e0 l'\u00e9quipement super rare de la mort qui tue en un coup (et qui vous rapportera des mille et des cents une fois revendus). L'argent d'ailleurs, il sert \u00e0 quoi ? Tout d'abord \u00e0 vous refaire une beaut\u00e9 en munitions (bah oui, les armes consomment des munitions, et une fois \u00e0 court, il vous faudra combattre au corps \u00e0 corps, ou prendre vos jambes \u00e0 votre cou :) ), mais \u00e9galement \u00e0 ressusciter.\n\nBref Borderlands, c'est un peu mon coup de coeur actuel. Ceci pour plusieurs raisons : d'abord le cot\u00e9 bourrin. On allume le jeu, on fait une mission, on \u00e9teint l'ordi. 30 minutes et vous aurez compl\u00e8tement d\u00e9compress\u00e9. Ensuite les graphismes qui permettent de s'\u00e9clater (et d'\u00e9clater) sans vraiment mettre mal \u00e0 l'aise. Avec un peu d'entrainement, m\u00eame les ennemis les plus coriaces n'auront plus l'air de grosses brutes mais de simples obstacles (donc non, ce n'est pas parce qu'un gros malabar vous fonce dessus avec une gatling qu'il faut forc\u00e9ment vider son chargeur dessus : on esquive un peu, on trouve le point faible, on vise la t\u00eate, on encaisse les points d'exp\u00e9rience et ramasse la thune. The end.) Pas besoin d'y passer n\u00e9cessairement un mois complet pour devenir une grosse b\u00eate et s'amuser. On peut toujours trouver des ennemis \u00e0 son niveau et qui offrent un challenge suffisamment p\u00eachu que pour ne pas trop se prendre la t\u00eate. Alors bien s\u00fbr, il y a quelques points qui blessent : la r\u00e9p\u00e9titivit\u00e9 de certaines missions, le fait que les ennemis soient tous si semblables, ou le manque de fun et d'action de certaines sc\u00e8nes risquent de faire d\u00e9crocher le joueur un peu pr\u00e9matur\u00e9ment. De l'autre cot\u00e9, on a des modes de jeu comme la coop\u00e9ration qui promettent de s'amuser \u00e0 plusieurs.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2010-11-22",
"title": "Borderlands"
},
{
"category": "au-coin-du-feu",
"content": "Bro on the Go\n=============\n\nPeu de temps apr\u00e8s m'\u00eatre procur\u00e9 le [Bro Code](https://www.amazon.com/Bro-Code-Barney-Stinson/dp/143911000X?SubscriptionId=AKIAILSHYYTFIVPWUY6Q), je me suis offert le [Bro on the Go](https://www.amazon.com/Bro-Go-Barney-Stinson/dp/1439173133).\n\nD'abord, le format du livre est petit, inhabituel et ne rendra pas sp\u00e9cialement bien dans une biblioth\u00e8que :-p Ensuite au niveau du contenu, il est un gros cran en dessous du Bro Code. Ok, il ne coute *que* 6\u20ac et pourra constituer un petit cadeau sympa, mais je ne le recommanderais pas pour les raisons suivantes : le Bro on the Go ne contient qu'une phrase par page, certaines \u00e9tant directement reprise du Bro Code, d'autres n'\u00e9tant pas sp\u00e9cialement int\u00e9ressantes. M\u00eame l'introduction donne un petit sentiment de \"pas assez\".\n\nPr\u00e9f\u00e9rez-lui le Bro Code, beaucoup plus complet, plus amusant et bourr\u00e9 de petits hints, d'exceptions et de sch\u00e9mas qui en font un bouquin vraiment agr\u00e9able \u00e0 lire. Si vous avez d\u00e9j\u00e0 le Bro Code, celui-ci n'en vaut pas vraiment la peine. Et si vous n'en avez aucun, prenez le Bro Code, il suffira \u00e0 lui tout seul !",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2011-01-27",
"title": "Bro on the Go"
},
{
"category": "au-coin-du-feu",
"content": "World War Z\n===========\n\nLe pitch est simple: l'apocalypse, des zombies, plein de morts qui cherchent \u00e0 faire leur casse-croute des vivants. Un lundi sous la pluie, quoi. Ce qui est sympa, c'est que le livre ne se fixe pas sur un petit groupe de survivants qui vont tous crever dans d'atroces souffrances les uns apr\u00e8s les autres, mais se pr\u00e9sente comme un recueil de petites interviews entre \"le h\u00e9ros\", un journaliste qui travaille pour l'ONU (ou plut\u00f4t ce qu'il en reste...) et diff\u00e9rents survivants. Chaque personnage y va de sa petite anecdote sur les \u00e9v\u00e8nements qui se sont d\u00e9roul\u00e9s, et c'est au travers de leurs yeux que l'on d\u00e9couvre les faits. On a ainsi un point de vue \"avant-apr\u00e8s\" pour plusieurs endroits de par le monde, en France, au Chili, en Chine, en Inde, ...\n\nL'auteur commence \u00e9videmment par l'apparition des premiers sympt\u00f4mes, puis encha\u00eene sur la mani\u00e8re dont le virus s'est rapidement r\u00e9pandu, suivie de \"La Grande Panique\", la guerre proprement (ahah...) dite, et finalement la fin des hostilit\u00e9s. Tout cela est vu par certains personnages cl\u00e9s, qui auront chacun eu leurs propres jugements et leurs propres exp\u00e9riences \u00e0 ces diff\u00e9rents moments. Il ne s'agit donc pas d'un livre d'horreur bourr\u00e9 de suspens et de descriptions horribles, mais plut\u00f4t d'un assemblage de t\u00e9moignages qui tendent \u00e0 rendre le r\u00e9cit plus r\u00e9el.\n\nCertaines personnes pourraient \u00eatre d\u00e9\u00e7ues que l'histoire ne rentre pas suffisamment dans les d\u00e9tails, et qu'aucune piste ne soit donn\u00e9e sur l'origine du mal. De ce c\u00f4t\u00e9-l\u00e0, il va falloir accepter pas mal de choses sans vouloir \u00e0 tout prix comprendre comment et pourquoi... Comme dans la plupart des histoires du genre, hein, sans vouloir faire la fine bouche.\n\nAu niveau des points forts: chaque histoire trouve ses racines dans un monde qui nous est familier, que l'on parcourt au quotidien et qui n'a pas besoin de faire appel \u00e0 notre imagination. Bien que chaque r\u00e9cit ne se concentre pas exclusivement sur les morts-vivants, on sent quand m\u00eame que ceux-ci ne sont jamais tr\u00e8s loin: l'homme a (enfin) un pr\u00e9dateur (autre que lui-m\u00eame), ce qui am\u00e8ne un comportement compl\u00e8tement d\u00e9sorganis\u00e9, des regroupements, une mise-en-place de plans de survie (qui impliquent g\u00e9n\u00e9ralement la mort d'un plus grand nombre pour sauver quelques privil\u00e9gi\u00e9s), ... un beau bordel, en somme.\n\nCe dernier point donne droit \u00e0 quelques sc\u00e8nes exceptionnelles, tant la mise en sc\u00e8ne est cr\u00e9dible et vicieuse. L'auteur d\u00e9peint r\u00e9ellement l'arrogance de l'humanit\u00e9 par rapport \u00e0 ce qu'elle ne connait pas, enfonce les m\u00e9dias pour leur recherche de la une et met en avant le path\u00e9tisme des d\u00e9cisions des personnes \"importantes\". Il va m\u00eame plus loin, puisqu'il \u00e9tale un contexte g\u00e9opolitique et imagine l'\u00e9volution et le d\u00e9clin de certaines grandes puissances. Je ne pense pas qu'un autre livre aille aussi loin dans la description du \"apr\u00e8s\": on nous bassine g\u00e9n\u00e9ralement avec le pr\u00e9sent, les monstres qui veulent se taper du burger d'humain et ces derniers qui ont souvent la bonne id\u00e9e de \"se s\u00e9parer en groupes de tout seul, pour avoir plus de chances de s'en sortir!\". Bref les explications sont cr\u00e9dibles et mettent dans l'ambiance. L'imagination fait le reste. C'est un peu \u00e7a qui fait aussi la force de ce roman: les grandes lignes de l'histoire sont trac\u00e9es, \u00e9crites, et les r\u00e9cits de quelques pages raccrochent tous ces \u00e9l\u00e9ments les uns aux autres. Du grand micro-art :)\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2011-11-24",
"title": "World War Z"
},
{
"category": "au-coin-du-feu",
"content": "Bounty Killer\n=============\n\nJ'ai h\u00e9sit\u00e9 entre 3 et 8/10. D'un c\u00f4t\u00e9, c'est compl\u00e8tement kitsch, \u00e7a p\u00e8te de partout, c'est ultra-gore et l'histoire est totalement naze.\n\nPuis de l'autre, on appr\u00e9cie quand m\u00eame un peu la mise en sc\u00e8ne, les d\u00e9cors, les personnages haut-en-couleurs (surtout en rouge, d'ailleurs), les r\u00e9pliques pourries, le peu de temps morts (contrairement aux ennemis*...) et le fait d'\u00eatre transport\u00e9 dans un monde entre Fallout et Mad Max.\n\nDonc 8/10 (principalement parce que Fallout, Wasteland, tout \u00e7a...). Il ne dure qu'1h30, c'est con, mais finalement pas si mal. :)\n\nHint: les ennemis, ce sont ceux en costard.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2014-04-19",
"title": "Bounty Killer"
},
{
"category": "au-coin-du-feu",
"content": "Divinity Original Sin\n=====================\n\nJ'ai toujours ador\u00e9 les jeux de r\u00f4les: prendre un perso niveau b\u00e9b\u00e9 et le faire progresser petit \u00e0 petit, trouver de l'\u00e9quipement de plus en plus puissant, trucider des ennemis de plus en plus gros, constituer une \u00e9quipe de plus en plus forte, ... Un brin m\u00e9galo, mais c'est \u00e7a qui me pla\u00eet :-) Les univers sont vari\u00e9s, les histoires profondes, et le temps \u00e0 y consacrer g\u00e9n\u00e9ralement en relation avec ces deux \u00e9l\u00e9ments.\n\nDivinity Original Sin ajoute quelques bonnes id\u00e9es aux t\u00e9nors du genre. On commence d'abord par se cr\u00e9er deux personnages; cela permet d\u00e9j\u00e0 de se constituer une petite \u00e9quipe \u00e9quilibr\u00e9e plut\u00f4t que d'essayer de se monter un mage guerrier qui ira battre la campagne avec son armure de plates et son b\u00e2ton de sorcier. Ici, on aura plut\u00f4t tendance \u00e0 se cr\u00e9er deux profils compl\u00e9mentaires, ce qui constituera un premier pas vers la sp\u00e9cialisation.\n\nEnsuite, le d\u00e9cor doit vraiment \u00eatre observ\u00e9 afin de tirer un avantage durant les combats: ma premi\u00e8re rencontre avec un troupeau (ok, ils \u00e9taient deux ou trois) de trolls, juste avant de rentrer dans la vile s'est sold\u00e9e par un presque-KO de mon \u00e9quipe. En retentant la m\u00eame manoeuvre, mais en observant un peu mieux l'environnement, j'ai constat\u00e9 qu'il y a une petite flaque d'huile au sol. Plut\u00f4t que d'y aller au galop en brandissant un paquet d'agraffes, j'ai envoy\u00e9 ma magicienne se faufiler furtivement au plus pr\u00e8s du combat, afin de lancer une boule de feu bien plac\u00e9e qui a laiss\u00e9 les deux monstres tel Jeanne d'Arc[1]. Les deux approches sont possibles, mais la seconde aura sans doute la faveur des joueurs \u00e9conomes en potions de soins.\n\nL'autre facette du jeu fait parfois place \u00e0 des dialogues entre vos deux personnages: au moment de leur cr\u00e9ation, il est possible de soit les g\u00e9rer vous-meme, soit de laisser l'IA s'en occuper. Laissez-moi vous raconter...\n\nDans la ville, je d\u00e9couvre un endroit o\u00f9 de la terre semble avoir \u00e9t\u00e9 r\u00e9cemment retourn\u00e9e. Curieux par nature (j'avoue, j'esp\u00e9rais y trouver un nouveau parchemin), je lance l'excavation. L'autre personnage intervient, et me demande si je suis s\u00fbr de ce que je fais... En y repensant \u00e0 deux fois, je me dis que non, et que je reviendrai plus tard. Mon autre perso (dirig\u00e9 par l'IA pour cette premi\u00e8re partie) continue son introspection, et tente de me persuader que ce serait finalement une bonne id\u00e9e.\nEn cas de conflit, le tout se joue un peu aux d\u00e9s. Manque de bol, il a gagn\u00e9, la tombe \u00e9tait pi\u00e9g\u00e9e, mon groupe a \u00e9t\u00e9 d\u00e9membr\u00e9 enti\u00e8rement, et j'ai pu recharger ma pr\u00e9c\u00e9dente partie.\n\nL'id\u00e9e est donc g\u00e9niale et permet de d\u00e9velopper une vraie personnalis\u00e9 pour vos personnages... Mais faites un effort et ne laissez pas l'IA, cette grosse garce, s'en occuper!\n\n[1] - Jeanne, qui s'est d'ailleurs \u00e9teinte deux heures apr\u00e8s sa mort.\n\n[Update de 2015]: La version `enhanced` de Divinity a \u00e9t\u00e9 rendue disponible. Elle apporte plein de petites am\u00e9liorations, et est gratuite pour tout possesseur du jeu original :)",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2014-08-02",
"title": "Divinity Original Sin"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Good Old Games\nDate: 2014-08-28\nSlug: good-old-games\n---\n\nSuite au test de Divinity: Original Sin dans le Canard PC de mi-juillet, r\u00e9sum\u00e9 par un simple \"9/10: Achetez ce jeu\", je me suis mis en qu\u00eate de la version id\u00e9ale, celle qui permet de grapiller quelques pi\u00e9cettes, qui offre quelques petits bonus.\n\nLe jeu est \u00e9videmment disponible **via** Steam. Avec un peu de recherche, on peut souvent trouver le m\u00eame contenu sur d'autres plateformes. C'est g\u00e9n\u00e9ralement le cas d'amazon.co.uk, qui propose les versions bo\u00eetes pour (souvent) moins cher que la version Steam. Ne trouvant rien (en stock) aux Royaumes-Unis, j'ai regard\u00e9 en France: [une version bo\u00eete pour 39,90\u20ac](http://www.amazon.fr/Focus-Divinity-Original-Sin/dp/B008AF1XLW/ref=sr_1_1?ie=UTF8&qid=1407157174&sr=8-1&keywords=divinity+original+sin)! Les frais de port sont offerts, le jeu est en stock, ... En m\u00eame temps, si c'est pour conserver une boite et ne rien faire d'autre que l'exposer, cela ne m'int\u00e9resse pas.\n\nDe fil en aiguille, je suis (re)tomber sur goodoldgames.com, qui propose quelques jeux r\u00e9cents au prix officiel. Divinity: Original Sin est disponible \u00e0 39.90\u20ac, avec une petite note expliquant ceci:\n\n> Gamers who are paying in EUR and GBP are generally charged more for the games that they buy than gamers in the US - this is called regional pricing. We will adamantly continue to fight for games with flat worldwide pricing, but if we cannot deliver it (as is the case with this game), we will make up most of the difference out of our own pocket by providing you with a mix of $9.99 and $5.99 game codes, which you can use to redeem games from our site. In the near future, once we have such functionality implemented, we will give you store credit instead, which you will then be able to use towards any purchase and cover the price of it in full, or partially. **If you paid 36.99 EUR, you will get one $9.99 code. If you paid 39.99 EUR, you will get one $5.99 and one $9.99 code. If you paid 29.99 GBP, you will get two $5.99 codes. As for the DLC, if you paid in EUR or GBP, you will get one $5.99 code from us**.\n\nEn gros, en payant un jeu \u00e0 39.90\u20ac, on re\u00e7oit \u00e9galement un bon d'achat un achat d'une valeur de $5.99, ainsi qu'un deuxi\u00e8me bon d'une valeur de $9.99. Apr\u00e8s le traditionnel passage \u00e0 la caisse, je me rends compte \u00e9galement que la cl\u00e9 Steam n'est pas inclue dans l'achat. Etonnant, puisque c'est une pratique courante que d'acheter un jeu sur une plateforme, et de recevoir simplement une cl\u00e9 pour le t\u00e9l\u00e9charger *via* Steam.\n\nCommen\u00e7ons par les d\u00e9savantages:\n\n * On ne profite pas de la mise-\u00e0-jour automatique du contenu\n * Ni de la plateforme de communication int\u00e9gr\u00e9e \u00e0 Steam (celle qui fait que votre petit cousin vous fait \"kikoo\" pendant que vous l\u00e2chez la tourelle sur une arm\u00e9e de robots dans BD2).\n * Ni des sauvegardes automatiques (s'il y en a); celles qui vous disent que votre contenu n'est pas synchronis\u00e9 avec le **cloud**, et qu'au final, vous venez de perdre les deux derni\u00e8res heures de jeu.\n\nEt parmi les avantages:\n\n * Pur\u00e9e mais c'est sans DRM! Ca existe encore, \u00e7a?!\n * La plateforme de t\u00e9l\u00e9chargement de GoG permet de choper toutes les parties du jeu sans avoir \u00e0 cliquer sur chacune d'entre elles.\n * C'est sans DRM. Je l'avais d\u00e9j\u00e0 dit?\n\nEn furetant un peu, on peut aussi d\u00e9couvrir quelques jeux qui en valent r\u00e9ellement la peine :\n\n * [Botanicula](http://www.gog.com/game/botanicula)\n * [Tetrobot](https://www.gog.com/game/tetrobot_and_co)\n * [Fallout 2](https://www.gog.com/game/fallout_2)\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2014-08-28",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "Good Old Games\n==============\n\nSuite au test de Divinity: Original Sin dans le Canard PC de mi-juillet, r\u00e9sum\u00e9 par un simple \"9/10: Achetez ce jeu\", je me suis mis en qu\u00eate de la version id\u00e9ale, celle qui permet de grapiller quelques pi\u00e9cettes, qui offre quelques petits bonus.\n\nLe jeu est \u00e9videmment disponible **via** Steam. Avec un peu de recherche, on peut souvent trouver le m\u00eame contenu sur d'autres plateformes. C'est g\u00e9n\u00e9ralement le cas d'amazon.co.uk, qui propose les versions bo\u00eetes pour (souvent) moins cher que la version Steam. Ne trouvant rien (en stock) aux Royaumes-Unis, j'ai regard\u00e9 en France: [une version bo\u00eete pour 39,90\u20ac](http://www.amazon.fr/Focus-Divinity-Original-Sin/dp/B008AF1XLW/ref=sr_1_1?ie=UTF8&qid=1407157174&sr=8-1&keywords=divinity+original+sin)! Les frais de port sont offerts, le jeu est en stock, ... En m\u00eame temps, si c'est pour conserver une boite et ne rien faire d'autre que l'exposer, cela ne m'int\u00e9resse pas.\n\nDe fil en aiguille, je suis (re)tomber sur goodoldgames.com, qui propose quelques jeux r\u00e9cents au prix officiel. Divinity: Original Sin est disponible \u00e0 39.90\u20ac, avec une petite note expliquant ceci:\n\n> Gamers who are paying in EUR and GBP are generally charged more for the games that they buy than gamers in the US - this is called regional pricing. We will adamantly continue to fight for games with flat worldwide pricing, but if we cannot deliver it (as is the case with this game), we will make up most of the difference out of our own pocket by providing you with a mix of $9.99 and $5.99 game codes, which you can use to redeem games from our site. In the near future, once we have such functionality implemented, we will give you store credit instead, which you will then be able to use towards any purchase and cover the price of it in full, or partially. **If you paid 36.99 EUR, you will get one $9.99 code. If you paid 39.99 EUR, you will get one $5.99 and one $9.99 code. If you paid 29.99 GBP, you will get two $5.99 codes. As for the DLC, if you paid in EUR or GBP, you will get one $5.99 code from us**.\n\nEn gros, en payant un jeu \u00e0 39.90\u20ac, on re\u00e7oit \u00e9galement un bon d'achat un achat d'une valeur de $5.99, ainsi qu'un deuxi\u00e8me bon d'une valeur de $9.99. Apr\u00e8s le traditionnel passage \u00e0 la caisse, je me rends compte \u00e9galement que la cl\u00e9 Steam n'est pas inclue dans l'achat. Etonnant, puisque c'est une pratique courante que d'acheter un jeu sur une plateforme, et de recevoir simplement une cl\u00e9 pour le t\u00e9l\u00e9charger *via* Steam.\n\nCommen\u00e7ons par les d\u00e9savantages:\n\n* On ne profite pas de la mise-\u00e0-jour automatique du contenu\n* Ni de la plateforme de communication int\u00e9gr\u00e9e \u00e0 Steam (celle qui fait que votre petit cousin vous fait \"kikoo\" pendant que vous l\u00e2chez la tourelle sur une arm\u00e9e de robots dans BD2).\n* Ni des sauvegardes automatiques (s'il y en a); celles qui vous disent que votre contenu n'est pas synchronis\u00e9 avec le **cloud**, et qu'au final, vous venez de perdre les deux derni\u00e8res heures de jeu.\n\nEt parmi les avantages:\n\n* Pur\u00e9e mais c'est sans DRM! Ca existe encore, \u00e7a?!\n* La plateforme de t\u00e9l\u00e9chargement de GoG permet de choper toutes les parties du jeu sans avoir \u00e0 cliquer sur chacune d'entre elles.\n* C'est sans DRM. Je l'avais d\u00e9j\u00e0 dit?\n\nEn furetant un peu, on peut aussi d\u00e9couvrir quelques jeux qui en valent r\u00e9ellement la peine :\n\n* [Botanicula](http://www.gog.com/game/botanicula)\n* [Tetrobot](https://www.gog.com/game/tetrobot_and_co)\n* [Fallout 2](https://www.gog.com/game/fallout_2)",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2014-08-28",
"title": "Good Old Games"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: \"La v\u00e9rite sur l'affaire Harry Quebert\"\nDate: 2014-09-04\nWriter: \"Jo\u00ebl Dicker\"\nImage: book/joel_dicker/harry-quebert-cover.jpg\nSlug: the-truth-about-harry-quebert\n---\n\nPour \u00eatre honn\u00eate, la couverture n'inspirait absolument pas confiance. Cela sentait les vacances, avec des couleurs pastels, un petit village champ\u00eatre, son \u00e9glise, un joli ciel bleu... Tout pour faire penser \u00e0 une belle histoire d'amour copi\u00e9e du dernier Marc Levy. En plus de cela, les 860 pages de mon \u00e9dition de poche laissaient franchement penser que je le l\u00e2cherais avant m\u00eame la fin de la premi\u00e8re partie.\n\nPerdu.\n\nPass\u00e9 les deux premiers chapitres, tout se met en place et s'acc\u00e9l\u00e8re. De nouveaux \u00e9v\u00e8nements interviennent apr\u00e8s chaque vague \u00e9motionnelle, on est immerg\u00e9 de plein gr\u00e9 dans une histoire qui nous d\u00e9passe, o\u00f9 chaque d\u00e9tail \u00e0 son importance et o\u00f9 l'auteur semble prendre un malin plaisir \u00e0 embrouiller volontairement gr\u00e2ce \u00e0 une mise en ab\u00eeme temporelle savament orchestr\u00e9e.\n\nOn s'accroche, on s'identifie aux personnages. Chacun d'entre eux cache quelque chose. On le sait, on le sent, mais on n'arrive pas r\u00e9ellement \u00e0 mettre la main sur ce qui cloche. On sait que cela va d\u00e9raper, sans jamais r\u00e9ellement mettre le pourquoi. Ou alors pour mieux glisser quelques pages plus loin.\n\nChaque d\u00e9tail va mettre la puce \u00e0 l'oreille; on se met m\u00e9fie de tout le monde, sans r\u00e9ellement y croire vu la quantit\u00e9 de pages restantes. Celle-ci se r\u00e9duit de plus en plus, jusqu'au d\u00e9nouement final, celui qu'on attendait, qu'on soup\u00e7onnait peut-\u00eatre, mais qui s'avera finalement lib\u00e9rateur tant les d\u00e9nouements, changements de rhytme et rebondissements sont fr\u00e9quents. C'est une \u00f4de \u00e0 l'amour, au fonctionnement des instincts humains primaires. On passe de la r\u00e9pulsion \u00e0 la compr\u00e9hension en quelques pages seulement: l'auteur intrpsecte. On s'attache et se d\u00e9tache des personnages comme on tourne les pages: les nouveaux \u00e9v\u00e8nements apportent de la fra\u00eecheur, des r\u00e9ponses et de nouvelles interrogations. Apr\u00e8s l'avoir lu, on a un peu l'impression que chaque page, dialogue ou introduction y a sa place, que chaque information ou discussion aura une suite et on fait attention \u00e0 chaque miette que l'auteur aura la bont\u00e9 de laisser derri\u00e8re lui et qu'il aura dispers\u00e9 parmi toutes ces phrases et paragraphes. On se prend finalement au jeu du roman, en esp\u00e9rant en avoir encore un peu par apr\u00e8s, en esp\u00e9rant que la prochaine page ne contiendra pas l'un de ces clich\u00e9s ou facilit\u00e9s autoris\u00e9es par l'\u00e9criture.\n\nD'habitude, une histoire se subit: on se laisse porter par le flot des dialogues, \u00e0 attendre qu'un \u00e9v\u00e8nement se passe. Ici, on se surprend \u00e0 inventer et imaginer la suite, \u00e0 porter des soup\u00e7ons, \u00e0 esp\u00e9rer qu'un \u00e9v\u00e8nement se produise. C'est l\u00e0 aussi tout le d\u00e9sespoir ce roman, c'est qu'il se passe simultan\u00e9ment dans le pass\u00e9 et dans le pr\u00e9sent. Le pr\u00e9sent fait place \u00e0 un r\u00e9el suspens. Ce qui arrive actuellement, la pression mise par certains personnages, la rancune tranmise par d'autres sont r\u00e9ellement ressenties, mais laissent place \u00e0 d'autres sentiments une fois \u00e9vapor\u00e9es. Le pass\u00e9 est pass\u00e9, on en connait la fin d\u00e8s les premi\u00e8res pages, mais on se prend quand m\u00eame \u00e0 esp\u00e9rer qu'il soit faux ou partiellement incorrect, que des indices laissent \u00e0 penser que... peut-\u00eatre qu'on se trompe? Peut-\u00eatre que tout \u00e7a ne s'est jamais pass\u00e9? Peut-\u00eatre que l'auteur r\u00eave tout ce qui lui arrive, que tout cela n'est jamais arriv\u00e9, et que la r\u00e9alit\u00e9 n'est pas celle qu'on lit?\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2014-09-04",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Door Kickers\nDate: 2014-12-17\nSlug: door-kickers\n---\n\nDes bons jeux, il y en a de moins en moins. Entre les suites et redites des jeux AAA annuels, et \u00e0 part la Wii U et sa mablette, on a un peu l'impression que les consoles et ordinateurs next-gen s'enfoncent sans se renouveler r\u00e9ellement.\n\nDoor Kickers fout un bon coup de latte \u00e0 ce principe. Original, il l'est, malgr\u00e9 qu'il se base sur des concepts existants depuis un bon bout de temps maintenant: on dirige une \u00e9quipe de SWAT sur-entra\u00een\u00e9e, et on doit zigouiller du terroriste/sauver des otages (voire les deux, si on est bon). On joue en vue du dessus, les lignes de vue sont r\u00e9alistes \u00e0 souhait et prennent bien les obstacles rencontr\u00e9s (vos p'tits gars tirent tous seuls, pour peu que l'ennemi soit dans leur champ de vision). Chaque mission peut \u00eatre r\u00e9alis\u00e9e en prenant son temps, mais des challenges (r\u00e9ussir la mission end\u00e9ans un certain temps, ne pas utiliser la pause strat\u00e9gique, ...) permettent d'acqu\u00e9rir des \u00e9toiles. Ces \u00e9toiles permettent alors d'am\u00e9liorer son \u00e9quipement ou les capacit\u00e9s de son \u00e9quipe.\n\nVoila pour le concept. Chaque mission peut se r\u00e9ussir en quelques minutes, mais vous risquez d'y passer pas mal de temps pour r\u00e9ussir tous les d\u00e9fis. A tout cela, on ajoute un super bon \u00e9diteur de niveaux, des mods \u00e0 d\u00e9velopper (et \u00e0 t\u00e9l\u00e9charger), des statistiques *alakon*, et on obtient un super bon jeu pour pas trop cher (c'est bient\u00f4t les f\u00eates de fin d'ann\u00e9e, non ?).\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2014-12-17",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: True Detective\nDate: 2015-01-13\nSlug: true-detective\n---\n\nLent et psychologique. Je crois que si je devais qualifier cette s\u00e9rie de deux adjectifs, ce seraient ceux-l\u00e0. D\u00e8s le d\u00e9but, on se sent envahis par une ivresse relaxante, mis sous pression et transport\u00e9 par un sc\u00e9nario digne du jeu des acteurs. Woody Harrelson est g\u00e9nial dans son r\u00f4le de p\u00e8re foireux et mari jaloux, dont le boulot de flic prend trop de temps sur la vie de famille. Il est le parfait compl\u00e9ment de Matthew McConaughey, sociopathe, homme bris\u00e9 et",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-01-13",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Le Soleil des Scorta\nDate: 2015-02-09\nWriter: \"Laurent Gaud\u00e9\"\nimage: book/soleil-scorta.jpg\nSlug: le-soleil-des-scorta\n---\n\n> Le Soleil des Scorta est un roman \u00e9crit par Laurent Gaud\u00e9 publi\u00e9 chez Actes Sud le 1er ao\u00fbt 2004 et ayant remport\u00e9 le prix Goncourt la m\u00eame ann\u00e9e, constituant le premier prix prestigieux obtenu par les \u00e9ditions Actes Sud. Ce roman a \u00e9galement re\u00e7u le prix du roman populiste et le prix du jury Jean-Giono en 2004.\n\nSource: [Wikipedia](https://fr.wikipedia.org/wiki/Le_Soleil_des_Scorta)",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-02-09",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: \"Le probl\u00e8me Spinoza\"\nDate: 2015-02-20\nImage: book/le-probleme-spinoza.jpg\nSlug: le-probleme-spinoza\n---\n\nNous sommes en juin, j'ai pris du retard dans mes \u00e9crits. Tant pis. Ce sera de m\u00e9moire, \u00e9pic\u00e9tou ! \n\nDe ce dont je me rappelle, c'est que ce livre donnait deux aper\u00e7us contradictoire sur la religion juive; d'une part, la vision de Spinoza quant aux obligations de la relagion, son exclusion de la communaut\u00e9 et ses \u00e9crits. De l'autre, [...] faisant partie des jeunesses Hitl\u00e9riennes, persuad\u00e9 de son bon droit, de la n\u00e9cessit\u00e9 de se d\u00e9barasser des Juifs. Ses professeurs lui demanderont un travail sur Spinoza, afin de relativiser ses id\u00e9aux face \u00e0 un Juif.\n\n*A priori*, cet article restera en brouillon :)",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-02-20",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: \"Un homme effac\u00e9\"\nDate: 2015-03-06\nSlug: un-homme-efface\n---\n\n> \"Quoiqu'il arrive, il faut vous faire \u00e0 l'id\u00e9e que vous ne ressortirez pas *blanchi* du tribunal. C'est une illusion de croire \u00e7a. On ne ressort pas blanchi d'un proc\u00e8s comme celui-ci. Soit on en ressort sali, soit on n'en ressort pas du tout.\"\n\nJe ne pense pas qu'il soit d\u00e9ontologiquement propice de cataloguer un livre parlant de p\u00e9do-pornographie comme \"touchant\", mais c'est le seul qui me soit venu \u00e0 l'esprit apr\u00e8s avoir tourn\u00e9 sa derni\u00e8re page.\n\nL'auteur y parle d'une m\u00e9prise: d'un professeur, petit-fils de c\u00e9l\u00e9brit\u00e9, qui est accus\u00e9 d'avoir t\u00e9l\u00e9charg\u00e9 un petit millier de photos impliquant b\u00e9b\u00e9s, enfants et d\u00e9gradations sexuelles. Son avocat lui conseille de plaider coupable. D\u00e9j\u00e0 pas terrible \u00e0 la base, sa vie lui \u00e9chappe un peu plus, sans qu'il ne puisse se rattacher \u00e0 quoi que ce soit qu'il connaisse: le moindre de ses actes pass\u00e9s devient un pr\u00e9texte, son entourage lui fait b\u00e9n\u00e9ficier de la pr\u00e9somption de culpabilit\u00e9 et aucun de ses coll\u00e8gues ne l\u00e8ve le petit doigt pour lui tendre la main.\n\nAu final, un bon pastiche sur la une des m\u00e9dia, la froideur d'un syst\u00e8me judiciaire, l'hypocrisie des relations humaines et les profondeurs dans lesquelles l'esprit humain peut parfois sombrer.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-03-06",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: \"Les proies\"\nDate: 2015-05-16\nSummary: \"Un huit-clos durant la guerre de s\u00e9cession.\"\nSlug: les-proies\nImage: book/les-proies.jpg\nWriter: \"Thomas Cullinan\"\n---\n\nUne brique de 600 pages en \"\u00e9crit-tout-petit\" compl\u00e8tement malsaine, o\u00f9 une pensionnaire ram\u00e8ne un soldat bless\u00e9 de l'arm\u00e9e adverse. Les pensionnaires vont se monter les unes sur les autres pour se rapprocher du nouveau venu, qui va tremper dans les discussions sordides et les coups mont\u00e9s foireux.\n\n> Le 6 mai 1864, la for\u00eat de la Wilderness est le th\u00e9\u00e2tre de l'une des plus effroyables batailles de la guerre de S\u00e9cession. L'orage d'acier que d\u00e9cha\u00eene ce jour-l\u00e0 l'artillerie rebelle de Robert Lee, \u00e0 laquelle r\u00e9pond celle du g\u00e9n\u00e9ral de l'Union Ulysses Grant, embrase sans distinction arbres et fantassins. Malgr\u00e9 ses blessures, un caporal nordiste r\u00e9ussit \u00e0 s'\u00e9chapper du brasier et trouve refuge dans un pensionnat pour jeunes filles conf\u00e9d\u00e9r\u00e9. Mais l'intrusion soudaine d'un m\u00e2le vient perturber la vie de recluses, p\u00e9trie de valeurs puritaines et de pulsions refoul\u00e9es, des huit femmes qu'abrite encore l'institution. Objet de tous les fantasmes, le soldat va s'employer \u00e0 les incarner avec un art consomm\u00e9 de la manipulation, jusqu'\u00e0 une nuit o\u00f9 tout bascule. D\u00e8s lors, la haine sera sa seule ma\u00eetresse, la vengeance l'unique motivation de ses anges gardiens.\n\nSource: [20minutes.fr](http://www.20minutes.fr/livres/1151927-20130514-20130508-les-proies-thomas-cullinan-chez-passage-nord-ouest-albi-france).\n\nPour l'anecdote (toujours du m\u00eame site):\n\n> En 1971, saisi par l'originalit\u00e9 de ce roman que les critiques litt\u00e9raires am\u00e9ricains qualifient de psychological sexual novel, Don Siegel le porte \u00e0 l'\u00e9cran, offrant enfin \u00e0 Clint Eastwood un r\u00f4le d'exception aux antipodes de son image habituelle de gunfighter triomphant.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-05-16",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "Little Bird\n===========\n\nJ'ai d\u00e9couvert Craig Johnson un peu au pif. Mon papou qui me sort un petit \"Tiens, cela pourrait te plaire...\" juste avant que je ne mette les voiles avec le schtroumpf. Mes voyages en m\u00e9tro commen\u00e7aient \u00e0 s'allonger, j'avais envie d'une histoire courte, prenante et dynamique. Il faut dire aussi qu'apr\u00e8s avoir lu [Les proies](2015-05-16-les-proies.md) (600 pages de bonne humeur dans un huit clos sanglant), j'avais besoin d'un truc frais, exp\u00e9ditif, dr\u00f4le, ouvert, a\u00e9r\u00e9, avec des grands espaces, des poneys qui courent et un arc-en-ciel. \n\nIl ne pouvait pas mieux tomber.\n\n> Apr\u00e8s vingt-quatre ann\u00e9es au bureau du sh\u00e9rif du comt\u00e9 d'Absaroka, Walt Longmire aspire \u00e0 finir sa carri\u00e8re en paix. Ses espoirs s'envolent quand on d\u00e9couvre le corps de Cody Pritchard pr\u00e8s de la r\u00e9serve cheyenne. Deux ans auparavant, Cody avait \u00e9t\u00e9 un des quatre adolescents condamn\u00e9s avec sursis pour le viol d'une jeune Indienne, un jugement qui avait aviv\u00e9 les tensions entre les deux communaut\u00e9s. Aujourd'hui, il semble que quelqu'un cherche \u00e0 venger la jeune fille. Alors que se pr\u00e9pare un violent blizzard, Walt devra parcourir les vastes \u00e9tendues du Wyoming sur la piste d'un assassin d\u00e9termin\u00e9 \u00e0 parvenir \u00e0 ses fins. Avec ce premier volet des aventures du sh\u00e9rif m\u00e9lancolique et d\u00e9sabus\u00e9, Walt Longmire, Craig Johnson s'impose d'embl\u00e9e parmi les plus grands.\n\nDu grand, du tr\u00e8s bon, de l'indispensable. A lire. Vite.\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-05-30",
"title": "Little Bird"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Le camp des morts\nDate: 2015-06-16\nWriter: Craig Johnson\nIllustration: book/craig_johnson/le-camp-des-morts.jpg\nSlug: craig-johnson-le-camp-des-morts\n---\n\nJe continue mon exploration du far west contemporain avec le sh\u00e9rif Walt Longmire. Apr\u00e8s avoir englouti le premier tome de ses aventures, *Little Bird*, je me suis lanc\u00e9 dans le deuxi\u00e8me tome.\n\n> \"Lorsque Mari Baroja est empoisonn\u00e9e \u00e0 la maison de retraite de Durant, Wyoming, le sh\u00e9rif Walt Longmire se trouve embarqu\u00e9 dans une enqu\u00eate qui le ram\u00e8ne cinquante ans en arri\u00e8re. Il se plonge alors dans le pass\u00e9 myst\u00e9rieux de cette femme et dans celui de son mentor, le sh\u00e9rif Lucian Connally \u00e0 la poigne l\u00e9gendaire. Tandis que l'histoire douloureuse de la victime trouve peu \u00e0 peu une r\u00e9sonance dans le pr\u00e9sent, d'autres meurtres se mettent sur le chemin des deux sh\u00e9rifs. Aid\u00e9 par son ami de toujours, l'Indien Henri Standing Bear, son adjointe au langage fleuri et un nouveau venu s\u00e9duisant, le sh\u00e9rif m\u00e9lancolique et d\u00e9sabus\u00e9 se lance \u00e0 la poursuite de l'assassin \u00e0 travers les Hautes Plaines enneig\u00e9es.\"\n\nMoins prenant que le premier, il n'en reste pas moins excellent dans son histoire, ses blagues vaseuses, sa violence et ses personnages hauts en noirceur. Le caract\u00e8re des personnages d\u00e9j\u00e0 crois\u00e9s y est approfondi et de nouveaux font leur apparition, le tout agr\u00e9ment\u00e9 des r\u00e9fl\u00e9xions du sh\u00e9rif ou de son pote de toujours, Henry Standing Bear. Lucian est un peu plus mis en avant dans cet \u00e9pisode, et devient un \u00e9l\u00e9ment cl\u00e9 pour l'enqu\u00eate.\n\nDu bon, du tr\u00e8s bon (quoiqu'un cran en dessous du premier), bref un *must read*.\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-06-16",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: L'indien blanc\nDate: 2015-06-28\nIllustration: book/craig_johnson/l-indien-blanc.jpg\nWriter: Craig Johnson\nSlug: craig-johnson-l-indien-blanc\n---\n\n> Walt Longmire, le sh\u00e9rif du comt\u00e9 d'Absaroka, n'a pas pour habitude de s'\u00e9loigner de ses terres famili\u00e8res du Wyoming. Quand il d\u00e9cide d'accompagner son vieil ami Henry Standing Bear \u00e0 Philadelphie, o\u00f9 vit sa fille Cady, il ne se doute pas que son s\u00e9jour va prendre une tournure tragique. Agress\u00e9e pour une raison inconnue, Cady se retrouve dans le coma, premi\u00e8re victime d'une longue liste, et Walt doit se lancer sur la piste d'un vaste r\u00e9seau de trafiquants de drogue. Commence alors une longue errance urbaine sous la surveillance d'un myst\u00e9rieux Indien blanc. Ce nouveau volet des aventures de Walt Longmire nous entra\u00eene dans une course-poursuite haletante au coeur de la Cit\u00e9 de l'amour fraternel.\n\nL'indien blanc est la troisi\u00e8me tome des aventures du sh\u00e9rif Longmire. Il reste un cran en dessous du premier (et du quatri\u00e8me!), mais toujours mieux que le deuxi\u00e8me :)\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-06-28",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "GTA V\n=====\n\nJ'ai commenc\u00e9 la s\u00e9rie des *Grand Theft Auto* avec le tout premier, sur PlayStation. A l'\u00e9poque, la description donnait plus envie d'y jouer que le jeu lui-m\u00eame: un monde ouvert et la possibilit\u00e9 de faire tout et n'importe quoi (et surtout n'importe quoi). Le 2 \u00e9tait clairement dans la m\u00eame veine que le premier, mis \u00e0 part quelques effets graphiques et pyrotehcniques suppl\u00e9mentaires. Puis est arriv\u00e9 GTA3, avec ses graphismes qui explosaient tout, la mod\u00e9lisation de la ville, la possibilit\u00e9 de passer ses propres MP3, ... Ensuite, San Andreas, le 4, ... Puis le 5.\n\nAttendant impatiemment (mais sagement) sa sortie sur PC, j'ai finalement craqu\u00e9 il y a quelques jours pour une version boite, afin de ne pas avoir \u00e0 tout t\u00e9l\u00e9charger (65Go, le bouzin). A l'installation, \u00e0 part le fait que les DVD ne fonctionnaient pas et que j'ai quand m\u00eame d\u00fb tout t\u00e9l\u00e9charger, rien \u00e0 signaler. Ma pauvre GTX 460 a directement tir\u00e9 la langue, quand les options pratiquement au minimum ne lui laissaient pratiquement pas de m\u00e9moire vive disponible pour respirer. Un petit changement de carte graphique plus tard, tout allait beaucoup mieux.\n\nAu niveau de l'histoire, c'est tr\u00e8s sympa de pouvoir suivre les 3 personnes en simultan\u00e9; les graphismes en jettent, les missions sont toujours aussi vari\u00e9es (m\u00eame si cela revient souvent \u00e0 rejoindre un point A \u00e0 un point F, on passe g\u00e9n\u00e9ralement par plein de petits retournements qui nous font passer par les points B, C, D et E), la ville vit pendant le jeu (et des petits \u00e9v\u00e8nements al\u00e9atoires attirent parfois notre attention).\n\nDu bon GTA :-) et sans doute un des plus grands bac \u00e0 sable de 2015. Enfin sur PC. Un an et demi apr\u00e8s que tous les consoleux aient pu en profiter, mais cela valait clairement le coup.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-07-05",
"title": "GTA V"
},
{
"category": "au-coin-du-feu",
"content": "Enfants de poussi\u00e8re\n====================\n\n> Absaroka, dans le Wyoming, est le comt\u00e9 le moins peupl\u00e9 de l'\u00c9tat le moins peupl\u00e9 d'Am\u00e9rique, aussi y d\u00e9couvrir le corps d'une jeune Asiatique \u00e9trangl\u00e9e est plus que d\u00e9concertant. Le coupable para\u00eet tout d\u00e9sign\u00e9 quand on trouve, \u00e0 proximit\u00e9 de la victime, un colosse indien frapp\u00e9 de mutisme en possession du sac \u00e0 main de la jeune femme. Mais le sh\u00e9rif Walt Longmire n'est pas du genre \u00e0 boucler son enqu\u00eate \u00e0 la va-vite. D'autant que le sac de la victime contient une vieille photo de Walt prise quarante ans plus t\u00f4t, et qui le renvoie \u00e0 ses souvenirs de la guerre du Vietnam.\n\nLe quatri\u00e8me (et meilleur) tome des aventures de Walt Longmire.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-07-06",
"title": "Enfants de poussi\u00e8re"
},
{
"category": "au-coin-du-feu",
"content": "Kingsman\n========\n\nInconnu au bataillon jusqu'\u00e0 hier, [Kingsman](http://www.allocine.fr/film/fichefilm_gen_cfilm=198771.html) est l'arch\u00e9type du bon film qui ne se prend pas au s\u00e9rieux. Malgr\u00e9 un sc\u00e9nario classique, l'enrobage est croustillant: dialogues succuleux, ambiance enveloppante et action omnipr\u00e9sente (et omniviolente). Ne le regardez pas en esp\u00e9rant y trouver le prochain James Bond, cela ne fonctionnera pas: regardez le plut\u00f4t comme le Love Actually du film d'espionnage: des personnages caricaturaux dans un d\u00e9cor *seventies* british au possible (le tout saupoudr\u00e9 de gadgets dignes de Q, quand m\u00eame!) pour vous faire passer un tr\u00e8s bon moment.\n\nDu bon, du tr\u00e8s bon et parfois du moins bon: le film part sacr\u00e9ment en sucette pendant un petit moment, et continue \u00e0 d\u00e9gringoler dans le grand n'importe quoi, en d\u00e9rapant sauvagement dans l'ironie avec une *maestria* certaine.\n\nPetit avertissement: des sc\u00e8nes, des propos ou des images peuvent heurter la sensibilit\u00e9 des spectateurs. Mais regardez-le quand m\u00eame. Ce n'est pas tous les jours qu'on a l'occasion de voir des films qui ne se prennent s\u00e9rieusement pas au s\u00e9rieux.\n\n*Hail to the King !*",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-07-23",
"title": "Kingsman"
},
{
"category": "au-coin-du-feu",
"content": "O\u00f9 on va, Papa ?\n================\n\nL'auteur est p\u00e8re de deux enfants handicap\u00e9s. Le livre est tourn\u00e9 comme un ensemble de petits dialogues, mis les uns \u00e0 la suite des autres et exposant des sc\u00e8nes de vie quotidiennes.\n\nBien que touchant, ces sc\u00e8nes sont \u00e9galement bourr\u00e9es de sarcasmes et d'ironie. Peut-\u00eatre la seule mani\u00e8re de remettre en question l'injustice de la vie par rapport \u00e0 une r\u00e9alit\u00e9 qui n'aura jamais lieu.\n\nA lire quand cela ne va pas; n'importe quel chapitre peut remettre tout ce qui ne va pas en question. Vous vous direz alors que \"non, vous n'\u00eates pas si mal loti que cela. Loin de l\u00e0\".",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-07-30",
"title": "O\u00f9 on va, Papa ?"
},
{
"category": "au-coin-du-feu",
"content": "Le premier jour du reste de ma vie\n==================================\n\nLorsque son mari f\u00eate ses 40 ans, l'h\u00e9ro\u00efne le plaque pour aller vivre un tour du monde en croisi\u00e8re.\n\nBon allez, zou, sans faire durer le suspens: je ne suis pas arriv\u00e9 au bout. Le livre fait passer un bon moment, tout se passe plus ou moins bien et les moments n\u00e9gatifs remontent g\u00e9n\u00e9ralement la pente assez vite. On y trouve toujours quelqu'un peut sauver la situation.\n\nBon pour le moral, mais manque de meurtres.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-08-06",
"title": "Le premier jour du reste de ma vie"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Le premier jour du reste de ma vie\nDate: 2015-08-06\nSummary: \"Un road-movie/book sur la crise de la quarantaine.\"\nSlug: le-premier-jour-du-reste-de-ma-vie\n---\n\nLorsque son mari f\u00eate ses 40 ans, l'h\u00e9ro\u00efne le plaque pour aller vivre un tour du monde en croisi\u00e8re.\n\nBon allez, zou, sans faire durer le suspens: je ne suis pas arriv\u00e9 au bout. Le livre fait passer un bon moment, tout se passe plus ou moins bien et les moments n\u00e9gatifs remontent g\u00e9n\u00e9ralement la pente assez vite. On y trouve toujours quelqu'un peut sauver la situation.\n\nBon pour le moral, mais manque de meurtres.\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-08-06",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "Le r\u00e9giment monstrueux\n======================\n\n> La guerre fait rage depuis des d\u00e9cennies en Borogravie. Pour retrouver son fr\u00e8re, la jeune Margot se d\u00e9guise en homme pour s\u2019engager dans l\u2019arm\u00e9e. Tr\u00e8s vite, ses fr\u00e8res d\u2019armes et elle se rendent compte que l\u2019issue de la guerre ne semble pas \u00eatre en leur faveur et qu\u2019ils constituent les derni\u00e8res recrues.\n\nFlemme d'\u00e9crire ce que j'en pense, donc je copie/colle sauvagement un avis avec lequel je suis plus-que-d'accord:\n\n> *Quand, en plus, il arrive \u00e0 \u00eatre captivant et dr\u00f4le, que dire de plus? Pratchett pr\u00e9sident?* -- Bibliosurf.com",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-08-28",
"title": "Le r\u00e9giment monstrueux"
},
{
"category": "au-coin-du-feu",
"content": "Jurassic World\n==============\n\nJurassic Park, sorti en 1993, est un monument de la culture (geek?). Plus de 20 ans apr\u00e8s sa sortie, il reste une r\u00e9f\u00e9rence dans le microcosme du cin\u00e9ma des dinosaures (et ce ne sont pas les x tentatives foireuses qui me contrediront).\n\nSa suite, plus brute et violente, constitue \u00e9galement un bon moment en compagnie des sauriens. Elle est cependant plus ax\u00e9e sur l'instinct primitif des bestioles, leur capacit\u00e9s de destruction (et de mastication) que sur la survie d'une poign\u00e9e d'humain: les troupes arm\u00e9es sont principalement pr\u00e9sentes pour servir d'amuse-gueule, que pour se refaire le d\u00e9barquement de *Saving Private Ryan*.\n\nArrive Jurassic World: il s'impose bien comme une suite et non pas comme un reboot. La premi\u00e8re partie sert principalement \u00e0 introduire toutes les mani\u00e8res dont les humains vont passer \u00e0 tr\u00e9pa - une petite partie g\u00e9n\u00e9tique expliquant pourquoi les dinosaures n'ont pas de plumes (merci l'actualit\u00e9!), puis on tombe sur le grand n'importe quoi g\u00e9n\u00e9tique, o\u00f9 le grotesque cotoie la s\u00e9rie B.\n\nTout le film se base sur une chasse \u00e0 l'homme, o\u00f9 la bestiole ne chasse que les h\u00e9ros, parce que les figurants ne servent qu'\u00e0 remplir l'\u00e9cran de victimes potentielles. Pas de retournement sc\u00e9naristique \u00e0 attendre, donc: juste des passages tellement improbables qu'ils font rire, des moments pr\u00e9visibles et des raccords techniques pour allonger superficiellement la dur\u00e9e du film.\n\nAu menu:\n\n- Un croisement deynonichus/T-Rex/cam\u00e9l\u00e9on\n- Des tremblements de terre (parfois)\n- Un signe de t\u00eate de l'un des Deynonichus \u00e0 un humain (maiiiiwiiiiii...)\n- Des clins d'yeux au premier Jurassic Park.\n\nBref, c'est nul. Ils auraient pu faire tellement mieux.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-09-13",
"title": "Jurassic World"
},
{
"category": "au-coin-du-feu",
"content": "Mr. Robot\n=========\n\nLe premier \u00e9pisode d\u00e9chire tout: \u00e7a parle de DDOS, de GNU/Linux, de KDE, Gnome et de groupes de hackers. D'anxi\u00e9t\u00e9 aussi. Et de drogues.\n\nLa suite est un peu moins funky-geeky: autant le d\u00e9but plaira \u00e0 tout hacker un chouia branch\u00e9 s\u00e9curit\u00e9, autant la suite pourra plus faire penser \u00e0 un mix de *House Of Cards* pour le c\u00f4t\u00e9 politique, Trainspotting pour le c\u00f4t\u00e9 junkies, Deux-Ex pour la musique.\n\nTrippant sur les premi\u00e8res heures, mais avec une micro-baisse de rythme pour la suite, compens\u00e9e par une mise sous pressions due aux personnages sociopathes pour la plupart. Petite palme pour Christian Slater dans son r\u00f4le de vieux pirate paternel en mode Robin des Bois.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-09-30",
"title": "Mr. Robot"
},
{
"category": "au-coin-du-feu",
"content": "Demain est un autre jour\n========================\n\n> \u00c0 la mort de sa m\u00e8re, Brett Bohlinger pense qu\u2019elle va h\u00e9riter de l\u2019empire de cosm\u00e9tique familial. Mais, \u00e0 sa grande surprise, elle ne re\u00e7oit qu\u2019un vieux papier jauni et chiffonn\u00e9 : la liste des choses qu\u2019elle voulait vivre, r\u00e9dig\u00e9e lorsqu\u2019elle avait 14 ans. Pour toucher sa part d\u2019h\u00e9ritage, elle aura un an pour r\u00e9aliser tous les objectifs de cette life list... Mais la Brett d\u2019aujourd\u2019hui n\u2019a plus rien \u00e0 voir avec la jeune fille de l\u2019\u00e9poque. Enseigner ? Elle n\u2019a aucune envie d\u2019abandonner son salaire confortable pour batailler avec des enfants rebelles. Un b\u00e9b\u00e9 ? Andrew, son petit ami avocat, n\u2019en veut pas. Entamer une vraie relation avec un p\u00e8re trop distant ? Les circonstances ne s\u2019y pr\u00eatent gu\u00e8re. Tomber amoureuse ? C\u2019est d\u00e9j\u00e0 fait, gr\u00e2ce \u00e0 Andrew, \u00e0 moins que... Malgr\u00e9 tout, Brett va devoir quitter sa cage dor\u00e9e pour tenter de relever le d\u00e9fi. Et elle est bien loin d'imaginer ce qui l'attend.\n\nJe l'ai lu il y a presque un an, maintenant, donc les d\u00e9tails ne sont plus tr\u00e8s frais. L'histoire est parfois un peu clich\u00e9, il y a quelques retournements de situation, et il est dans l'ensemble tr\u00e8s agr\u00e9able \u00e0 lire :).",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-10-12",
"title": "Demain est un autre jour"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Demain est un autre jour\nDate: 2015-12-10\nImage: book/demain-est-un-autre-jour.jpg\nSlug: demain-est-un-autre-jour\n---\n\n> \u00c0 la mort de sa m\u00e8re, Brett Bohlinger pense qu\u2019elle va h\u00e9riter de l\u2019empire de cosm\u00e9tique familial. Mais, \u00e0 sa grande surprise, elle ne re\u00e7oit qu\u2019un vieux papier jauni et chiffonn\u00e9 : la liste des choses qu\u2019elle voulait vivre, r\u00e9dig\u00e9e lorsqu\u2019elle avait 14 ans. Pour toucher sa part d\u2019h\u00e9ritage, elle aura un an pour r\u00e9aliser tous les objectifs de cette life list... Mais la Brett d\u2019aujourd\u2019hui n\u2019a plus rien \u00e0 voir avec la jeune fille de l\u2019\u00e9poque. Enseigner ? Elle n\u2019a aucune envie d\u2019abandonner son salaire confortable pour batailler avec des enfants rebelles. Un b\u00e9b\u00e9 ? Andrew, son petit ami avocat, n\u2019en veut pas. Entamer une vraie relation avec un p\u00e8re trop distant ? Les circonstances ne s\u2019y pr\u00eatent gu\u00e8re. Tomber amoureuse ? C\u2019est d\u00e9j\u00e0 fait, gr\u00e2ce \u00e0 Andrew, \u00e0 moins que... Malgr\u00e9 tout, Brett va devoir quitter sa cage dor\u00e9e pour tenter de relever le d\u00e9fi. Et elle est bien loin d'imaginer ce qui l'attend.\n\nJe l'ai lu il y a presque un an, maintenant, donc les d\u00e9tails ne sont plus tr\u00e8s frais. L'histoire est parfois un peu clich\u00e9, il y a quelques retournements de situation, et il est dans l'ensemble tr\u00e8s agr\u00e9able \u00e0 lire :).\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2015-12-10",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "L'\u00e9l\u00e9gance du h\u00e9risson\n======================\n\nCopi\u00e9-coll\u00e9 du r\u00e9sum\u00e9 [depuis Wikipedia](https://fr.wikipedia.org/wiki/L'%C3%89l%C3%A9gance_du_h%C3%A9risson):\n\n> Bien que tr\u00e8s dou\u00e9e et dot\u00e9e d'une immense culture g\u00e9n\u00e9rale, acquise en autodidacte en fr\u00e9quentant les biblioth\u00e8ques, Ren\u00e9e, cinquante-quatre ans, a d\u00e9cid\u00e9 de vivre cach\u00e9e sous les dehors de la concierge niaiseuse et inculte que les habitants du 7, rue de Grenelle croient conna\u00eetre. C'est donc en clandestine qu'elle lit du Proust, qu'elle a appel\u00e9 son chat L\u00e9on en r\u00e9f\u00e9rence \u00e0 Tolsto\u00ef et qu'elle emprunte des livres de philosophie \u00e0 la biblioth\u00e8que universitaire du quartier. Aucun de ces \u00ab riches suffisants \u00bb ne doit penser que sous ses airs de concierge rev\u00eache se cache une intelligence brillante doubl\u00e9e d'une grande culture.\n>\n> Paloma, 12 ans, brillante et r\u00e9volt\u00e9e, habite \u00e9galement au 7, rue de Grenelle. Elle refuse le monde des adultes qu'elle consid\u00e8re comme un bocal \u00e0 poissons rempli d'inepties et de faux-semblants. C'est pourquoi elle a pris sa d\u00e9cision : \u00e0 la fin de l'ann\u00e9e scolaire, le jour de ses 13 ans, elle se suicidera et mettra le feu \u00e0 l'appartement familial.\n>\n> Mais des changements surviennent quand Kakuro Ozu, un Japonais f\u00e9ru de culture, lointain parent du cin\u00e9aste Yasujir\u014d Ozu (qu'affectionne particuli\u00e8rement Ren\u00e9e), emm\u00e9nage dans l'immeuble...\n\nEn (tr\u00e8s) gros, un bon livre dont on savoure chaque page et dialogue, et apr\u00e8s lecture duquel on a tripl\u00e9 son vocabulaire.\n\nA savourer au coin du feu (ou dans le m\u00e9tro).",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-01-18",
"title": "L'\u00e9l\u00e9gance du h\u00e9risson"
},
{
"category": "au-coin-du-feu",
"content": "La liste de mes envies\n======================\n\n> Jocelyne est une modeste merci\u00e8re habitant \u00e0 Arras. Elle est mari\u00e9e \u00e0 Jocelyn, son premier amour, ouvrier dans l'usine de glaces H\u00e4agen-Dazs de la ville et ils sont parents de deux grands enfants, partis faire leur vie. Jocelyne tient, en plus de sa boutique, un blog, \u00ab dixdoigtsdor \u00bb, qui rencontre un certain succ\u00e8s. Elle se souvient souvent de la vie qu'elle aurait souhait\u00e9e mais r\u00e9ussit n\u00e9anmoins \u00e0 \u00eatre heureuse dans l'existence qu'elle m\u00e8ne.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-02-03",
"title": "La liste de mes envies"
},
{
"category": "au-coin-du-feu",
"content": "Le livre des Baltimores\n=======================\n\n(Synopsis copi\u00e9/coll\u00e9 depuis [Amazon](http://www.amazon.fr/Le-Livre-Baltimore-Jo%C3%ABl-Dicker/dp/2877069478)).\n\n> Jusqu au jour du Drame, il y avait deux familles Goldman. Les Goldman-de-Baltimore et les Goldman-de-Montclair.\n> Les Goldman-de-Montclair, dont est issu Marcus Goldman, l auteur de La V\u00e9rit\u00e9 sur l Affaire Harry Quebert, sont une famille de la classe moyenne, habitant une petite maison \u00e0 Montclair, dans le New Jersey.\n> Les Goldman-de-Baltimore sont une famille prosp\u00e8re \u00e0 qui tout sourit, vivant dans une luxueuse maison d une banlieue riche de Baltimore, \u00e0 qui Marcus vouait une admiration sans borne.\n> Huit ans apr\u00e8s le Drame, c est l histoire de sa famille que Marcus Goldman d\u00e9cide cette fois de raconter, lorsqu en f\u00e9vrier 2012, il quitte l hiver new-yorkais pour la chaleur tropicale de Boca Raton, en Floride, o\u00f9 il vient s atteler \u00e0 son prochain roman.\n> Au gr\u00e9 des souvenirs de sa jeunesse, Marcus revient sur la vie et le destin des Goldman-de-Baltimore et la fascination qu il \u00e9prouva jadis pour cette famille de l Am\u00e9rique hupp\u00e9e, entre les vacances \u00e0 Miami, la maison de vacances dans les Hamptons et les frasques dans les \u00e9coles priv\u00e9es. Mais les ann\u00e9es passent et le vernis des Baltimore s effrite \u00e0 mesure que le Drame se profile. Jusqu au jour o\u00f9 tout bascule. Et cette question qui hante Marcus depuis : qu est-il vraiment arriv\u00e9 aux Goldman-de-Baltimore ?\n\nEntre nous, j'esp\u00e9rais un peu (re)trouver l'ambiance de [la v\u00e9rit\u00e9 sur l'affaire Harry Quebert](/the-truth-about-harry-quebert). Il n'y a pas vraiment \u00e0 \u00eatre d\u00e9\u00e7u, puisqu'\u00e0 part quelques personnes crois\u00e9es dans ce dernier livre, les deux histoires sont pratiquement ind\u00e9pendantes. On y retrouve Marcus Goldman, qui nous raconte une part de son histoire, et qui le fait bien. Toujours par rapport au dernier livre (et puisque c'est mon seul point de rep\u00e8re), on n'y retrouve cependant pas la m\u00eame tension. L'histoire se lit, on se laisse happer, mais ce n'est plus la m\u00eame chose: elle ne d\u00e9colle que vers la moiti\u00e9 du livre, avant laquelle on se retrouve souvent avec comme seul *hangover* la fin d'un chapitre, **LE DRAME**. On a parfois l'impression de suivre une [mauvaise rediffusion de la Star Ac'](http://zonevideo.telequebec.tv/media/24876/je-choisis-jonathan/like-moi), tant le fil conducteur peut sembler commercial.\n\nApr\u00e8s cela, on commence \u00e0 cerner un peu mieux les diff\u00e9rents \u00e9l\u00e9ments, \u00e0 laisser vaguer son imagination et \u00e0 imaginer ce qui a bien pu foirer dans cette famille si parfaite. Lorsqu'il faudra finalement faire face \u00e0 la r\u00e9alit\u00e9, on aura envie de continuer \u00e0 traverser cette temp\u00eate de verglas, en esp\u00e9rant un d\u00e9nouement un peu plus joyeux que cette petite glissade dans la d\u00e9pression et le malheur. Au final, c'est (bien s\u00fbr) un bon livre (qui suis-je pour juger quelque chose que je ne saurai \u00e9crire moi-m\u00eame? :-)), mais il faut s'accrocher un peu pour les 250 premi\u00e8res pages.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-02-25",
"title": "Le livre des Baltimores"
},
{
"category": "au-coin-du-feu",
"content": "Heavy Water War\n===============\n\nAussi connu sous le nom de \"The Saboteurs\", Heavy Water War est une s\u00e9rie TV de six petits \u00e9pisodes. L'histoire est bas\u00e9e sur des faits r\u00e9els, et reprend le probl\u00e8me d'approvisonnement de l'Allemagne en *eau lourde*.\n\n> 943, l\u2019Europe est en flammes. La Seconde Guerre Mondiale fait rage.\nAlors que l\u2019Allemagne nazie entreprend de cr\u00e9er la premi\u00e8re bombe atomique, une op\u00e9ration secr\u00e8te s\u2019organise afin de contrecarrer la menace.\nLeur objectif : d\u00e9truire une usine allemande d\u2019Eau Lourde, un composant essentiel \u00e0 la cr\u00e9ation de l\u2019arme nucl\u00e9aire, perch\u00e9 au c\u0153ur des montagnes de Norv\u00e8ge.\n\nEt juste parce que le lien vaut le coup: [Six reasons you need to watch The Heav Water War](http://www.sbs.com.au/guide/article/2016/03/08/6-reasons-you-need-watch-heavy-water-war).",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-06-20",
"title": "Heavy Water War"
},
{
"category": "au-coin-du-feu",
"content": "Gravity\n=======\n\nJe pense que la meilleure mani\u00e8re de r\u00e9sumer ce film peut \u00eatre attribu\u00e9e \u00e0 M. Fran\u00e7ois P\u00e9russe pour son \"Et gal\u00e8re, et merde, oh merde!\".\n\nEn soi, le film est une exp\u00e9rience cin\u00e9matographique \u00e0 vivre en 3D plus qu'une histoire \u00e0 suivre (bien qu'ils aient fait des films comme Titanic et la Passion du Christ, mais bon...). On a une action continue pendant pr\u00e8s de 90 minutes, sans aucun temps mort. Vu la quantit\u00e9 de tuiles qui leur tombe dessus, on en viendrait presque \u00e0 \u00eatre d\u00e9\u00e7u de la fin: si Hollywood m'avait demand\u00e9 mon avis, j'aurais fait un crossover avec Jaws pour qu'un requin les bouffe \u00e0 leur arriv\u00e9e sur Terre. BIzarrement, ils ne l'ont pas fait.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-09-04",
"title": "Gravity"
},
{
"category": "au-coin-du-feu",
"content": "Le si\u00e8ge de Jadotville\n======================\n\nEncore une partie de l'Histoire qu'on n'apprend pas \u00e0 l'\u00e9cole... Le si\u00e8ge de Jadotville raconte l'intervetion des UN, en se concentrant sur une petite division irlandaisae apr\u00e8s l'ex\u00e9cution de Lumumba en 1961, et la prise du pouvoir par le g\u00e9n\u00e9ral Tsombe.\n\nPlusieurs probl\u00e8mes:\n\n- Jadotville est visiblement la principale source d'uranium du pays (en pleine guerre froide, faut bien se chauffer un peu),\n- Quelques petits connerues des UN (genre une petite trentaine de victimes suite \u00e0 une erreur d'appr\u00e9ciation \u00e0 la grenade) vont les faire basculer de pacificateurs \u00e0 cibles mouvants.\n\nVoir aussi l'op\u00e9ration Morthor.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-11-11",
"title": "Le si\u00e8ge de Jadotville"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Paul \u00e0 Qu\u00e9bec\nDate: 2016-11-21\nSlug: paul-a-quebec\nCover: \"\"\nStatus: draft\n---\n\nUn petit film familial tout mignon (et un peu dramatique quand m\u00eame), tir\u00e9 d'une bande dessin\u00e9e et adapt\u00e9 au cin\u00e9ma.\n\n> To be completed ;)",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2016-11-21",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "Lib\u00e9rez votre cerveau\n=====================\n\n## TL; DR\n\nPlut\u00f4t que d'en faire un r\u00e9sum\u00e9, j'ai repris plusieurs passages et citations qui m'ont particuli\u00e8rement int\u00e9ress\u00e9s dans le livre [Lib\u00e9rez votre cerveau](http://livre.fnac.com/a9483923/Idriss-Aberkane-Liberez-votre-cerveau) d'Idriss Aberkane. Concr\u00e8tement, on y trouve une foule d'anecdotes concernant l'\u00e9ducation, le cerveau, la sociologie, ainsi que quelques pointes de psychologie, d'informatique et de marketing.\n\nQuel que soit votre domaine de comp\u00e9tences ou d'expertise, vous devriez y trouver des anecdotes qui vous toucheront plus que d'autres.\n\n> J'aimerais bien mourir sur Mars. Mais pas \u00e0 l'impact. [Elon Musk]\n\n## Pr\u00e9face & introduction\n\nComme l'\u00e9crit [Serge Tisseron](http://www.sergetisseron.com/) dans la pr\u00e9face:\n\n> Les projets qui nous tiennent le plus \u00e0 coeur sont ceux qui nous permettent \u00e0 la fois de nous \u00e9panouir et de nous rendre utiles au monde, \u00e0 condition toutefois que nous ne fassions pas passer la r\u00e9ussite sociale du projet et les b\u00e9n\u00e9fices secondaires que nous pouvons en retirer avant le bonheur qu'il y a \u00e0 le mener, [...] Idriss Aberkane rappelle sans cesse l'importance d'une exp\u00e9rimentation lib\u00e9r\u00e9e face aux certitudes \u00e9tablies, aux conformismes et aux hi\u00e9rarchies n\u00e9es des id\u00e9ologies du pass\u00e9.\n\nBienvenue dans la neuroergonomie, l'art de bien utiliser le cerveau humain. L'auteur y parle de m\u00e9moire spatiale, \u00e9pisodique et proc\u00e9durale, d'empan (ce qu'on peut saisir) et d'affordance (la partie d'un objet la plus naturellement prise par nos mains), d'\u00e9ducation industrielle inadapt\u00e9e et de quantit\u00e9 primant sur la qualit\u00e9 (ces fameux pourcentages, notes, facteurs G et quotients intellectuels qui rythment nos vies).\n\nIdriss Aberkane fait partie des gens qui pensent que nous pourrions tous \u00eates prodiges dans un domaine, pour peu que l'on s'en donne les moyens (et qu'on l'ait envie de se les donner). D'apr\u00e8s lui, n'importe qui ayant suffisament de motivation et d'\u00e9nergie peut arriver \u00e0 un r\u00e9sultat \"prodigieux\" sous r\u00e9serve de deux choses:\n\n1. Soit que ce th\u00e8me lui soit pr\u00e9f\u00e9rentiel\n2. Soit qu'il ait accumul\u00e9 suffisament *d'heures de vol* pour en assimiler tous les recoins.\n\nDans le premier cas, le prodige ne pratique pas parce qu'on le lui demande, mais parce qu'il adore ce qu'il fait. Il ne travaille pas pour une note ou pour la reconnaissance de ses pairs: il le fait pour lui, par *d\u00e9sir inconditionnel de ce qu'il produit* [pg31]. Cela signifie seulement que le salaire n'est pas sa motivation premi\u00e8re, rien de plus.\n\n> ... et puis la grande proclamation de la modernit\u00e9, c'\u00e9tait que le progr\u00e8s allait en quelque sorte lib\u00e9rer l'\u00eatre humain. Mais moi, quand je prenais l'itin\u00e9raire d'un \u00eatre humain dans la modernit\u00e9, je trouvais une s\u00e9rie d'incarc\u00e9rations, \u00e0 tort ou \u00e0 raison. De la maternelle \u00e0 l'universit\u00e9, on est enferm\u00e9s. On appelle \u00e7a un \"bahut\", tout le monde travaille dans des boites, des petites, des grandes, etc. M\u00eame pour aller s'amuser hein, on va \"en boite\", bien s\u00fbr dans sa caisse, bien entendu... Et puis vous avez la derni\u00e8re boite, o\u00f9 on stocke les vieux, en attendant la derni\u00e8re boite que je vous laisse deviner. Vous pourquoi je me pose la question: existe-t-il une vie **avant** la mort? [Pierre Rabhi - Conf\u00e9rence TEDxParis 2011 - [pg29]].\n\nLa conformit\u00e9 n'est pas une fin en soi et elle ne remplira jamais une vie humaine (pg140). La pression des pairs est un moteur puissant dans la structuration de notre pens\u00e9e et de nos comportements; l'humain pr\u00e9f\u00e9rera en g\u00e9n\u00e9ral un monde connu mais malsain \u00e0 un monde sain mais inconnu (page 149) (voir aussi [l'exp\u00e9rience de Milgram](https://fr.wikipedia.org/wiki/Exp%C3%A9rience_de_Milgram) ou [l'exp\u00e9rience d'Asch](https://fr.wikipedia.org/wiki/Exp%C3%A9rience_de_Asch), o\u00f9 les *sujets indiquaient ne faire que s'int\u00e9grer*. La promesse d'une r\u00e9compense encourage notre cerveau \u00e0 se placer dans une situation connue [...]; son absence augmente ses degr\u00e9s de libert\u00e9 (page 156).\n\n## Qualit\u00e9 vs. Quantit\u00e9\n\nLe quotient intellectuel ne permet que de classer les gens dans des boites; cet enfermement est une telle condition \u00e0 notre vie que l'on ne pense pas \u00e0 se d\u00e9finir diff\u00e9rement [pg29]. Ceux qui sont sagement rest\u00e9s \u00e0 leur place ont tendance \u00e0 trouver insupportable d'\u00eatre confront\u00e9s \u00e0 des [Mavericks](https://en.wikipedia.org/wiki/Maverick_(animal)), parce que cela leur rappelle qu'ils auraient pu ou d\u00fb quitter le troupeau des gens marqu\u00e9s au fer [pg31].\n\nQuand il parle du **r\u00e8gle de la quantit\u00e9**, il fait r\u00e9f\u00e9rence aux notes, aux pourcentages qui sont associ\u00e9s \u00e0 notre travail et \u00e0 notre \u00e9volution. Qu'aujourd'hui, l'\u00e9go\u00efsme, l'indiff\u00e9rence et la maltraitance sont trois vertus capitales de nos soci\u00e9t\u00e9s postmodernes [pg35]. Et que \"plus vous essayez de rentrer dans le moule, plus vous allez ressembler \u00e0 une tarte\". A force de ne plus penser par soi-m\u00eame, on se trouve confin\u00e9 dans un moule qui ne d\u00e9nonce plus l'autorit\u00e9 ou les absurdit\u00e9s. Ce sont les gens fi\u00e8rement scolaris\u00e9s, persuad\u00e9s de leur valeur individuelle, qui ont commis sans broncher les plus faramineuses atrocit\u00e9s sur Terre [pg38].\n\n## Hackschooling\n\n[Que voudras-tu faire quand tu seras grand ?](https://www.youtube.com/watch?v=2T8E8Ie0m1M). On s'attend \u00e0 avoir des r\u00e9ponses comme \"astronaute\", \"neurochirurgien\", etc. Alors qu'en fait, n'importe qui qui aurait conserv\u00e9 son \u00e2me d'enfant s'orientera vers quelque chose qui lui plait, quelque chose avec lequel il aura d\u00e9j\u00e0 de l'exp\u00e9rience. Bref, quelque chose bas\u00e9 sur l'attraction, l'impulsion et la variation humorale, qui se r\u00e9sume globalement \u00e0 [huit choses](http://www.eachoneteachone.tv/2014/01/8-lifestyle-changers-by-dr-roger-walsh-what-youth-say-about-it/) (du Dr. Roger Walsh: \"Therapeutic Lifestyle Changes\" - TLC):\n\n* De l'exercice\n* Un \u00e9quilibre nutritionnel\n* Du temps \u00e0 l'ext\u00e9rieur\n* Du temps au service des autres\n* Des relations\n* Des r\u00e9cr\u00e9ations\n* De la relaxation et de la gestion du stress\n* Un brin de spiritualit\u00e9.\n\nLa question pos\u00e9e est: est-ce que l'\u00e9ducation aujourd'hui fait de ces huit points une priorit\u00e9? En fait, non: la plupart du temps, l'\u00e9cole fait en sorte qu'une personne puisse r\u00e9ussir sa vie plut\u00f4t que de la vivre.\n\n> L'heure n'est plus \u00e0 l'\u00e9ducation de stock, mais \u00e0 l'\u00e9ducation de flux, c'est \u00e0 la dynamique d'apprentissage qu'il faut s'int\u00e9resser, pas au stock des savoirs [pg42] [...] S'il y a \u00e9chec scolaire, qui est responsable? Le ministre ? Le recteur ? Le programme ? L'inspection ? Le chef d'\u00e9tablissement ? Le professeur ? Reste un seul coupable possible: l'\u00e9l\u00e8ve... La meilleure fa\u00e7on de progresser, c'est d'\u00eatre au contact imm\u00e9diat des cons\u00e9quences de ses d\u00e9cisions, et c'est exactement ce que fait le ministre. Le professeur [...] est le plus \u00e0 m\u00eame d'exp\u00e9rimenter des pratiques p\u00e9dagogiques et d'innover. Il est le seul \u00e0 qui l'on puisse confier l'innovation. [pg43].\n\nL'id\u00e9e est de donner du relief aux choses pour mieux les agripper, de *donner des poign\u00e9es aux objets mentaux*. On parle souvent de vulgarisation; Idriss parle de *popularisation*. Ou simplement de **p\u00e9dagogie**. Donc de neuroergonomie.\n\nEt comme le cerveau aime les raccourcis [pg91], les pens\u00e9es automatiques seront conditionn\u00e9es par notre v\u00e9cu, par la saturabilit\u00e9 de notre cerveau.\n\n> Issue de la r\u00e9volution industrielle, notre \u00e9ducation est centr\u00e9e sur la pens\u00e9e de l'usine, et sa vertu cardinale est la conformit\u00e9. Pas la cr\u00e9ativit\u00e9, pas le caract\u00e8re, pas l'amour des savoirs, pas l'\u00e9panouissement. Non, la conformit\u00e9 avant toute chose [pg120].\n\nQuand une copie est corrig\u00e9e, ce que l'on y voit, c'est qui nous manque, pas ce qui a \u00e9t\u00e9 assimil\u00e9 [pg121].\n\nAu final, la socialisation \u00e0 l'\u00e9cole se produit par accident dans la cour de r\u00e9cr\u00e9ation et non pas en classe. Tout comme les valeurs pr\u00f4n\u00e9es par l'\u00e9cole ne sont ni ce dont un enfant est capable naturellement, ni ce dont une personne a besoin pour r\u00e9ellement s'\u00e9lever dans une soci\u00e9t\u00e9 \u00e9volutive et bienfaisante.\n\n## Les cinq fantastiques\n\n 1. [Ken Robinson](https://fr.wikipedia.org/wiki/Ken_Robinson), qui souligne l'aspect industriel de notr \u00e9cole \"traditionnelle\". Dans certains pays, en une journ\u00e9e, les \u00e9l\u00e8ves passent moins de temps \u00e0 l'ext\u00e9rieur que les prisonniers de droit commun.\n 2. Matthew Peterson, qui a r\u00e9ussi \u00e0 enseigner les math\u00e9matiques \u00e0 ses \u00e9l\u00e8ves uniquemement avec des [jeux vid\u00e9os](http://www.youtube.com/watch?v=2VLje8QRrwg)\n 3. [Jane McGonigal](https://en.wikipedia.org/wiki/Jane_McGonigal): \"jouer est la meilleure fa\u00e7on d'apprendre\". Le jeu encourage une pratique prolong\u00e9e et assidue [...] L'excellence \u00e9merge spontan\u00e9ment chez ceux qui se cr\u00e9ent des d\u00e9fis autour de leur pratique.\n 4. [Simon Sinek](https://fr.wikipedia.org/wiki/Simon_Sinek): on ne d\u00e9place pas des foules, on n'engage pas des gens autour des questions \"quoi\" et \"comment\", mais de la question \"pourquoi\". Au niveau de l'\u00e9ducation, la question n'est pas de noter ou non, mais de savoir pourquoi on le fait. Un jeu est intens\u00e9ment not\u00e9, il poss\u00e8de un score qui nous stimule; c'est le joueur qui r\u00e9clame la note, elle rend l'ensemble encore plus amusant et accrocheur.\n 5. [Gunter Pauli](https://fr.wikipedia.org/wiki/Gunter_Pauli): \"ce n'est pas \u00e0 la nature \u00e0 produire comme nos usines, mais \u00e0 nos usines \u00e0 produire comme la nature\". Dans la mesure o\u00f9 notre \u00e9cole est devenue une usine \u00e0 \u00e9duquer, il faut la r\u00e9former en suivant la nature, dans laquelle les flux de connaissance sont multicanaux et ergonomiques.\n\nIl faut *\u00e9laborer une gastronomie de la connaissance pour sortir du mod\u00e8le fast-food* et remettre le plaisir au coeur de l'\u00e9cole. Dans l'\u00e9cole actuelle, les professeurs souffrent autant que les \u00e9l\u00e8ves.\n\n(pages 127-130)\n\n## Obs\u00e9nit\u00e9 \u00e9loquente et \u00e9ducation\n\n(page 141)\n\n * C\u00f4t\u00e9 prof: Je me fais chier \u00e0 donner ce cours, tu vas te faire chier \u00e0 l'apprendre, tout va bien.\n * C\u00f4t\u00e9 \u00e9l\u00e8ve: Je me fais chier \u00e0 venir, tu vas te faire chier \u00e0 me donner cours, tout va bien.\n\n*Un tel syst\u00e8me est infiniment plus vulgaire et m\u00e9rite bien un peu d'obs\u00e9nit\u00e9 \u00e9loquente* (Patton).\n\nOn ne consolide jamais mieux un cours que lorsqu'on l'enseigne \u00e0 autrui (pg142). Tout enseignant, d\u00e8s la maternelle, est un *enseignant-chercheur* qui a pour mission d'am\u00e9liorer les pratiques p\u00e9dagogiques (page 143).\n\nEt nous changerons notre soci\u00e9t\u00e9 si nous pla\u00e7ons l'\u00e9panouissement devant l'utilit\u00e9 \u00e9conomique: l\u00e0 o\u00f9 le sens ne coule pas, les humains pourrissent lentement et affreusement (page 145).\n\n## Jeux videos\n\nA l'instart de Jane McGonigal, un *geek joue pour apprendre et transforme son travail en jeu* (page 158).\n\n> Boire sans soif, sans recul et sans d\u00e9velopper finement sa subjectivit\u00e9 n'est pas la fa\u00e7on id\u00e9ale de consommer un grand cru. Il en va de m\u00eame pour le jeu vid\u00e9o (page 158).\n\nSi certains *progamers* \u00e9taient en \u00e9chec scolaire, ils avaient d\u00e9velopp\u00e9 pour certains un niveau de comp\u00e9tences en algorithmique, informatique et optimisation digne d'un \u00e9l\u00e8ve de master (page 159). Les jeux videos sont aussi une excellente mani\u00e8re d'apprendre la programmation et devraient \u00eatre utilis\u00e9s comme tels.\n\nL'auteur propose cinq conseils pour profiter (et faire profiter) des jeux vid\u00e9os \u00e0 vos enfants (pages 160-162):\n\n1. Impliquez-vous dans le choix des jeux, d'une fa\u00e7on constructive et non-invasive\n2. Jouez avec vos enfants, notamment pour faciliter l'arr\u00eat du jeu et prenez cinq minutes \u00e0 la fin de la s\u00e9ancepour d\u00e9briefer\n3. *Devenez un sommelier du jeu vid\u00e9o*. Elevez leur go\u00fbt, faites-en non pas des consommateurs mais des critiquesvid\u00e9oludiques.\n4. Instaurez des cr\u00e9dits jeux vid\u00e9o, avec un ratio entre 1 et 1.5 en faveur du temps de travail. Cela fait deuxheures de jeu gagn\u00e9es pour 3h de travail. Et aux t\u00e2ches sp\u00e9ciales, on accorde des r\u00e9compenses sp\u00e9ciales.\n5. Diversifiez le r\u00e9gime alimentaire.\n\n## Le cerveau\n\nPour arriver \u00e0 mieux saisir certains concepts, l'id\u00e9e est de d'inhiber le cortex pr\u00e9fontal, pous d\u00e9sinhib\u00e9s l'individu. En augmentant la confiance en soi et en r\u00e9duisant la part de doute dans la planification d'une t\u00e2che, la d\u00e9sinhibition peut augmenter les performances et stimuler la cr\u00e9ativit\u00e9, notamment dans la r\u00e9solution de probl\u00e8mes ou dans l'\u00e9criture. Par exemple, prendre une petite dose d'alcool pour limiter le trac [pg70].\n\nDe fait, lorsque nous nous persuadons que nous sommes incapables de r\u00e9aliser une t\u00e2che, nous avons beaucoup plus de chances d'y \u00e9chouer [pg71].\n\nOn parlait plus haut de *hacking*. Au niveau du cerveau, cela peut \u00eatre fait gr\u00e2ce \u00e0 l'hypnose, qui court-circuite une partie de notre esprit critique. Un autre moyen de *hacker* le cerveau est d'utiliser la \"c\u00e9cit\u00e9 d'inattention\" dans le cas d'un stimulus sensoriel [pg74]: par exemple en demandant au sujet de r\u00e9pondre \u00e0 une question de calcul mental ou de culture g\u00e9n\u00e9rale afin de le rendre insensible \u00e0 la douleur durant un court laps de temps (juste le temps de faire la piq\u00fbre... :)). L'information de la douleur aura bien \u00e9t\u00e9 relev\u00e9e, mais elle n'aura pas acc\u00e8s \u00e0 la conscience qui sera accapar\u00e9e par une autre t\u00e2che.\n\nUn peu plus loin (page 73), \"*si le cerveau ne calcule pas rapidement la racine 73\u00e8me d'un nombre \u00e0 500 chiffres, ce n'est pas parce qu'il n'en est pas capable, mais parce que cette capacit\u00e9 n'a jamais \u00e9t\u00e9 fond\u00e9e par un instinct de survie*\".\n\nNos neuronnes ont d'abord servi \u00e0 d\u00e9finir une kin\u00e9sph\u00e8re - un ensemble des mouvements possibles - puis une noosph\u00e8re - un ensemble de pens\u00e9es possibles - et cette noosph\u00e8re nous est encore largement inconnue [...] L'humain, lui, s'interdit certaines explorations mentales et la pression des pairs l'encourage au confinement [pg110-pg111].\n\n> Nous avons une attitude irrationnelle vis-\u00e0-vis des gains et des pertes: la douleur d'une perte n'est pas sym\u00e9trique au plaisir d'un gain. De plus, la courbe de r\u00e9ponse est logarithmique: apr\u00e8s avoir gagn\u00e9 100\u20ac, il faudra en gagner 1000 (10 fois plus) pour gagner une seule dose de dopamine suppl\u00e9mentaire (page 157). **Le cerveau trivialise les gains et amplifie les pertes**.\n\n## En bref\n\nHackez les choses, passez 5 heures, 500 heures ou 50 000 heures sur ce qui vous passionnent, exp\u00e9rimentez, sentez, ma\u00eetrisez.\n\n## Liens, r\u00e9f\u00e9rences et notes\n\n* [Moonwalking with Einstein, the Art and Science of Remembering Everything](#)\n\nIl y a [disonnance cognitive](https://fr.wikipedia.org/wiki/Dissonance_cognitive) lorsqu'on voit brise ce que l'on croit. Sous le III\u00e8 r\u00e9publique, on enseignait la nage sur tabouret, sans jamais aller dans l'eau. Si une personne de cette \u00e9poque rencontrait quelqu'un qui sait d\u00e9j\u00e0 nager sans avoir jamais suivi ce cours, elle pourrait imaginer tout plein d'explications fantaisistes pour expliquer ce ph\u00e9nom\u00e8ne, jusqu'aux possibilit\u00e9s de \"cet enfant a \u00e9t\u00e9 form\u00e9 \u00e0 la nage sur tabouret\" et \"cet enfant n'existe pas\". D\u00e9formation professionnelle bien connue des scientifiques: \"si je l'ignore, cela n'existe pas, et si cela n'existe pas, cela ne peut pas exister\".\n\nEn neurosciences, il arrive que l'on prenne la corr\u00e9lation pour une causalit\u00e9. C'est l'hypoth\u00e8se erron\u00e9e que parce que plusieurs choses sont li\u00e9es (corr\u00e9l\u00e9es), il y a un [lien de cause \u00e0 effet](https://explorable.com/fr/correlation-et-causalite).\n\n> Conviction que les foules votantes prennent plaisir \u00e0 leur propre infantilisation. D'o\u00f9 l'encha\u00eenement cynique mais logique, de la neuroergonomie de la politique avec celle de l'arnaque.\n\n * Pendant longtemps, le Paris haussmanien associait \u00e0 chaque \u00e9tage une couche sociale bien pr\u00e9cise. Le deuxi\u00e8me \u00e9tait par exemple l'\u00e9tage noble, r\u00e9serv\u00e9 aux riches, quand le dernier, sous les combles, abritait les chambres de bonne. Avec l'apparition de l'ascenceur, comme le note Serge Soudoplatoff, cete socialologie verticale s'est trouv\u00e9e substitu\u00e9e par une sociologie horizontale: les familles pauvres ont \u00e9t\u00e9 progressivement bout\u00e9es hors de Paris, et les derniers \u00e9tages, plus lumineux et calmes, sont devenus la coqueluche des acheteurs *hype*... [pg97].\n * Les [fab labs](https://fr.wikipedia.org/wiki/Fab_lab)\n\n> La publicit\u00e9 est un monde o\u00f9 les guimauves semblent bel et bien pousser sur les arbres (page 183).\n\nPhoto by Elijah Hiett on Unsplash",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2017-05-02",
"title": "Lib\u00e9rez votre cerveau"
},
{
"category": "au-coin-du-feu",
"content": "# Firewatch\n\n![](../../images/games/firewatch.jpg)\n\nPremier jeu sur lequel j'ai le plaisir de passer un peu de temps depuis de Schtroumpf n\u00b02. Plusieurs raisons qui m'on pouss\u00e9es vers celui-ci: les soldes d'\u00e9t\u00e9 sur [GoG](https://www.gog.com/) et les avis de [Coin-coin magazine](https://www.canardpc.com/). Premier *walking simulator* sur lequel j'ai l'honneur de poser mes gros doigts boudin\u00e9s aussi. Le jeu parfait pour jeune p\u00e8re de famille: il se termine en 3 \u00e0 5h les doigts dans le pif e tconcentre toute sa force dans les dialogues plus que dans l'action (quasi) inexistante: l'essentiel des choix se fera souvent en un temps limit\u00e9, en r\u00e9ponse \u00e0 Delilah, le tout par radio interpos\u00e9e. Delilah, c'est la coll\u00e8gue d'en face, celle qui vous guidera entre vos diff\u00e9rents objectifs et qui sera (presque) votre seul point de contact pendant les 79 jours de votre p\u00e9riple (un peu raccourci, quand m\u00eame).\n\nPas mal de petits rebondissements aussi, mais c'est surtout dans sa dimension humaine que le jeu est prenant. En fonction des choix, les dialogues \u00e9voluent, votre caract\u00e8re impreigne votre avatar et fait \u00e9voluer votre relation avec Delilah.\n\nAu niveau des missions, c'est principalement du \"rejoins X\" ou \"trouve Y\": on reste rarement bloqu\u00e9. Le reste du temps, on marche dans des d\u00e9cors super jolis, pratiquement sans musique, sauf \u00e0 des moments cl\u00e9s.\n\nBref, une aventure sans stress, jolie, bien foutue, courte (et donc g\u00e9rable avec deux Schtroumpfs), pas comme un jeu de r\u00f4les o\u00f9 il faut 40h de jeu pour passer un niveau.\n\nUn chouette \u00e9chappatoire, en somme.\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2017-06-17",
"title": "# Firewatch"
},
{
"category": "au-coin-du-feu",
"content": "Je pense trop\n=============\n\n:summary: J'ai d\u00e9marr\u00e9 ce livre \u00e9crit par Christel Petitcollin avec un sentiment de \"boah!, \u00e7a va encore \u00eatre nul\". Tu parles. J'ai commenc\u00e9 \u00e0 cocher les cases petit \u00e0 petit en me demandant si tout ce que je ressentais n'\u00e9tait pas issu de l\u00e0.\n\nJ'ai d\u00e9marr\u00e9 ce livre \u00e9crit par Christel Petitcollin avec un sentiment de \"boah!, \u00e7a va encore \u00eatre nul\". Tu parles. J'ai commenc\u00e9 \u00e0 cocher les cases petit \u00e0 petit en me demandant si tout ce que je ressentais n'\u00e9tait pas issu de l\u00e0.\n\nChez la plupart des gens, un tri s'op\u00e8re automatiquement parmi les informations sensorielles disponibles. Les informations inutiles se mettent naturellement en veille. Le cerveau est disponible pour se focaliser sur l'essentiel. Cette hi\u00e9rarchisation automatique des stimuli permet de se concentrer sans effort sur ce qui est pertinent. Chez certaines personnes, ce tri doit \u00eatre fait manuellement. C'est \u00e0 la personne \u00e0 d\u00e9cider ce qui m\u00e9rite son attention ou non et de faire l'effort mental de passer le reste au second plan.\n\n> Hypersensibilit\u00e9: l'inconfort de l'impuissance \u00e0 garder le contr\u00f4le. Un mot est rarement le synonyme d'un autre; les nuances de ton et la gestuelle ont leur importance. Les gens hypersensibles sont sensibles (forc\u00e9ment), \u00e9motifs et ont besoin d'affection. Ils sont ballad\u00e9s fortement en fonction de leurs humeurs (d'o\u00f9 anxi\u00e9t\u00e9, col\u00e8re et moments de d\u00e9prime).\n\nCes personnes ont \u00e9norm\u00e9ment besoin d'affection, d'encouragements et de chaleur humaine, d'un climat relationnel serein et positif. Ils ont un \u00e9go tr\u00e8s faible, sont maladivement sensibles au jugement d'autrui et ont en permanence besoin d'\u00eatre rassur\u00e9s sur eux-m\u00eames.\n\nA cause de leur hippocampe bugg\u00e9 (qui est l'\u00e9quivalent d'un syst\u00e8me de stockage), ils peuvent en permanence revivre mentalement un souvenir intact. L'\u00e9quivalent d'un stress post-traumatique. Cela provient de situations intenses pi\u00e9g\u00e9es dans l'amygdale.\n\nIls sont \u00e9galement empathiques et agissent comme une \u00e9ponge \u00e0 sentiments: ils sont incapables de rester serein \u00e0 c\u00f4t\u00e9 de quelqu'un de triste ou de rester calme avec quelqu'un de stress\u00e9. Ils ne peuvent \u00eatre biens que si les personnes autour d'eux vont bien; et puisqu'elle sera la premi\u00e8re \u00e0 souffrir du mal qu'elle ferait \u00e0 autrui, elle est condamn\u00e9e \u00e0 la gentillesse.\n\n> La gentillesse ne peut \u00eatre qu'un \u00e9tat d'\u00eatre, pas un calcul. La m\u00e9chancet\u00e9 gratuite et la malveillance sont inconcevables, ce qui les rend vuln\u00e9rables aux manipulateurs et aux escrocs. De trahison en trahison (incompr\u00e9hensibles, puisque la malveillance n'existe pas), elles deviennent m\u00e9fiantes (voire parano\u00efaques) et se replient sur eux-m\u00eames.\n\nAutre probl\u00e8me: la pens\u00e9e en arborescence: une id\u00e9e en fait jaillir de nouvelles, qui en font de jaillir d'autres, etc. \"Chez les cerveaux droits, la d\u00e9cision est un art: elle sera fulgurante ou impossible\". Cela implique qu'il faut \"se regarder penser\" pour pouvoir visualiser le flot d'id\u00e9es et choisir le bon chemin. Cela peut aussi avoir un lien avec les sauts d'humeur: une pens\u00e9e n\u00e9gative parmi le flot d'id\u00e9es aura un impact sur l'humeur de la personne (euphorie suivie d'une grosse d\u00e9prime par exemple). Il s'agit *grosso modo* d'une usine \u00e0 fabriquer des doutes et des questions. Un autre soucis li\u00e9 \u00e0 ceci est qu'on va user notre plaisir avant de l'avoir r\u00e9ellement, \u00e0 force d'imaginer toutes les options possibles. A force, il n'y aura plus rien \u00e0 d\u00e9couvrir. Bref, il faut apprendre \u00e0 se recentrer sur l'instant pr\u00e9sent.\n\nAu final, il y a \u00e9norm\u00e9ment d'aller-retours entre le pass\u00e9 (ce qui s'est d\u00e9j\u00e0 d\u00e9roul\u00e9 et qu'on revit) et le futur (dans lequel on ne cesse de se projeter, pour lequel on ne cesse d'imaginer toutes les issues possibles). On note aussi que les \"d\u00e9cisions qui sont prises sont aussi sages que prudentes\" et que \"les risques de foncer dans le mur, d'avoir des inconv\u00e9nients pires que les solutions sont quasiment nuls\". Les d\u00e9cisions respecteront tant le syst\u00e8me personnel, familial que relationnel, \u00e0 court et \u00e0 moyen terme.\n\nIl y a aussi le principe d'anorexie intellectuelle: le fait de devoir alimenter son cerveau avec des des mati\u00e8res nouvelles pour sortir de la d\u00e9pression; et avec si possible plusieurs projets \u00e0 mener en parall\u00e8le.\n\nAu niveau du sommeil, les nuits sont entrecoup\u00e9es de r\u00e9veils, agit\u00e9es, de r\u00eaves compliqu\u00e9s et de cauchemars hyperr\u00e9alistes. Solutions: sport, sophrologie, alimentation.\n\n\"Quand on me demande d'accomplir une t\u00e2che, je ne me pose pas la question de savoir si je veux la faire ou non. Cette \u00e9tape est zapp\u00e9e, car c'est forc\u00e9ment oui. Je serai surtout occup\u00e9 \u00e0 savoir comment je vais caser ce nouvel \u00e9l\u00e9ment dans mon emploi du temps\". Ce concept est l'anitchambre du burn-out pour ces personnes.\n\n> La peur du rejet, les critiques et les moqueries peuvent s'assimler \u00e0 des violences psychologiques. M\u00eame s'il ne s'agit que de micro-aggressions, le stress qui en d\u00e9coule peut cr\u00e9er un syndr\u00f4me de Stockholm qui peut expliquer que certaines personnes restent en lecture permanente, cherchant toujours \u00e0 satisfaire leurs interlocuteurs, \u00e9pousant de ce fait toutes les causes au bout de quelques phrases et incapables de s'opposer \u00e0 quoi que ce soit.\n\n\"Pour gu\u00e9rir de cette d\u00e9pression latente, il faut retrouver sa spontan\u00e9it\u00e9. Genre: \"cela ne m'arrange pas\", plut\u00f4t que \"oui, d'accord!\". \"Seul l'enfant a besoin d'un amour inconditionnel; l'adulte peut s'en passer. Vous n'avez pas besoin de plaire \u00e0 tout le monde pour rester en vie\".\n\nQuelques questions \u00e0 se poser:\n\n 1. Jusqu'o\u00f9 je suis gentil, \u00e0 partir de quel moment est-ce que je deviens stupide?\n 2. A partir de quel moment est-ce que je deviens soumis ? (ob\u00e9ir \u00e0 l'autre au lieu de se faire respecter)\n 3. A partir de quel moment est-ce que je deviens l\u00e2che ? Ma peur de la confrontation n'est pas en train de prendre le dessus ?\n 4. Cette personne m\u00e9rite-t-elle r\u00e9ellement ma gentillesse ?\n\nEt finalement, pour r\u00e9ssuciter son estime de soi:\n\n 1. Renoncer \u00e0 la perfection\n 2. Valider ses r\u00e9ussites sans restriction, \u00e9viter le \"mais\" et arriver \u00e0 se limiter aux points positifs.\n 3. Valoriser l'image de soi (= fa\u00e7on subjective dont on se voit soi-m\u00eame et dont on pense que les autres nous voient). Devoir prouver sa valeur est un pi\u00e8ge sans-fond: plus on cherche \u00e0 la prouver, plus on la minimise. \"Vous \u00eates quelqu'un de bien et valable, vous n'avez rien \u00e0 prouver \u00e0 personne\".\n 4. Cultiver l'amour de soi: les gens qui ne s'aiment pas se n\u00e9gligent; les gens qui s'aiment se respectent et se font respecter.\n\nEn se d\u00e9barassant de sa perfection, un liste devient ce vers quoi on doit tendre et non plus ce qu'on doit atteindre.\n\nQuatre besoins:\n\n 1. Apprentissage permanent: cela demande de la pers\u00e9v\u00e9rance et de la simplification (et un brin de p\u00e9dagogie)\n 2. Faire du sport et/ou de la relaxation\n 3. Exploiter sa cr\u00e9ativit\u00e9. Le plus d\u00e9solant est de se retrouver dans une fonction ex\u00e9cutive, qui manque d'autonomie et de cr\u00e9ativit\u00e9. Voir l'artisanat et les professions lib\u00e9rales. De l'art et de l'affectif.\n 4. Apprendre \u00e0 g\u00e9rer les critiques (les gens parlent en fait de ce qu'ils s'interdisent eux-m\u00eames). En profiter pour \u00e9couter et am\u00e9liorer nos propres interdits. Si d'accord, \"ok\", si pas d'accord, \"c'est votre avis\". Dans la foul\u00e9e, soigner sa blessure de rejet, cadrer sa bienveillance.\n\nPhoto by [Patrick Perkins](https://unsplash.com/photos/ETRPjvb0KM0?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unsplash.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2017-07-20",
"title": "Je pense trop"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Le magasin des suicides\nSummary: How to get away with self-murder\nDate: 2017-07-31\nCategory: Livres\n---\n\n> Imaginez un magasin o\u00f9 l'on vend depuis dix g\u00e9n\u00e9rations tous les ingr\u00e9dients possibles pour se suicider. Cette petite entreprise familiale prosp\u00e8re dans la tristesse et l'humeur sombre jusqu'au jour abominable o\u00f9 surgit un adversaire impitoyable : la joie de vivre...\n\nCela se lit super-facilement, c'est bourr\u00e9 d'humour noir et d'id\u00e9es que Franquin ne renierait pas et l'histoire ne stagne pratiquement pas. Le th\u00e8me est cependant us\u00e9 jusqu'\u00e0 la corde (ahah). De l\u00e0 \u00e0 le conseiller, bouaif... Sans plus.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2017-07-31",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "---\nTitle: Edelweiss\nWriters: Lucy Mazel, C\u00e9dric Mayen\nDate: 2017-08-02\n---\n\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2017-08-02",
"title": "---"
},
{
"category": "au-coin-du-feu",
"content": "",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2017-12-18",
"title": "{Title unknown}"
},
{
"category": "au-coin-du-feu",
"content": "La fractale des raviolis\n========================\n\nD'abord, quelques d\u00e9finitions: une [fractale](https://fr.wikipedia.org/wiki/Fractale), tout le monde conna\u00eet. Mais des raviolis? Des sortes de p\u00e2tes, g\u00e9n\u00e9ralement pr\u00e9sent\u00e9es en conserve, baignant dans une sauce chimique \u00e0 la crois\u00e9e d'un bol de Canigou et d'une gamelle de Whiskas. Assaisonn\u00e9s de digitales pourpres, ils permettent de trucider proprement son mari infid\u00e8le.\n\nMaintenant que les pr\u00e9sentations sont faites, le synopsis!\n\n> \"Je suis d\u00e9sol\u00e9, ma ch\u00e9rie, je l'ai saut\u00e9e par inadvertance.\" Je comprends que l'on puisse sauter une femme par d\u00e9pit, par vengeance, par piti\u00e9, par compassion, par curiosit\u00e9, par habitude, par int\u00e9r\u00eat, par gourmandise, et m\u00eame parfois par amour. Par inadvertance, \u00e7a non. \u00bb\n>\n> Comment se venger d'un mari volage ? En l'empoisonnant avec son plat pr\u00e9f\u00e9r\u00e9. Mais rien ne se passe comme pr\u00e9vu et c'est tout un engrenage qui se met en place.\n\nConcr\u00e8tement, le d\u00e9but est cool! \u00c7a part d'une tr\u00e8s bonne id\u00e9e, on d\u00e9couvre des petites nouvelles intelligentes, faciles \u00e0 lire et divertissantes: \u00e0 la fin de chaque nouvelle, on rebondit sur un \u00e9l\u00e9ment pour sauter sur une nouvelle petite anecdote, et ainsi de suite (d'o\u00f9 la fractale du titre).\n\nLe probl\u00e8me, c'est qu'avec toutes ces anecdotes, pour peu qu'on ne lise pas tout d'un trait, on s'y perd un peu... Et au final, certains \u00e9l\u00e9ments ne sont pas pertinents et noient un peu trop le poisson: l'histoire principale se torche en 30 pages maxi et n'a finalement pas \u00e9norm\u00e9ment d'int\u00e9r\u00eat.\n\nBref, id\u00e9e sympa (tr\u00e8s!), d\u00e9roulement int\u00e9ressant, mais finalit\u00e9 moyenne.\n\nUn autre avis \u00e0 lire sur un autre site: https://jemelivre.blogspot.be/2014/11/la-fractale-des-raviolis-pierre-raufast.html.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2018-01-15",
"title": "La fractale des raviolis"
},
{
"category": "au-coin-du-feu",
"content": "Le temps est assassin\n=====================\n\n> **\u00c9t\u00e9 1989**. La Corse, presqu'\u00eele de la Revellata, entre mer et montagne. Sur cette route de corniche, au-dessus d'un ravin de vingt m\u00e8tres, une voiture route trop vite et bascule dans le vide. Une seule survivante : Clotilde, quinze ans. Ses parents et son fr\u00e8re n'ont pas eu la m\u00eame chance.\n\n> **\u00c9t\u00e9 2016**. Clotilde revient pour la premi\u00e8re fois sur les lieux du drame, accompagn\u00e9e de son mari et de sa fille adolescente. Elle veut profiter de ces vacances pour exorciser le pass\u00e9. C'est au camping dans lequel elle a v\u00e9cu son dernier \u00e9t\u00e9 avec ses parents que l'attend une lettre... de sa m\u00e8re. *Vivante ?*\n\nLe livre qui m'a r\u00e9concili\u00e9 avec la lecture :-) Une petite brique de 600 pages qui bringuebale le lecteur entre deux \u00e9poques. Peut-\u00eatre un peu d\u00e9cevant sur la fin, mais sympa \u00e0 lire malgr\u00e9 tout.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2018-02-11",
"title": "Le temps est assassin"
},
{
"category": "au-coin-du-feu",
"content": "La chute des g\u00e9ants\n===================\n\n> En 1911, les grandes puissances vivent leurs derniers instants d'insouciance. Bient\u00f4t la guerre va d\u00e9ferler sur le monde... Cinq familles - am\u00e9ricaine, russe, allemande, anglaise et galloise - vont se croiser, s'aimer, se d\u00e9chirer, au rythme des bouleversements de l'Histoire : la Premi\u00e8re Guerre mondiale et la R\u00e9volution russe. Cette gigantesque fresque d\u00e9peint toute la gamme des sentiments humains et dresse une galerie de portraits saisissants. Des personnages exceptionnels, passionn\u00e9s, attachants, tourment\u00e9s, qui, en d\u00e9pit des trag\u00e9dies, bravent les obstacles et les peurs pour s'accomplir.\n\nLe point central de l'histoire est la guerre 14-18; comment on y est arriv\u00e9 (quoiqu'en prenant un peu le train en marche - on oublie toute la partie pr\u00e9-20\u00e8me si\u00e8cle). Pour une fois, le point central n'est pas la guerre en elle-m\u00eame, mais tout ce qui tourne autour: quelles en ont \u00e9t\u00e9 les cons\u00e9quences avant, pendant et apr\u00e8s, quelles nations ont \u00e9t\u00e9 impliqu\u00e9es et pourquoi, comment les populations ont r\u00e9ussi \u00e0 traverser cette \u00e9poque (et ce, \u00e0 diff\u00e9rent niveaux de cat\u00e9gories socio-professionnelles - le comte gallois de Fitzherbert s'en sortira un peu mieux que 90% de la population de Petrograd...).\n\nPetite proposition: mettez \u00e7a au programme de l'\u00e9cole, qu'on nous d\u00e9barasse des M\u00e9sopotamiens et des Egyptiens pendant les premi\u00e8res ann\u00e9es scolaires, et qu'on passe plus de temps \u00e0 \u00e9tudier les raisons pour lesquelles on en est ici, l\u00e0, actuellement, maintenant.\n\nLa fiction est noy\u00e9e dans les d\u00e9tails historiques, \u00e0 tel point qu'on ne fait plus vraiment la part des choses entre l'Histoire et les petites ancedotes amoureuses et d\u00e9convenues des diff\u00e9rents personnages. Comme chacun des protagonistes appartient \u00e0 sa propre cat\u00e9gorie socio-culturelle, cela permet de se mettre en situation et de r\u00e9ellement suivre l'\u00e9volution des mentalit\u00e9s, des choses qui choquaient et de ce \u00e0 quoi la population aspirait: culture, gr\u00e8ves, diplomatie, politique. Les grands noms sont cit\u00e9s et jouent leur r\u00f4le; les personnages fictifs se croisent et d\u00e9peignent une partie de l'histoire que nous sommes tous trop jeunes pour conna\u00eetre.\n\n> Nos officiers sont-ils des imb\u00e9ciles ou des menteurs ?\n\nPetit point bonus sur la description de la bataille de Somme, qui pourrait \u00eatre compar\u00e9e \u00e0 la reconstitution du d\u00e9barquement de juin 1944 mis en sc\u00e8ne par Spielberg. Apr\u00e8s 7 jours de pillonage, les Alli\u00e9s attaquent les tranch\u00e9es allemandes, pour ne gagner que 11 malheureux kilom\u00e8tres \u00e0 la fin de la bataille. C'est dur, bien d\u00e9crit, et on en vient r\u00e9ellement \u00e0 prendre parti pour la Paix plut\u00f4t que pour la guerre \u00e0 outrance, d\u00e9clar\u00e9e en f\u00e9vrier 1916.\n\nBref, j'ai mis longtemps \u00e0 le sortir de son lit de poussi\u00e8re, mais une fois d\u00e9marr\u00e9, je ne l'ai plus l\u00e2ch\u00e9.\n\n\n",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2018-03-17",
"title": "La chute des g\u00e9ants"
},
{
"category": "au-coin-du-feu",
"content": "L'Hiver du Monde\n================\n\n> Entre 1933 et 1949, des salles de bal de Buffalo aux chambres du Parlement anglais, de la bataille de Normandie au terrible Blitz, L'Hiver du monde entra\u00eene le lecteur dans le tourbillon de la Seconde Guerre mondiale.\n>\n> De l'\u00e9mergence du IIIe Reich \u00e0 l'aube de l'\u00e8re atomique, la grande aventure du XXe si\u00e8cle telle que personne ne l'a jamais racont\u00e9e.\n1933, Hitler s'appr\u00eate \u00e0 prendre le pouvoir : l'Allemagne entame les heures les plus sombres de son histoire et va entra\u00eener le monde entier dans la barbarie et la destruction. Cinq familles de nationalit\u00e9s diff\u00e9rentes, intimement li\u00e9es, vont \u00eatre emport\u00e9es par le tourbillon de la Seconde Guerre mondiale.\nAmours contrari\u00e9es, douloureux secrets, trag\u00e9dies, coups du sort... Des salons du Yacht-Club de Buffalo \u00e0 Pearl Harbor bombard\u00e9, des sentiers des Pyr\u00e9n\u00e9es espagnoles \u00e0 Londres sous le Blitz, de Moscou en pleine \u00e9vacuation \u00e0 Berlin en ruines, le lecteur est projet\u00e9 au coeur des drames mais aussi des joies v\u00e9cus par ces femmes et ces hommes exceptionnels. Boy Fitzherbert, Carla von Ulrich, Lloyd Williams, Daisy Pechkov, Gus Dewar et les autres vont chacun \u00e0 leur mani\u00e8re tenter de faire face au milieu du chaos.\n\nLe tome 2 de la trilogie du [Si\u00e8cle de Ken Follett](https://www.babelio.com/livres/Follett-Le-Siecle-tome-2--Lhiver-du-monde/390254). L\u00e0 o\u00f9 le premier donnait envie d'entrer en politique, le deuxi\u00e8me donne juste envie de ne plus faire confiance \u00e0 personne. Certains passages sont beaucoup plus crus que dans le premier tome, les personnes sont peut-\u00eatre moins attachants et des sc\u00e8nes sont moins cr\u00e9dibles/r\u00e9alistes. Il se lit malgr\u00e9 tout d'une (preqsue) traite.\n\nPour ceux qui sont attach\u00e9s aux h\u00e9ros, sachez de Ken Follett tente malgr\u00e9 tout une petite entr\u00e9e remarqu\u00e9e dans l'univers de [George R. R. Martin](https://fr.wikipedia.org/wiki/George_R._R._Martin) et ne manque pas de faire souffrir certains de ses h\u00e9ros. Accrochez-vous pour certains passages.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2018-04-16",
"title": "L'Hiver du Monde"
},
{
"category": "au-coin-du-feu",
"content": "Zelda: Breath of the Wild\n=========================\n\nJ'ai craqu\u00e9 sur le dernier Zelda. Avant cela, il a fallu passer \u00e0 la caisse, parce que Zelda, c'est en fait les 60\u20ac du jeu + les 320\u20ac de la Switch + les 42\u20ac pour Mario (je me suis concoct\u00e9 un pack perso :-)).\n\nChronologiquement, j'ai \u00e9pluch\u00e9 Link's Awakening sur GameBoy, j'ai torch\u00e9 la premi\u00e8re moiti\u00e9 de A Link to the Past et j'ai termin\u00e9 les deux \u00e9pisodes sortis sur GameBoy Advance (Oracle of Seasons/Oracle of Ages).\n\nQuelques ann\u00e9es plus tard, j'ai \u00e0 nouveau re\u00e7u une piq\u00fbre de Zelda, qui m'intimait de passer \u00e0 la caisse pour m'offrir une Switch.\n\nConcr\u00e8tement, l'aventure d\u00e9marre de mani\u00e8re.",
"keywords": [],
"path": "articles\\au-coin-du-feu",
"publication_date": "2018-08-09",
"title": "Zelda: Breath of the Wild"
},
{
"category": "dev",
"content": "# Peewee & Flask\n\nJ'\u00e9tais parti sur un article sur les [API Rest](https://en.wikipedia.org/wiki/Representational_state_transfer) en utilisant [Flask](http://flask.pocoo.org/) et [Peewee](http://docs.peewee-orm.com/en/latest/), mais vu la relative complexit\u00e9 de ces micro-frameworks pour sortir un code propre et compl\u00e8tement fonctionnel, je me suis dit qu'il serait bien d'avoir une petite introduction d\u00e9finissant les bases d'un projet.\n\n[Flask](http://flask.pocoo.org/docs/foreword/) est un micro-framework (en Python) qui propose un ensemble de fonctions essentielles pour mettre une application Web en place, et dans laquelle tout \u00e9l\u00e9ment peut \u00eatre facilement modifi\u00e9.\n\n[Peewee](http://docs.peewee-orm.com/en/latest/), pour sa part, est un [ORM](http://en.wikipedia.org/wiki/Object-relational_mapping) (\u00e9galement \u00e9crit en Python). C'est la couche d'abstraction entre le code source et la base de donn\u00e9es, permettant de construire directement le sch\u00e9ma SQL \u00e0 partir du code pur. En gros, c'est comme n'importe quelle autre d\u00e9finition de classe, sauf que l'ORM assure la persistance et s'occupe (normalement) du lien entre le SGDB, quel qu'il soit (Oracle, MSSQL, MySQL, ...), et votre mod\u00e8le de donn\u00e9es.\n\n[Flask-peewee](http://flask-peewee.readthedocs.org/en/latest/) finalement est un wrapper entre le framework Web Flask et l'ORM peewee, mais y ajoute \u00e9galement toute une s\u00e9rie de fonctionnalit\u00e9s tr\u00e8s utiles pour d\u00e9marrer rapidement: `des pages d'administration <http://flask-peewee.readthedocs.org/en/latest/admin.html>`_ pour g\u00e9rer les instances, une gestion des utilisateurs et des droits, `une interface REST <(http://flask-peewee.readthedocs.org/en/latest/rest-api.html>`_, ...\n\nPour l'exemple ci-dessous, j'ai structur\u00e9 mon projet comme suit:\n\n```shell\ngwift.py # les vues, le mod\u00e8le de donn\u00e9es, la partie admin, ...\nconfig.py # la configuration de l'application en elle-m\u00eame\ntemplates/ # les templates html, leurs d\u00e9pendances, ...\n css/\n img/\n js/\n```\n\nLes templates ne seront utilis\u00e9s que pour l'utilisation concr\u00e8te de l'application. En attendant d'arriver \u00e0 cette \u00e9tape, il est possible de construire quelque chose d'utilisable, en se basant uniquement sur la d\u00e9finition du mod\u00e8le et sur la partie d'administration.\n\nPour la premi\u00e8re phase, on va donc d\u00e9finir un mod\u00e8le, et mettre en place la partie d'administration de l'application.\nL'ORM de Peewee n'est pas compliqu\u00e9 \u00e0 mettre en place, il faut juste respecter les \u00e9tapes dans le bon ordre:\n\n## D\u00e9finition de la configuration\n\nJe l'ai mise dans un fichier \u00e0 part, pour plus de clart\u00e9. Ce fichier sera ensuite charg\u00e9 \u00e0 l'instanciation de l'application Flask, gr\u00e2ce aux imports suivants:\n\n```python\nimport config\n\napp = Flask(__name__, static_folder='static', static_url_path='')\napp.config.from_object(config)\n\ndb = Database(app)\n```\n\nLe fichier `config.py` se pr\u00e9sente de la mani\u00e8re suivante :\n\n```python\nDATABASE = {\n 'name' : 'example.db',\n 'engine' : 'peewee.SqliteDatabase',\n}\n\nSECRET_KEY = 'my_reeeeeeally_secret_key'\n\nDEBUG = True\n```\n\nL'avantage, c'est qu'il suffit de modifier le param\u00e8tre `DATABASE` pour changer la connexion vers la base (SQLite, Postgres, MySQL, ...).\n\nLe mod\u00e8le\n=========\n\nOn va d\u00e9finir quelques classes dans le fichier `gwift.py`, et les lier \u00e0 la base de donn\u00e9es d\u00e9finies ci-dessus.\n\n```python\nfrom flask import Flask, render_template\nfrom flask_peewee.rest import RestAPI, RestResource, UserAuthentication\nfrom flask_peewee.auth import Auth\nfrom flask_peewee.db import Database\n\nfrom peewee import SqliteDatabase, Model, CharField, DateField, ForeignKeyField, DateTimeField, BooleanField, DecimalField, IntegerField\nfrom flask_peewee.admin import Admin\n\nimport config\n\napp = Flask(__name__, static_folder='static', static_url_path='')\napp.config.from_object(config)\n\ndb = Database(app)\n\nauth = Auth(app, db)\n\n\nclass WishList(db.Model):\n name = CharField()\n description = CharField()\n validity_date = DateField()\n user = ForeignKeyField(auth.User, related_name='wishlists')\n\n class Meta:\n order_by = ('name',)\n\n\nclass Item(db.Model):\n name = CharField()\n description = CharField(max_length=2000, null=True)\n url = CharField()\n price = DecimalField(max_digits=10, decimal_places=2)\n wishlist = ForeignKeyField(WishList, related_name='items')\n numberOfParts = IntegerField()\n\n\nclass Part(db.Model):\n user = ForeignKeyField(auth.User, related_name='gifts')\n item = ForeignKeyField(Item, related_name='parts')\n```\n\nOn a trois classes: *WishList*, *Item*, et *Part*. Chaque champ appartenant \u00e0 ces classes est typ\u00e9, et la syntaxe se rapproche \u00e9norm\u00e9ment de celle de l'`ORM de Django <https://docs.djangoproject.com/en/dev/topics/db/models/>`_. Les attributs *Meta* sont utilis\u00e9s pour donner un ordre par d\u00e9faut lors d'une requ\u00eate, rien de plus. `D'autres attributs <http://peewee.readthedocs.org/en/latest/peewee/models.html#model-options-and-table-metadata>`_ sont disponibles.\n\nChaque classe h\u00e9rite de **db.Model**, afin de sp\u00e9cifier une base de donn\u00e9es par d\u00e9faut. On pourrait tout \u00e0 fait se passer de cet h\u00e9ritage, mais il faudrait alors ajouter la ligne `database = db` dans les **Meta** pour chaque nouvelle classe, ce qui p\u00e8te un peu le principe de `DRY <https://fr.wikipedia.org/wiki/Ne_vous_r%C3%A9p%C3%A9tez_pas>`_.\n\nJe triche un peu en ajoutant d\u00e9j\u00e0 maintenant la configuration de l'authentification de l'application: cela me permet de lier les instances de *WishList* et de *Part* \u00e0 un utilisateur d\u00e9j\u00e0 existant (et cela force les utilisateurs \u00e0 avoir un compte avant de commencer \u00e0 interagir avec les donn\u00e9es).\n\nOn cr\u00e9e ensuite les tables au moment du lancement du script, dans la m\u00e9thode `main()`:\n\n.. code-block:: python\n\n if __name__ == '__main__':\n\t auth.User.create_table(fail_silently=True)\n\t WishList.create_table(fail_silently=True)\n\t Item.create_table(fail_silently=True)\n\t Part.create_table(fail_silently=True)\n\nPour tester tout \u00e7a, lancez un interpr\u00e9teur Python dans un shell, depuis le r\u00e9pertoire o\u00f9 se trouvent tous vos fichiers :\n\n.. code-block:: python\n\n >>> import models\n >>> models.create_tables()\n >>> from datetime import datetime\n >>>\n >>> u = models.User()\n >>> u.username = 'root'\n >>> u.password = 'admin'\n >>> u.email = ''\n >>> u.join_date = datetime.now()\n >>> u.save()\n\nEt pour v\u00e9rifier que cela fonctionne bien :\n\n >>> users = models.User.select()\n >>> users.count()\n 1\n >>> users[0].username\n u'root'\n\nDes `contraintes <http://peewee.readthedocs.org/en/latest/peewee/models.html#indexes-and-unique-constraints>`_ (unicit\u00e9, indexes, ...) pourraient \u00eatre ajout\u00e9es sur ce mod\u00e8le pour r\u00e9ellement correspondre \u00e0 un besoin, mais la base est l\u00e0 et fonctionne.\n\nMaintenant que le mod\u00e8le existe, on peut le remplir en ajoutant la couche d'administration \u00e0 notre appli Flask. Je disais plus haut avoir trich\u00e9: la couche d'administration s'obtient en cr\u00e9ant d'abord la couche d'authentification (les utilisateurs), puis un instanciant un objet ``Admin`` sur l'application, puis en enregistrant les diff\u00e9rentes classes qui seront g\u00e9r\u00e9es par l'administration.\n\n.. code-block:: python\n\n User = auth.User\n admin = User(username='admin', admin=True, active=True)\n admin.set_password('root')\n\nPour aller plus loin, il existe un exemple plus complet d'application avec Peewee dans la `document du projet <http://peewee.readthedocs.org/en/latest/peewee/example.html>`_.\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2013-03-06",
"title": "# Peewee & Flask"
},
{
"category": "dev",
"content": "---\nTitle: Breadcrumb en CSS\nDate: 2013-03-08\nTags: css, html\nSlug: css-breadcrumb\n---\n\nEn vrac, un petit style pour d\u00e9finir facilement un breadcrumb en css:\n\n```css\nul.breadcrumb\n{\n margin-bottom: 20px;\n padding: 10px;\n background-color: rgb(245, 245, 245);\n border: 1px solid rgb(227, 227, 227);\n}\n\nul.breadcrumb li\n{\n display: inline;\n}\n\nul.breadcrumb li:after\n{\n content: \" \u00bb \";\n}\n\nul.breadcrumb li:last-child:after\n{\n content: \"\";\n}\n```\n\nL'id\u00e9e est super simple: il suffit de d\u00e9finir une liste non-ordonn\u00e9e et ses \u00e9l\u00e9ments de mani\u00e8re classique, et d\u00e9finir la classe **'breadcrumb'** sur l'\u00e9l\u00e9ment *ul*. Le **display: inline;** sur les \u00e9l\u00e9ments *li* les affichera sur une seule ligne (obviously), et les pseudo-\u00e9l\u00e9ments **:after** et **:last-child:after** d\u00e9finiront la s\u00e9paration.\n\n```html\n<ul class=\"breadcrumb\">\n <li>Mon premier element</li>\n <li>Le second element</li>\n <li>Le troisieme</li>\n <li>Et le dernier.</li>\n</ul>\n```\n\nLe r\u00e9sultat final donnera quelque chose comme :\n\n```\nMon premier element \u00bb Le second element \u00bb Le troisieme \u00bb Et le dernier.\n```\n\nAttention que ceci pourrait ne pas fonctionner sur certains navigateurs (test\u00e9 sur IE > 7, FF, Chrome et Safari quand m\u00eame)...\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2013-03-08",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Ramasse-miettes\nDate: 2013-05-23\nTags: python, sql, breadcrumb, dev\nSlug: breadcrumbs-folly\n---\n\nPour faire suite \u00e0 [un premier article](|filename|../css/breadcrumb-css.md) et toujours sur le m\u00eame th\u00e8me, voici une petite s\u00e9rie d'id\u00e9es d'impl\u00e9mentation pour mettre un ramasse-miettes en place.\n\nEn SQL, le plus simple est d'avoir une table qui a une r\u00e9f\u00e9rence vers elle-m\u00eame. Un petit exemple ci-dessous en T-SQL:\n\n```sql\nCREATE TABLE Entity (\n\t[Id] int IDENTITY(1,1) NOT NULL PRIMARY KEY,\n\t[ParentId] int NULL FOREIGN KEY REFERENCES Entity(Id),\n\t[Label] nvarchar(255) NOT NULL\n)\n```\n\nThat's it. Par contre, cela ne donne quasiment aucune information, puisque pour construire l'arborescence sur cinq niveaux, il va falloir faire cinq requ\u00eates distinctes: une premi\u00e8re pour choper l'entit\u00e9 ayant un identifiant en particulier, ensuite choper son parent, puis choper le parent du parent, ... Jusqu'\u00e0 arriver \u00e0 la racine, pour laquelle le champ ParentId sera nul.\n\nUne autre possibilit\u00e9 est de construire une fonction tabulaire qui, pour un identifiant donn\u00e9, va construire la liste et la retourner dans une table temporaire, en y ajoutant un indice de position, la racine ayant la position z\u00e9ro.\n\n```sql\nCREATE FUNCTION [dbo].[BreadCrumb]\n(\n\t@currentid int\n)\nRETURNS @Tab TABLE (Id int, pos int, ParentId int, Label nvarchar(255))\n\tAS\nBegin\n\tDeclare @parentid int;\n\tDeclare @label nvarchar(max);\n\tDeclare @entitytypeid int;\n\tDeclare @i int;\n\n\tSet @parentid = @currentid;\n\tSet @i = 0;\n\n\tWhile(@parentid is not null)\n\tBegin\n\t\tset @currentid = @parentid;\n\n\t\t(Select @parentid = ParentId, @label = Entity.Label\n\t\t\tFrom Entity Where Entity.Id = @currentid);\n\n\t\tINSERT INTO @Tab (id, pos, label, parentid)\n\t\tVALUES (@currentid, @i, @label, @parentid)\n\t\tset @i = @i + 1;\n\tEnd\n\n\treturn;\nEND;\n```\n\nComme expliqu\u00e9 ci-dessus, le r\u00e9sultat retourne une table qui contient quelques colonnes (l'id, le parentid, le label et la position), et permet de chipoter un peu parmi les liens de l'arborescence, puisqu'il suffit de filer un identifiant en param\u00e8tre \u00e0 la fonction pour ressortir toute l'arborescence. Magique (ou presque).\n\nUne autre approche est de passer par un ORM. Pour l'exemple (et parce que \"c'est le plus mieux\" \u00a9), \u00e7a sera l'ORM de Django. Pour l'exemple, j'ai cr\u00e9\u00e9 une simple classe 'Album', chaque album pouvant contenir plusieurs sous-albums. Le principe est le m\u00eame: pour retracer l'arborescence d'un \u00e9l\u00e9ment, il faut remonter jusqu'\u00e0 la racine, afin de pouvoir tracer le ramasse-miettes.\n\n```python\nclass Album(models.Model):\n\tname = models.CharField(verbose_name='Nom', max_length=50)\n\tslug = models.SlugField(max_length=50, blank=False, editable=True)\n\tdescription = models.CharField(verbose_name='Description', max_length=255, null=True, blank=True)\n\tparent = models.ForeignKey('self', null=True, blank=True)\n\tcreated_at = models.DateTimeField(verbose_name='Date de cr\u00e9ation', auto_now_add=True)\n\tupdated_at = models.DateTimeField(verbose_name='Date de modification', auto_now=True)\n\n\tdef __unicode__(self):\n\t\treturn self.name\n\n\tdef illustration(self):\n\t\t\"\"\" returns an illustration for the album \"\"\"\n\t\tpictures = self.picture_set.all()\n\n\t\tif len(pictures) > 0:\n\t\t\treturn pictures[0].picture\n\t\telse:\n\t\t\treturn None\n\n\tdef parentbreadcrumb(self):\n\t\treturn self.breadcrumb()[:-1]\n\n\tdef breadcrumb(self):\n\t\t\"\"\" Returns the breadcrumb for the current album \"\"\"\n\t\tif self.parent == None:\n\t\t\treturn (self,)\n\n\t\treturn self.parent.breadcrumb() + (self,)\n\n\tdef path(self):\n\t\t\"\"\"\n\t\treturns the path where the album structure should be stored\n\t\t\"\"\"\n\t\treturn os.sep.join((x.name for x in self.breadcrumb()))\n```\n\n(Avec quelques m\u00e9thodes en plus pour faire joli).\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2013-05-23",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Ex\u00e9cuter du code Powershell au travers d'un service WCF\nDate: 2013-07-16\nSlug: powershell-code-execution-through-wcf-service\nTags: powershell, wcf, dotnet, code, runspace\n---\n\n[PowerShell](https://fr.wikipedia.org/wiki/Windows_PowerShell) permet d'\u00e9crire et d'ex\u00e9cuter des scripts avec un mod\u00e8le objet plut\u00f4t complet, et se basant sur le framework .Net. En gros, cela remplace (avantageusement) les scripts `.bat`, tout en se rapprochant de ce que les shells Unix permettent de faire depuis 20 ans.\n\nLes d\u00e9pendances PowerShell \u00e9tant sp\u00e9cifiques \u00e0 la machine h\u00f4te (et aux librairies qui y sont install\u00e9es, forc\u00e9ment), impossible d'acc\u00e9der \u00e0 certaines fonctionnalit\u00e9s depuis n'importe quel poste client. C'est notamment le cas pour tout ce qui concerne les actions li\u00e9es \u00e0 l'Active Directory. Pour bypasser ce m\u00e9canisme, je fais en sorte que ce soit la machine sur laquelle les outils d'administration AD sont install\u00e9s qui ex\u00e9cute les scripts PowerShell. J'acc\u00e8de ensuite au lancement et \u00e0 la gestion de ces scripts au travers d'un service [WCF](https://fr.wikipedia.org/wiki/Windows_Communication_Foundation) d\u00e9ploy\u00e9 sur cette m\u00eame machine, au travers d'IIS.\n\nLa difficult\u00e9 principale est donc d'\u00e9crire les scripts PowerShell, de leur passer des param\u00e8tres et de r\u00e9cup\u00e9rer le r\u00e9sultat.\n\n## Interface et client WCF\n\nLe service WCF ne pr\u00e9sente pas vraiment de difficult\u00e9, puisqu'il ne fait qu'exposer les param\u00e8tres et les diff\u00e9rentes m\u00e9thodes au travers du protocole existant. Une interface de management (`[ServiceContract]`) expose toutes les m\u00e9thodes disponibles. Celles-ci sont tagg\u00e9es par un attribut `[OperationContract]`.\n\n```csharp\n[ServiceContract]\npublic interface IManagement\n{\n\t[OperationContract]\n\tResult CreateAdAccount(int uid, string samaccountname, int? regimental, string displayname, string name, string firstname, string service, string defaultPassword);\n\n\t[OperationContract]\n\tResult CreateHomeFolder(string samAccountName);\n\n\t[OperationContract]\n\tResult CreateEmailAddress(string samAccountName, string emailAddress);\n\n\t[OperationContract]\n\tResult GetADUser(string samAccountName);\n}\n```\n\nC\u00f4t\u00e9 client, on appellera ces diff\u00e9rentes m\u00e9thodes gr\u00e2ce \u00e0 une instance d'un client WCF (apr\u00e8s l'avoir ajout\u00e9 dans les d\u00e9pendances du projet):\n\n```csharp\nvar client = new ADServiceReference.ManagementClient();\n\nclient.GetADUser('james_bond');\n\n/* ... */\n```\n\n## Script PowerShell\n\nOn construit ensuite un script `get-aduser.ps1` que l'on place dans le r\u00e9pertoire `Scripts`:\n\n```powershell\n\n<#\nGet-ADUser et ses propri\u00e9t\u00e9s, sur base du sam account name.\n#>\n\nparam(\n\t[Parameter(Mandatory = $true)] [string] $SAMAccount\n)\n\nImport-Module ActiveDirectory\n\n$user = Get-ADUser -Identity $SAMAccount -Properties *\n$MaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.TotalDays\n$passwordExpirationDate = $user.PassWordLastSet + $MaxPasswordAge\n\nWrite-Output \"DisplayName:\", $user.DisplayName\nWrite-Output \"Password last set: \", $user.PasswordLastSet\nWrite-Output \"Password Expiration: \", $passwordExpirationDate\nWrite-Output \"\"\nWrite-Output \"Member of: \", $user.MemberOf\nWrite-Output \"\"\nWrite-Output \"when changed:\", $user.whenChanged\nWrite-Output \"When created:\", $user.whenCreated\n```\n\n## Runspace .Net\n\nRetour au code .Net, dans l'impl\u00e9mentation des m\u00e9thodes du service WCF: on construit un `runspace` en lui passant les param\u00e8tres qui collent avec ce que le script attend. La premi\u00e8re \u00e9tape est de forcer le chargement des modules et des *snapins* PowerShell. On ouvre ensuite le pipeline pour y enquiller les param\u00e8tres, avant de lancer l'ex\u00e9cution proprement dite:\n\n```csharp\nusing System.Management.Automation;\nusing System.Management.Automation.Runspaces;\nusing System.ServiceModel.Activation;\n\npublic class Management : IManagement\n{\n\tpublic Result GetADUser(string samAccountName)\n\t{\n\t\tstring SCRIPT_PATH = @\"Scripts/get-aduser.ps1\";\n\n\t\tStringBuilder stringBuilder = new StringBuilder();\n\n\t\ttry\n\t\t{\n\t\t\tInitialSessionState initial = InitialSessionState.CreateDefault();\n\n\t\t\tPSSnapInException snapinException = new PSSnapInException();\n\n\t\t\tinitial.ImportPSSnapIn(\"Microsoft.Exchange.Management.PowerShell.Admin\", out snapinException);\n\t\t\tinitial.ImportPSModule(new string[] { \"ActiveDirectory\" });\n\n\t\t\tusing (Runspace runspace = RunspaceFactory.CreateRunspace(initial))\n\t\t\t{\n\t\t\t\trunspace.ApartmentState = System.Threading.ApartmentState.STA;\n\t\t\t\trunspace.ThreadOptions = PSThreadOptions.UseNewThread;\n\n\t\t\t\trunspace.Open();\n\n\t\t\t\tPipeline pipeline = runspace.CreatePipeline();\n\n\t\t\t\tCommand cmd = new Command(System.Web.HttpContext.Current.Server.MapPath(SCRIPT_PATH));\n\n\t\t\t\tcmd.Parameters.Add(new CommandParameter(\"SAMAccount\", samAccountName));\n\n\t\t\t\tpipeline.Commands.Add(cmd);\n\n\t\t\t\tvar result = pipeline.Invoke();\n\n\t\t\t\tforeach (var res in result)\n\t\t\t\t{\n\t\t\t\t\tstringBuilder.AppendLine(res.ToString());\n\t\t\t\t}\n\n\t\t\t\tManageErrors(pipeline);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex)\n\t\t{\n\t\t\tstringBuilder.Append(ex.ToString());\n\n\t\t\treturn new Result() { Status = \"NOK\", Content = stringBuilder.ToString() };\n\t\t}\n\n\t\treturn new Result() { Status = \"OK\", Content = stringBuilder.ToString() };\n\t}\n}\n```",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2013-07-16",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Composition avec MEF\nDate: 2014-03-30\nSlug: composition-with-mef\nTags: framework, composition, code, dev\n---\n\n[MEF](http://msdn.microsoft.com/en-us/library/dd460648%28v=vs.110%29.aspx) est un framework permettant d'\u00e9tendre facilement des applications. Il embarque tout un ensemble de m\u00e9thodes pour permettre de charger dynamiquement des contextes et composants plus petits, utiles pour un utilisateur, en cr\u00e9ant par exemple un m\u00e9canisme de *plugins*. L'id\u00e9e est donc de d\u00e9finir un **chargeur** (*loader*) et de d\u00e9finir une interface qui sera respect\u00e9e par tous les plugins. Au chargement de l'application, le loader s'occupera de r\u00e9cup\u00e9rer tous les petits morceaux \u00e9parpill\u00e9s (dans une assembly, dans un r\u00e9pertoire, ...) et de les lancer. L'\u00e9tape de r\u00e9cup\u00e9ration est appel\u00e9e \"composition\".\n\nTout d'abord, il faut bien entendu installer MEF (*via* [Nuget](https://www.nuget.org/packages/Microsoft.Composition)) et pouvoir inclure les namespaces suivants (disponibles dans la DLL `System.ComponentModel.Composition`):\n\n```csharp\nusing System.ComponentModel.Composition;\nusing System.ComponentModel.Composition.Hosting;\nusing System.ComponentModel.Composition.Primitives;\n```\n\nL'utilisation que j'en fais est assez simple: j'ai un ensemble de traitement \u00e0 ex\u00e9cuter dans un ordre d\u00e9fini; chaque traitement est d\u00e9fini dans une classe (voire dans un projet s\u00e9par\u00e9), et expose des propri\u00e9t\u00e9s au travers d'une interface, que j'ai appel\u00e9e `IDataLoader`. Cette interface ressemble \u00e0 ceci:\n\n```csharp\nusing System.ComponentModel.Composition;\n\n[InheritedExport]\npublic interface IDataLoader\n{\n void Start();\n int Priority { get; }\n string Type { get; }\n event EventHandler OnMessageSent;\n event EventHandler OnPercentageChange;\n}\n```\n\nChaque traitement (*plugin*) va h\u00e9riter de cette interface, et va impl\u00e9menter une m\u00e9thode `Start()`, ainsi que la propri\u00e9t\u00e9 `Priority` qui sera utilis\u00e9e par la suite. L'attribut `InheritedExport` indique que les classes h\u00e9ritant de cette interface devront \u00e9galement \u00eatre reprises lors de la composition.\n\n## Cr\u00e9ation des modules\n\nPour cr\u00e9er un nouveau module, il suffit de d\u00e9finir une nouvelle classe qui h\u00e9rite de l'interface `IDataLoader` d\u00e9finie ci-dessus:\n\n```csharp\npublic class Module1 : IDataLoader\n{\n public void Start()\n {\n // do something\n }\n\n public string Type\n {\n get { return this.GetType().ToString(); }\n }\n\n public int Priority\n {\n get { return 0; }\n }\n}\n```\n\n## Composition\n\nLa composition en elle-m\u00eame se fait au travers d'un catalogue (le bidule qui r\u00e9pertorie toutes les classes \u00e0 instancier) et d'une liste de modules. C'est une liste qui contient des instances de l'interface d\u00e9finie ci-dessus. Dans la classe \"h\u00f4te\" (le fichier `main.cs` par exemple):\n\n```csharp\n[ImportMany]\npublic List<IDataLoader> LoadedModules { get; set; }\n\nprivate void Compose()\n{\n catalog = new DirectoryCatalog(\".\");\n var container = new CompositionContainer(catalog);\n container.ComposeParts(this);\n}\n```\n\nLe catalogue, c'est simplement une classe qui h\u00e9rite de `ComposablePartCatalog` (dans le namespace `System.ComponentModel.Composition.Primitives`). Parmi les types existants, on a par exemple:\n\n * DirectoryCatalog, qui va p\u00eacher les classes parmi les assemblies pos\u00e9es dans un r\u00e9pertoire particulier\n * AssemblyCatalog pour ne prendre que les classes situ\u00e9es dans une assembly sp\u00e9cifique (genre `var catalog = AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());`)\n * ...\n\nCi-dessus, j'utilise un `new DirectoryCatalog(\".\")`, qui va parcourir le r\u00e9pertoire courant pour y r\u00e9cup\u00e9rer les classes int\u00e9ressantes. On instancie ensuite un `container`, qui va inventorier toutes ces classes, puis on appelle la m\u00e9thode `ComposeParts` sur le container pour que l'objet courant (`this`) soit initialis\u00e9 avec les bidules trouv\u00e9s dans le catalogue.\nMon interface s'appelle `IDataLoader`, il existe donc une `List<IDataLoader>` dans l'objet courant, qui sera remplie avec toutes les classes h\u00e9ritant de cette interface (vous vous rappelez de l'attribut `InheritedExport` sur l'interface?). L'attribut `ImportMany` indique au container de charger autant de classes qu'il trouvera.\n\nApr\u00e8s la composition, les instances sont dispos au travers de la liste d\u00e9clar\u00e9e ci-dessus. Dans l'exemple, apr\u00e8s que les *plugins* aient \u00e9t\u00e9 charg\u00e9s, on les parcourt dans une liste tri\u00e9e par priorit\u00e9, et on appelle la m\u00e9thode `Start()`:\n\n```csharp\nforeach (var module in LoadedModules.OrderBy(p => p.Priority))\n{\n module.Start();\n}\n```\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2014-03-30",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Git\nDate: 2014-08-02\nStatus: draft\nTags: git, vcs\n---\n\nAu plus j'utilise Git, au moins je peux m'en passer. J'ai commenc\u00e9 \u00e0 utiliser un outil de contr\u00f4le de sources pendant un travail de groupe. Le but \u00e9tait de d\u00e9velopper une petite application Web en SmallTalk, sous VisualWorks. Les assistants avaient d\u00e9ploy\u00e9 un service SVN, sur lequel on pouvait se connecter et d\u00e9ployer notre code source. Plus tard, durant mon parcours pro, on a \u00e9galement d\u00e9ploy\u00e9 un serveur SVN. On l'utilisait finalement de mani\u00e8re tr\u00e8\u00e8\u00e8s basique: quelques hooks, un serveur Trac, les commits de mani\u00e8re centralis\u00e9e (et se gueuler dessus parce que quelqu'un avait foir\u00e9 sa partie) et quelques tags.\nPar facilit\u00e9, tous nos projets se trouvaient dans le m\u00eame repository: plus besoin de jouer sur les d\u00e9pendances, tout \u00e9tait au m\u00eame endroit. Et puisqu'on jouait tr\u00e8s peu avec les branches, forc\u00e9ment, \u00e7a clashait r\u00e9guli\u00e8rement.\n\nPlus tard, je suis pass\u00e9 avec un coll\u00e8gue sur Git. On bossait chacun sur des projets diff\u00e9rents, mais on avait quand m\u00eame s\u00e9rieusement besoin de pouvoir centraliser le code source. Finalement, c'est moins le c\u00f4t\u00e9 partage de sources et plus le c\u00f4t\u00e9 \"\u00e7a m'a permis de gagner du temps\" qui aura \u00e9t\u00e9 b\u00e9n\u00e9fique sur le long terme. Aujourd'hui encore, je bosse pratiquement uniquement avec Git. Mes textes sont sur Git, mes sources aussi. J'ai un compte Github (que j'utilise trop peu), un serveur perso, ... Et je jongle de plus en plus avec les branches, et b\u00e9nis la facilit\u00e9 avec laquelle l'appli permet leur gestion.\n\nJe vous \u00e9pargnerai la cr\u00e9ation d'un nouveau repository... quoique... Bon allez, on recommence \u00e0 z\u00e9ro.\n\nPour initialiser un d\u00e9p\u00f4t, il suffit de taper un petit `git init` dans le r\u00e9pertoire souhait\u00e9. Cela cr\u00e9era un r\u00e9pertoire `.git`, contenant toutes les informations n\u00e9cessaires, notamment la configuration (dans le fichier `.git/config`).\n\nune fois que c'est fait, tout reste en local. Aucun serveur distant n'est configur\u00e9. Pour y rem\u00e9dier, on va ajouter un `git remote add origin <url du serveur>`. Ceci permettra de synchroniser avec le serveur distant: il est d\u00e8s lors tr\u00e8s facile de d\u00e9finir plusieurs h\u00f4tes, de synchroniser des branches et fichiers depuis l'une de ces sources, et de les amener vers une autre. C'est notamment comme cela que fonctionne les *pull requests* sur Github:\n\n 1. une personne (A) cr\u00e9e un repository;\n 2. une deuxi\u00e8me (B) le clone et cr\u00e9e un deuxi\u00e8me repository bas\u00e9 sur le premier.\n 3. A ce stade, les deux sont d\u00e9corell\u00e9s. Par contre, si B ajoute le premier repository comme h\u00f4te distant, il lui sera possible de se synchroniser sur le \"ma\u00eetre\".\n\nPar exemple, je clone le repository `orf/simple`. Ceci cr\u00e9e un nouveau repository sous mon compte, baptis\u00e9 de la m\u00eame mani\u00e8re (`grimbox/simple`). Pour commencer \u00e0 travailler sur ce code source, je vais le rappatrier en local :\n\n\tgit clone https://github.com/grimbox/simple.git\n\nPar d\u00e9faut, la fonction `clone` ajoute l'h\u00f4te sous la d\u00e9nomination `origin`. Pour garder la synchronisation avec le repertoire maitre, je vais \u00e9galement l'ajouter sous la d\u00e9nomination `upstream` (mais on pourrait l'appeler patate que ce serait pareil. C'est juste une convention).\n\n\tgit remote add upstream https://github.com/orf/simple.git\n\nEnsuite, je vais cr\u00e9er une nouvelle branche dans mon code source, y travailler, et soumettre une pull request.\n\n```\n\tgit checkout -b new_branch\n\t...\n\tgit add .\n\tgit commit -m \"new functionality\"\n\tgit push origin new_branch\n```\n\nEn r\u00e9sum\u00e9:\n\n * On part d'un repertoire existant\n * On le clone\n * On conserve le lien vers le r\u00e9pertoire originel\n * On bosse comme un acharn\u00e9 pour sortir une nouvelle fonctionnalit\u00e9 indispensable qui r\u00e9volutionnera le monde\n * On add/commit/push cette nouvelle fonctionnalit\u00e9, et on soumet une pull request (ou pas, si on pr\u00e9f\u00e8re garder le fork tel quel).\n\nSi on souhaite r\u00e9cup\u00e9rer le contenu du r\u00e9pertoire ma\u00eetre, on va commencer par en r\u00e9cup\u00e9rer le contenu gr\u00e2ce \u00e0 un `fetch upstream`, puis on va merger ce contenu dans notre branche master \u00e0 nous.\n\n```\n\tgit fetch upstream\n\tgit checkout master\n\tgit merge upstream/master\n```\n\nCa a peut-\u00eatre l'air un chouia indigeste pour une premi\u00e8re fois, mais on s'y adapte parfaitement. Les branches permettent r\u00e9ellement de faire tout et n'importe quoi, de garder une branche stable, une branche de d\u00e9veloppement, de partir sur de nouvelles branches pour de nouvelles fonctionnalit\u00e9s, puis de tout fusionner par la suite.\n\nDes exemples pratiques, j'en ai quelques uns: j'ai derni\u00e8rement d\u00fb travailler sur plusieurs fonctionnalit\u00e9s simultan\u00e9ment. Plut\u00f4t que de travailler uniquement sur la branche ma\u00eetre, j'ai cr\u00e9\u00e9 une premi\u00e8re branche `development`, qui sert de base (et de r\u00e9ceptacle) pour toute nouvelle fonctionnalit\u00e9. J'ai donc commenc\u00e9 \u00e0 travailler sur un nouveau module d'import pour une application. Cela a men\u00e9 \u00e0 la branche `dev-ug`, dans laquelle je fusionne r\u00e9guli\u00e8rement la branche de d\u00e9veloppement principale, pour r\u00e9cup\u00e9rer les derniers hotfixes par exemple.\nJ'ai \u00e9galement d\u00fb travailler sur une nouvelle fonctionnalit\u00e9 pour la cr\u00e9ation de comptes dans l'Active Directory: une nouvelle branche `dev-ad`. Et vu que la validation de mes modifications aura presque pris un mois, cela m'aura permis de continuer \u00e0 travailler sur d'autres points, de faire \u00e9voluer mon code, sans d\u00e9pendre du bon vouloir (et des vacances) de mes coll\u00e8gues ador\u00e9s. Une fois ma validation en poche, je suis revenu sur la branche `development`, sur laquelle j'ai fusionn\u00e9 la branche `dev-ad`, apr\u00e8s quoi j'ai fusionn\u00e9 ces modifications dans la branche ma\u00eetre.\n\nDe nouveau, cela permet de conserver une \"porte de sortie\", un endroit d'o\u00f9 on peut sortir un patch de derri\u00e8re les fagots si l'on se rend compte qu'un bug a \u00e9t\u00e9 trouv\u00e9: on revient sur la branche ma\u00eetre, on cr\u00e9e une branche `hotfix`, on d\u00e9veloppe le sparadrap et on le ram\u00e8ne dans la branche ma\u00eetre. L'id\u00e9al est \u00e9videmment de rapatrier \u00e9galement ce patch vers les autres branches... Mais vu que la finalit\u00e9 est de tout ramener \u00e0 la branche ma\u00eetre, le patch finira bien par \u00eatre pr\u00e9sent partout. Attention \u00e0 la pr\u00e9sence de la branche `development`, qui permet quand m\u00eame de faire un gros test de non-r\u00e9gression avant de passer en production.\n\nVoir aussi :\n\n * [Github flow aliases](http://haacked.com/archive/2014/07/28/github-flow-aliases pour les alias et quelques id\u00e9es de flux).\n * [Inverser les derniers commits avec Git](http://sametmax.com/inverser-les-derniers-commits-avec-git/)\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2014-08-02",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Compatibilit\u00e9 Python 2.x/3.x\nDate: 2014-08-27\nSlug: python-six-compat-2.x-3.x\nTags: python, six, dev, 2to3\n---\n\nEn adaptant une appli qui tourne sur du Python 2.7+ vers du Python 3.4, on remarque qu'il y a [beaucoup de nouveaut\u00e9s](https://docs.python.org/3/whatsnew/3.0.html). Pr\u00e9parez-vous \u00e0 adapter votre code pour que cela fonctionne :-)\n\nParmi les quelques nouveaut\u00e9s:\n\n * La d\u00e9claration `print` devient une fonction; oubliez donc tous vos `print 'bidule'`: on passe \u00e0 `print('bidule')` maintenant !\n * La fonction `raw_input` disparait au profit de `input`.\n * ...\n\nPetit exemple avec la fonction `raw_input` qui devient `input`. Une mani\u00e8re de faire est la suivante:\n\n```python\ndef _default_input_func(*args, **kwargs):\n \"\"\"\n Check if we can use `input()` from python3.\n If not, fallback to `raw_input()`.\n \"\"\"\n func = None\n try:\n func = input(*args, **kwargs)\n except NameError:\n func = raw_input(*args, **kwargs)\n\n return func\n```\n\nOn utilise alors cette nouvelle fonction `_default_input_func(*args, **kwargs)` quand on attend un *input* de l'utilisateur. Bref, c'est sympa, mais cela ne fonctionne que si une fonction est renomm\u00e9e entre deux versions majeures de l'interpr\u00e9teur.\n\nUne autre mani\u00e8re de faire pour que votre code tourne autant sur Python 2.7 que sur Python 3.x est de passer par [six](https://pypi.python.org/pypi/six) (*2 to 3 equals 6*, oui, simplement). En gros, l'id\u00e9e est de passer par des fonctions *tampons*, qui feront la redirection vers la **bonne** m\u00e9thode ou fonction (en fonction de la version de l'interpr\u00e9teur). Au niveau du code par contre, on appelle directement la bonne fonction d\u00e9finie dans le package `six`.\n\nPour revenir \u00e0 l'exemple ci-dessus, on pourrait importer la fonction `input` du package `six` et l'utiliser, ind\u00e9pendamment de la version de l'interpr\u00e9teur utilis\u00e9e.\n\n```python\nfrom six.moves import input\n```\n\nEn gros, tout se passe gr\u00e2ce \u00e0 deux flags: `six.PY2` et `six.PY3`, qui indiquent quelle version est utilis\u00e9e. Cela revient plus ou moins \u00e0 notre super fonction `_default_input_func`, sauf que c'est g\u00e9r\u00e9, maintenu et centralis\u00e9. La liste des fonctions uniformis\u00e9es est disponible ici: [https://pythonhosted.org/six/](https://pythonhosted.org/six/).\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2014-08-27",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Ruby Version Manager\nLanguage: Ruby\nTags: dev, ruby, environment\n---\n\nIl y a quelques jours, j'ai voulu essayer [Jekyll](http://jekyllrb.com/), un g\u00e9n\u00e9rateur de site statique, au m\u00eame titre que [Pelican](http://docs.getpelican.com/en/3.5.0/quickstart.html), [Nikola](http://getnikola.com/) ou [Hyde](http://ringce.com/hyde). Il propose plusieurs avantages, notamment sa compatibilit\u00e9 avec [GitHub Pages](https://help.github.com/articles/using-jekyll-with-pages/) ou sa grande flexibilit\u00e9.\n\nEn regardant le site Web, l'installation ressemble \u00e0 ceci:\n\n``` shell\n~ $ gem install jekyll\n~ $ jekyll new my-awesome-site\n~ $ cd my-awesome-site\n~ $ jekyll serve\n```\n\nDans la r\u00e9alit\u00e9, et pour un b\u00e9otien en Ruby (moi :-)), on en est loin du compte. `ruby` et `gem` sont bien install\u00e9s sur ma machine, mais l'installation a d\u00e9j\u00e0 plant\u00e9 deux fois avec un message d'erreur un-peu-pas-tout-\u00e0-fait-super-tr\u00e8s-tr\u00e8s compr\u00e9hensible... L'utilisation des commandes ci-dessus a finalement bien install\u00e9 ce qu'il fallait, mais impossible de retrouver les binaires. Etant adepte de `virtualenv` et `pew`, je ne d\u00e9sesp\u00e8re pas et trouve [RVM](https://rvm.io/), afin de cr\u00e9er un environnement virtuel dans lequel je pourrais d\u00e9ployer Jekyll.\n\nPour commencer, il faut ajouter la cl\u00e9 GPG et t\u00e9l\u00e9chargez RVM avec les commandes suivantes: \n\n``` shell\n$ gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3\n$ curl -sSL https://get.rvm.io | bash -s stable\n```\n\nCe script fra\u00eechement t\u00e9l\u00e9charg\u00e9 installe les binaires pour l'utilisateur courant, dans le r\u00e9pertoire `~/.rvm`. Pour le d\u00e9sinstaller, il suffira de supprimer ce r\u00e9pertoire.\nLe chemin vers les binaires est ajout\u00e9 au fichier `~/.profile`. Comme expliqu\u00e9 dans la documentation (au moment de l'installation), ajouter un `source ~/.profile` \u00e0 la fin de votre fichier `~/.bash_profile` pour en profiter sans avoir \u00e0 tout recopier.\n\nUne [cheat sheet](http://cheat.errtheblog.com/s/rvm) est disponible. Le but ici est de param\u00e9trer RVM pour l'utiliser de la m\u00eame mani\u00e8re que l'on utiliserait `virtualenv`.\n\nInstallation de Ruby\n--------------------\n\nRVM ne permet pas d'utiliser la version utilis\u00e9e par le syst\u00e8me. Il s'agit en fait d'un gestionnaire de versions pour Ruby (comme l'indique l'acronyme...).\nPour d\u00e9finir la version de ruby qui sera utilis\u00e9e par RVM, commencez par la commande `rvm install ruby`, afin de r\u00e9cup\u00e9rer automatiquement la derni\u00e8re version en date.\n\n``` shell\n$ rvm install ruby\nSearching for binary rubies, this might take some time.\nNo binary rubies available for: arch/libc-2.20/x86_64/ruby-2.2.0.\nContinuing with compilation. Please read 'rvm help mount' to get more information on binary rubies.\nChecking requirements for arch.\nRequirements installation successful.\nInstalling Ruby from source to: /home/fred/.rvm/rubies/ruby-2.2.0, this may take a while depending on your cpu(s)...\n[...]\nInstall of ruby-2.2.0 - #complete \nRuby was built without documentation, to build it run: rvm docs generate-ri\n``` \n\nPour finir, on d\u00e9finit la version utilis\u00e9e par RVM avec la commande `rvm use 2.2.0`. V\u00e9rifiez que la version de Ruby correspond \u00e0 celle initialis\u00e9e ci-dessus gr\u00e2ce \u00e0 `ruby -v`. Pour revenir \u00e0 la version de base, il faut utiliser `rvm use system`. Vous pouvez \u00e9galement v\u00e9rifier quelle binaire est ex\u00e9cut\u00e9 avec `which ruby`, qui devrait vous retourner quelque chose comme `/home/fred/.rvm/rubies/ruby-2.2.0/bin/ruby` au lieu de `/usr/bin/ruby`.\n\nIl est \u00e9galement possible d'installer une version particuli\u00e8re de Ruby, en utilisant la commande `rvm install 2.1.0`. Cela installera (par exemple) la version 2.1.0 dans le r\u00e9pertoire `~/.rvm/rubies/ruby-2.1.0/bin/ruby` et pourra \u00eatre appel\u00e9e gr\u00e2ce \u00e0 `rvm use 2.1.0`. \n\nPour revenir \u00e0 la version de base, il faut utiliser `rvm use system`. Vous pouvez \u00e9galement v\u00e9rifier quelle binaire est ex\u00e9cut\u00e9 avec `which ruby`, qui devrait vous retourner quelque chose comme `/home/fred/.rvm/rubies/ruby-2.2.0/bin/ruby` au lieu de `/usr/bin/ruby`.\n\nCr\u00e9ation d'un gemset\n--------------------\n\nLa cr\u00e9ation d'un nouvel environnement virtuel se fait gr\u00e2ce \u00e0 la commande `rvm gemset create project_name`. Toutes les commandes li\u00e9es \u00e0 ces environnements sont g\u00e9r\u00e9es par le pr\u00e9fixe `rvm gemset`, suivi de la commande souhait\u00e9e:\n\n``` bash\nrvm gemset create project_name # create a gemset\nrvm gemset use project_name # use a gemset in this ruby\nrvm gemset list # list gemsets in this ruby\nrvm gemset delete project_name # delete a gemset\nrvm 2.1.0@other_project_name # use another ruby and gemset\nrvm 2.2.0@_project --create --rvmrc # use and create gemset & .rvmrc\n```\n\nJekyll\n------\n\nMaintenant que toutes les \u00e9tapes ci-dessus ont \u00e9t\u00e9 r\u00e9alis\u00e9es, on peut passer \u00e0 l'installation de Jekyll: `gem install jekyll`.\nPour info, j'ai rencontr\u00e9 un probl\u00e8me li\u00e9 au runtime ExecJS:\n\n``` bash\nhome/fred/.rvm/gems/ruby-2.2.0/gems/liquid-2.6.1/lib/liquid/htmltags.rb:43: warning: duplicated key at line 46 ignored: \"index0\"\n/home/fred/.rvm/gems/ruby-2.2.0/gems/execjs-2.2.2/lib/execjs/runtimes.rb:51:in `autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)\n[...]\n```\n\nL'installation du paquet `nodejs` a r\u00e9solu le probl\u00e8me... et j'ai finalement pu cr\u00e9er un nouveau site. Par d\u00e9faut, ce site est pratiquement vide.\n\nLe param\u00e9trage du site se fait au travers du fichier `_config.yml`, notamment pour les valeurs de titre, l'email de l'auteur, la description, les noms d'utilisateurs Twitter et GitHub, ...\n\nPour aller plus loin:\n\n * [Cr\u00e9er un nouveau post](http://jekyllrb.com/docs/posts/)\n * [Ajouter une page](http://jekyllrb.com/docs/pages/)\n * [Le reste de la documentation](http://jekyllrb.com/docs/home/)\n\nOctopress\n---------\n\n[Octopress](http://octopress.org/) est un framework bas\u00e9 sur Jekyll. L'avantage par rapport \u00e0 ce dernier est que la configuration par d\u00e9faut propose quelque chose de tr\u00e8s rapidement fonctionnel (plus rapidement qu'avec Jekyll en tout cas).\n\nCloner le d\u00e9p\u00f4t Git, puis installer les d\u00e9pendances. Installez ensuite le th\u00e8me par d\u00e9faut, et commencez \u00e0 \u00e9crire :\n\n``` bash\n### Clone du d\u00e9p\u00f4t\ngit clone git://github.com/imathis/octopress.git octopress\ncd octopress\n\n### Installation des d\u00e9pendances (toujours sur base de notre Ruby install\u00e9 avec RVM)\ngem install bundler\nbundle install\n\n### Installation du th\u00e8me par d\u00e9faut\nrake install\n\n### Cr\u00e9ation d'un nouveau post\nrake new_post[\"My new blog post\"]\n\n### Cr\u00e9ation d'une nouvelle page\nrake new_page[\"My new page\"]\n```\n\nLes articles se trouvent dans le r\u00e9pertoire `_posts`, avec la structure `YYYY-MM-DD-my-new-blog-post`. Pour pr\u00e9visualiser votre nouveau site, utilisez `rake preview` et rendez-vous \u00e0 l'url `http://localhost:4000`.\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2014-12-30",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Lien actif dans une page\nDate: 2015-01-13\nSlug: active-link-in-a-page\nTags: web, code, dev, dotnet, html\n---\n\nUn \u00e9l\u00e9ment essentiel pour la compr\u00e9hension de l'interface utilisateur est de savoir o\u00f9 on se trouve. Pour cela, il existe plusieurs *patterns* (breadcrumb, historique de navigation, ...): tout pour \u00e9viter que l'utilisateur n'appuye quatorze fois sur la touche retour en esp\u00e9rant tomber sur la bonne page.\n\nUn \u00e9l\u00e9ment \u00e0 combiner avec les id\u00e9es ci-dessous est de **placer le lien actif de la page en gras**, afin d'avoir une bonne visualisation de \"o\u00f9 suis-je?\".\n\nOn commence par cr\u00e9er un helper, qui permet de g\u00e9n\u00e9rer dynamiquement un \u00e9l\u00e9ment `<li>` auquel est associ\u00e9 la classe CSS `active` s'il correspond \u00e0 l'URL actuelle du navigateur.\n\n```csharp\nusing System;\nusing System.Web.Mvc;\nusing System.Web.Mvc.Html;\n\nnamespace RPS.Web.Helpers\n{\n public static class MenuExtensions\n {\n public static MvcHtmlString MenuItem(\n this HtmlHelper htmlHelper,\n string text,\n string action,\n string controller,\n object routeValues,\n object htmlAttributes\n )\n {\n var li = new TagBuilder(\"li\"); \t\t\t\t\t\t\t\t\t\t// ajoute l'\u00e9l\u00e9ment <li></li>\n var routeData = htmlHelper.ViewContext.RouteData; \t\t\t\t\t// r\u00e9cup\u00e8re la route\n var currentAction = routeData.GetRequiredString(\"action\"); \t\t\t// r\u00e9cup\u00e8re l'action\n var currentController = routeData.GetRequiredString(\"controller\"); \t// r\u00e9cup\u00e8re le contr\u00f4leur\n if (String.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&\n String.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))\n {\n li.AddCssClass(\"active\"); // si l'url correspond \u00e0 la route, on ajoute une classe `active` sur l'\u00e9l\u00e9ment `<li>`.\n }\n\n\t\t\t// construit le code HTML \u00e0 l'int\u00e9rieur de la balise <li> avec un `ActionLink`\n li.InnerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, htmlAttributes).ToHtmlString();\n\n return MvcHtmlString.Create(li.ToString());\n }\n }\n}\n```\n\nDernier probl\u00e8me: cette extension de m\u00e9thode ne peut \u00eatre appel\u00e9e directement depuis la syntaxe Razor. Pour pallier \u00e0 cela, il suffit d'ajouter le namespace d\u00e9fini ci-dessus dans le fichier `Web.config` qui se trouve dans le r\u00e9pertoire `Views`:\n\n```xml\n<system.web.webPages.razor>\n <host factoryType=\"System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\" />\n <pages pageBaseType=\"System.Web.Mvc.WebViewPage\">\n <namespaces>\n <add namespace=\"System.Web.Mvc\" />\n <add namespace=\"System.Web.Mvc.Ajax\" />\n <add namespace=\"System.Web.Mvc.Html\" />\n <add namespace=\"System.Web.Optimization\" />\n <add namespace=\"System.Web.Routing\" />\n <add namespace=\"RPS.Web.Helpers\" />\n </namespaces>\n </pages>\n </system.web.webPages.razor>\n```\n\nOn peut ensuite l'appeler directement dans le rendu HTML de la page (pas besoin de d\u00e9finir l'\u00e9l\u00e9ment `li`, puisque celui-ci sera g\u00e9n\u00e9r\u00e9 par le helper):\n\n```\n<ul id=\"entityLinksMenu\">\n\t@Html.MenuItem(\"Details\", \"Details\", \"Entity\", new { id = Model.ID }, null)\n\t@Html.MenuItem(\"Display\", \"Display\", \"Entity\", new { id = Model.ID }, null)\n</ul>\n```\n\nFinalement, on ajoute une classe `.active` dans le style CSS:\n\n```\n#entityLinksMenu li.active {\n\tfont-weight: bold;\n}\n```\n\n## R\u00e9f\u00e9rences\n\n * [Better way to get active page link in MVC3](http://stackoverflow.com/questions/6323021/better-way-to-get-active-page-link-in-mvc-3-razor)\n * [How to add active class to HTML ActionLink in ASP MVC](http://stackoverflow.com/questions/20410623/how-to-add-active-class-to-html-actionlink-in-asp-net-mvc)\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-01-13",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: The Zen Of Python\nDate: 2015-02-23\nSlug: the-zen-of-python\nTags: zen, python, dev\n---\n\nDeux petites choses hyper importantes \u00e0 savoir en Python (m\u00eame que cela a sauv\u00e9 la vie de Chuck Norris. Deux fois.): `import this` et `import antigravity`.\n\n```\n>>> import this\nThe Zen of Python, by Tim Peters\n\nBeautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!\n```\n\nA vous d'essayer `import antigravity`.\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-02-23",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Rendu partiel (et asynchrone) avec ASP MVC & jQuery\nDate: 2015-08-17\nSlug: partial-render-using-asynchronous-js\nTags: dev, code, jquery, js\n---\n\nEn faisant du chargement asynchrone, on donne l'impression \u00e0 l'utilisateur que la page se charge plus rapidement qu'elle ne se charge r\u00e9ellement: le serveur r\u00e9pond d'abord une premi\u00e8re fois avec le squelette (et le contenu) de la page racine, puis une fois que cette page est compl\u00e8tement charg\u00e9e, on va r\u00e9cup\u00e9rer le reste des donn\u00e9es (\u00e9quivalent du `$(document).ready(function(...) { ... });`.\n\nAu niveau des contr\u00f4leurs, on va d\u00e9finir une premi\u00e8re m\u00e9thode (qui retourne un `ActionResult`) et qui envoie les donn\u00e9es vers une vue pour l'affichage de la page principale. On d\u00e9finit ensuite une deuxi\u00e8me m\u00e9thode, qui retourne un objet de type `PartialViewResult` (mais qui fonctionne grosso-modo de la m\u00eame mani\u00e8re):\n\n```csharp\npublic ActionResult Details(int? id)\n{\n\t/* fetch objects */\n\n\treturn View(...);\n}\n\npublic PartialViewResult GetAdUser(string samAccountName)\n{\n\t/* fetch objects */\n\n\treturn PartialView(...);\n}\n```\n\nDans la page principale (celle qui correspond \u00e0 la m\u00e9thode **/Details**), il faut:\n\n * Inclure jQuery\n * Ecrire un petit morceau de code pour charger les donn\u00e9es une fois que la page est compl\u00e8tement charg\u00e9e\n\n## Inclure jQuery\n\n```html\n<script src=\"/Assets/js/jquery-1.8.2.js\" type=\"text/javascript\"></script>\n```\n\nOui. C'est tout.\n\n## Le morceau de code\n\nEn fait, on doit d'abord d\u00e9finir l'emplacement o\u00f9 le r\u00e9sultat sera stock\u00e9. Soit avec une classe, soit avec un identifiant. Par exemple:\n\n```html\n<div class=\"partialContent\" data-url=\"/GetAdUser?samAccountName=fred\">\n\tLoading...\n</div>\n```\n\nLe `Loading...` peut \u00eatre remplac\u00e9 par une petite image qui s'agite, \u00e7a rendra tr\u00e8s tr\u00e8s bien. Dans cet exemple, on va utiliser l'attribut `class` pour identifier les \u00e9l\u00e9ments devant \u00eatre appel\u00e9s apr\u00e8s le chargement de la page, et l'attribut `data-url` pour initier l'URL \u00e0 contacter.\n\nFinalement, le code Javascript permettant d'op\u00e9rer la magie est le suivant:\n\n```html\n<script type=\"text/javascript\">\n\t$(document).ready(function(e) {\n\t\t$(\".partialContent\").each(function (index, item) {\n\t\t\tvar url = $(item).data(\"url\");\n\t\t\tif (url && url.length > 0)\n\t\t\t\t$(item).load(url);\n\t\t});\n\t});\n</script>\n```\n\nEn gros, pour chaque \u00e9l\u00e9ment du s\u00e9lecteur `$(\".partialContent\")`, on r\u00e9cup\u00e8re la valeur de l'attribut `data-url` et on charge le contenu de cette action en dessous de l'\u00e9l\u00e9ment actuel. Ici, le r\u00e9sultat va donc remplacer le `Loading...`.\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-08-17",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Dapper .Net\nDate: 2015-08-18\nTags: dev, dotnet, dapper, db, orm\nSlug: dapper-dot-net\n---\n\n[Dapper](https://github.com/StackExchange/dapper-dot-net) est un *wrapper* pour le framework .Net qui \u00e9tend, par des extensions de m\u00e9thodes, les fonctionnalit\u00e9s pr\u00e9sentes dans le *namespace* `System.Data.Client` pour la connexion \u00e0 une base de donn\u00e9es. En gros, on reste avec du code dans lequel on ouvre gentiment ses connexions et dans lequel on fait ses requ\u00eates. *\u00e0 l'ancienne*, mais en ajoutant un ensemble de fonctions 'achement utiles, comme par exemple `Query<T>` qui va faire correspondre les colonnes de la requ\u00eate avec les champs d'une classe. On est un niveau plus bas qu'un ORM, mais un niveau plus haut qu'un client ADO.Net classique. On garde donc la main sur la construction de nos requ\u00eates... Ce qui a ses avantages et inconv\u00e9nients :)\n\nEn plus de cela, il existe le projet [Dapper.Contrib](https://github.com/StackExchange/dapper-dot-net/tree/master/Dapper.Contrib), dans lequel on trouve notamment la classe `SqlBuilder`, qui permet d'am\u00e9liorer la construction des requ\u00eates. Son fonctionnement est un chouia touchy la premi\u00e8re fois, mais fonctionne particuli\u00e8rement bien au second tour :-) Tout fonctionne en fait sur base de templates et de clauses: on d\u00e9finit une requ\u00eate de base dans laquelle des cha\u00eenes de caract\u00e8res particuli\u00e8res seront remplac\u00e9es par les clauses:\n\n```csharp\nusing Dapper;\n\nSqlBuilder builder = new SqlBuilder();\n\nvar template = builder.AddTemplate(\n @\"Select * From Table /**where**/\");\n\nbuilder.Where(\"EntityAttribute.[Key] = 'Route'\");\nbuilder.Where(\"EntityAttributeValue.EntityId = @entityid\", new { entityid = entityId });\n\nusing (SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings[\"RPS\"].ConnectionString))\n{\n var result = sqlConnection.Query<string>(template.RawSql, template.Parameters).Select(s => int.Parse(s));\n}\n```\n\nEn r\u00e9sum\u00e9, on cr\u00e9e un `SqlBuilder` et un `template` *via* la m\u00e9thode `AddTemplate`. Puis on applique un ensemble de clauses *via* la m\u00e9thode `Where`, sur notre nouveau `builder`.\nLe r\u00e9sultat sera ensuite g\u00e9n\u00e9r\u00e9 en ouvrant une connection classique gr\u00e2ce \u00e0 une nouvelle instance de `SqlConnection`, ouverte gr\u00e2ce \u00e0 une cha\u00eene de connexion disponible dans le `ConfigurationManager`. Ensuite, on utilisera la m\u00e9thode `Query<T>` dont on parlait ci-dessus pour r\u00e9cup\u00e9rer toutes les occurences de la db, en lui passant le template et les clauses en param\u00e8tres.\n\nBref, cela demande un peu de r\u00e9flexion par rapport \u00e0 une connexion classique, cela demande un peu plus de travail qu'un (micro-)ORM, mais cela permet \u00e9galement d'avoir un \u00e9norme contr\u00f4le sur les requ\u00eates ex\u00e9cut\u00e9es. Et apr\u00e8s avoir essay\u00e9 plusieurs ORM pour le framework .Net, j'en reviens toujours \u00e0 cette solution-ci. En terme de performances, c'est sans \u00e9quivalent (bien que je ne doute pas que le contraire existe :)).\n\nSources:\n\n * [Dapper Tutorial Part II](https://liangwu.wordpress.com/2012/08/20/dapper-net-tutorial-ii/)\n * [SqlBuilder.cs](https://github.com/StackExchange/dapper-dot-net/blob/63460c60e92caadb53542dbde10221958b6630d6/Dapper.SqlBuilder/SqlBuilder.cs)\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-08-18",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: PEP8\nDate: 2015-08-19\nTags: pep8, flake8, python, code quality\n---\n\nLe langage [Python](https://www.python.org/) fonctionne avec un syst\u00e8me d'am\u00e9liorations bas\u00e9es sur des propositions: les [PEP](https://www.python.org/dev/peps/), ou \"Python Enhancement Proposal\". Chacune d'entre elles doit \u00eatre approuv\u00e9e par le [Benevolent Dictator For Life](https://www.python.org/dev/peps/pep-0001/#python-s-bdfl).\n\nCelle qui m'int\u00e9resse pour la suite de cet article est la [PEP-8](https://www.python.org/dev/peps/pep-0008/), ou \"Style Guide for Python Code\". Elle sp\u00e9cifie comment du code Python doit \u00eatre organis\u00e9 ou format\u00e9, quelles sont les conventions pour l'indentation, le nommage des variables et des classes, ... En bref, elle d\u00e9crit comment \u00e9crire du code proprement pour que d'autres d\u00e9veloppeurs puissent le reprendre facilement, ou simplement que votre base de code ne d\u00e9rive lentement vers un seuil de non-maintenabilit\u00e9. \n\nSur cette base, un outil existe et listera l'ensemble des conventions qui ne sont pas correctement suivies dans votre projet: [pep8](https://pypi.python.org/pypi/pep8). Pour l'installer, passez par `pip`. Lancez ensuite la commande `pep8` suivie du chemin \u00e0 analyser (`.`, le nom d'un r\u00e9pertoire, le nom d'un fichier `.py`, ...). Si vous souhaitez uniquement avoir le nombre d'erreur de chaque type, saisissez les options `--statistics -qq`.\n\n```python\n$ pep8 . --statistics -qq\n\n7 E101 indentation contains mixed spaces and tabs\n6 E122 continuation line missing indentation or outdented\n8 E127 continuation line over-indented for visual indent\n23 E128 continuation line under-indented for visual indent\n3 E131 continuation line unaligned for hanging indent\n12 E201 whitespace after '{'\n13 E202 whitespace before '}'\n86 E203 whitespace before ':'\n```\n\nSi vous ne voulez pas \u00eatre d\u00e9rang\u00e9 sur votre mani\u00e8re de coder, et que vous voulez juste avoir un retour sur une analyse de votre code, essayez [pyflakes](https://pypi.python.org/pypi/pyflakes): il analaysera vos sources \u00e0 la recherche d'erreurs (imports inutils\u00e9s, m\u00e9thodes inconnues, etc.\n\nEt finalement, si vous voulez grouper les deux, il existe [flake8](https://pypi.python.org/pypi/flake8). Sur base la m\u00eame interface que `pep8`, vous aurez en plus des avertissements concernant le code source :)\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-08-19",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Un p'tit parser de fichiers en C#\nDate: 2015-10-01\nSlug: a-little-csharp-files-parser\nTags: dev, dotnet, csv, fichier, parser\n---\n\nPour faciliter l'analyse de fichiers `.csv`, j'ai \u00e9crit un petit ensemble de classes (loin d'\u00eatre parfait, mais qui a le m\u00e9rite de plut\u00f4t bien fonctionner pour mon utilisation). Cet analyseur ne traite pas les cas o\u00f9 un d\u00e9limiteur se trouve perdu au beau milieu d'un champ (ce qui est quand m\u00eame la base, je sais bien), il faudrait donc am\u00e9liorer la partie *lecture du fichier* pour qu'elle crache un tableau de cha\u00eenes de caract\u00e8res et ce sera bon (genre [ici](www.filehelpers.net) ou [l\u00e0](https://github.com/JoshClose/CsvHelper)).\n\n## Les interfaces de construction\n\nL'interface `IBuilder` est juste l'interface dont d\u00e9pendent les classes de repr\u00e9sentation des *records*. Si un fichier repr\u00e9sente des personnes, on d\u00e9finira ensuite une classe `People` qui impl\u00e9mente l'interface ci-dessous (et en particulier la m\u00e9thode `Build(string[] content);`).\n\n```csharp\npublic interface IBuilder<T>\n{\n T Build(string[] content);\n}\n\npublic class BuilderException : Exception\n{\n public BuilderException(string message) : base(message) { }\n}\n```\n\nEnsuite, on a une interface `IManager`, pour d\u00e9finir la mani\u00e8re dont sont g\u00e9r\u00e9s les *records*. Plusieurs lignes du fichier lu peuvent par exemple repr\u00e9senter une et une seule personne (et plusieurs de ses contrats, par exemple). Cela permet d'avoir un gestionnaire qui va stocker chaque personne dans une cl\u00e9, et qui renverra la liste des \u00e9l\u00e9ments connus au travers de la m\u00e9thode `Items()`.\n\n```csharp\npublic interface IManager<T> where T : new()\n{\n /// <summary>\n /// Ajoute un \u00e9l\u00e9ment \u00e0 la liste interne.\n /// </summary>\n /// <param name=\"item\">L'\u00e9l\u00e9ment \u00e0 ajouter.</param>\n void Add(T item);\n\n /// <summary>\n /// Retourne tous les \u00e9l\u00e9ments de la liste.\n /// </summary>\n /// <returns>Une instance de liste g\u00e9n\u00e9rique de type T.</returns>\n List<T> Items();\n}\n```\n\nEt finalement, la m\u00e9thode `Read()`, qui lit le fichier pass\u00e9 en param\u00e8tre (plut\u00f4t un tableau contenant les lignes, en fait) et qui retourne la liste des \u00e9l\u00e9ments de type `T` au travers du gestionnaire (impl\u00e9mentant l'interface `IManager`), s'il existe.\n\n```csharp\npublic List<T> Read<T>(string[] lines,\n char[] delimiters = null,\n bool processFirstLine = false,\n Managers.IManager<T> manager = null)\n where T : Builders.IBuilder<T>, new() // implements a default ctor and IBuilder\n{\n if (delimiters == null || delimiters.Length == 0)\n delimiters = new char[2] { ';', '\\t' };\n\n List<T> list = new List<T>();\n\n for (int i = 0; i < lines.Count(); i++)\n {\n if (!processFirstLine && i == 0) // avoid line zero, as it contains titles\n continue;\n\n string line = lines[i];\n\n try\n {\n string[] array = line.Split(delimiters, StringSplitOptions.None);\n\n // checks at least one item is not empty or white spaces\n if (array.All(c => String.IsNullOrWhiteSpace(c)))\n continue;\n\n // init element with default ctor\n T elem = new T();\n\n // call Builder method with string array\n elem.Build(array);\n\n if (manager != null)\n {\n manager.Add(elem);\n }\n else\n {\n // add item to returned list\n list.Add(elem);\n }\n }\n catch (Builders.BuilderException buildex)\n {\n System.Diagnostics.Debug.WriteLine(buildex.ToString());\n }\n catch (Exception ex)\n {\n System.Diagnostics.Debug.WriteLine(ex.ToString());\n }\n }\n\n if (manager != null)\n return manager.Items();\n\n return list;\n}\n```\n\nDu coup, les parties \u00e0 revoir seraient le `split` sur la ligne, qui n'est franchement pas top, et la gestion des exceptions, puisque dans l'exemple ci-dessus, on ne log strictement rien.",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-10-01",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: todo.txt avec Django\nDate: 2015-10-10\nSlug: todo.txt-avec-django\nTags: django, todo, dev\n---\n\nUn petit d\u00e9but d'impl\u00e9mentation de [todo.txt](http://todotxt.com/) avec [Django](https://www.djangoproject.com/).\n\n```python\n# app/models.py\n\nfrom datetime import date\nimport re\n\nfrom django.db import models\nfrom django.contrib.auth.models import User\n\n\nclass Project(models.Model):\n \"\"\"D\u00e9crit un projet.\n\n Attributes:\n name (str): Le nom du projet en cours.\n \"\"\"\n\n name = models.CharField(max_length=255)\n\n def __str__(self):\n return self.name\n\n\nclass Context(models.Model):\n \"\"\"D\u00e9crit un contexte.\n\n Attributes:\n name (str): Le nom du contexte.\n \"\"\"\n\n name = models.CharField(max_length=255)\n\n def __str__(self):\n return self.name\n\n\nclass Task(models.Model):\n \"\"\"D\u00e9crit quelque chose qui doit \u00eatre fait :)\n\n Attributes:\n description (str): La description compl\u00e8te.\n projects (Project): La liste des projets qui sont li\u00e9s \u00e0 la t\u00e2che en cours.\n contexts (Context): La liste des contextes qui sont li\u00e9s \u00e0 la t\u00e2che en cours.\n priority (str): Le niveau de priorit\u00e9 (A, B, C, ...)\n deadline (date): L'\u00e9ch\u00e9ance \u00e0 laquelle la t\u00e2che doit avoir \u00e9t\u00e9 effectu\u00e9e.\n creator (User): L'utilisateur qui a cr\u00e9\u00e9 la t\u00e2che.\n completed (boolean): Indique si la t\u00e2che est termin\u00e9e ou pas.\n completion_date (date): La date \u00e0 laquelle la t\u00e2che a \u00e9t\u00e9 cl\u00f4tur\u00e9e.\n \"\"\"\n\n description = models.CharField(max_length=2000)\n projects = models.ManyToManyField('Project')\n contexts = models.ManyToManyField('Context')\n priority = models.CharField(max_length=1, null=True)\n deadline = models.DateField(null=True)\n creator = models.ForeignKey(User, null=True)\n completed = models.BooleanField(default=False)\n completion_date = models.DateTimeField(null=True)\n\n @property\n def iscomplete(self):\n \"\"\"V\u00e9rifie que la t\u00e2che est termin\u00e9e.\n\n La m\u00e9thode se base sur la pr\u00e9sence d'un `x` au d\u00e9but de la ligne.\n \"\"\"\n return self.description.startswith('x ')\n\n @staticmethod\n def create(description):\n \"\"\"Cr\u00e9e une nouvelle t\u00e2che, en se basant sur sa description.\n\n Pour rappel, les sp\u00e9cifications de `todo.txt` sont dispos `ici <http://todotxt.com/>`_.\n \"\"\"\n\n t = Task()\n t.description = description\n t.priority = t.__buildpriority()\n t.date = t.__builddate()\n t.completed = t.iscomplete\n t.save()\n\n for project_name in t.buildprojects():\n p, insert_result = Project.objects.get_or_create(name=project_name)\n t.projects.add(p)\n\n for context_name in t.buildcontexts():\n c, insert_result = Context.objects.get_or_create(name=context_name)\n t.contexts.add(c)\n\n return t\n\n def complete(self, adddate=False):\n \"\"\"Cl\u00f4ture une t\u00e2che, en y ajoutant soit la date de cl\u00f4ture, soit simplement un `x`.\n \"\"\"\n if not self.iscomplete:\n if adddate:\n today = date.today().strftime('%Y-%m-%d') + ' '\n self.description = 'x ' + today + self.description\n else:\n self.description = 'x ' + self.description\n self.completed = True\n self.save()\n\n def __buildpriority(self):\n \"\"\"Retourne la priorit\u00e9 de la t\u00e2che, en se basant sur sa description.\n\n La m\u00e9thode regarde si la t\u00e2che d\u00e9bute par une lettre majuscule [A-Z], suivie d'un espace.\n \"\"\"\n re_result = re.findall(r'^\\([A-Z]\\) ', self.description)\n if re_result:\n return re_result[0].strip()\n\n return None\n\n def __builddate(self):\n \"\"\"R\u00e9cup\u00e8re l'\u00e9ch\u00e9ance depuis la description.\n\n Selon les sp\u00e9cifications, l'\u00e9ch\u00e9ance se trouve *apr\u00e8s* la d\u00e9finition de la priorit\u00e9.\n On recherche donc une cha\u00eene de caract\u00e8res repr\u00e9sent\u00e9e par une date au format YYYY-MM-DD.\n \"\"\"\n re_result = re.findall(r'^(\\([A-Z]\\) )?[0-9]{4}-[0-9]{2}-[0-9]{2}',\n self.description)\n if re_result:\n return date(2011, 9, 9)\n\n return None\n\n def __str__(self):\n \"\"\"Retourne la description de la t\u00e2che.\"\"\"\n return self.description\n\n def __buildvars(self, char):\n \"\"\"Retourne tous les mots pr\u00e9c\u00e9d\u00e9s du param\u00e8tre `char` dans la description.\n\n Example:\n self.description = \"blabla @truc @machin #chose\"\n print(self.__buildvars('@'))\n >>>> ['truc', 'machin']\n print(self.__buildvars('#'))\n >>>> ['chose']\n \"\"\"\n return [x[1:] for x in re.findall(r'[%s]\\w+' % (char,), self.description)]\n\n def buildprojects(self):\n \"\"\"R\u00e9cup\u00e8re tous les projets associ\u00e9s \u00e0 la t\u00e2che en cours.\"\"\"\n return self.__buildvars('+')\n\n def buildcontexts(self):\n \"\"\"R\u00e9cup\u00e8re tous les contextes associ\u00e9s \u00e0 la t\u00e2che en cours.\"\"\"\n return self.__buildvars('@')\n```\n\nEt les tests qui vont bien:\n\n```python\n# app/tests.py\n\nfrom datetime import date\n\nfrom django.test import TestCase\n\nfrom potatoe.models import Task\n\n\nclass TaskTestCase(TestCase):\n\n def setUp(self):\n pass\n\n def test_build_task_projects(self):\n \"\"\"R\u00e9cup\u00e8re les projets li\u00e9s \u00e0 une t\u00e2che.\"\"\"\n t = Task.create(\"(A) Todo rps blablab +RPS +SharePoint\")\n projects = [str(p) for p in t.projects.all()]\n self.assertIn('RPS', projects)\n self.assertIn('SharePoint', projects)\n\n def test_build_task_contexts(self):\n \"\"\"R\u00e9cup\u00e8re tous les contextes li\u00e9s \u00e0 une t\u00e2che.\"\"\"\n t = Task.create(\"(B) Todo bidule @brol @machin +RPS\")\n contexts = [str(c) for c in t.contexts.all()]\n self.assertIn('brol', contexts)\n self.assertIn('machin', contexts)\n self.assertNotIn('RPS', contexts)\n\n def test_priorities(self):\n \"\"\"\n Rule 1: If priority exists, it ALWAYS appears first.\n\n The priority is an uppercase character from A-Z enclosed\n in parentheses and followed by a space.\n \"\"\"\n t = Task.create(\"Really gotta call Mom (A) @phone @someday\")\n self.assertIsNone(t.priority)\n\n t = Task.create(\"(b) Get back to the boss\")\n self.assertIsNone(t.priority)\n\n t = Task.create(\"(B)->Submit TPS report\")\n self.assertIsNone(t.priority)\n\n def test_dates(self):\n \"\"\"\n Rule 2: A task\u2019s creation date may optionally appear\n directly after priority and a space.\n\n If there is no priority, the creation date appears first.\n If the creation date exists, it should be in the format YYYY-MM-DD.\n \"\"\"\n\n t = Task.create(\"2011-03-02 Document +TodoTxt task format\")\n self.assertEqual(t.deadline, date(2011, 3, 2))\n\n t.description = \"(A) 2011-03-02 Call Mom\"\n self.assertEqual(t.deadline, date(2011, 3, 2))\n\n t.description = \"(A) Call Mom 2011-03-02\"\n self.assertIsNone(t.deadline, None)\n\n def test_contexts_and_projects(self):\n \"\"\"\n Rule 3: Contexts and Projects may appear anywhere in the line\n after priority/prepended date.\n \"\"\"\n t = Task.create(\"(A) Todo rps blablab +RPS +SharePoint\")\n projects = [str(p) for p in t.projects.all()]\n\n self.assertIn('RPS', projects)\n self.assertIn('SharePoint', projects)\n\n t = Task.create(\"(A) Todo rps blablab @phone @email\")\n contexts = [str(c) for c in t.contexts.all()]\n self.assertIn('phone', contexts)\n self.assertIn('email', contexts)\n\n def tearDown(self):\n pass\n\n\nclass TestCompleteTasks(TestCase):\n def setUp(self):\n pass\n\n def tearDown(self):\n pass\n\n def test_complete_without_date(self):\n t = Task.create(\"Some task @machin @brol +chose\")\n t.complete()\n self.assertTrue(t.iscomplete)\n self.assertTrue(t.description.startswith('x'))\n\n t = Task.create(\"xylophone lesson\")\n self.assertFalse(t.iscomplete)\n\n t.description = \"X 2012-01-01 Make resolutions\"\n self.assertFalse(t.iscomplete)\n\n t.description = \"(A) x Find ticket prices\"\n self.assertFalse(t.iscomplete)\n\n def test_complete_with_date(self):\n t = Task.create(\"Some task @machin @brol #chose\")\n t.complete(True)\n\n value = 'x ' + date.today().strftime('%Y-%m-%d')\n beginstr = t.description[0:12]\n\n self.assertEqual(value, beginstr)\n```\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2015-10-10",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: SOLID principle\nDate: 2016-02-09\nSlug: solid-principles\nTags: pattern, dev, code\n---\n\n * S : SRP (Single Responsibility\n * O : Open closed\n * L : LSP (Liskov Substitution)\n * I : Interface Segregation\n * D : Dependency Inversion\n\n## Single Responsibility Principle\n\nLe principe de responsabilit\u00e9 unique d\u00e9finit que chaque concept ou domaine d'activit\u00e9 ne s'occupe que d'une et d'une seule chose. En prenant l'exemple d'une m\u00e9thode qui communique avec une base de donn\u00e9es, ce ne sera pas \u00e0 cette m\u00e9thode \u00e0 g\u00e9rer l'inscription d'une exception \u00e0 un emplacement quelconque. Cette action doit \u00eatre prise en compte par une autre classe (ou un autre concept), qui s'occupera elle de d\u00e9finir l'emplacement o\u00f9 l'\u00e9v\u00e8nement sera enregistr\u00e9 (base de donn\u00e9es, Graylog, fichier, ...).\n\nCette mani\u00e8re d'organiser le code ajoute une couche d'abstraction (ie. \"I don't care\") sur les concepts, et centralise tout ce qui touche \u00e0 type d'\u00e9v\u00e8nement \u00e0 un et un seul endroit. Ceci permet \u00e9galement de centraliser la configuration pour ce type d'\u00e9v\u00e8nements, et augmenter la testabilit\u00e9 du code.\n\n## Open Closed\n\nUn des principes essentiels en POO est l'h\u00e9ritage de classes et la surcharge de m\u00e9thodes: plut\u00f4t que de partir sur une s\u00e9rie de comparaisons pour d\u00e9finir le comportement d'une instance, il est parfois pr\u00e9f\u00e9rable de d\u00e9finir une nouvelle sous-classe, qui surcharge une m\u00e9thode bien pr\u00e9cise. Pour l'exemple, on pourrait ainsi d\u00e9finir trois classes:\n\n * Une classe `Customer`, pour laquelle la m\u00e9thode `GetDiscount` ne renvoit rien;\n * Une classe `SilverCustomer`, pour laquelle la m\u00e9thode revoit une r\u00e9duction de 10%; \n * Une classe `GoldCustomer`, pour laquelle la m\u00eame m\u00e9thode renvoit une r\u00e9duction de 20%.\n\nSi on rencontre un nouveau type de client, il suffit alors de cr\u00e9er une nouvelle sous-classe. Cela \u00e9vite d'avoir \u00e0 g\u00e9rer un ensemble cons\u00e9quent de conditions dans la m\u00e9thode initiale, en fonction d'une autre variable (ici, le type de client).\n\nEn anglais, dans le texte : \"Putting in simple words the \u201cCustomer\u201d class is now closed for any new modification but it\u2019s open for extensions when new customer types are added to the project.\". En r\u00e9sum\u00e9: on ferme la classe `Customer` \u00e0 toute modification, mais on ouvre la possibilit\u00e9 de cr\u00e9er de nouvelles extensions en ajoutant de nouveaux types [h\u00e9ritant de `Customuer`].\n\n## Liskov Substitution\n\nLe principe de substitution fait qu'une classe B qui h\u00e9rite d'une classe A doit se comporter de la m\u00eame mani\u00e8re que cette derni\u00e8re. Il n'est pas question que la classe B n'impl\u00e9mente pas certaines m\u00e9thodes, alors que celles-ci sont disponibles pour A.\n\n> [...] if S is a subtype of T, then objects of type T in a computer program may be replaced with objects of type S (i.e., objects of type S may be substituted for objects of type T), without altering any of the desirable properties of that program (correctness, task performed, etc.). (Source: [Wikip\u00e9dia](http://en.wikipedia.org/wiki/Liskov_substitution_principle)).\n\n> Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S, where S is a subtype of T. (Source: [Wikip\u00e9dia aussi](http://en.wikipedia.org/wiki/Liskov_substitution_principle))\n\nCe principe s'applique \u00e0 tout type de polymorphisme, et m\u00eame aux langages de type *duck typing*: \"when I see a bird that quacks like a duck, walks like a duck, has feathers and webbed feet and associates with ducks\u2014I\u2019m certainly going to assume that he is a duck\" (Source: [Wikipedia (as usual)](http://en.wikipedia.org/wiki/Duck_test)). Pour le cas \u00e9mis ci-dessus, ce n'est donc parce qu'une classe a besoin **d'une m\u00e9thode** d\u00e9finie dans une autre classe qu'elle doit forc\u00e9ment en h\u00e9riter. Cela bousillerait le principe de substitution (et par la m\u00eame occasion le *duck test*).\n\n## Interface Segregation\n\nCe principe stipule qu'un client ne peut en aucun cas d\u00e9pendre d'une m\u00e9thode dont il n'a pas besoin. Plus simplement, plut\u00f4t que de d\u00e9pendre d'une seule et m\u00eame (grosse) interface pr\u00e9sentant un ensemble cons\u00e9quent de m\u00e9thodes, il est propos\u00e9 d'exploser cette interface en plusieurs (plus petites) interfaces. Ceci permet aux diff\u00e9rents clients de n'utiliser qu'un sous-ensemble pr\u00e9cis d'interfaces, r\u00e9pondant chacune \u00e0 un besoin particulier.\n\nL'exemple par d\u00e9faut est d'avoir une interface permettant d'acc\u00e9der \u00e0 des \u00e9l\u00e9ments. Modifier cette interface pour permettre l'\u00e9criture impliquerait que toutes les applications ayant d\u00e9j\u00e0 acc\u00e8s \u00e0 la premi\u00e8re, obtiendraient (par d\u00e9faut) un acc\u00e8s en \u00e9criture, ce qui n'est pas souhait\u00e9/souhaitable.\n\nPour contrer ceci, on aurait alors une premi\u00e8re interface permettant la lecture, tandis qu'une deuxi\u00e8me (h\u00e9ritant de la premi\u00e8re) permettrait l'\u00e9criture. On aurait alors le sch\u00e9ma suivant :\n\n * A : lecture\n * B (h\u00e9ritant de A) : lecture (par A) et \u00e9criture.\n\n## Dependency inversion\n\nDans une architecture conventionnelle, les composants de haut-niveau d\u00e9pendant directement des composants de bas-niveau. Une mani\u00e8re tr\u00e8s simple d'impl\u00e9menter ceci est d'instancier un nouveau composant. L'inversion de d\u00e9pendances stipule que c'est le composant de haut-niveau qui poss\u00e8de la d\u00e9finition de l'interface dont il a besoin, et le composant de bas-niveau qui l'impl\u00e9mente.\n\nLe composant de haut-niveau peut donc d\u00e9finir qu'il s'attend \u00e0 avoir un `Publisher` pour publier du contenu vers un emplacement particulier. Plusieurs impl\u00e9mentation de cette interface peuvent alors \u00eatre mise en place:\n\n * Une publication par SSH\n * Une publication par FTP\n * Une publication\n * ...\n\nL'injection de d\u00e9pendances est un patron de programmation qui suit le principe d'inversion de d\u00e9pendances.\n\n## Sources\n\n * [Understanding SOLID principles on CodeProject](http://www.codeproject.com/Articles/703634/SOLID-architecture-principles-using-simple-Csharp)\n * [Software Craftmanship](http://en.wikipedia.org/wiki/Software_craftsmanship)\n * [Dependency Injection is NOT the same as dependency inversion](http://lostechies.com/derickbailey/2011/09/22/dependency-injection-is-not-the-same-as-the-dependency-inversion-principle/)\n * [Injection de d\u00e9pendances](http://en.wikipedia.org/wiki/Dependency_injection)\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-02-09",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: D\u00e9finition du lien actif avec Django et un templatetag\nDate: 2016-02-19\nSlug: django-definition-lien-actif-menu\nTags: django, templatetag, dev, web\n---\n\nPour que l'utilisateur ne se perde pas trop dans l'application, il est n\u00e9cessaire qu'il ait des rep\u00e8res correctement d\u00e9finis. Que le menu principal ait toujours la m\u00eame structure, et que le lien dans le menu sur lequel il vient de cliquer soit mis en gras, par exemple. Avec Django, on peut utiliser les [templatetags](https://docs.djangoproject.com/en/1.10/ref/templates/), de la mani\u00e8re suivante:\n\n 1. On d\u00e9finit un nouveau `templatetag` dans un fichier `tools/menuitems.py`. Il doit prendre le contexte actuel en param\u00e8tre (`takes_context=True`) et regarder si le lien qu'on lui demande de construire est identique \u00e0 l'URL actuelle.\n 2. Ajoutez l'application `tools` (ou quel que soit le nom que vous lui aurez donn\u00e9) dans les `INSTALLED_APPS`, dans le fichier de configuration.\n 3. Dans le template, il suffit d'importer le package d\u00e9fini ci-dessus et d'utiliser la nouvelle fonction lorsqu'on construit un lien.\n\n## D\u00e9finition du template tag\n\n```python\n# tools/menuitems.py\n\nfrom django import template\n\nregister = template.Library()\n\n@register.simple_tag(takes_context=True)\ndef menuitem(context, url, title):\n\tif context.request.path == url:\n\t\treturn '<li class=\"active\"><a href=\"' + url + '\">' + title + '</a></li>'\n\telse:\n\t\treturn '<li><a href=\"' + url + '\">' + title + '</a></li>\u2019\n```\n\n## D\u00e9finition du template\n\n```django\n<!-- templates/file.html -->\n\n{% load menuitems %}\n\n<ul>\n {% menuitem '/' 'Overview' %}\n {% menuitem '/gymnast/' 'Gymnasts' %}\n {% menuitem '/routines/' 'Routines' %}\n</ul>\n```\n\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-02-19",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Un site multilingue avec Pelican\nDate: 2016-04-22\nSlug: multilingual-site-with-pelican\nTags: pelican, dev, static, site, web\n---\n\nPour un petit projet perso, on m'a demand\u00e9 de d\u00e9velopper un petit site de location de chambres. En soi, j'aurais pu simplement cr\u00e9er quelques pages HTML statiques, copier le tout sur un serveur et le tour aurait \u00e9t\u00e9 jou\u00e9. Il y avait cependant quelques contraintes \u00e0 prendre en compte:\n\n * Besoin d'un site multilangues (en, fr, nl)\n * Besoin d'une gallerie d'images, une gallerie devant \u00eatre associ\u00e9e \u00e0 une page.\n * Besoin d'une carte, pour pr\u00e9senter les choses int\u00e9ressantes \u00e0 voir dans le quartier.\n * Et beaucoup de discussions, pour arriver \u00e0 un r\u00e9sultat convaincant.\n\nIl me fallait quelque chose de flexible, permettant de g\u00e9rer facilement les images, de mettre le texte en forme, de g\u00e9rer l'affichage des informations, ... Le tout, sans que cela ne prenne trop de temps. \n\nEn parcourant les diff\u00e9rents CMS existants, je me suis rendu compte qu'il existait assez peu de solutions autorisant ces trois contraintes nativement. [Wordpress](https://wordpress.org/) le permet, mais seulement gr\u00e2ce \u00e0 l'installation de plusieurs plugins; [Drupal](https://www.drupal.org/) me semblait trop compliqu\u00e9 \u00e0 appr\u00e9hender; [PluXML](http://www.pluxml.org/) n\u00e9cessiterait sans doute trop de param\u00e9trage, ... Celle qui m'aurait le plus bott\u00e9 \u00e9tait [Wagtail](https://wagtail.io/), mais le temps fait (un peu) d\u00e9faut pour le moment... En gros, j'avais le choix entre les deux solutions suivantes:\n\n 1. Un vrai CMS dynamique, o\u00f9 mon utilisateur ador\u00e9 pourrait se d\u00e9brouiller tout seul. Il aurait alors fallu renforcer la s\u00e9curit\u00e9, configurer la base de donn\u00e9es, configurer les backups, v\u00e9rifier la coh\u00e9rence des donn\u00e9es au restore, le former \u00e0 la manipulation des donn\u00e9es et aux traductions\n 2. Ou alors, partir sur un site statique pr\u00e9sentant les informations de mani\u00e8re fixe, n\u00e9cessitant relativement peu de param\u00e9trage, mais l'obligeant \u00e0 me contacter pour toute modification.\n\nPuisqu'on parle d'une personne (tr\u00e8s) proche, je suis parti sur la seconde option. Et puisqu'on parle d'un site statique, je suis parti sur [Pelican](docs.getpelican.com/).\n\n## Multilinguisme\n\nPour g\u00e9rer un site multilangue, il y a deux solutions:\n\n 1. Soit utiliser les m\u00e9tadonn\u00e9es `lang` et `slug` dans chaque article/page. Cette solution ne convient qu'\u00e0 moiti\u00e9, car la langue principale du site reste inchang\u00e9e, quelle que soit l'entr\u00e9e sur laquelle l'utilisateur se trouve: si le visiteur clique sur un lien, il arrivera donc sur la page traduite dans la langue par d\u00e9faut, mais s'il se trouvait sur une page traduite dans une autre langue. Ce qu'on souhaite, c'est que le site soit en fait un sous-site du site principal, avec sa langue sp\u00e9cifique: en traduisant la page dans une langue, on *resterait* dans cette langue-ci.\n 2. Soit utiliser le plugin `i18n_subsites`, qui permet de d\u00e9finir un site principale (bas\u00e9 sur une langue), puis un ensemble de sous-sites, chacun d'entre eux correspondant \u00e0 une langue.\n\nEn gros, la structure devient la suivante:\n\n```\npages/\n en/\n page1.md\n page2.md\n fr/\n page1.md\n page2.md\n nl/\n page1.md\n page2.md\n```\n\nCeci colle d\u00e9j\u00e0 plus \u00e0 ce que l'on souhaite. Pour activer le plugin, il suffit de cloner le d\u00e9p\u00f4t [pelican-plugins](https://github.com/getpelican/pelican-plugins.git) (ou de copier le plugin dans un sous-r\u00e9pertoire de l'installation, \u00e0 la hussarde). Attention qu'on trouve quelques probl\u00e8mes de compatibilit\u00e9 entre greffons: `i18n_subsites` pose plus ou moins probl\u00e8me avec le plugin `gallery` si des images d'albums diff\u00e9rents portent le m\u00eame nom.\n\n## Gallerie d'images\n\nPour la gallerie d'images, je suis parti des plugins `gallery` et `thumbnailer`. Le premier permet de cr\u00e9er une gallerie et y copiant un ensemble de photos; le second permet de cr\u00e9er des thumbnails pour chacune des images (au format *square*, *wide* ou *cropped*). Dans chaque page, j'ajoute une m\u00e9tadonn\u00e9e `gallery: `, qui indique le nom du r\u00e9pertoire dans lequel les images doivent \u00eatre r\u00e9cup\u00e9r\u00e9es. Dans le template (\u00e9galement fix\u00e9 au niveau des propri\u00e9t\u00e9s de la page), on peut alors parcourir les diff\u00e9rentes images et les afficher. En associant ce m\u00e9canisme avec un plugin [Lightbox pour jQuery](http://lokeshdhakar.com/projects/lightbox2/), on peut ainsi charger les miniatures \u00e0 l'affichage, et pr\u00e9senter l'image originelle lorsque l'utilisateur cliquera sur le thumbnail.\n\n```\n{% for image in page.galleryimages %}\n <a class=\"thumbnail\" data-lightbox=\"pictures-set\" href=\"/pictures/gallery/{{page.album}}/{{ image }}\">\n <img class=\"img-thumbnail img-responsive\" src=\"/thumbnails/thumbnail_wide/{{ image }}\" alt=\"\">\n </a>\n{% endfor %}\n```\n\n## Index\n\nLa page d'accueil est fix\u00e9e et ne se base pas sur du contenu. Je l'ai configur\u00e9e directement au niveau du th\u00e8me. \nLa navigation pour l'utilisation est la suivante: lorsqu'il se connecte au site, il arrive sur la page d'accueil - quelques images, menu en anglais par d\u00e9faut. Il peut alors s\u00e9lectionner une langue, ce qui l'enverra vers la page `{lang}/index.html`. Cette page-ci correspond \u00e0 du contenu r\u00e9dig\u00e9 en Markdown, dans lequel on trouve les m\u00e9tadonn\u00e9es suivantes: \n\n```\nTitle: Around us\nSlug: index\nLang: en\nTranslation: true\nTemplate: pagewithmap\nGallery: brussels\n```\n\nA priori, toutes les propri\u00e9t\u00e9s sp\u00e9cifi\u00e9es ont une utilis\u00e9: \n\n * Le titre est utilis\u00e9 dans le template et dans les menus de navigation\n * Le slug permet d'overrider le nom du fichier (mais on aurait aussi pu passer par la propri\u00e9t\u00e9 `save_as`). Il s'agit aussi de la cl\u00e9 qui associera tous les contenus ayant le m\u00eame `slug`.\n * La propri\u00e9t\u00e9 `Lang` d\u00e9finit la langue\n * Le `template` permet d'associer la pr\u00e9sentation \u00e0 une page HTML sp\u00e9cifique. Celle-ci est plac\u00e9e dans le r\u00e9pertoire `themes/{theme_name}/templates/pagewithmap.html`.\n * La propri\u00e9t\u00e9 `gallery` est utilis\u00e9e par le plugin `gallery` que l'on a charg\u00e9 plus haut. Celui-ci va charger toutes les images qui se trouvent dans le r\u00e9pertoire `pictures/gallery/{gallery_name}/`.\n \n## A am\u00e9liorer\n \n Plut\u00f4t que d'avoir des pages statiques, toutes li\u00e9es \u00e0 un template, j'aurais appr\u00e9ci\u00e9 pouvoir structurer mes donn\u00e9es dans des blocs. Par exemple, dans une page, j'aurais pu avoir un bloc `description`, un bloc `comment nous joindre`, un bloc `prix`, ... A r\u00e9p\u00e9ter dans les diff\u00e9rentes langues. [Wagtails](https://wagtail.io/) le permet (et c'est m\u00eame son mode de structuration par d\u00e9faut - \u00e0 coupler avec [Django Medusa](https://github.com/mtigas/django-medusa)). Je crois [Hyde](https://hyde.github.io/) fonctionne un peu selon le m\u00eame principe, avec l'avantage qu'il g\u00e9n\u00e8re par d\u00e9faut du contenu statique. En fait, il y a des propri\u00e9t\u00e9s globales au site que j'aurais aim\u00e9 pouvoir d\u00e9finir (dans les diff\u00e9rentes langues :-)) et r\u00e9utiliser \u00e0 des endroits pr\u00e9cis. \n \n En m\u00eame temps, j'aurais aim\u00e9 pouvoir associer plusieurs galleries d'images \u00e0 une m\u00eame page. Le plugin `gallery` ne permet d'associer qu'un r\u00e9pertoire; il ne g\u00e8re pas les sous-r\u00e9pertoires (la m\u00e9thode utilis\u00e9e est un `listdir` et pas un `walk` - et cela impliquerait de modifier la structure de retour pour associer le nom du sous-r\u00e9pertoire aux images, en plus du r\u00e9pertoire initial). ",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-04-22",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: An introduction to programming in Go\nDate: 2016-05-10\nTags: ebook, go\nImage: book/an-introduction-to-programming-in-go.jpg\nSlug: an-introduction-to-programming-in-go\n---\n\n[Go](https://golang.org/) est un langage relativement \u00e0 la mode. Il est parfois pr\u00e9sent\u00e9 comme une \u00e9volution du langage [Python](https://www.python.org/), parfois comme un subset aux langages C/C++. Avant de vous faire un avis tranch\u00e9, essayez-le. Il pr\u00e9sente de tr\u00e8s bonnes id\u00e9es, tout en restant relativement *low-level*.\n\nLe livre que je viens de terminer s'intitule [An introduction to programming in Go](http://www.golang-book.com/books/intro) (disponible gratuitement \u00e0 l'adresse ci-contre) et reprend les bases du langages. Les premiers chapitres sont d'ailleurs vraiment accessibles.\n\n> A short, concise introduction to computer programming using the language Go. Designed by Google, Go is a general purpose programming language with modern features, clean syntax and a robust well-documented common library, making it an ideal language to learn as your first programming language.\n\nLes premiers chapitres donnent un aper\u00e7u extr\u00eamement basique du langage (installation, utilisation du terminal, d\u00e9claration de variables, les conditions, boucles, ...). Le chapitre 5 devient r\u00e9ellement int\u00e9ressant, avec les fonctions, *go-routine*, gestion des threads et de la concurrence.\n\nUne des applications qui m'a un peu tap\u00e9 dans l'oeil, c'est [Gogs](https://gogs.io/): il s'agit d'une interface Web de gestion de d\u00e9p\u00f4ts [Git](https://git-scm.com/). En cherchant un peu, on trouve pas mal d'autres exemples qui ont l'air int\u00e9ressants:\n\n * [Macaron](https://go-macaron.com/), *a high productive and modular web framework in Go*.\n * [Peach](https://peachdocs.org/), *a web server for multi-language, real-time synchronization and searchable documentation*.\n * [XORM](https://github.com/go-xorm/xorm) comme ORM.\n\nBref, \u00e0 l'occasion. Le PDF vaut clairement le coup et s'avale assez rapidement (165 pages au garot).\n\nProchains livres \u00e0 lire (ou d\u00e9j\u00e0 en cours): [Why Rust?](http://www.oreilly.com/programming/free/why-rust.csp) et [Enterprise Pharo](http://files.pharo.org/books/enterprise-pharo/) :) .",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-05-10",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Regex cheat sheet\nStatus: draft\n\n---\n\nJuste un m\u00e9mo pour ce qui touche aux expressions r\u00e9guli\u00e8res. Je ne sais plus exactement d'o\u00f9 proviennent les informations ci-dessous, par contre...\n\n * http://regexr.com/\n * [Regex tester and debugger online](http://www.regextester.com/)\n\n\n\n+----------+-----------------------------+\n|`.` + any character except newline|\n+----------+-----------------------------+\n|`\\w \\d \\s`+word, digit, whitespace |\n+----------+-----------------------------+\n|`\\W \\D \\S`+ not word, digit, whitespace |\n+----------+-----------------------------|\n\n[abc] \t any of a, b, or c\n[^abc] \t not a, b, or c\n[a-g] \t character between a & g\n```\n\nAnchors\n-------\n```\n^abc$ \t start / end of the string\n\\b \t word boundary\n```\n\nEscaped characters\n------------------\n```\n\\. \\* \\\\ \t escaped special characters\n\\t \\n \\r \t tab, linefeed, carriage return\n\\u00A9 \t unicode escaped \u00a9\n```\n\nGroups & Lookaround\n-------------------\n```\n(abc) \t capture group\n\\1 \t backreference to group #1\n(?:abc) \t non-capturing group\n(?=abc) \t positive lookahead\n(?!abc) \t negative lookahead\n```\n\nQuantifiers & Alternation\n-------------------------\n```\na* a+ a? \t 0 or more, 1 or more, 0 or 1\na{5} a{2,} exactly five, two or more\na{1,3} \t between one & three\na+? a{2,}? match as few as possible\nab|cd \t match ab or cd\n```\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-06-03",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Extraction de donn\u00e9es en CSV avec PSQL\nDate: 2015-06-23\nSlug: extract-data-as-csv-with-psql\nTags: db, sql, psql, csv, extract\n---\n\nPour copier des r\u00e9sultats chop\u00e9s depuis une commande `psql`, la syntaxe est relativement simple quand elle est d\u00e9compos\u00e9e. En gros, la commande ressemble \u00e0 ceci:\n\n```\n$ psql -c \"\\copy (<ma_requ\u00eate>) to <output_file> DELIMITER E'\\t' CSV HEADER;\" <db_user> <db_password>\n```\n\nCe qui signifie plus prosa\u00efquement:\n\n> Cher PSQL, copie-moi les r\u00e9sultats de `<ma_requ\u00eate>` vers le fichier `<output_file>`, en utilisant une tabulation pour s\u00e9parer les champs (tu peux inclure le `HEADER`, merci). Pour la connexion, tu peux utiliser `<db_user>` et `<db_password>`. Bisous.\n\nLe script complet (en `.bat`), avec un fichier de sortie timestamp\u00e9.\n\n```\n@echo off\nset output_dir=\"C:\\Extracts\"\nset db_host=localhost\nset db_user=postgres\nset db_name=db_name\nset db_passwd=db_password\nset psql_dir=\"C:\\PSQL\\9.2\\bin\"\n\nfor /f \"tokens=1-3 delims=/ \" %%i in (\"%date%\") do (\n set day=%%i\n set month=%%j\n set year=%%k\n)\n\nfor /f \"tokens=1-3 delims=: \" %%l in (\"%time%\") do (\n set hour=%%l\n set min=%%m\n)\n\nset datestr=%year%%month%%day%_%hour%_%min%\n\nset output_file=%output_dir%_%datestr%.list.txt\n\nSET PGPASSWORD=%db_passwd%\n\n%psql_dir%\\psql -c \"\\copy (Select SubscriberId, LastName, FirstName From subscriber) to '%output_file%' DELIMITER E'\\t' CSV HEADER;\" %db_user% %db_passwd%\n```",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-06-23",
"title": "---"
},
{
"category": "dev",
"content": "Int\u00e9gration continue avec Gitlab\n================================\n\nJ'ai r\u00e9cemment cr\u00e9\u00e9 un nouveau projet sur [Framagit](https://framagit.org/Grimbox/heima), qui propose une des derni\u00e8res versions de [Gitlab](https://about.gitlab.com/), avec son [module d'int\u00e9gration continue](https://about.gitlab.com/gitlab-ci/). Cela devient juste super facile de mettre un process d'int\u00e9gration continue sur son projet :-)\n\nPour mon projet Django, j'ai ajout\u00e9 deux d\u00e9pendances (bon, trois, avec Django): `coverage` et `django_coverage_plugin` dans un fichier `requirements/dev.txt`:\n\n```shell\n# requirements/base.txt\ndjango\n```\n\n```shell\n# requirements/dev.txt\n-r base.txt\ncoverage\ndjango_coverage_plugin\n```\n\nOn cr\u00e9e ensuite un fichier `.gitlab-ci.yml` \u00e0 la racine du projet, avec le contenu suivant:\n\n```shell\nbefore_script:\n - pip install -r requirements/dev.txt\n\ntest:python-3.4:\n stage: test\n image: python:3.4-slim\n script:\n - coverage run src/manage.py test sherlock\n - coverage report -m\n```\n\nLes param\u00e8tres importants sont:\n\n * L'`image` qui sp\u00e9cifie l'image [Docker](https://hub.docker.com/_/python/) \u00e0 utiliser (sans quoi les binaires `python` ne seront par exemple pas disponible). En fonction du langage utilis\u00e9, choisissez [une autre image](https://hub.docker.com/).\n * Et la partie `script`. Ici, `sherlock` est le nom de mon application Django; elle se situe dans le sous-r\u00e9pertoire `src/`.\n\n## En bonus\n\nPour avoir le pourcentage de couverture de code, ajoutez, dans les param\u00e8tres du projet, la valeur `\\d+\\%\\s*$` \u00e0 l'option `test coverage parsing`.\n\nAu niveau du fichier `README.md`, ajoutez le contenu suivant: `[![build status](https://framagit.org/Grimbox/heima/badges/master/build.svg)](https://framagit.org/Grimbox/heima/commits/master)`\n\n## R\u00e9sultat\n\nR\u00e9sultat, les d\u00e9pendances sont install\u00e9es, les tests sont lanc\u00e9s et la couverture de code indique un pourcentage qui est chop\u00e9e au passage par la regex ci-dessus. Magique. Petit badge de r\u00e9ussite sur la page d'accueil, couverture de code indiqu\u00e9e sur les tests, tout va bien.\n\n```shell\nRunning with gitlab-ci-multi-runner 1.4.1 (fae8f18)\nUsing Docker executor with image python:3.4-slim ...\nPulling docker image python:3.4-slim ...\nRunning on runner-ed7dbd37-project-7675-concurrent-0 via ruth...\nFetching changes...\nHEAD is now at ff9e6aa add coverage\nFrom https://framagit.org/Grimbox/heima\n+ ff9e6aa...aaf716d master -> origin/master (forced update)\nChecking out aaf716d6 as master...\n$ pip install -r requirements/dev.txt\nCollecting django (from -r requirements/base.txt (line 1))\nDownloading Django-1.10-py2.py3-none-any.whl (6.8MB)\nCollecting coverage (from -r requirements/dev.txt (line 2))\nDownloading coverage-4.2.tar.gz (359kB)\nCollecting django_coverage_plugin (from -r requirements/dev.txt (line 3))\nDownloading django_coverage_plugin-1.3.1.tar.gz\nCollecting six>=1.4.0 (from django_coverage_plugin->-r requirements/dev.txt (line 3))\nDownloading six-1.10.0-py2.py3-none-any.whl\nInstalling collected packages: django, coverage, six, django-coverage-plugin\nRunning setup.py install for coverage: started\n Running setup.py install for coverage: finished with status done\nRunning setup.py install for django-coverage-plugin: started\n Running setup.py install for django-coverage-plugin: finished with status done\nSuccessfully installed coverage-4.2 django-1.10 django-coverage-plugin-1.3.1 six-1.10.0\n$ coverage run src/manage.py test sherlock\n....\n----------------------------------------------------------------------\nRan 4 tests in 0.024s\n\nOK\nCreating test database for alias default...\nDestroying test database for alias default...\n\n$ coverage report -m\nName Stmts Miss Cover Missing\n-----------------------------------------------------------------------\nsrc/heima/__init__.py 0 0 100%\nsrc/heima/settings.py 18 0 100%\nsrc/manage.py 13 6 54% 9-21\nsrc/sherlock/__init__.py 0 0 100%\nsrc/sherlock/admin.py 8 0 100%\nsrc/sherlock/migrations/0001_initial.py 7 0 100%\nsrc/sherlock/migrations/__init__.py 0 0 100%\nsrc/sherlock/models.py 18 0 100%\nsrc/sherlock/tests.py 30 0 100%\n-----------------------------------------------------------------------\nTOTAL 94 6 94%\nBuild succeeded\n\n```\n\n## Int\u00e9gration avec Flake8\n\n[Update du 08/08/2016]\n\nToujours dans la m\u00eame veine, on peut pousser l'int\u00e9gration avec [Flake8](2015-08-19-pep8.md). Il suffit d'ajouter `flake8` dans les pr\u00e9requis, ainsi qu'un fichier `.tox.ini` dans lequel on trouvera le contenu suivant:\n\n```shell\n[flake8]\nmax-line-length = 100\nexclude = migrations, manage.py\n```\n\nOn modifie ensuite le fichier `.gitlab-ci.yml` pour y ajouter l'int\u00e9gration `flake8`:\n\n```shell\nbefore_script:\n- pip install -r requirements/dev.txt\n\ntest:python-3.4:\n stage: test\n image: python:3.4-slim\n script:\n - flake8 src/\n - coverage run src/manage.py test sherlock\n - coverage report -m\n```\n\nAttention que si `flake8` renvoie le moindre avertissement, l'int\u00e9gration continue du projet passera en **failed**.\n\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-08-05",
"title": "Int\u00e9gration continue avec Gitlab"
},
{
"category": "dev",
"content": "---\nTitle: Un client SOAP en Python avec Suds\nDate: 2016-08-23\nTags: python, soap, suds, wcf\n---\n\nLa mani\u00e8re la plus simple que j'ai trouv\u00e9e pour contacter un serveur SOAP (WCF) avec un client Python, est de passer par [Suds](https://fedorahosted.org/suds/wiki/Documentation). Apr\u00e8s avoir contact\u00e9 le serveur, cette librairie construit dynamiquement les diff\u00e9rentes m\u00e9thodes directement sur le service client. Si par exemple le service sur le serveur expose les m\u00e9thodes `RunQuery` et `Execute`, vous pourrez directement les invoquer *via* `client.service.RunQuery` et `client.service.Execute`.\n\nAttention que la version officielle n'est compatible qu'avec Python2. Pour une compatibilit\u00e9 avec Python3, il existe [suds-py3](https://github.com/cackharot/suds-py3). Les deux sont disponibles sur [Pypi](https://pypi.python.org/pypi), et installable avec `pip`.\n\nLa seule difficult\u00e9 a \u00e9t\u00e9 de construire les param\u00e8tres. Comme les param\u00e8tres XML peuvent \u00eatre beaucoup plus complexes que les param\u00e8tres en [JSON](http://json.org/) (ie. *string, number, object, array, bool ou nul*), il vous faudra [construire ces param\u00e8tres](https://fedorahosted.org/suds/wiki/Documentation#ComplexArguments) en passant par une `factory`:\n\n```python\nfrom suds.client import Client\n\nwsdl = 'http://localhost:88/WebService.svc?wsdl'\n\nclient = Client(wsdl)\nprint(client)\n\nSuds ( https://fedorahosted.org/suds/ ) version: 1.3.2.0 IN build: 20160428\n\nService ( HAWWebService )\n tns=\"http://tempuri.org/\"\n Prefixes (4)\n ns0 = \"http://schemas.datacontract.org/2004/07/ImagoInboxWebService.Requests\"\n ns1 = \"http://schemas.datacontract.org/2004/07/ImagoInboxWebService.ResponseBase\n ns2 = \"http://schemas.microsoft.com/2003/10/Serialization/\"\n ns3 = \"http://tempuri.org/\"\n\n Ports (1):\n (BasicHttpBinding_IHAWWebService)\n Methods (1):\n RunQuery(ns0:RequestRunQuery request,)\n Types (7):\n ns0:RequestBase\n ns0:RequestRunQuery\n ns1:ResponseBase\n ns1:ResponseRunQuery\n ns2:char\n ns2:duration\n ns2:guid\n```\n\nDans l'exemple ci-dessus, on voit qu'il y a une m\u00e9thode `RunQuery`, qui prend un param\u00e8tre de type `ns0:RequestRunQuery` (ou, plus pr\u00e9cis\u00e9ment, un param\u00e8tre de type `http://schemas.datacontract.org/2004/07/ImagoInboxWebService.Requests.RequestRunQuery`. Pour instancier cet objet, il y a deux mani\u00e8res de faire, la seconde \u00e9tant sans doute pr\u00e9f\u00e9rable:\n\n```python\nparam1 = client.factory.create('ns0:RequestRunQuery')\nparam2 = client.factory.create('{http://schemas.datacontract.org/2004/07/ImagoInboxWebService.Requests}RequestRunQuery')\n```\n\nApr\u00e8s, cela on envoie les param\u00e8tres correctement construits dans la m\u00e9thode d'appel, et on r\u00e9cup\u00e8re le r\u00e9sultat:\n\n```python\nresponse = client.service.RunQuery(param2)\nprint(response)\n```",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-08-23",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Building Maintainable Software\nDate: 2016-09-12\nTags: ebook, software, maintenance\nImage: book/building-maintainable-software.jpg\nSlug: building-maintainable-software\n---\n\nEn profitant d'une petite promo de -50% chez [O'Reilly](http://www.oreilly.com/>), je me suis offert l'ebook [Building Maintainable Software, \u00e9dition C-Tartine](http://shop.oreilly.com/product/0636920049555.do). Le livre propose de suivre une s\u00e9rie de pr\u00e9ceptes permettant d'am\u00e9liorer la qualit\u00e9 du code produit. Bien que le contenu ressemble parfois plus \u00e0 une grosse page marketing pour le [Software Improvment Group](https://www.sig.eu/nl/), il reste int\u00e9ressant et vaut le coup d'\u00eatre lu. Deux petits probl\u00e8mes par contre:\n\n 1. On part parfois d'un cas concret (qui ressemble parfois \u00e0 ce que j'ai pu commettre de code foireux), en prenant une m\u00e9thode dans laquelle on trouve plusieurs concepts diff\u00e9rents (appel \u00e0 la db, cast vers une classe type *DTO*, validation d'input). Juste apr\u00e8s, on passe directement sur un autre exemple, beaucoup plus simple \u00e0 r\u00e9soudre.\n 2. J'ai l'impression que cela parle plus de th\u00e9orie, sans proposer de solution automatique, ce qui rejoint un peu ce que je disais au niveau marketing: \"si vous voulez vous am\u00e9liorer, signez chez nous!\".\n\nLes principaux conseils sont les suivants (pour les d\u00e9tails, il vous faudra acheter le bouquin :) ):\n\n## Au niveau des m\u00e9thodes\n\n * Gardez vos m\u00e9thodes/fonctions courtes. Pas plus de 15 lignes, en comptant les commentaires. Des exceptions sont possibles, mais dans une certaine mesure uniquement (pas plus de 6.9% de plus de 60 lignes; pas plus de 22.3% de plus de 30 lignes, au plus 43.7% de plus de 15 lignes et au moins 56.3% en dessous de 15 lignes). Oui, c'est dur \u00e0 tenir, mais faisable.\n * Conserver une complexit\u00e9 de McCabe en dessous de 5, c'est-\u00e0-dire avec quatre branches au maximum. A nouveau, si on a une m\u00e9thode avec une complexit\u00e9 cyclomatique de 15, la s\u00e9parer en 3 fonctions avec une complexit\u00e9 de 5 conservera globalement le nombre 15, mais rendra le code de chacune de ces m\u00e9thodes plus lisible, plus maintenable.\n * N'\u00e9crivez votre code qu'une seule fois: \u00e9vitez les duplications, copie, etc., c'est juste mal: imaginez qu'un bug soit d\u00e9couvert dans une fonction; il devra alors \u00eatre corrig\u00e9 dans toutes les fonctions qui auront \u00e9t\u00e9 copi\u00e9es/coll\u00e9es. C'est aussi une forme de r\u00e9gression.\n* Conservez de petites interfaces. Quatre param\u00e8tres, pas plus. Au besoin, refactorisez certains param\u00e8tres dans une classe, plus facile \u00e0 tester.\n\n## Au niveau des classes\n\n * Privil\u00e9giez un couplage faible entre vos classes. Ceci n'est pas toujours possible, mais dans la mesure du possible, \u00e9clatez vos classes en fonction de leur domaine de comp\u00e9tences. L'impl\u00e9mentation du service ``UserNotificationsService`` ne doit pas forc\u00e9ment se trouver embarqu\u00e9 dans une classe ``UserService``. De m\u00eame, pensez \u00e0 passer par une interface (commune \u00e0 plusieurs classes), afin d'ajouter une couche d'abstraction. La classe appellante n'aura alors que les m\u00e9thodes offertes par l'interface comme points d'entr\u00e9e.\n\n## Au niveau des composants\n\n * Tout comme pour les classes, il faut conserver un couplage faible au niveau des composants \u00e9galement. Une mani\u00e8re d'arriver \u00e0 ce r\u00e9sultat est de conserver un nombre de points d'entr\u00e9e restreint, et d'\u00e9viter qu'on ne puisse contacter trop facilement des couches s\u00e9par\u00e9es de l'architecture. Pour une architecture n-tiers par exemple, la couche d'abstraction \u00e0 la base de donn\u00e9es ne peut \u00eatre connue que des services; sans cela, au bout de quelques semaines, n'importe quelle couche de pr\u00e9sentation risque de contacter directement la base de donn\u00e9es, \"juste parce qu'elle en a la possibilit\u00e9\". Vous pourrez \u00e9galement passer par des interfaces, afin de r\u00e9duire le nombre de points d'entr\u00e9e connus par un composant externe (qui ne conna\u00eetra par exemple que `IFileTransfer` avec ses m\u00e9thodes `put` et `get`, et non pas les d\u00e9tails d'impl\u00e9mentation complet d'une classe `FtpFileTransfer` ou `SshFileTransfer`).\n * Conserver un bon balancement au niveau des composants: \u00e9vitez qu'un composant **A** ne soit un \u00e9norme mastodonte, alors que le composant juste \u00e0 c\u00f4t\u00e9 n'est capable que d'une action. De cette mani\u00e8re, les nouvelles fonctionnalit\u00e9s seront mieux r\u00e9parties parmi les diff\u00e9rents syst\u00e8mes, et les responsabilit\u00e9s plus faciles \u00e0 g\u00e9rer. Un conseil est d'avoir un nombre de composants compris entre 6 et 12 (id\u00e9alement, 12), et que ces composants soit approximativement de m\u00eame taille.\n\n## Et de mani\u00e8re plus g\u00e9n\u00e9rale\n\n * Conserver une densit\u00e9 de code faible: il n'est \u00e9videmment pas possible d'impl\u00e9menter n'importe quelle nouvelle fonctionnalit\u00e9 en moins de 20 lignes de code; l'id\u00e9e ici est que la r\u00e9\u00e9criture du projet ne prenne pas plus de 20 hommes/mois. Pour cela, il faut (activement) passer du temps \u00e0 r\u00e9duire la taille du code existant: soit en faisant du refactoring (intensif?), soit en utilisant des librairies existantes, soit en explosant un syst\u00e8me existant en plusieurs sous-syst\u00e8mes communiquant entre eux. Mais surtout en \u00e9vitant de copier/coller b\u00eatement du code existant.\n * Automatiser les tests, ajouter un environnement d'int\u00e9gration continue d\u00e8s le d\u00e9but du projet et v\u00e9rifier par des outils les points ci-dessus.\n\nCeci est sans doute un des points les plus ennuyants de ce livre: il n'y a finalement que tr\u00e8s peu d'exemples concrets, notamment pour la mise en place d'un tel environnement. Ok, \u00e7a parle de Jenkins du d\u00e9but \u00e0 la fin, mais plus comme un exemple \u00e0 suivre (ou parfois \u00e0 ne pas suivre) que comme un outil \u00e0 utiliser. De mani\u00e8re plus g\u00e9n\u00e9rale, j'ai l'impression que le code .Net reste extr\u00eamement ferm\u00e9 \u00e0 des outils open source permettant d'augmenter la qualit\u00e9 du code. Il existe des *linters* pratiquement pour tous les langages, mais si vous voulez quelque chose de fonctionnel pour C#, il va falloir passer par la caisse. Une strat\u00e9gie MS classique en sommme: \"on vous offre les outils pour pas grand chose, et pour aller plus loin, vous douillez\".\n\nEn regardant un peu \u00e0 droite-\u00e0 gauche, pour du code .Net, les outils suivants ont l'air sympa, comme:\n\n * [SonarLint](http://www.sonarlint.org) (en [cli](http://www.sonarlint.org/commandline/index.html), int\u00e9gr\u00e9 dans [un IDE](http://www.sonarlint.org/visualstudio/index.html) ou en mode [CI](http://www.sonarqube.org/)) (dont je ne peux plus me passer :-) )\n * [StyleCop](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)\n * [Refactoring Essentials](http://vsrefactoringessentials.com/)\n * [CodeMaid](https://visualstudiogallery.msdn.microsoft.com/76293c4d-8c16-4f4a-aee6-21f83a571496?SRC=VSIDE), pour un code propre et soyeux. En zieutant la description, on trouve que *CodeMaid is an open source Visual Studio extension to cleanup, dig through and simplify our C#, C++, F#, VB, PHP, JSON, XAML, XML, ASP, HTML, CSS, LESS, SCSS, JavaScript and TypeScript coding*.\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-09-12",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Recherche full-text dans toute la db... avec grep\nDate: 2016-09-30\nTags: db, python, mssql, extract\nSlug: full-text-search-db-with-pyodbc-and-grep\n---\n\nJe n'en suis franchement pas fier parce que c'est tout sauf propre et r\u00e9utilisable, mais cela pourrait peut-\u00eatre \u00e0 nouveau servir \u00e0 l'occasion... Le script ci-dessous lit l'ensemble d'une base de donn\u00e9es en utilisant [pyodbc](https://github.com/mkleehammer/pyodbc) et \u00e9crit leur contenu dans un fichier texte, nomm\u00e9 d'apr\u00e8s la table dont elles sont issues. En mode bourrin, en somme, puisqu'on liste toutes les tables, et qu'on fait ensuite un `select` sur chacune d'entre elles, avant d'en dumper le contenu dans un fichier texte. Int\u00e9r\u00eat? Ex\u00e9cuter un `grep -rin` par la suite sur les fichiers \u00e9crits.\n\n```python\nimport pyodbc\n\nCXSTR = 'DRIVER={SQL Server};SERVER=...;DATABASE=...;UID=...;PWD=...;'\n\nif __name__ == '__main__':\n\n cnxn = pyodbc.connect(CXSTR)\n cursor = cnxn.cursor()\n\n cursor.execute(\"SELECT * FROM information_schema.tables WHERE TABLE_TYPE='BASE TABLE'\")\n for row in cursor.fetchall():\n cursor2 = cnxn.cursor()\n cursor2.execute(\"Select * From \" + row[2])\n\n print('using {}'.format(row[2] + '.txt'))\n with open(row[2] + '.txt', 'wt', encoding='utf-8') as f:\n for row2 in cursor2.fetchall():\n f.write(str(row2))\n```\n\nQuand je disais qu'il y avait moyen de faire plus propre... :-) Allez, pour le fun: le script s'en sort avec un score PyLint de 2.67/10 (*missing docstring*, *invalid name*, *lines too long*, *no member* et *anomalous backslash in string*).\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-09-30",
"title": "---"
},
{
"category": "dev",
"content": "---\nTitle: Django et ses contexts processors\nDate: 2016-10-25\nSlug: django-context-processors\nTags: django,\"python, config, dev\n---\n\nDe mani\u00e8re tr\u00e8s grossi\u00e8re, les *`contexts processors`* permettent de d\u00e9finir du contenu accessible globalement dans l'application, par exemple pour d\u00e9finir un menu de navigation ou le titre du site. On parle donc d'\u00e9l\u00e9ments qui ne sont pas sp\u00e9cifiques au contexte (vue, fonction, ...) actuel, mais plut\u00f4t d\u00e9finis globalement par rapport \u00e0 l'application.\n\nAu niveau de la vue, on a pour habitude de passer un dictionnaire au template; celui-ci sera compl\u00e9t\u00e9 par un ensemble d'autres informations, d\u00e9finies dans les *contexts processors*.\n\nTechniquement, il s'agit simplement de fonctions r\u00e9f\u00e9renc\u00e9es au niveau de la configuration de l'application. Si on souhaite g\u00e9n\u00e9rer un menu global, il suffit d\u00e8s lors de d\u00e9finir une fonction dans un module particulier:\n\n```python\n# my_module/navigation.py\n\ndef main_menu(request):\n return { 'links': ['Accueil', 'Se restaurer', 'Informations pratiques' ] }\n```\n\nOn peut d\u00e8s lors y acc\u00e9der dans le template de base:\n\n```django\n<!-- templates/base.html -->\n<!DOCTYPE HTML>\n<html>\n {% for link in links %}\n <a href=\"#\">{{ link }}</a>\n {% endfor %}\n</html>\n```\n\nPour \u00e9viter que ces variables ne soient \u00e9cras\u00e9es par la construction de la vue, la transmission du dictionnaire vers la vue doit \u00eatre construite en utilisant la fonction `render(request, template, context)`, de la mani\u00e8re suivante. Evitez la fonction `render_to_response`:\n\n```python\ndef events(request):\n context = { 'events': events = Event.objects.all() }\n\n return render(request, 'events.html', context)\n```\n\nDepuis Django 1.10, la variable `TEMPLATE_CONTEXT_PROCESSORS` est d\u00e9pr\u00e9ci\u00e9e et doit \u00eatre remplac\u00e9e par l'option `context_processors`:\n\n```python\nTEMPLATES = [\n {\n 'BACKEND': 'django.template.backends.django.DjangoTemplates',\n 'DIRS': ['templates', ],\n 'APP_DIRS': True,\n 'OPTIONS': {\n 'context_processors': [\n '...',\n ],\n },\n },\n]\n```\n\n",
"keywords": [],
"path": "articles\\dev",
"publication_date": "2016-10-25",
"title": "---"
},
{
"category": "en cuisine",
"content": "Le g\u00e2teau au chocolat\n=====================\n\n- 200g de chocolat\n- 150g de sucre\n- 50g de farine\n- 150g de beurre\n- 4 oeufs.\n\nLe chocolat et le beurre fondu, puis le sucre, puis les oeufs, puis la farine.\nAu four \u00e0 190\u00b0 pendant 20 minutes.\n",
"keywords": [],
"path": "articles\\en cuisine",
"publication_date": "2015-12-31",
"title": "Le g\u00e2teau au chocolat"
},
{
"category": "en cuisine",
"content": "---\nTitle: Cr\u00e8me au chocolat au Tofu\nDate: 2017-08-28\nTags: chocolat, miam\n---\n\nVous aurez besoin de:\n\n * 400g de tofu soyeux\n * 200g de chocolat.",
"keywords": [],
"path": "articles\\en cuisine",
"publication_date": "2017-08-28",
"title": "---"
},
{
"category": "en cuisine",
"content": "Dentifrice home made\n====================\n\nCopi\u00e9/coll\u00e9 d'une coll\u00e8gue.\n\nIngr\u00e9dients:\n\n* 3 c.s d\u2019argile blanche\n* 1c.s de bicarbonate\n* 7 gouttes d\u2019Huile essentielle de menthe.\n\nBien m\u00e9langer le tout et mettre dans un petit r\u00e9cipient pas en m\u00e9tal.\n\nMouiller sa brosse \u00e0 dents et tremper dans son petit pot.\n\n**Attention**: ne pas prendre ni m\u00e9langer l\u2019argile blanche avec une cuill\u00e8re en m\u00e9tal, mais en bois car sinon l\u2019argile perd ses propri\u00e9t\u00e9s.\n",
"keywords": [],
"path": "articles\\en cuisine",
"publication_date": "2018-01-23",
"title": "Dentifrice home made"
},
{
"category": "home",
"content": "---\nTitle: Sansa Clip Zip\nDate: 2012-12-26\nSlug: sansa-clip-zip\n---\n\nJ'ai longuement h\u00e9sit\u00e9 entre ce mod\u00e8le, recommand\u00e9 par certains sites, et d'autres lecteurs plus chers, plus grands, plus tactiles, mieux finis... pour finalement craquer sur celui-ci: il ne fait qu'une et une seule chose, mais il le fait bien.\n\nAucun probl\u00e8me \u00e0 l'utilisation, les touches physiques sont accessibles malgr\u00e9 la petitesse de l'appareil et ont du r\u00e9pondant. L'interface est simpliste, mais suffisamment ergonomique. Les transferts de fichiers sont id\u00e9aux (pas besoin de passer par un logiciel particulier (iTunes, ...)): on branche et cela fonctionne. La lecture des formats autres que le MP3 est \u00e9galement un gros plus: Flac et Ogg Vorbis nativement. Un bonheur :).\n\nL'\u00e9cran est petit, pr\u00e9sente une tr\u00e8s faible r\u00e9solution, affiche peu d'informations, mais affiche l'essentiel (et m\u00eame plus: cover si trouv\u00e9e par exemple :)). Les principales fonctions sont l\u00e0 \u00e9galement: play/pause, mise en veille, suivante, pr\u00e9c\u00e9dente, ... et tombent plus ou moins sous le sens. Pas besoin de chercher de midi \u00e0 quatorze heure pour faire une action. Efficace.\n\nLa qualit\u00e9 de fabrication est un cran en dessous de ce \u00e0 quoi je m'attendais, mais n'est pas catastrophique non plus: c'est du tout plastique, mais condens\u00e9 :) Et vu le peu de fonctionnalit\u00e9s pr\u00e9sentes (\u00e9couter de la musique.- ), l'appareil ne risque pas d'\u00eatre tritur\u00e9 toutes les deux minutes.\n\nUn dernier point extr\u00eamement int\u00e9ressant est la possibilit\u00e9 d'ajouter une carte micro SD dans l'appareil afin d'am\u00e9liorer sa capacit\u00e9 de stockage, ce qui est loin d'\u00eatre n\u00e9gligeable.\n\nJe voulais un lecteur audio pratique \u00e0 emporter avec moi, et c'est chose faite!\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2012-12-26",
"title": "---"
},
{
"category": "home",
"content": "Getting Things Done!\n====================\n\nSi vous en avez marre que votre bo\u00eete mail d\u00e9borde de t\u00e2ches \u00e0 faire et que la m\u00e9thode du drapeau rouge d'Outlook ne suffit plus, peut-\u00eatre que vous avez simplement besoin de continuer \u00e0 faire les choses, mais diff\u00e9remnt :-) Une mani\u00e8re de faire:\n\n* Essayez de vider votre bo\u00eete mail. Un message non tri\u00e9 est un message \u00e0 faire. Si votre bo\u00eete est vide, f\u00e9licitations! Votre journ\u00e9e peut continuer.\n* Ne lancez pas syst\u00e9matiquement Outlook en arrivant au boulot le matin. Les actus sont parfois plus int\u00e9ressantes qu'un message d'insultes de votre chef ador\u00e9, vous demandant o\u00f9 en est votre travail.\n* Essayez de faire fr\u00e9quemment un point sur votre \u00e9tat d'avancement. Regardez derri\u00e8re vous, faites le point sur les choses d\u00e9j\u00e0 faites, plut\u00f4t que de vous lamenter sur ce qui n'a pas encore \u00e9t\u00e9 fait.\n\nVoir aussi sur [Lifehacker](http://lifehacker.com/develop-discipline-by-seeing-the-good-in-any-task-1629748447). Les commentaires valent un coup d'oeil.\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2014-02-09",
"title": "Getting Things Done!"
},
{
"category": "home",
"content": "---\nTitle: Getting Things Done!\nDate: 2014-02-09\nTags: gtd, life\nSlug: getting-things-done\nIllustration: kelly-sikkema-post-it.jpg\n---\n\nSi vous en avez marre que votre bo\u00eete mail d\u00e9borde de t\u00e2ches \u00e0 faire et que la m\u00e9thode du drapeau rouge d'Outlook ne suffit plus, peut-\u00eatre que vous avez simplement besoin de continuer \u00e0 faire les choses, mais diff\u00e9remnt :-) Une mani\u00e8re de faire:\n\n* Essayez de vider votre bo\u00eete mail. Un message non tri\u00e9 est un message \u00e0 faire. Si votre bo\u00eete est vide, f\u00e9licitations! Votre journ\u00e9e peut continuer.\n* Ne lancez pas syst\u00e9matiquement Outlook en arrivant au boulot le matin. Les actus sont parfois plus int\u00e9ressantes qu'un message d'insultes de votre chef ador\u00e9, vous demandant o\u00f9 en est votre travail.\n* Essayez de faire fr\u00e9quemment un point sur votre \u00e9tat d'avancement. Regardez derri\u00e8re vous, faites le point sur les choses d\u00e9j\u00e0 faites, plut\u00f4t que de vous lamenter sur ce qui n'a pas encore \u00e9t\u00e9 fait.\n\nVoir aussi sur [Lifehacker](http://lifehacker.com/develop-discipline-by-seeing-the-good-in-any-task-1629748447). Les commentaires valent un coup d'oeil.\n\nPhoto by [Kelly Sikkema](https://unsplash.com/photos/-1_RZL8BGBM?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unsplash\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2014-02-09",
"title": "---"
},
{
"category": "home",
"content": "---\nTitle: 28 aout 2015\nDate: 2015-08-28\nStatus: draft\nTags: life\n---\n\nCoucou mon Petilou,\n\nHier, tu as eu 19 mois. Tu grandis de jour en jour, et je vois tous les efforts que tu fais pour progresser. Les trois dernieres nuits ont ete particulirement difficiles: tu te r\u00e9veillais sans cesse, demandait a recevoir des calins, pour te rendormir aussi vite.\nCe soir, en venant te chercher \u00e0 la cr\u00eache, tu t'es directement blotti contre mon epaule avant de dire au revoir a tout le monde. Tu as recu des bisous de tous les enfants encore pr\u00e9sents, + un gros de Dominique. Nicole \u00e9tait encore occup\u00e9e a discuter avec deux futurs parents, mais tu lui as quand meme fait un signe de la main.\n\nDans la poussette, tu as garde une main tendue vers moi. Tu \u00e9tais fatigu\u00e9, mais tu ne voulais pas de tute. Les grands ne prennent pas de tute quand ils sont fatigu\u00e9s. Arriv\u00e9s a la maison, tu as fil\u00e9 vers la cuisine. Un petit rituel entre toi et moi: tu recois toujours un petit quelque chose quand tu le demandes. Il n'y avait plus de pain, tu ne voulais pas de galettes de riz, ... On a fini le raisin, toi et moi. Toi en le grignotant du bout des dents, moi en le lancant en l'air pour le rattraper directement dans ma bouche. Cela te faisait rire :)\n\nLe bain a dur\u00e9 10 minutes. L'eau n'\u00e9tait pas tr\u00e8s chaude, tu n'as pas voulu rester plus longtemps. Tu as re\u00e7u ton biberon directement apr\u00e8s, mais tu n'en as bu que la moiti\u00e9. Tu etais fatigu\u00e9, j'ai propos\u00e9 de te mettre au lit. On a lu une histoire juste avant, puis on s'est dirig\u00e9 vers ta chambre. Une fois au lit, tu as recommenc\u00e9 \u00e0 geindre. J'ai \u00e9lev\u00e9 la voix, tu t'es alors simplement allong\u00e9 sur le ventre et tu t'es endormi.\n\nJ'ai du hausser la voix, et je le regrette. Je m'en veux de ne pas r\u00e9ussir \u00e0 \u00eatre toujours calme. Ca fait partie du r\u00f4le de p\u00e8re, de ton p\u00e8re, mais je ne veux pas de ce role: je veux encore manger du raisin en le lan\u00e7ant en l'air, je veux qu'on rigole tous les deux en regardant les chiens en rue ou en lisant des histoires. Je ne veux pas de confrontations comme celles-ci. J'y perds un peu a chaque fois que je gagne.\n\nPapa.\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2015-08-28",
"title": "---"
},
{
"category": "home",
"content": "Un p'tit tour sur le Play Store\n===============================\n\nEn trainant un peu sur le Play Store, j'ai un peu zieut\u00e9 le top des applications que Google propose aux utilisateurs. Parmi celles-ci, on trouve :\n\n* Facebook Messenger\n* Facebook\n* Whatsapp\n* Skype\n* Snapchat\n\nOk. Avec un petit milliard d'utilisateurs pour Facebook (et autant de p\u00e9riph\u00e9riques Android en circulation?), je suppose qu'il est normal de trouver des applications de discussions (et de r\u00e9seaux sociaux) dans les top charts. La suite est plus int\u00e9ressante, avec notamment :\n\n* Candy Crush Saga\n* Candy Crush Soda\n* Instagram\n* Fruit Ninja\n* Clash of clans\n\nBref, pas hyper convaincu par ces quelques propositions... Pour pousser un peu plus loin, je passe d\u00e9sormais par [F-Droid](https://f-droid.org/). Son catalogue ne contient que des applications open source, il s'occupe de faire les mises \u00e0 jour lorsqu'elles sont disponibles, ...\nUn peu comme le Play Store en fait, mais en libre.\n\nSuivant les usages, tout ne sera sans doute pas disponible sur F-Droid, mais ce serait d\u00e9j\u00e0 un bon d\u00e9but. A l'occasion, pensez-y pour un premier pas dans la [d\u00e9googlification](http://degooglisons-internet.org/).",
"keywords": [],
"path": "articles\\home",
"publication_date": "2015-09-02",
"title": "Un p'tit tour sur le Play Store"
},
{
"category": "home",
"content": "---\nTitle: R\u00e9sistance thermique\nDate: 2015-09-20\nSlug: thermal-resistance\n---\n\n* R = R\u00e9sistance thermique (en m\u00e8tre\u00b2 Kelvin par Watt m\u00b2K/W)\n* Lambda = conductivit\u00e9 thermique (en Watts par m\u00e8tre Kelvin)\n* e = \u00e9paisseur (en m\u00e8tre)\n\nEt on a la formule `R = e / Lambda`. Plus qu'\u00e0 compl\u00e9ter le papier pour les primes :)\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2015-09-20",
"title": "---"
},
{
"category": "home",
"content": "F-Droid\n=======\n\nJ'ai r\u00e9cemment (= hier) r\u00e9initialis\u00e9 mon t\u00e9l\u00e9phone, suite \u00e0 un probl\u00e8me de place et de configuration. Apr\u00e8s le red\u00e9marrage, le constructeur (Samsung) a cru bon d'y ajouter un certain nombre d'applications compl\u00e8tement inutiles: Zalando, un brol pour commander des pizze, des applications propri\u00e9taires dans tous les sens, ...\n\nTant que j'y \u00e9tais, j'en ai profit\u00e9 pour essayer de passer au maximum par [F-Droid](https://f-droid.org/) (dans un but avou\u00e9 de [d\u00e9googlisation](https://degooglisons-internet.org/)). A premi\u00e8re vue, je ne m'en sors pas *trop* mal :) Il reste quelques morceaux non libres, mais c'est d\u00e9j\u00e0 un bon d\u00e9but.\n\nDepuis le [d\u00e9p\u00f4t F-Droid](https://f-droid.org/repository/browse/), j'ai s\u00e9lectionn\u00e9 les applications suivantes:\n\n* [Calendar Widget](https://f-droid.org/repository/browse/?fdfilter=calendar+widget&fdid=com.plusonelabs.calendar) pour la liste de mes prochains rendez-vous sur l'\u00e9cran d'accueil. Il est personnalisable, fonctionnel et plut\u00f4t joli. Deux petits boutons permettent d'ajouter rapidement un nouvel \u00e9l\u00e9ment ou de rafra\u00eechir les calendriers.\n* [Diaspora](https://f-droid.org/repository/browse/?fdfilter=diaspora&fdid=com.github.dfa.diaspora_android). Cetteversion, issue d'un fork, est normalement la derni\u00e8re en vigueur et la plus compl\u00e8te.\n* [DuckDuckGo](https://f-droid.org/repository/browse/?fdfilter=duckduck&fdid=com.duckduckgo.mobile.android), pour avoir acc\u00e8s au widget de recherche et aux *Stories*.\n* F-Droid (obviously...)\n* [FBReader](https://f-droid.org/repository/browse/?fdfilter=fbreader&fdid=org.geometerplus.zlibrary.ui.android)\n* [Firefox](https://f-droid.org/repository/browse/?fdfilter=firefox&fdid=org.mozilla.firefox)\n* [K-9 Mail](https://f-droid.org/repository/browse/?fdfilter=k9&fdid=com.fsck.k9): attention \u00e0 bien d\u00e9gager la **signature automatique** (je n'ai jamais compris ce principe...)\n* [ownCloud](https://f-droid.org/repository/browse/?fdfilter=owncloud&fdid=com.owncloud.android\n* [Shaarlier](https://f-droid.org/repository/browse/?fdfilter=shaarlier&fdid=com.dimtion.shaarlier)\n* [Tinfoil](https://f-droid.org/repository/browse/?fdfilter=tinfoil&fdid=com.mill_e.twitterwrapper) (pas encoreconvaincu) - pour acc\u00e9der \u00e0 Twitter de mani\u00e8re *presque* anonyme (ou en tout cas, un peu plus masqu\u00e9e).\n* [Torch](https://f-droid.org/repository/browse/?fdfilter=torch&fdid=com.doomy.torch), pour y voir plus clair dansle noir\n* [VLC](https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc) pour tous les fichiers media.\n* [Writeily Pro](https://f-droid.org/repository/browse/?fdfilter=writeily&fdid=me.writeily) pour l'\u00e9dition de fichiers Markdown.\n\nIl reste alors les applications suivantes qui d\u00e9pendent du Play Store:\n\n* [Signal Private Messenger](https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms)\n* [Bruxelles Transports](https://play.google.com/store/apps/details?id=be.digitalia.stib&hl=fr) pour ne pas me perdre...\n* [Yatse](https://play.google.com/store/apps/details?id=org.leetzone.android.yatsewidgetfree&hl=fr) pour contr\u00f4ler le media center (sur Openelec).\n* [Google Maps](https://play.google.com/store/apps/details?id=com.google.android.apps.maps&hl=fr)\n* Et les applis li\u00e9es au Synology ([DS File](https://play.google.com/store/apps/details?id=com.synology.DSfile&hl=fr) et [DS Finder](https://play.google.com/store/apps/details?id=com.synology.DSfinder&hl=fr), principalement)",
"keywords": [],
"path": "articles\\home",
"publication_date": "2016-05-25",
"title": "F-Droid"
},
{
"category": "home",
"content": "Six lois pour la gestion du temps\n=================================\n\n## LOI DE PARKINSON\n\n> Plus on a le temps pour r\u00e9aliser une t\u00e2che, plus cette t\u00e2che prends du temps.\n\n## LOI DE MURPHY\n\n> Toute chose prend plus de temps qu\u2019on ne l\u2019avait pr\u00e9vu.\n\n## LOI D\u2019ILLICH\n\n> Au-del\u00e0 d\u2019un certain seuil de travail l\u2019efficacit\u00e9 d\u00e9croit.\n\n## LOI DE CARSON\n\n> Faire un travail de fa\u00e7on continue prend moins de temps que le faire en plusieurs fois.\n\n## LOI DE FRAISSE\n\n> Une heure n\u2019est pas toujours \u00e9gale \u00e0 une heure.\n\n## LOI DE PARETO\n\n> 20% de nos activit\u00e9s produisent 80% de nos r\u00e9sultats.",
"keywords": [],
"path": "articles\\home",
"publication_date": "2016-11-24",
"title": "Six lois pour la gestion du temps"
},
{
"category": "home",
"content": "---\nTitle: Passage chez EDPNet\nTags: internet, fai\nIllustration: nicolas-picard-web.jpg\n---\n\nOn est le 14 ao\u00fbt, j'ai explos\u00e9 le quota de 150GB qui m'a \u00e9t\u00e9 gr\u00e2cement allou\u00e9 par Proximus pour ma ligne *Internet Comfort*. 150GB de choses l\u00e9gitimes: t\u00e9l\u00e9chargements *via* [Good Old Games](https://www.gog.com), r\u00e9ception de donn\u00e9es sur le NAS et transferts vers OneDrive. Oui, cela fait beaucoup, mais \u00e0 c\u00f4t\u00e9 de cela, Proximus propose des quota allant jusqu'\u00e0 750GB pour une ligne plus ou moins identique, mais beaucoup plus ch\u00e8re (\u00e0 ce jour, je paye 36\u20ac/mois avec un EPP - l'offre au-dessus est \u00e0 48\u20ac, sur laquelle je pourrais obtenir une r\u00e9duction de 10%, mais cela me reviendrait malgr\u00e9 tout \u00e0 10\u20ac de plus/mois - donc 120\u20ac par an -).\n\nJ'ai toujours \u00e9t\u00e9 tr\u00e8s satisfait de la qualit\u00e9 de la ligne Proximus; moins des contraintes techniques. La Bbox3 (que j'ai fini par acheter moi-m\u00eame, puisqu'impossible d'en obtenir une sur simple \u00e9change de la Bbox2) ne supporte par exemple pas le [Hairpinning](#), ce qui emp\u00eache l'auto-h\u00e9bergement. En leur demandant conseil sur l'ouverture des ports, personne n'a \u00e9t\u00e9 en mesure de m'informer par rapport aux limitations de ma ligne. Ensuite ce principe de quota ne me convient pas: une fois d\u00e9pass\u00e9, j'ai la possibilit\u00e9 de commander un *pack* de 20GB pour 5\u20ac. Bref, si je veux me d\u00e9barasser de cette contrainte, je dois passer sur le pack au-dessus.\n\n## 18/08/2017 - la commande.\n\nD\u00e9but juillet, une nouvelle proc\u00e9dure *Easy Switch* a point\u00e9 le bout de son nez. Elle permet, sur base des identifiants de l'op\u00e9rateur actuel (num\u00e9ro de ligne, Easy Switch Id et num\u00e9ro de client) d'autoriser le nouvel op\u00e9rateur \u00e0 s'occuper de toutes les d\u00e9marches administratives de cl\u00f4ture et d'avoir une continuit\u00e9 dans la distribution et l'acc\u00e8s aux services. Les donn\u00e9es de facturation sont directement d\u00e9duites des informations communiqu\u00e9es par la ligne.\n\n> (Attention: le mot de passe initial est transmis par email - \u00e0 modifier directement)\n\nTotal \u00e0 payer: 50\u20ac de frais d'activation et 35\u20ac/mois. Je conserve ma BBOX3 (puisque Proximus n'a jamais voulu changer la BBOX2 contre le \"nouveau\" mod\u00e8le - je devrai sans doute aller la rapporter dans une point). Il est aussi possible de commander du mat\u00e9riel AVM (Fr!tzBox 7390 ou 7490) \u00e0 un prix avantageux (respectivement 99\u20ac et 179\u20ac - pour info, la 7490 est dispo chez [Coolblue](https://www.coolblue.be) pour 209\u20ac.\n\n## 18/08/2017 - la commande (suite)\n\nDeux mails re\u00e7us dans la journ\u00e9e:\n\n 1. Un mandat de migration simple (mais sans directive de savoir quoi en faire, s'il faut le signer ou quoi :))\n 2. Mes identifiants pour EDPNet Telephony (\u00e0 nouveau, avec les mots de passe en clair!)\n\n ## 21/08/2017 - la confirmation\n\nA nouveau deux petits mails re\u00e7us ce jour:\n\n 1. Un message de confirmation m'indiquant que ma commande sera activ\u00e9e le 24/08\n 2. Un deuxi\u00e8me message me communiquant mes identifiants/mots de passe \u00e0 indiquer dans l'interface du routeur.\n\n## 22/08/2017 - No transferable phone number\n\n - **14h32** : Un ticket est ouvert pour me signaler que mon ancien num\u00e9ro Proximus ne pourra pas \u00eatre transf\u00e9r\u00e9. Dans le ticket, l'op\u00e9rateur/trice me demande si je suis d'accord pour recevoir un nouveau num\u00e9ro de ligne.\n - **15h46**: \"Oui, pas de soucis, allez-y\"\n - **16h42**: \"Voil\u00e0, vous aurez un nouveau num\u00e9ro\".\n\n## 24/08/2017 - Comme promis\n\nEn rentrant chez moi, un courrier de Proximis m'attendant pour m'informer que ma ligne avait \u00e9t\u00e9 coup\u00e9e. Je conserve un acc\u00e8s de 18 mois \u00e0 mes emails (que je n'utilise quand m\u00eame pas) ainsi qu'\u00e0 quelques autres fonctionnalit\u00e9s. Une facture a \u00e9t\u00e9 \u00e9mise par EDPNet, et il m'a suffit de modifier les informations d'identification du routeur pour que la connexion soit \u00e9tablie chez EDPNet.\n\n## Autres notes\n\n * Pour les informations concernant le retour de mat\u00e9riel (BBOX), c'est [par ici](https://www.proximus.be/support/fr/id_sfaqr_device_return_end/particuliers/support/espace-client/demenager-ou-resilier/resilier-votre-contrat/remplacer-ou-renvoyer-un-appareil.html#/modem2).\n * En regardant ma derni\u00e8re facture, je remarque que dor\u00e9navant, les promotions d'affiliations ne concerneront que les packs trio (Internet+TV+T\u00e9l\u00e9phone) \u00e0 partir d'octobre. Encore 4\u20ac que Proximus nous sucre sans r\u00e9elle raison?\n\n## Epilogue (?) - 05/12/2017\n\nIl me reste ma BBox2, re\u00e7ue au moment o\u00f9 mon abonnement Proximus avait \u00e9t\u00e9 command\u00e9. Leur page stipule que *si vous ne recevez pas de courriel ou de courrier vous indiquant la proc\u00e9dure \u00e0 suivre pour renvoyer le mat\u00e9riel, contactez-nous\"*. Ce que j'ai fait: j'ai pass\u00e9 une petite dizaine de minutes avec une personne du support, pour expliquer qu'il me restait du mat\u00e9riel Proximus, que mon contrat avait \u00e9t\u00e9 r\u00e9sili\u00e9. La r\u00e9ponse a \u00e9t\u00e9 de *contacter mon nouveau fournisseur, pour v\u00e9rifier que toute la proc\u00e9dure avait bien \u00e9t\u00e9 suivie\"*. Bref, j'ai autre chose \u00e0 faire que leur courir apr\u00e8s pour leur restituer du mat\u00e9riel qu'ils ne semblent pas press\u00e9s de r\u00e9cup\u00e9rer.\n\nPhoto by [Nicolas Picard](https://unsplash.com/photos/-lp8sTmF9HA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unsplash\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2017-08-24",
"title": "---"
},
{
"category": "home",
"content": "Passage chez EDPNet\n===================\n\nOn est le 14 ao\u00fbt, j'ai explos\u00e9 le quota de 150GB qui m'a \u00e9t\u00e9 gr\u00e2cement allou\u00e9 par Proximus pour ma ligne *Internet Comfort*. 150GB de choses l\u00e9gitimes: t\u00e9l\u00e9chargements *via* [Good Old Games](https://www.gog.com), r\u00e9ception de donn\u00e9es sur le NAS et transferts vers OneDrive. Oui, cela fait beaucoup, mais \u00e0 c\u00f4t\u00e9 de cela, Proximus propose des quota allant jusqu'\u00e0 750GB pour une ligne plus ou moins identique, mais beaucoup plus ch\u00e8re (\u00e0 ce jour, je paye 36\u20ac/mois avec un EPP - l'offre au-dessus est \u00e0 48\u20ac, sur laquelle je pourrais obtenir une r\u00e9duction de 10%, mais cela me reviendrait malgr\u00e9 tout \u00e0 10\u20ac de plus/mois - donc 120\u20ac par an -).\n\nJ'ai toujours \u00e9t\u00e9 tr\u00e8s satisfait de la qualit\u00e9 de la ligne Proximus; moins des contraintes techniques. La Bbox3 (que j'ai fini par acheter moi-m\u00eame, puisqu'impossible d'en obtenir une sur simple \u00e9change de la Bbox2) ne supporte par exemple pas le [Hairpinning](#), ce qui emp\u00eache l'auto-h\u00e9bergement. En leur demandant conseil sur l'ouverture des ports, personne n'a \u00e9t\u00e9 en mesure de m'informer par rapport aux limitations de ma ligne. Ensuite ce principe de quota ne me convient pas: une fois d\u00e9pass\u00e9, j'ai la possibilit\u00e9 de commander un *pack* de 20GB pour 5\u20ac. Bref, si je veux me d\u00e9barasser de cette contrainte, je dois passer sur le pack au-dessus.\n\n## 18/08/2017 - la commande.\n\nD\u00e9but juillet, une nouvelle proc\u00e9dure *Easy Switch* a point\u00e9 le bout de son nez. Elle permet, sur base des identifiants de l'op\u00e9rateur actuel (num\u00e9ro de ligne, Easy Switch Id et num\u00e9ro de client) d'autoriser le nouvel op\u00e9rateur \u00e0 s'occuper de toutes les d\u00e9marches administratives de cl\u00f4ture et d'avoir une continuit\u00e9 dans la distribution et l'acc\u00e8s aux services. Les donn\u00e9es de facturation sont directement d\u00e9duites des informations communiqu\u00e9es par la ligne.\n\n> (Attention: le mot de passe initial est transmis par email - \u00e0 modifier directement)\n\nTotal \u00e0 payer: 50\u20ac de frais d'activation et 35\u20ac/mois. Je conserve ma BBOX3 (puisque Proximus n'a jamais voulu changer la BBOX2 contre le \"nouveau\" mod\u00e8le - je devrai sans doute aller la rapporter dans une point). Il est aussi possible de commander du mat\u00e9riel AVM (Fr!tzBox 7390 ou 7490) \u00e0 un prix avantageux (respectivement 99\u20ac et 179\u20ac - pour info, la 7490 est dispo chez [Coolblue](https://www.coolblue.be) pour 209\u20ac.\n\n## 18/08/2017 - la commande (suite)\n\nDeux mails re\u00e7us dans la journ\u00e9e:\n\n 1. Un mandat de migration simple (mais sans directive de savoir quoi en faire, s'il faut le signer ou quoi :))\n 2. Mes identifiants pour EDPNet Telephony (\u00e0 nouveau, avec les mots de passe en clair!)\n\n ## 21/08/2017 - la confirmation\n\nA nouveau deux petits mails re\u00e7us ce jour:\n\n 1. Un message de confirmation m'indiquant que ma commande sera activ\u00e9e le 24/08\n 2. Un deuxi\u00e8me message me communiquant mes identifiants/mots de passe \u00e0 indiquer dans l'interface du routeur.\n\n## 22/08/2017 - No transferable phone number\n\n - **14h32** : Un ticket est ouvert pour me signaler que mon ancien num\u00e9ro Proximus ne pourra pas \u00eatre transf\u00e9r\u00e9. Dans le ticket, l'op\u00e9rateur/trice me demande si je suis d'accord pour recevoir un nouveau num\u00e9ro de ligne.\n - **15h46**: \"Oui, pas de soucis, allez-y\"\n - **16h42**: \"Voil\u00e0, vous aurez un nouveau num\u00e9ro\".\n\n## 24/08/2017 - Comme promis\n\nEn rentrant chez moi, un courrier de Proximis m'attendant pour m'informer que ma ligne avait \u00e9t\u00e9 coup\u00e9e. Je conserve un acc\u00e8s de 18 mois \u00e0 mes emails (que je n'utilise quand m\u00eame pas) ainsi qu'\u00e0 quelques autres fonctionnalit\u00e9s. Une facture a \u00e9t\u00e9 \u00e9mise par EDPNet, et il m'a suffit de modifier les informations d'identification du routeur pour que la connexion soit \u00e9tablie chez EDPNet.\n\n## Autres notes\n\n * Pour les informations concernant le retour de mat\u00e9riel (BBOX), c'est [par ici](https://www.proximus.be/support/fr/id_sfaqr_device_return_end/particuliers/support/espace-client/demenager-ou-resilier/resilier-votre-contrat/remplacer-ou-renvoyer-un-appareil.html#/modem2).\n * En regardant ma derni\u00e8re facture, je remarque que dor\u00e9navant, les promotions d'affiliations ne concerneront que les packs trio (Internet+TV+T\u00e9l\u00e9phone) \u00e0 partir d'octobre. Encore 4\u20ac que Proximus nous sucre sans r\u00e9elle raison?\n\n## Epilogue (?) - 05/12/2017\n\nIl me reste ma BBox2, re\u00e7ue au moment o\u00f9 mon abonnement Proximus avait \u00e9t\u00e9 command\u00e9. Leur page stipule que *si vous ne recevez pas de courriel ou de courrier vous indiquant la proc\u00e9dure \u00e0 suivre pour renvoyer le mat\u00e9riel, contactez-nous\"*. Ce que j'ai fait: j'ai pass\u00e9 une petite dizaine de minutes avec une personne du support, pour expliquer qu'il me restait du mat\u00e9riel Proximus, que mon contrat avait \u00e9t\u00e9 r\u00e9sili\u00e9. La r\u00e9ponse a \u00e9t\u00e9 de *contacter mon nouveau fournisseur, pour v\u00e9rifier que toute la proc\u00e9dure avait bien \u00e9t\u00e9 suivie\"*. Bref, j'ai autre chose \u00e0 faire que leur courir apr\u00e8s pour leur restituer du mat\u00e9riel qu'ils ne semblent pas press\u00e9s de r\u00e9cup\u00e9rer.\n\nPhoto by [Nicolas Picard](https://unsplash.com/photos/-lp8sTmF9HA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unsplash\n\n## Update du 27/12/2017\n\nUn article sur [Lalibre.be](http://www.lalibre.be/actu/belgique/tout-ce-qui-change-ce-1er-janvier-5a436da7cd70b09cef4df1fe), o\u00f9 on voit que **Proximus augmente plusieurs tarifs**: mon abonnement que je payais encore 36\u20ac l'ann\u00e9e pass\u00e9e (EPP, tout \u00e7a) passera \u00e0 ... 42.95\u20ac en 2018.",
"keywords": [],
"path": "articles\\home",
"publication_date": "2017-08-24",
"title": "Passage chez EDPNet"
},
{
"category": "home",
"content": "---\nTitle: Fractal Design Node 804\nSummary: Un boitier \u00b5-ATX sympa, mais pas pour tout le monde\nDate: 2017-11-21\nIllustration: thoughts/fractal-node-804.jpg\n---\n\nMon cahier de charge \u00e9tait relativement simple: on a h\u00e9rit\u00e9 d'un vieux bureau massif de la famille, tout en moulures, courbes et enluminures. Le probl\u00e8me de cette salo$%\u00f9@ de meuble est que la \"hauteur sous tiroir\" ne d\u00e9passe pas les 54cm et ne donne clairement pas un acc\u00e8s facile aux boutons de la tour, pour peu qu'ils se trouvent sur le dessus. Bref, c'\u00e9tait mal barr\u00e9 pour ma fid\u00e8le [Lian-Li PC7B](#) - pas de boutons en fa\u00e7ade, dimensions juste trop grandes que pour s'oublier sous le bureau, ...\n\nJe pars en qu\u00eate d'un nouveau boitier! Le cahier de charge est simple (ou pas: on va le voir juste apr\u00e8s):\n\n * Pas plus de 50cm\n * Possibilit\u00e9 d'accueillir plusieurs disques (deux disques durs + deux SSD)\n * Facilit\u00e9 d'\u00e9volution\n * Que mon mat\u00e9riel actuel rentre dedans sans forcer et sans sortir le pied-de-biche (Noctua 120 et GTX 960)\n",
"keywords": [],
"path": "articles\\home",
"publication_date": "2017-11-21",
"title": "---"
},
{
"category": "home",
"content": "Ghost\n=====\n\nJ'avais d\u00e9j\u00e0 essay\u00e9 [Ghost](https://ghost.org) il y a quelques semaines, mais deux-trois trucs m'avaient confirm\u00e9 que ce n'\u00e9tait pas (encore) la solution parfaite. J'avais continu\u00e9 mon exploration, en repassant notamment par [Pelican](http://docs.getpelican.com/en/stable/), [Hugo](http://gohugo.io/), [Pluxml](http://pluxml.org/) et [Blogotext](https://lehollandaisvolant.net/blogotext/fr/). Aucun ne colle r\u00e9ellement \u00e0 ma mani\u00e8re de prendre note.\n\nJusqu'\u00e0 pr\u00e9sent, je tapais du texte, synchronis\u00e9 avec un d\u00e9p\u00f4t [#git]() et converti en site statique. Ce type de conversion me gonfle: on part d'un pseudo-standard (*markdown*) et finalement, il n'y a rien de normalis\u00e9, car tout d\u00e9pend de la mani\u00e8re dont les informations sont repr\u00e9sent\u00e9es. C'est encore pire avec [Hugo](http://gohugo.io/), puisque chaque section peut avoir sa propre repr\u00e9sentation. C'est top, vraiment. Mais pas envie d'adapter MA mani\u00e8re d'\u00e9crire \u00e0 ce qu'une autre personne aura imagin\u00e9. Je fais d\u00e9j\u00e0 assez \u00e7a au taf que pour m'y plier \u00e0 la maison.\n\nPour [Pluxml](http://pluxml.org/) et [Blogotext](https://lehollandaisvolant.net/blogotext/fr/), c'est diff\u00e9rent: le premier demande a \u00e9t\u00e9 *pluginis\u00e9* avant de pouvoir commencer \u00e0 \u00e9crire. La partie \u00e9dition est fonctionnelle, mais pas sans distraction (*distraction free*, pour ceux qui parlent la langue de Batman). Blogotext est sans doute ce qui approchait le plus ce que je souhaitais... Mais avec (de nouveau) sa propre syntaxe \u00e0 apprendre (et donc tout mon contenu existant \u00e0 convertir). J'ai m\u00eame envisag\u00e9 de revenir vers WordPress, mais son \u00e9diteur me repousse encore plus loin de la simplicit\u00e9 que je souhaite. Et comme la majorit\u00e9 de mon contenu contient des snippets, il aura finalement \u00e0 nouveau fallu d\u00e9nicher le bon plugin, avec la bonne coloration syntaxique, qui n'ajoute pas b\u00eatement des num\u00e9ros de lignes ou un ascenseur horizontal pour arriver \u00e0 la fin de la ligne.\n\nBref, Ghost. Parce que:\n\n* Markdown + markdown extra (pieds de page, *strike through*, ...)\n* Une appli Android franchement bien foutue, m\u00eame hors ligne\n* Pas de taxonomies louches ou de trucs compliqu\u00e9s, les tags sont \u00e0 peu pr\u00e8s la solution \u00e0 tout probl\u00e8me de cat\u00e9gorisation: une cat\u00e9gorie principale? Un tag. Une modification de template? Un tag. Une page sp\u00e9cifique ? Un tag. Un flux RSS par \"section\"? Un tag. Sisi, c'est aussi b\u00eate que \u00e7a.\n* Et une chouette gestion des images, avec une interface ergonomique d'upload, un mode sans distraction, une pr\u00e9visualisation en live, un mode *Hemingway*, ...\n\nNan, je vous jure. C'est pas parfait... Mais sans prise de t\u00eate.\n\nM\u00eame l'installation est accessible (et pourtant, c'est du node.js sous le capot hein), jusqu'\u00e0 la configuration d'nginx et de let's encrypt.",
"keywords": [],
"path": "articles\\home",
"publication_date": "2018-01-12",
"title": "Ghost"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "Authentification en deux \u00e9tapes\n===============================\n\nEn r\u00e9installant Pidgin, j'ai eu la d\u00e9sagr\u00e9able surprise de constater que mon compte Google n'\u00e9tait plus reconnu. Une erreur me disait que je n'\u00e9tais pas autoris\u00e9 \u00e0 me connecter. Les param\u00e8tres \u00e9taient (\u00e9videmment) bons: Pidgin a le bon go\u00fbt de proposer des configurations par d\u00e9faut pour plusieurs protocoles, dont un qui s'appelle \"GTalk\" (mais qui n'est jamais qu'un sur-param\u00e9trage \u00e0 [XMPP](https://en.wikipedia.org/wiki/XMPP) avec d'autres valeurs par d\u00e9faut).\n\nQuelques minutes plus tard, je re\u00e7ois un mail me disant ceci:\n\n> **Google Account: sign-in attempt blocked**\n>\n> Sign in attempt details\n> Date & Time: Monday, December 29, 2014 3:20:14 PM UTC\n> Location: Belgium\n>\n> If this wasn't you\n> Please review your Account Activity page at https://security.google.com/settings/security/activity to see if anything looks suspicious. Whoever tried to sign in to your > account knows your password; we recommend that you change it right away.\n>\n> If this was you\n> You can switch to an app made by Google such as Gmail to access your account (recommended) or change your settings at https://www.google.com/settings/security/lesssecureapps > so that your account is no longer protected by modern security standards.\n>\n> To learn more, see https://support.google.com/accounts/answer/6010255.\n>\n> Sincerely,\n> The Google Accounts team\n\nEn navigant parmi les liens, on se rend compte que Google classifie les applications en `s\u00e9curis\u00e9es` et `moins s\u00e9curis\u00e9es`. Pidgin fait partie de la deuxi\u00e8me cat\u00e9gorie. Pour l'autoriser \u00e0 vous connecter en utilisant votre compte Google, il faut donc [autoriser](https://www.google.com/settings/security/lesssecureapps) _toutes_ les applications classifi\u00e9es comme `moins s\u00e9curis\u00e9es`. Pas de juste milieu dans ce cas-ci. Cette classification se base en fait sur \"les derni\u00e8res normes de s\u00e9curit\u00e9\" (sans sp\u00e9cifier lesquelles).\n\nUne autre solution, afin de permettre de conserver les normes de s\u00e9curit\u00e9 (et donc n'autoriser que les applications identifi\u00e9es comme telles), est de d\u00e9finir [un mot de passe par application](https://security.google.com/settings/security/permissions?pli=1#accesscodes) ayant besoin d'un acc\u00e8s aux informations de votre compte. Ces autorisations n\u00e9cessitent d'avoir activer [l'authentification en deux-\u00e9tapes](http://www.google.com/landing/2step/), un m\u00e9canisme qui permet de v\u00e9rifier que la personne qui essaie de connecter \u00e0 votre compte :\n\n 1. Connaisse votre mot de passe\n 2. Ait acc\u00e8s au t\u00e9l\u00e9phone auquel le compte Google est li\u00e9.\n\nUne fois que cette fonctionnalit\u00e9 sera activ\u00e9e, il sera possible de g\u00e9n\u00e9rer un mot de passe pour une application en particulier. Cela donnera \u00e0 cette application un acc\u00e8s complet \u00e0 votre compte, mais en utilisant un mot de passe sp\u00e9cifique \u00e0 elle-seule. Pour activer tout ceci:\n\n 1. Rendez-vous sur la [page de param\u00e9trage de votre compte](https://myaccount.google.com/)\n 2. Si ce n'est pas d\u00e9j\u00e0 fait, activez l'authentification en deux \u00e9tapes (commun\u00e9ment appel\u00e9e *2-steps verification* ou encore *two factors authentication* dans la langue de Batman).\n 3. Une fois que ce sera fait, vous pourrez demander \u00e0 g\u00e9n\u00e9rer le mot de passe dont il \u00e9tait question ci-dessus. Rendez-vous sur la page [App Passwords](https://security.google.com/settings/security/apppasswords) afin d'ajouter une nouvelle entr\u00e9e.\n 4. Parmi les choix possibles, s\u00e9lectionnez `Other (custom app)` et suivez les \u00e9tapes.\n\n![app-password](/blog/content/images/2018/01/app-password.png)\n\nLe mot de passe g\u00e9n\u00e9r\u00e9 peut alors \u00eatre utilis\u00e9 dans la configuration de Pidgin sans que cela n'alt\u00e8re les autres param\u00e8tres de s\u00e9curit\u00e9.\n\nEn r\u00e9sum\u00e9, on peut se connecter \u00e0 son compte Google depuis n'importe quelle application, \u00e0 deux conditions:\n\n 1. Soit toutes les applications sont autoris\u00e9es \u00e0 se connecter,\n 2. Soit l'authentification en deux \u00e9tapes est activ\u00e9e, et un mot de passe particulier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 pour cette application.",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2014-12-29",
"title": "Authentification en deux \u00e9tapes"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "---\nTitle: Protonmail\nDate: 2015-03-23\nSlug: Protonmail\nTags: vie priv\u00e9e, privacy, mail\n---\n\nProtonmail est un service de messagerie bas\u00e9 en Suisse (visiblement plus tourn\u00e9s vers la vie priv\u00e9e?), dont le frontend est compl\u00e8tement open source et bas\u00e9 sur la librairie [OpenPGP.js](https://openpgpjs.org/).\n\nLe fonctionnement de ProtonMail est un peu diff\u00e9rent de ce qu'on trouve chez les autres providers de messagerie: votre compte client est prot\u00e9g\u00e9 par un mot de passe; la boite mail est \u00e9galement encrypt\u00e9e avec un (autre) mot de passe. En clair (sans mauvais jeu de mots), l'acc\u00e8s \u00e0 votre compte ne permet pas d'acc\u00e9der \u00e0 votre messagerie.\n\nD'autres fonctionnalit\u00e9s sont \u00e9galement disponibles, comme le partage de mails directement au sein de ProtonMail, sans que cela ne transite par un serveur SMTP classique.\n\nBref, \u00e0 surveiller (\u00e0 nouveau, sans aucun jeu de mots).\n",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2015-03-23",
"title": "---"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "---\nTitle: Play Store\nDate: 2015-09-02\nSlug: play-Store\n---\n\nEn trainant un peu sur le Play Store, j'ai un peu zieut\u00e9 le top des applications que Google propose aux utilisateurs. Parmi celles-ci, on trouve : \n\n * Facebook Messenger\n * Facebook\n * Whatsapp\n * Skype\n * Snapchat\n\nOk. Avec un petit milliard d'utilisateurs pour Facebook (et autant de p\u00e9riph\u00e9riques Android en circulation?), je suppose qu'il est normal de trouver des applications de discussions (et de r\u00e9seaux sociaux) dans les top charts. La suite est plus int\u00e9ressante, avec notamment : \n\n * Candy Crush Saga\n * Candy Crush Soda\n * Instagram\n * Fruit Ninja\n * Clash of clans\n\nBref, pas hyper convaincu par ces quelques propositions... Pour pousser un peu plus loin, je passe d\u00e9sormais par [F-Droid](https://f-droid.org/). Son catalogue ne contient que des applications open source, il s'occupe de faire les mises \u00e0 jour lorsqu'elles sont disponibles, ... \nUn peu comme le Play Store en fait, mais en libre. \n\nSuivant les usages, tout ne sera sans doute pas disponible sur F-Droid, mais ce serait d\u00e9j\u00e0 un bon d\u00e9but. A l'occasion, pensez-y pour un premier pas dans la [d\u00e9googlification](http://degooglisons-internet.org/).\n",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2015-09-02",
"title": "---"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "---\nTitle: F-Droid\nDate: 2016-05-25\nSlug: f-droid\nTags: applications, android\n---\n\nJ'ai r\u00e9cemment (= hier) r\u00e9initialis\u00e9 mon t\u00e9l\u00e9phone, suite \u00e0 un probl\u00e8me de place et de configuration. Apr\u00e8s le red\u00e9marrage, le constructeur (Samsung) a cru bon d'y ajouter un certain nombre d'applications compl\u00e8tement inutiles: Zalando, un brol pour commander des pizze, des applications propri\u00e9taires dans tous les sens, ...\n\nTant que j'y \u00e9tais, j'en ai profit\u00e9 pour essayer de passer au maximum par [F-Droid](https://f-droid.org/) (dans un but avou\u00e9 de [d\u00e9googlisation](https://degooglisons-internet.org/)). A premi\u00e8re vue, je ne m'en sors pas *trop* mal :) Il reste quelques morceaux non libres, mais c'est d\u00e9j\u00e0 un bon d\u00e9but.\n\nDepuis le [d\u00e9p\u00f4t F-Droid](https://f-droid.org/repository/browse/), j'ai s\u00e9lectionn\u00e9 les applications suivantes:\n\n * [Calendar Widget](https://f-droid.org/repository/browse/?fdfilter=calendar+widget&fdid=com.plusonelabs.calendar), pour la liste de mes prochains rendez-vous sur l'\u00e9cran d'accueil. Il est personnalisable, fonctionnel et plut\u00f4t joli. Deux petits boutons permettent d'ajouter rapidement un nouvel \u00e9l\u00e9ment ou de rafra\u00eechir les calendriers.\n * [Diaspora](https://f-droid.org/repository/browse/?fdfilter=diaspora&fdid=com.github.dfa.diaspora_android). Cette version, issue d'un fork, est normalement la derni\u00e8re en vigueur et la plus compl\u00e8te.\n * [DuckDuckGo](https://f-droid.org/repository/browse/?fdfilter=duckduck&fdid=com.duckduckgo.mobile.android), pour avoir acc\u00e8s au widget de recherche et aux *Stories*.\n * F-Droid (obviously...)\n * [FBReader](https://f-droid.org/repository/browse/?fdfilter=fbreader&fdid=org.geometerplus.zlibrary.ui.android)\n * [Firefox](https://f-droid.org/repository/browse/?fdfilter=firefox&fdid=org.mozilla.firefox)\n * [K-9 Mail](https://f-droid.org/repository/browse/?fdfilter=k9&fdid=com.fsck.k9): attention \u00e0 bien d\u00e9gager la **signature automatique** (je n'ai jamais compris ce principe...)\n * [ownCloud](https://f-droid.org/repository/browse/?fdfilter=owncloud&fdid=com.owncloud.android\n * [Shaarlier](https://f-droid.org/repository/browse/?fdfilter=shaarlier&fdid=com.dimtion.shaarlier)\n * [Tinfoil](https://f-droid.org/repository/browse/?fdfilter=tinfoil&fdid=com.mill_e.twitterwrapper) (pas encore convaincu) - pour acc\u00e9der \u00e0 Twitter de mani\u00e8re *presque* anonyme (ou en tout cas, un peu plus masqu\u00e9e).\n * [Torch](https://f-droid.org/repository/browse/?fdfilter=torch&fdid=com.doomy.torch), pour y voir plus clair dans le noir\n * [VLC](https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc) pour tous les fichiers media.\n * [Writeily Pro](https://f-droid.org/repository/browse/?fdfilter=writeily&fdid=me.writeily) pour l'\u00e9dition de fichiers Markdown.\n\nIl reste alors les applications suivantes qui d\u00e9pendent du Play Store:\n\n * [Signal Private Messenger](https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms)\n * [Bruxelles Transports](https://play.google.com/store/apps/details?id=be.digitalia.stib&hl=fr) pour ne pas me perdre...\n * [Yatse](https://play.google.com/store/apps/details?id=org.leetzone.android.yatsewidgetfree&hl=fr) pour contr\u00f4ler le media center (sur Openelec).\n * [Google Maps](https://play.google.com/store/apps/details?id=com.google.android.apps.maps&hl=fr)\n * Et les applis li\u00e9es au Synology ([DS File](https://play.google.com/store/apps/details?id=com.synology.DSfile&hl=fr) et [DS Finder](https://play.google.com/store/apps/details?id=com.synology.DSfinder&hl=fr), principalement)",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2016-05-25",
"title": "---"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "Privacy Badger\n==============\n\n[Privacy Badger](https://www.eff.org/privacybadger) est une extension pour [Firefox](https://www.eff.org/files/privacy-badger-latest.xpi) ou [Chrome](https://chrome.google.com/webstore/detail/pkehgijcmpdhfbdbbnkijodmdjhbjlgp) qui s'occupe de bloquer certaines requ\u00eates en fonction de vos habitudes. En gros, elle ne se base pas sur une liste blanche ou noire, mais sur les pages que vous visitez habituellement et sur lesquelles on trouve g\u00e9n\u00e9ralement les m\u00eames *trackers*.\n\n![](https://www.eff.org/sites/all/themes/badger/badger.png)\n\nAu fur et \u00e0 mesure, ces traceurs seront plac\u00e9s sur un mode \"hum, bof!\" jusqu'\u00e0 un blacklistage pur et simple. Je l'utilise principalement au boulot, o\u00f9 certains sites sont prohib\u00e9s (Facebook, Twitter, tout ce qui touche \u00e0 des r\u00e9seaux sociaux en gros); cela me permet d'ignorer les demandes d'acc\u00e8s *via* le serveur proxy et de ne plus \u00eatre d\u00e9rang\u00e9. Au final, cela donne une navigation plus fluide, puisque d\u00e9barass\u00e9e d'une bonne partie d'\u00e9l\u00e9ments que je n'utilise de toutes mani\u00e8res pas. Attention que lorsqu'un tracker est enti\u00e8rement bloqu\u00e9 (en rouge), cela peut aussi exploser la structure de la page (par exemple en bloquant un [CDN](https://fr.wikipedia.org/wiki/Content_Delivery_Network)).\n\nUne meilleure pr\u00e9sentation est dispo \u00e0 [l'adresse suivante](resource://jid1-mnnxcxisbpnsxq-eff-at-jetpack/data/firstRun.html#slideshow).",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2016-08-17",
"title": "Privacy Badger"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "Passage \u00e0 Windows 10. Ou Pas.\n=============================\n\nJe connais au moins deux personnes qui ont \u00e9t\u00e9 forc\u00e9es de passer \u00e0 Windows 10. Pas forc\u00e9es-oblig\u00e9es, mais-presque. Une des derni\u00e8res mises \u00e0 jour ouvrait une fen\u00eatre en plein \u00e9cran, avec un compteur, indiquant que cette nouvelle version allait s'installer end\u00e9ans les XX minutes (oui-oui, on parle en minutes :) comme dans \"Il te reste 7min39 pour profiter de cette super offre. Tu peux annuler, mais tu as jusqu'au 29 juillet pour r\u00e9fl\u00e9chir - apr\u00e8s, ce sera trop tard\". Un lien *putaclic* ne ferait pas mieux sur n'importe quel site d'actus.\n\nBref! Quand on n'y connait rien, voir cet \u00e9cran ne laisse pas vraiment d'ouverture. Une fois d\u00e9barqu\u00e9 en mode \"Saving Private Ryan\" sur les plages de Normandie, c'est *trek je plan*: le saut technologique est trop important que pour quelqu'un qui n'a pas le temps ou l'envie de se plonger dedans ne le fera pas et se sentira perdu. OK, les documents sont toujours au m\u00eame endroit, mais les diff\u00e9rences d'agencement sont relativement \u00e9loign\u00e9es; je ne critique pas (pas encore...) le dernier opus de Windows, juste son matraquage marketing oppressant, pas adapt\u00e9 aux personnes (plus) \u00e2g\u00e9es. Et aussi parce que le support informatique, quand il y a un truc qui foire, c'est pour ma pomme :) Bref, retour \u00e0 Windows 7! L'option est bien planqu\u00e9e: elle se trouve dans les param\u00e8tres ('tention! Ce n'est plus le fameux panneau de configuration, bien qu'il existe encore, ce sont les param\u00e8tres: une application en mode *m\u00e9tro* qui pr\u00e9sente diff\u00e9rentes options de mani\u00e8re-pas-si-intuitive-finalement... Donc, un petit tour dans les options syst\u00e8mes de restauration et on y trouve la possibilit\u00e9 de revenir \u00e0 Windows 7, **pour peu que le dossier `C:\\Windows.old` existe toujours!**. Si vous l'avez supprim\u00e9, ce sera perdu.\n\nApr\u00e8s r\u00e9flexion, je me demande si une distribution Linux ne ferait finalement pas mieux. Je parlais plus haut du temps pass\u00e9 \u00e0 apprendre de nouvelles technologies, mais avec l'open source, on arrive pratiquement \u00e0 une situation o\u00f9 le temps pass\u00e9 \u00e0 apprendre quelque chose de neuf ne sera jamais perdu: prenez un environnement connu (KDE): depuis ses premi\u00e8res versions, il n'a finalement pas tant \u00e9volu\u00e9 que cela. On me disait encore r\u00e9cemment que \"KDE, c'est comme Windows\": une grosse barre en dessous, un explorateur touffu et un \"menu d\u00e9marrer\". Mis \u00e0 part peut-\u00eatre le cas \"Gnome2 vs Gnome3\" (et encore; Mate s'en sort tr\u00e8s bien pour offrir une alternative cr\u00e9dible aux deux gros mastodontes cit\u00e9s ci-dessus). En plus, en fonction du choix de la distribution, les nouveaux environnements sont rarement directement adopt\u00e9s. Gnome n'a pas \u00e9t\u00e9 *releas\u00e9* partout d\u00e8s sa premi\u00e8re version, pas plus que Plasma 5 pour KDE.\n\nApr\u00e8s r\u00e9flexion donc, KDE repr\u00e9senterait une tr\u00e8s tr\u00e8s bonne alternative: il a toujours gard\u00e9 le m\u00eame comportement, en y apportant de petites am\u00e9liorations. Sa configuration est clairement beaucoup trop \u00e9labor\u00e9e pour un d\u00e9butant ou quelqu'un qui souhaite que \"it just works!\". A la recherche d'une distribution fonctionnelle par d\u00e9faut... Trois choix:\n\n 1. OpenSuse\n 2. KaOS\n 3. Gentoo. Ah non. KDE Neon pourrait \u00eatre sympa :) Voire m\u00eame une [Debian](<{filename}2014-12-27-debian.md), en fait.\n\nSi vous \u00eates d\u00e9butant, vous aurez de toutes mani\u00e8res besoin d'un coup de main pour l'installation: certains param\u00e8tres sont d\u00e9j\u00e0 bien techniques (peut-\u00eatre moins pour la KaOS qui vous accueille \u00e0 bras ouverts, en vous proposant un menu tr\u00e8s clair et concis). OpenSuse (Leap) aborde d\u00e9j\u00e0 des th\u00e8mes plus complexes, et sp\u00e9cifie \u00e0 l'utilisateur que \"la m\u00e9thode de codage du mot de passe est SHA-512\" ou que \"la m\u00e9thode d'authentification est /etc/passwd.local\". Un peu touchy... Pour le reste, rien \u00e0 dire: les options par d\u00e9faut sont bien choisies: si on n'y connait rien, on peut faire une installation *Windows-style* en cliquant fr\u00e9n\u00e9tiquement sur `suivant` jusqu'\u00e0 ce qu'il se transforme en `terminer`!\n\nApr\u00e8s l'installation, on a un syst\u00e8me pr\u00eat \u00e0 l'emploi dans tous les cas. Du bonheur :)\n\nPS : je cherche donc une ou deux personnes \u00e2g\u00e9es pour un test d'adaptation technologique au XXI\u00e8me si\u00e8cle. Cela inclut: th\u00e9orie de l'open source, mise en situation pratique apr\u00e8s suppression du cache du navigateur (\"retrouvez votre mot de passe\") et recherche d'informations en utilisant Qwant ou Duckduckgo. Repas et g\u00eete non-offerts.\n",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2016-10-07",
"title": "Passage \u00e0 Windows 10. Ou Pas."
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "Cozy Advent Calendar\n====================\n\nJe n'invente rien, je me fais juste un petit aide-m\u00e9moire par rapport au [calendrier de l'avent de Cozy](https://www.myadvent.net/calendars/?id=60a3f8cf02141a43ec6efbd8a76a02a6).\n\n1. Utilisez un navigateur qui ne vous traque pas ([Firefox](https://www.mozilla.org/fr/firefox/new/) ou [Chromium](https://www.chromium.org/getting-involved/download-chromium) - Non, pas Chrome! :-) )\n2. Installez l'extension [disconnect.me](https://disconnect.me/), t\u00e9l\u00e9chargeable directement dans le [d\u00e9p\u00f4t de greffons Firefox](https://addons.mozilla.org/en-US/firefox/addon/disconnect/?src=search)\n3. Un documentaire sur [Do not track](https://donottrack-doc.com/fr/episode/1)\n4. [Pensez \u00e0 l'auto-h\u00e9bergement](https://yunohost.org/#/)\n5. Utilisez une messagerie chiffr\u00e9e qui respecte votre vie priv\u00e9e gr\u00e2ce \u00e0 [Protonmail][https://protonmail.com/)]\n6. Gardez vos mots de passe s\u00e9curis\u00e9s gr\u00e2ce \u00e0 [Keepass](http://keepass.info/)\n7. Pour chiffrer ses messages, il y a [Signal](https://whispersystems.org/) (Update 11/12/2017: il y a peut-\u00eatre mieux, depuis...)\n8. N'utilisez pas Google, passez par [Qwant](https://www.qwant.com/) (ou [Duckduckgo](https://duckduckgo.com/)).\n9. Limiter les traces collect\u00e9es par Google, en passant par la page [activity control](https://myaccount.google.com/activitycontrols). La page [Ungoogle my life](https://myactivity.google.com/myactivity) liste, elle, toutes les informations que Google r\u00e9colte sur vous. Pensez \u00e0 d\u00e9sactiver ce qui n'est pas obligatoire.\n10. Passez par [MyPermissions](https://mypermissions.com/) pour avoir une id\u00e9e de ce que les applications pompent comme donn\u00e9es priv\u00e9es.\n11. [Reprendre le contr\u00f4le](http://framabook.org/numerique-reprendre-le-controle/)\n13. Vous voulez envoyer du contenu ? Passez par [ZeroBin](https://www.zerobin.net/).\n14. Partagez des fichiers de mani\u00e8re anonyme en utilisant [framadrop](https://framadrop.org/) (bon, perso, j'ai mon nextcloud pas loin et il me convient tr\u00e8s bien; inutile d'aller stocker du contenu sur *l'ordinateur de quelqu'un d'autre*).\n15. Venez b\u00e2tir un Internet libre, neutre et d\u00e9centralis\u00e9 avec [La Brique Internet](https://labriqueinter.net/) ! L\u00e0, j'h\u00e9site: on a bien [Neutrinet](https://neutrinet.be/), mais je n'ai pas encore franchi le pas.\n16. Un peu d'auto-promotion pour [Tristant Nitot](http://www.nitot.com/cv/), avec son livre [Surveillance://](http://cfeditions.com/surveillance/).\n17. Linux ? [Why not](http://www.ubuntu-fr.org/)?\n18. Prot\u00e9gez votre smartphone des synchronisations non souhait\u00e9es avec [SyncStop][http://syncstop.com/)]\n19. Un [tuto sur comment installer Cozy sur un Raspberrypi](https://blog.cozycloud.cc/post/2016/06/23/materiel-auto-hebergement-cozy-raspberry)\n20. Encore une extension: [uBlock Origin](https://www.ublock.org/)\n21. Envie de votre propre nom de domaine? Il y a [Gandi][https://gandi.net/).]\n22. Marre de Doodle? Utilisez [Framadata](https://framadate.org/)\n23. Un biopic sur E. Snowden \u00e0 voir au cin\u00e9ma :)\n24. Et encore un peu d'auto-promotion: utilisez [CozyCloud](https://cozy.io/fr/try-it).\n\nEn compl\u00e9ment:\n\n* [https://github.com/gorhill/uBlock/](https://github.com/gorhill/uBlock/)\n* [Privacy policy](https://github.com/gorhill/uBlock/wiki/Privacy-policy)",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2016-12-24",
"title": "Cozy Advent Calendar"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "---\ntitle: La r\u00e8gle de trois\nsummary: Ou comment se prot\u00e9ger de ces salet\u00e9s de ransomwares de m*rde\ndate: 2017-06-28\ntags: securit\u00e9, backup, synology\ncategory: S\u00e9curit\u00e9\nshow-toc: true\n---\n\n## TL; DR\n\nChaque fichier indispensable doit se trouve *a minima* sur trois solutions de sauvegarde: deux en local, une \u00e0 distance.\n\nPour les solutions en local:\n\n * Choisissez une solution autorisant un RAID 1. Ce n'est pas une solution de sauvegarde, juste une pr\u00e9vention au cas o\u00f9 un disque meurt.\n * Investissez dans un disque externe\n\nPour les solutions \u00e0 distance:\n\n * Trouvez une personne en qui vous pouvez avoir confiance et qui pourra h\u00e9berger vos donn\u00e9es.\n\n## En d\u00e9tails\n\nPetite histoire du vendredi soir: Papa m'appelle pour taper la discute et m'annonce au milieu de la conversation qu'il y a un truc bizarre \u00e0 l'\u00e9cran: *Vos fichiers ont \u00e9t\u00e9 chiffr\u00e9s, payez-nous pour r\u00e9cup\u00e9rer la cl\u00e9*. Berf. *Bouge pas, j'arrive*.\n\nLe gros stress. Le truc que je garde dans un coin de mon esprit, pour essayer de trouver une solution compl\u00e8te qui couvre tous les cas de foirage. Et j'\u00e9tais s\u00fbr d'avoir oubli\u00e9 quelque chose, mais je ne savais pas quoi. Est-ce que j'ai bien configur\u00e9 les sauvegardes? Est-ce qu'elles sont compl\u00e8tes? Est-ce qu'elles sont toujours accessibles ?\n\nDeux-trois consid\u00e9rations \u00e0 prendre en compte:\n\n 1. Cette saloperie ne fait pas **que** chiffrer les fichiers: elle d\u00e9truit \u00e9galement les sauvegardes et l'historique des fichiers Windows, pour peu qu'ils soient accessibles par l'utilisateur (et elles l'\u00e9taient). Concr\u00e8tement il suffit qu'un des fichiers de conf' soit chiffr\u00e9 pour que Windows n'arrive plus \u00e0 restaurer quoi que ce soit.\n 2. Les derni\u00e8res versions des *ransomwares* sont encore plus fourbes: elles chiffrent les fichiers **et** la MBR (et forcent un *reboot* de la machine; seule solution: avoir des sauvegardes \u00e0 l'ext\u00e9rieur).\n\nPour ma part, j'ai install\u00e9 un #Synology. L'avantage de ce genre de brol, est que cela fonctionne presque *out-of-the-box*, avec un installeur en mode clicodr\u00f4me (*next-next-finish*). Le d\u00e9savavantage, c'est qu'il faut aller un cran plus loin pour avoir une protection r\u00e9elle. Explications.\n\n### Cloud Station Backup / Cloud Station Sync\n\nUn des premiers trucs \u00e0 activer sur les postes clients: [Cloud Station Backup](https://www.synology.com/fr-fr/knowledgebase/DSM/help/CloudStationBackup/cloudstationbackup). Apr\u00e8s cr\u00e9ation des r\u00e9pertoires utilisateurs sur le NAS, cette application permet de s\u00e9lectionner certaines r\u00e9pertoires et fichiers, pour qu'ils soient automatiquement sauvegard\u00e9s vers le r\u00e9pertoire `/volumeX/homes/<user>/Backup`.\n\nLe probl\u00e8me, c'est que la synchronisation intervient en *presque-temps-r\u00e9el*: il suffit de r\u00e9aliser un chouia trop tard que la machine a \u00e9t\u00e9 infect\u00e9e pour que la synchronisation ait d\u00e9j\u00e0 eut lieu. Ce cas se pr\u00e9sente \u00e9galement si on utilise [Cloud Station Drive][https://www.synology.com/fr-fr/dsm/6.1/cloud_file_syncing], qui est *grosso-modo* un ersatz de Dropbox, OneDrive et consorts. Par rapport \u00e0 ces solutions priv\u00e9es, il n'y a en effet aucun historique de versions, \u00e0 moins que...\n\n### Synology Hyper Backup\n\n... \u00e0 moins d'avoir activer une r\u00e8gle de sauvegarde *via* [Hyper Backup](https://www.synology.com/fr-fr/knowledgebase/DSM/help/HyperBackup/data_backup). L'id\u00e9e ici est d'utiliser une solution propri\u00e9taire (beurk) qui s'occupera de cr\u00e9er un *snapshot* \u00e0 partir d'autres informations pr\u00e9sentes sur le disque.\n\nTechniquement, ces snapshots sont suppos\u00e9s se trouver sur un autre volume que les donn\u00e9es. En pratique, ce n'est pas toujours faisable.\nL'avantage d'Hyper Backup est de proposer une solution de roulement intelligent. On a en fait deux possibilit\u00e9s:\n\n 1. Soit un backup est r\u00e9alis\u00e9 \u00e0 intervalle r\u00e9gulier (tous les lundis, quotidiennement, \u00e0 19h, etc.), et on ne conserve que les X derni\u00e8res versions.\n 2. Soit les sauvegardes sont conserv\u00e9es sur [...]\n\n### Sauvegarde \u00e0 distance\n\nPour la sauvegarde \u00e0 distance, on a \u00e0 nouveau plusieurs possibilit\u00e9s. La plus simple \u00e9tant de partir d'office des donn\u00e9es pr\u00e9sentes sur le NAS, et de le laisser faire ses transferts en dehors des heures de bureau. Il n'est en effet pas n\u00e9cessaire de plomber votre connexion Internet \u00e0 un moment o\u00f9 vous pourriez en avoir besoin. Faites \u00e7a lui nuit :)\n\n## Outils\n\nEn r\u00e9sum\u00e9, on a besoin des outils suivants:\n\n 1. Une sauvegarde en local, par le syst\u00e8me d'exploitation: Windows Restore, File History, whatever.\n 2. Une sauvegarde \u00e0 distance vers un serveur accessible, si possible au travers d'un r\u00e9seau rapide (Ethernet Cat5 minimum - visez le Gigabit)\n 3. Un syst\u00e8me de r\u00e9plicat / snapshots\n 4. Un envoi \u00e0 intervalle r\u00e9gulier de ces snapshots.\n\nAu niveau de la s\u00e9curit\u00e9, pensez \u00e0 v\u00e9rifier les points suivants:\n\n 1. Les utilisateurs locaux n'ont **pas** besoin d'un acc\u00e8s \u00e0 toute la machine. Essayez de les identifier en tant qu'utilisateurs normaux.\n 2. Que les processus de sauvegarde soient ex\u00e9cut\u00e9s par des utilisateurs isol\u00e9s.\n\nPetit sch\u00e9ma qui poutre:\n",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2017-06-28",
"title": "---"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "Authentification en deux \u00e9tapes\n===============================\n\n:Summary: Je viens encore vous casser les pieds avec mes rh\u00e9toriques de s\u00e9curit\u00e9.\n\nLe m\u00e9canisme de 2-factors-authentication (2FA ou Authentification multi-facteurs) permet de s'assurer que la personne qui se connecte est bien celle qu'elle dit \u00eatre; elle prouve cet \u00e9tat en montrant en entrant un message secret qu'elle aura re\u00e7u sur son adresse email ou par SMS.\n\nSi un mot de passe est compromis, le pirate devra malgr\u00e9 tout montrer patte blanche et sera bloqu\u00e9 car il ne connaitra pas le message secret.\n\nBref, \u00e0 activer obligatoirement. Les \"grandes\" applications le permettent (GMail, Facebook, Dropbox, etc.). C'est chiant la premi\u00e8re fois, puisqu'on doit sortir son t\u00e9l\u00e9phone et entrer le code, mais celui-ci est g\u00e9n\u00e9ralement enregistr\u00e9 pour toute utilisation future.\n\nPour GMail (et Google en g\u00e9n\u00e9ral), c'est par ici: [https://myaccount.google.com/security](https://myaccount.google.com/security)\nPour Facebook, cela doit se trouver dans les param\u00e8tres de confidentialit\u00e9. Idem pour Dropbox.\n\nD'un c\u00f4t\u00e9, vous communiquerez une information sensible (votre num\u00e9ro de t\u00e9l\u00e9phone, g\u00e9n\u00e9ralement) \u00e0 la firme, d'un autre, vous lui donner d\u00e9j\u00e0 tellement que cela ne changera pas grand chose :)\n\ndes bisous.",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2017-09-01",
"title": "Authentification en deux \u00e9tapes"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "---\nTitle: Authentification en deux \u00e9tapes\nTags: 2fa, authentication\nIllustration: security.jpg\n---\n\nCoucou,\nJe viens encore vous casser les pieds avec mes rh\u00e9toriques de s\u00e9curit\u00e9.\n\nLe m\u00e9canisme de 2-factors-authentication (2FA ou Authentification multi-facteurs) permet de s'assurer que la personne qui se connecte est bien celle qu'elle dit \u00eatre; elle prouve cet \u00e9tat en montrant en entrant un message secret qu'elle aura re\u00e7u sur son adresse email ou par SMS.\n\nSi un mot de passe est compromis, le pirate devra malgr\u00e9 tout montrer patte blanche et sera bloqu\u00e9 car il ne connaitra pas le message secret.\n\nBref, \u00e0 activer obligatoirement. Les \"grandes\" applications le permettent (GMail, Facebook, Dropbox, etc.). C'est chiant la premi\u00e8re fois, puisqu'on doit sortir son t\u00e9l\u00e9phone et entrer le code, mais celui-ci est g\u00e9n\u00e9ralement enregistr\u00e9 pour toute utilisation future.\n\nPour GMail (et Google en g\u00e9n\u00e9ral), c'est par ici: [https://myaccount.google.com/security](https://myaccount.google.com/security)\nPour Facebook, cela doit se trouver dans les param\u00e8tres de confidentialit\u00e9. Idem pour Dropbox.\n\nD'un c\u00f4t\u00e9, vous communiquerez une information sensible (votre num\u00e9ro de t\u00e9l\u00e9phone, g\u00e9n\u00e9ralement) \u00e0 la firme, d'un autre, vous lui donner d\u00e9j\u00e0 tellement que cela ne changera pas grand chose :)\n\nSi questions, envoyez ;)\n\ndes bisous.\n",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2017-09-06",
"title": "---"
},
{
"category": "securit\u00e9+intimit\u00e9",
"content": "Pour d\u00e9gager l'avertissement comme quoi le mot de passe sera envoy\u00e9 en clair, il faut cocher la cl\u00e9 `security.insecure_field_warning.contextual.enabled` dans la page `about:config`.",
"keywords": [],
"path": "articles\\securit\u00e9+intimit\u00e9",
"publication_date": "2017-12-19",
"title": "Pour d\u00e9gager l'avertissement comme quoi le mot de passe sera envoy\u00e9 en clair, il faut cocher la cl\u00e9 `security.insecure_field_warning.contextual.enabled` dans la page `about:config`."
},
{
"category": "sys",
"content": "# Tethering avec un t\u00e9l\u00e9phone Android\n\nSuite \u00e0 un gros orage survenu ce samedi soir, j'ai pr\u00e9f\u00e9r\u00e9 couper tous les appareils \u00e9lectriques pour \u00e9viter de devoir lancer une exp\u00e9dition chez Mediamarkt pour tout remplacer le lendemain.\n\nMe voila donc \u00e0 tapoter gaiement sur mon laptop, avec pour seule source de donn\u00e9es, mon petit cerveau (plut\u00f4t en l'\u00e9tat de \"cerv\u00f4\u00f4\u00f4\u00f4\u00f4\" que de \"dangerous mind\", mais soit.), et un acc\u00e8s Internet sur mon t\u00e9l\u00e9phone Android, (re)flash\u00e9 r\u00e9cemment en 2.3 pour ... euh ... les besoins de la science... sans doute.\n\nL'id\u00e9e est simple: votre t\u00e9l\u00e9phone poss\u00e8de un acc\u00e8s \u00e0 Internet (GPRS, Edge, 3G, HSDPA, ...), mais pas le reste de votre \u00e9quipement? P\u00f4 grave, vous avez deux possibilit\u00e9s, toutes deux consistant \u00e0 acc\u00e9der \u00e0 Internet depuis une machine en passant par la connexion de votre Smartphone:\n\n * Soit on y acc\u00e8de _via_ un c\u00e2ble USB: quelques ondes en moins, connexion plus facile \u00e0 administrer, elle pompe \u00e9galement moins la batterie. Et on en profite pour recharger l'appareil en m\u00eame temps :)\n * Soit on partage la connexion _via_ la puce WiFi de l'appareil t\u00e9l\u00e9phonique: cela permet alors de partager les informations vers plusieurs machines (le Smartphone agit comme un point d'acc\u00e8s et devient visible pour chaque appareil poss\u00e9dant une connectivit\u00e9 WiFi), mais cela risque de drainer plus rapidement la batterie; une solution serait de brancher le t\u00e9l\u00e9phone en USB (pour la recharge) et de laisser le WiFi pour agir en tant qu'h\u00f4te.\n\nCette solution existe normalement depuis le noyau dispo sous Android 2.2, mais devrait \u00eatre fonctionnelle sur une ROM custom un peu r\u00e9cente.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2011-09-04",
"title": "# Tethering avec un t\u00e9l\u00e9phone Android"
},
{
"category": "sys",
"content": "# Miniircd\n\nSi vous cherchez \u00e0 installer un petit serveur IRC, tournez-vous vers [Miniircd](https://github.com/jrosdahl/miniircd). L'installation est super simple, et vous aurez ce qu'il faut pour lancer votre chan :)\n\nPour un client l\u00e9ger en console, c'est par ici: [irssi](https://fr.wikipedia.org/wiki/Irssi).\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2012-11-04",
"title": "# Miniircd"
},
{
"category": "sys",
"content": "# Petit m\u00e9mo SCP\n\n## T\u00e9l\u00e9chargement d'un r\u00e9pertoire du serveur\n\n``` shell\nscp -r -P <port> <login>@<server>:/path/to/the/folder .\n```\n\n## Envoi d'un fichier vers le serveur\n\n``` shell\nscp -P <port> /path/to/the/file <login>@<server>:<destination_path>\n```\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2013-03-25",
"title": "# Petit m\u00e9mo SCP"
},
{
"category": "sys",
"content": "# Configuration de CNTLM / NTLMaps\n\nCNTLM est t\u00e9l\u00e9chargeable dans sa derni\u00e8re version \u00e0 l'adresse http://cntlm.sourceforge.net/. Sous Windows, il s'installera automatiquement en tant que service. Pour le contr\u00f4ler, il vous suffira donc d'ex\u00e9cuter les commandes suivantes:\n\n``` bash\nnet start cntlm\nnet stop cntlm\n```\n\nApr\u00e8s l'installation, il reste \u00e0 le configurer (proprement). Pour cela, rendez vous dans le r\u00e9pertoire d'installation avec un shell, pour configurer les informations suivantes :\n\n 1. Le nom d'utilisateur, son mot de passe et le domaine d'authentification;\n 2. Le serveur DNS vers lequel les requ\u00eates seront envoy\u00e9es;\n 3. Le port sur lequel CNTLM va \u00e9couter les requ\u00eates entrantes (par d\u00e9faut: 3128)\n 4. Un \u00e9ventuel tunneling pour rediriger un certain port d'\u00e9coute vers une ip particuli\u00e8re.\n\n## Configuration du proxy\n\nCommencez par remplir les variables importantes; pour cela, ouvrez le fichier `cntlm.ini`\net remplissez les informations suivantes:\n\n 1. Username\n 2. Domain\n 3. Proxy\n 4. NoProxy\n 5. Listen.\n\nPour v\u00e9rifier que le proxy fonctionne bien et que le fichier `cntlm.ini` ne contient aucune erreur, tapez l'une des deux commandes suivantes:\n\n 1. `cntlm.exe -c cntlm.ini -I -M http://duckduckgo.com`\n 2. `cntml.exe -H`\n\nDans les deux cas, le mot de passe associ\u00e9 \u00e0 l'utilisateur r\u00e9f\u00e9renc\u00e9 ci-dessus vous sera demand\u00e9. Une fois obtenu, copiez le r\u00e9sultat dans le fichier `cntlm.ini`.\n\nD\u00e9marrez ensuite le proxy en mode debug avec la commande `cntlm.exe -c cntlm.ini -v`.\nPassez ensuite \u00e0 l'\u00e9tape de configuration ci-dessous et v\u00e9rifiez que tout fonctionne bien.\n\nSi tout se passe bien, d\u00e9marrez le service en arri\u00e8re-plan: `net start cntlm`\n\n## Tunneling\n\nLa configuration des tunnels se fait toujours dans le fichier cntml.ini, tout \u00e0 la fin. La syntaxe est super simple:\n\n``` bash\nTunnel\t\t<port>:<ip>:<port de destination>\n```\n\nPour rediriger le port interne 11443 vers le port 22 de l'ip 169.25.12.23, la configuration est la suivante:\n\n``` bash\nTunnel\t\t11443:169.25.12.23:22\n```\n\nEn utilisant ce port en local, vous arriverez ainsi \u00e0 vous connecter sur l'h\u00f4te distant. La configuration ci-dessus permet de se connecter sur la machine 169.25.12.23:22\nen utilisant l'h\u00f4te local et le port 11443; par exemple: `ssh localhost -p 11443 -l my_login`.\n\n## Configuration\n\n### CMD\n\nset http_proxy=http://localhost:3128\nset https_proxy=http://localhost:3128\n\nIl est possible de configurer cmder dans les param\u00e8tres `startup/environment`, qui permettent de donner directement ces deux variables. Un peu comme un fichier `bash_profile`.\n\n### pip\n\nAlors, pip, il est gentil, mais le param\u00e8tre --proxy semble lui poser un petit probl\u00e8me (que je n'ai pas plus creus\u00e9). Pour r\u00e9soudre ceci, il faut en fait initialiser les variables d'environnements de la mani\u00e8re suivante :\n\n``` bash\nexport http_proxy=\"localhost:3128\"\nexport https_proxy=\"localhost:3128\"\n```\n\n### Yarn\n\n``` bash\nyarn config set proxy http://localhost:8080\nyarn config set https-proxy http://localhost:8080\nyarn config set https_proxy http://localhost:8080\nyarn config set strict-ssl false\n```\n\nL'id\u00e9al \u00e9tant de placer ces initialisations dans un fichier .bashrc \u00e0 la racine du r\u00e9pertoire utilisateur. Pour un environnement full-windows, c'est `set` et pas `export`...\n\n### R\u00e9initialisation de la configuration\n\n```bash\nset \"http_proxy=\"\nset \"https_proxy=\"\n\nnpm config rm proxy\nnpm config rm http-proxy\nnpm config rm https-proxy\n```",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2013-04-05",
"title": "# Configuration de CNTLM / NTLMaps"
},
{
"category": "sys",
"content": "---\nTitle: Copie conforme de disques durs\nDate: 2013-11-30\nSlug: copie-conforme-de-disques-durs-dd\n---\n\nLorsque l'on remplace un disque dur, il est g\u00e9n\u00e9ralement conseill\u00e9 de r\u00e9installer le syst\u00e8me. C'est plus propre, cela permet de refaire les partitions, de nettoyer un peu les dossiers, ... Mais ce n'est pas toujours faisable non plus. Pour passer d'un disque \u00e0 un autre tout en gardant la m\u00eame installation de l'OS, le plus efficace est de passer par la commande `dd`.\n\nPour faire simple:\n\n * T\u00e9l\u00e9chargez un LiveCD / USB Linux\n * Identifiez bien chacun des disques (une erreur dans la commande pouvant simplement effacer le contenu)\n * D\u00e9marrez la machine sur l'environnement Live.\n * Identifiez chacun des disques dans le syst\u00e8me (/dev/sda, /dev/sdb, ...)\n * Lancez un terminal !\n\nA partir d'ici, lancez la commande suivante :\n\n```bash\ndd if=/dev/sdX of=/dev/sdY bs=4096 conv=notrunc,noerror\n```\n\nEn gros:\n\n * `if` identifie la source\n * `of` identifie la destination\n * `bs` permet de donner la taille des blocs \u00e0 copier. Il semble que des blocs de 4K soient le meilleur compromis sur les disques actuels.\n * `conv` ajoute les informations suivantes:\n * `notrunc` pour ne pas tronquer les donn\u00e9es\n * `noerror` ne s'arr\u00eate sur aucune erreur.\n\nCette mani\u00e8re de faire copiera tout. Les donn\u00e9es, les partitions, la MBR, ...\n\n**Sources**: [ici](http://askubuntu.com/questions/139643/update-mbr-of-new-drive-after-cloning), [l\u00e0](http://doc.ubuntu-fr.org/dd) et [l\u00e0](http://en.wikipedia.org/wiki/Dd_%28Unix%29).\n\nPour info, le temps de copie entre un Seagate 7200.12 500Go et un WD Blue 1To aura pris environ 3h40, \u00e0 raison de 102MB/s. Apr\u00e8s cette \u00e9tape, le remplacement du disque actuel par le nouveau a \u00e9t\u00e9 un jeu d'enfant.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2013-11-30",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Cr\u00e9ation d'une LiveUSB\nDate: 2014-05-05\nSlug: creation-d-une-cle-live-usb\n---\n\n# V\u00e9rification du checksum\n\nLorsque vous t\u00e9l\u00e9chargez un fichier depuis un emplacement, il se peut que certains \u00e9l\u00e9ments des fichiers diff\u00e8rent entre la source et la destination. Pour v\u00e9rifier que les deux fichiers sont identiques, on peut utiliser des [sommes de contr\u00f4le](https://fr.wikipedia.org/wiki/Somme_de_contr%C3%B4le), afin de calculer une empreinte. Cette empreinte est repr\u00e9sent\u00e9e par des caract\u00e8res alphanum\u00e9riques, et est unique (ou en tout cas essaie de l'\u00eatre: certains algorithmes pr\u00e9sentent une possibilit\u00e9 de [collisions](http://fr.wikipedia.org/wiki/Collision_%28informatique%29) - notament [MD5](http://fr.wikipedia.org/wiki/MD5)).\n\nExemple:\n\n```\n$ sha256sum wheezy-raspbian.img\n7a6cf5d1d96fcd6df0ff91e4f11c40a72a5ef3734ae8ea528e012e1c774273df wheezy-raspbian.img\n```\n\nLe fichier analys\u00e9 est `wheezy-raspbian.img` et son empreinte en utilisant `sha256` est la valeur `7a6cf5d1d96fcd6df0ff91e4f11c40a72a5ef3734ae8ea528e012e1c774273df`.\nIl existe plusieurs algos permettant cette v\u00e9rification. V\u00e9rifiez lequel lancer avant d'effectuer la comparaison.\n\n# Copie des informations sur un support amovible\n\n```\n# lsblk\n# dd bs=4M if=/path/to/archlinux.iso of=/dev/sdx && sync\n```\n\n`lsblk` liste les p\u00e9riph\u00e9riques disponibles, ainsi que les partitions d\u00e9j\u00e0 cr\u00e9\u00e9es. Avec un disque et une cl\u00e9 USB branch\u00e9e, vous devriez avoir quelque chose comme ceci : \n\n```\n[fred@aerys ~]$ lsblk\nNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT\nsda 8:0 0 119.2G 0 disk\n\u251c\u2500sda1 8:1 0 512M 0 part /boot\n\u251c\u2500sda2 8:2 0 2G 0 part\n\u251c\u2500sda3 8:3 0 30G 0 part /\n\u2514\u2500sda4 8:4 0 86.8G 0 part /home\nsdb 8:16 0 465.8G 0 disk\n\u2514\u2500sdb1 8:17 0 465.8G 0 part /run/media/fred/Chromatic\n```\n\n`/dev/sda` repr\u00e9sente mon disque principale, tandis que `/dev/sdb` repr\u00e9sente le second, branch\u00e9 en USB. Avec une carte SD, regardez du c\u00f4t\u00e9 de `/dev/mmcblkX`.\n\nAttention \u00e0 bien sp\u00e9cifier le p\u00e9riph\u00e9rique et non la partition. Apr\u00e8s cela, faites en sorte de d\u00e9marrer sur le support amovible. Si cela ne fonctionne pas, et que le BIOS/UEFI vous sort une injure genre \"pas de syst\u00e8me d'exploitation trouv\u00e9\", essayez un autre p\u00e9riph\u00e9rique.\n\n# Sources\n\n * [arch wiki live usb guide](https://wiki.archlinux.org/index.php/USB_flash_installation_media#In_GNU.2FLinux)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2014-04-05",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Retrospective\nDate: 2014-08-18\nTags: linux, gnu, arch, fedora, debian\nSlug: linux-retrospective\n---\n\nJ'ai d\u00e9couvert Linux un peu par hasard, chez le marchand de jounaux, en achetant un Linux Magazine qui contenait une Mandrake 7.1 ou 7.2. A l'\u00e9poque, pas de Live Cd, de Wubi ou de machines virtuelles: la d\u00e9couverte et l'installation ne faisaient qu'un: oblig\u00e9s d'installer l'OS pour voir de quoi il retournait. Heureusement que le dual boot \u00e9tait d\u00e9j\u00e0 d'actualit\u00e9 (et facile \u00e0 mettre en place), sans quoi la machine familiale aurait sans doute eu droit \u00e0 sa r\u00e9installation mensuelle pr\u00e9matur\u00e9e de Windows 98...\n\nApr\u00e8s avoir scand\u00e9 partout que \"Linux c'est trop bien! Au fait, comment on installe un .exe?\", la chute a \u00e9t\u00e9 relativement dure. Je me suis un peu accroch\u00e9, et j'avoue que la premi\u00e8re compilation de Gimp avec un tas de commandes incompr\u00e9hensibles dans un terminal (Konsole, puisqu'il s'agissait d'un environnement KDE) \u00e9tait sacr\u00e9ment agr\u00e9able pour le petit b\u00e9b\u00e9 g33k que j'\u00e9tais \u00e0 l'\u00e9poque. Ceci dit, la Mandrake n'aura pas tenu longtemps. J'aurai r\u00e9it\u00e9r\u00e9 l'exp\u00e9rience avec les successeuses (Mandrake 8 et 9, sorties respectivement en 2001 et 2002), mais elles n'auront pas r\u00e9ussi \u00e0 me garder. Il faut dire aussi qu'\u00e0 l'\u00e9poque, l'ordinateur \u00e9tait principalement utilis\u00e9 pour du rendu 3D avec Bryce et du chat avec MSN. Pour les jeux, la PlayStation tr\u00f4nait fi\u00e8rement au milieu du salon. \n\nEntretemps, la distribution Red Hat passera sur le grill (en version 7.x, principalement). J'utiliserai la 8 pour remettre un Celeron 400 \u00e0 jour. Si je me rappelle bien, cela avait \u00e9t\u00e9 la croix et la banni\u00e8re pour faire fonctionner le maudit modem (\"modimodem\"?) de cet OS. Pas de bol: fournir une station d'accueil pour une connexion Internet, perdu au fin fond du Sud Ouest fran\u00e7ais aurait \u00e9t\u00e9 son principal int\u00e9r\u00eat. Apr\u00e8s cela, j'aurai suivi les principales \u00e9volutions, mais en restant bien \u00e0 distance. C'est plus ou moins \u00e0 ce moment-l\u00e0 que je me suis approch\u00e9 du projet Debian; en suivant pas mal de tutoriaux (et en participant assidument au forum Linux de PCInpact), j'ai r\u00e9ussi \u00e0 la faire tourner et \u00e0 la conserver pendant un petit moment. Le bonheur d'apt-get, aptitude et autres outils de gestion. Le moins-bonheur de passer en \"testing puis sur Sid, avant de tout r\u00e9installer\".\n\nFinalement, celle qui me laissera sans doute le plus de souvenirs (et d'apprentissage) sera Gentoo. Un manuel super bien fait, une communaut\u00e9 pr\u00e9sente, des chouettes fonds d'\u00e9cran (bah quoi? On peut \u00eatre geek et esth\u00e8te :)) et beaucoup de temps de compilation devant soi m'ont permis de maintenir le syst\u00e8me pendant pratiquement toutes mes ann\u00e9es d'universit\u00e9. Ubunutu commen\u00e7ait tout doucement \u00e0 d\u00e9coller \u00e0 ce moment-l\u00e0, je l'aurai essay\u00e9 et utilis\u00e9e (puisqu'install\u00e9e par d\u00e9faut dans les salles informatiques, \u00e0 d\u00e9faut d'une Red Hat non maintenue \u00e0 jour). Cette derni\u00e8re aura beaucoup plus touch\u00e9 les foules, mais pas au m\u00eame titre que la Gentoo, qui donnait r\u00e9ellement l'impression de ma\u00eetriser le syst\u00e8me. Je ne pense pas que les flags et les optimisations possibles de GCC aient r\u00e9ellement agit sur la rapidit\u00e9 du syst\u00e8me, mais il est clair que la documentation qu'il fallait potasser avant d'arriver \u00e0 quelque chose m'a appris **BEAUCOUP**. \nMais au final, c'\u00e9tait juste g\u00e9nial d'avoir des d\u00e9p\u00f4ts complets, faciles \u00e0 utiliser (parce que oui, \u00e0 part le Stage 1 de l'installation, la maintenance demandait principalement du temps de compilation, pas du temps de compr\u00e9hension par l'utilisateur). Et quand il a fallu installer un compilateur/interpr\u00e9teur Cobol (tinyCobol) sur la machine h\u00f4te, cela a \u00e9t\u00e9 fait en deux coups de cuill\u00e8re \u00e0 Portage. Sans parler de la configuration de l'acc\u00e8s SSH pour tous mes potes \u00e9tudiants qui n'avaient pas ce qu'il fallait chez eux, qui s'embourbaient dans des compilations de d\u00e9pendances incompatibles avec leur syst\u00e8me ou qui n'y comprenaient simplement rien. Bref, joie, bonheur et cotillons (et un peu de frime aussi, j'avoue).\n\nL'installation d'un adaptateur Wifi non support\u00e9 a fini d'achever ma distribution et me forcera \u00e0 revenir \u00e0 Windows XP. Puis Vista (pour essayer). Puis 7 (par commodit\u00e9). Entretemps, j'aurai eu l'occasion d'essayer \u00e9galement une Arch Linux, cousine de Gentoo, mais pr\u00e9sentant plus de facilit\u00e9 (et de rapidit\u00e9) pour l'installation: les paquets \u00e9tant tous d\u00e9j\u00e0 compil\u00e9s pour une architecture commune (x86 ou x86_64), pas besoin de compiler chaque paquet pour les besoins sp\u00e9cifiques du processeur.\n\nEn 2010, je passerai finalement sur une Fedora, dont j'avais plus ou moins suivi les d\u00e9buts, mais que j'avais abandonn\u00e9 suite aux d\u00e9boirs de la Red Hat 8. Si je me rappelle bien, Yum n'en \u00e9tait encore qu'\u00e0 ses d\u00e9buts... Le passage \u00e0 une Fedora 15 pr\u00e9sentait forc\u00e9ment quelques (gros) changements par rapport \u00e0 une simple Red Hat 8 :) Les versions se succederont finalement jusqu'\u00e0 la Fedora 20, o\u00f9, pris d'une soudaine envie d'essayer la derni\u00e8re version de Windows (et ayant envie d'avancer sur un gros projet .Net, avec Visual Studio), je scraperai compl\u00e8tement mes partitions pour revenir sur le monde Microsoftien. Qui ne durera finalement que quelques semaines, le temps de constater que oui, Windows 8.1 n'est pas *si* mal, mais que non, d\u00e9finitivement, Linux me convient mieux! \n\nDu coup, ayant envie de revenir un peu sur Arch Linux que j'appr\u00e9cie tout particuli\u00e8rement, mais n'ayant pas envie de me retaper toute l'installation, configuration, chroot et tout le bordel, je passerai sur une Antergos, avec (quitte \u00e0 faire du changement), KDE, environnement sur lequel je n'\u00e9tais plus revenu depuis ... la Mandrake 7.1.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2014-08-18",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Installation de Debian sur un EeePc\nDate: 2014-12-27\nSlug: installation-debian-eeepc\n---\n\nUn coll\u00e8gue de Lili m'a demand\u00e9 r\u00e9cemment d'installer Linux sur son portable. La machine ressemblait \u00e0 un EeePc, avec un Atom Dual core, 1Go de RAM et un disque an\u00e9mique de 320Go qui tourne \u00e0 90 tours par seconde.\n\nPr\u00e9paration\n-----------\n\nLa premi\u00e8re \u00e9tape a \u00e9t\u00e9 de sauver les donn\u00e9es actuelles. A part quelques images, PDF et pr\u00e9sentations PowerPoint, pas grand chose \u00e0 mettre sous le disque. Pendant la copie des 20Go de donn\u00e9es, j'ai entam\u00e9 le processus de recherche de la distribution ad\u00e9quate. Parmi les candidates, je me suis dirig\u00e9 vers une distribution int\u00e9grant d'office LXDE, XFCE ou MATE, le premier me semblant \u00eatre l'id\u00e9al:\n\n 1. [Fedora LXDE](https://spins.fedoraproject.org/lxde/) : la version 21 vient en plus de sortir, les logiciels auraient \u00e9t\u00e9 suffisament \u00e0 jour et il n'y aurait pas eu grand chose \u00e0 faire pour que la machine soit fonctionnelle. Cependant, l'OS n'a jamais d\u00e9marr\u00e9: un \u00e9cran noir intervenait \u00e0 chaque fois apr\u00e8s la s\u00e9lection du syst\u00e8me sur lequel d\u00e9marrer. Je suppose qu'un param\u00e8tre au niveau de Grub aurait r\u00e9solu le probl\u00e8me, mais cela me rassure d'avoir une installation parfaitement fonctionnelle sans bidouillages.\n 2. Arch Linux : niveau rapidit\u00e9, \u00e7'aurait \u00e9t\u00e9 parfait, mais cette distribution ne me semble pas adapt\u00e9e pour d\u00e9buter sous Linux. Keep It Simple ! (but accessible en m\u00eame temps).\n 3. [Debian avec LXDE](http://lxde.org/) : le site d'LXDE r\u00e9f\u00e9rence [une image de Debian 7.6](http://cdimage.debian.org/debian-cd/current-live/i386/iso-hybrid/debian-live-7.6.0-i386-lxde-desktop.iso). Les liens de t\u00e9l\u00e9chargement ne fonctionnant pas, je n'ai pas cherch\u00e9 \u00e0 approfondir le sujet. Puis tant qu'\u00e0 installer Debian avec LXDE, autant installer directement Debian, puis LXDE par apr\u00e8s.\n 4. [Lubuntu](http://lubuntu.net/) (Ubuntu 14.10 avec LXDE, vous vous en doutiez). Cela me semblait \u00eatre une bonne solution, et \u00e7'aurait \u00e9t\u00e9 la suivante si Debian n'avait pas fonctionn\u00e9 comme je le souhaitais.\n\nCr\u00e9ation du disque et installation\n----------------------------------\n\nPour copier l'image sur un p\u00e9riph\u00e9rique externe (ma cl\u00e9 USB ne fonctionne pas, j'ai choisi une carte SD de 4Go), il suffit d'utiliser la commande `dd`, de sp\u00e9cifier l'image d'origine, le p\u00e9riph\u00e9rique de destination et la taille des blocks: `dd bs=4M if=/path/to/archlinux.iso of=/dev/sdx && sync` (Pour lister les p\u00e9riph\u00e9riques disponibles, utilisez la commande `lsblk`).\n\nEn fait, l'installation de Debian s'est super bien d\u00e9roul\u00e9. Tout le mat\u00e9riel (\u00e0 l'exception du Bluetooth, voir plus bas) a \u00e9t\u00e9 parfaite, \u00e0 tel point que les deux interfaces r\u00e9seaux ont \u00e9t\u00e9 d\u00e9tect\u00e9es **pendant** l'installation! J'ai l'habitude d'avoir des cartes WiFi propri\u00e9taires: que l'installeur me propose automatiquement de me connecter \u00e0 un r\u00e9seau disponible m'a \u00e9tonn\u00e9. Surtout que je partais avec beaucoup d'*a priori* concernant les nouveaut\u00e9s disponibles dans la distribution.\nDurant l'installation, on a le choix des paquets utilis\u00e9s. J'en ai profit\u00e9 pour supprim\u00e9 Gnome (par d\u00e9faut) et cocher LXDE et Mate, OpenBox ne me semblant pas \u00eatre une bonne solution pour un n\u00e9ophyte.\n\nLes partitions propos\u00e9es automatiquement \u00e9taient un *chouia* bizarres \u00e9galement. 10Go pour le syst\u00e8me me semblait un peu limite... J'ai pr\u00e9f\u00e9r\u00e9 un partitionnement plus classique:\n\n * /boot de 512M\n * swap de 2G\n * / de 30 ou 40G\n * le reste (environ 280G) pour /home\n\nLors du premier d\u00e9marrage, plein de bonnes nouvelles:\n\n * J'ai install\u00e9 Jessie et non Wheezy. M\u00eame Mate en \u00e9tait \u00e0 sa derni\u00e8re version.\n * Toutes les *hotkeys* \u00e9taient fonctionnelles. Pas que ce soit \u00e9tonnant, mais c'est toujours agr\u00e9able ne pas avoir \u00e0 tripatouiller la config' d'Xorg pour que cela fonctionne.\n * Les interfaces r\u00e9seaux qui fonctionnent *out-of-the-box*\n * Le lecteur de carte SD aussi (heureusement, puisque c'\u00e9tait mon support d'installation...)\n\nPour le Bluetooth, la seule contrainte a \u00e9t\u00e9 d'activer les d\u00e9p\u00f4t `non-free` parmi les sources pour les paquets. Apr\u00e8s cela, il a fallu installer le paquet `firmware-atheros` (ainsi que l'applet pour la gestion des associations). Pour info, Mate utilise d\u00e9sormais Blueman [depuis sa version 1.8](https://wiki.archlinux.org/index.php/MATE#Bluetooth) et non pas `gnome-bluetooth-applet`.\n\nNiveau performances, cela se tra\u00eene un peu au d\u00e9marrage, mais une fois la session Mate charg\u00e9e, tout semble bien fonctionner.\nLa r\u00e9solution de l'\u00e9cran est un peu limite, mais \u00e0 nouveau, elle suffit pour consulter des pages Web et quelques documents.\n\n# Notes\n\n * J'ai activ\u00e9 le `popularity-contest`, afin d'envoyer des statistiques sur l'utilisation des paquets. Pour en modifier le comportement, il suffit de lancer la commande `dpkg-reconfigure popularity-contest`.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2014-12-27",
"title": "---"
},
{
"category": "sys",
"content": "Title: Automatisation des sauvegardes Wordpress\n\nhttp://codex.wordpress.org/WordPress_Backups\n\nWordpress est un CMS cod\u00e9 en PHP et dont les donn\u00e9es sont stock\u00e9es dans une base MySQL. Les images et param\u00e8tres particuliers sont plac\u00e9s dans un r\u00e9pertoire `wp-content`. Toutes ces informations (configuration + assets + base de donn\u00e9es) doivent \u00eatre sauvegard\u00e9s r\u00e9guli\u00e8rement, pour pouvoir restaurer la situation telle qu'elle \u00e9tait au moment souhait\u00e9.\n\nLe site [codex.wordpress.org] a bien une section concernant les sauvegardes automatiques, mais son contenu est un peu insuffisant : \n\n> Various plugins exist to take automatic scheduled backups of your WordPress database. This helps to manage your backup collection easily. You can find automatic backup plugins in the Plugin Browser on the WordPress Administration Screens or through the WordPress Plugin Directory. \n\nQuelques liens sont donn\u00e9s en plus, afin d'aller un peu plus loin dans la sauvegarde des donn\u00e9es, notamment : \n\n * [A shell script for a complete wordpress backup](http://theme.fm/2011/06/a-shell-script-for-a-complete-wordpress-backup-4/)\n * [Backing up your database](http://codex.wordpress.org/Backing_Up_Your_Database)\n * [Restoring your database from backup](http://codex.wordpress.org/Restoring_Your_Database_From_Backup)\n\nPour la sauvegarde, on va d\u00e9finir les \u00e9tapes suivantes:\n\n 1. Sauvegarder la base de donn\u00e9es\n 2. Sauvegarder les donn\u00e9es\n 3. Automatisation tout ce brol en se basant sur le premier lien, ci-dessus.\n\nSauvegarde des donn\u00e9es\n----------------------\n\nPour la base de donn\u00e9es, le plus simple est d'utiliser la commande `mysqldump` pour copier la structure des tables et leurs donn\u00e9es dans un fichier. Il existe un plugin ([WP-DBManager](https://wordpress.org/plugins/wp-dbmanager/)), qui fait exactement la m\u00eame chose, si vous pr\u00e9f\u00e9rez.\n\n``` \nmysqldump --add-drop-table -h <server_name> -u <db_user> -p <db_name> | gzip > backup-2015-01-04.bak.sql.gz\n``` \n\nIl faut ensuite sauvegarder le contenu de l'installation, afin de pouvoir restaurer les m\u00e9dia, la configuration, les th\u00e8mes, etc.\n\nUn script [existe](http://theme.fm/wp-content/uploads/2011/06/wordpress-backup-shell-script.txt) et s'occupe tr\u00e8s bien de toutes ces \u00e9tapes. Ce script doit \u00eatre adapt\u00e9 un chouia pour correspondre \u00e0 vos besoins (notamment sur le nom des fichiers g\u00e9n\u00e9r\u00e9s). En cas de modifications/am\u00e9liorations, n'h\u00e9sitez pas \u00e0 [poster vos changements](http://theme.fm/2011/06/a-shell-script-for-a-complete-wordpress-backup-4/).\nPour ma part, les changements effectu\u00e9s sont dispos ci-dessous et sur [Gist](https://gist.github.com/Grimbox/5609ee6eb8fd1947cc55). Ils prennent les param\u00e8tres pass\u00e9s au script pour les attribuer \u00e0 l'URL du site, au nom d'utilisateur, mot de passe et nom de la base de donn\u00e9es. Pas encore parfait, loin de l\u00e0:\n\n```\n#!/bin/bash\n\n# This script creates a compressed backup archive of the given directory and the given MySQL table. More details on implementation here: http://theme.fm\n# Feel free to use this script wherever you want, however you want. We produce open source, GPLv2 licensed stuff.\n# Author: Konstantin Kovshenin exclusively for Theme.fm in June, 2011\n# Modified by me in June 2015.\n\n# Set the date format, filename and the directories where your backup files will be placed and which directory will be archived.\nNOW=$(date +\"%Y-%m-%d-%H%M\")\n\nSITEURL=\"$1\"\nUSERNAME=$(whoami)\n\nFILE=\"$SITEURL.$NOW.tar\"\nBACKUP_DIR=\"/home/$USERNAME/backups\"\nWWW_DIR=\"/var/www/$SITEURL/\"\n\n# MySQL database credentials\nDB_USER=\"$2\"\nDB_PASS=\"$3\"\nDB_NAME=\"$4\"\nDB_FILE=\"$SITEURL.$NOW.sql\"\n\n# Tar transforms for better archive structure.\nWWW_TRANSFORM=\"s,^var/www/$SITEURL,www,\"\nDB_TRANSFORM=\"s,^home/$USERNAME/backups,database,\"\n\n# Create the archive and the MySQL dump\ntar -cvf $BACKUP_DIR/$FILE --transform $WWW_TRANSFORM $WWW_DIR\nmysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $BACKUP_DIR/$DB_FILE\n\n# Append the dump to the archive, remove the dump and compress the whole archive.\ntar --append --file=$BACKUP_DIR/$FILE --transform $DB_TRANSFORM $BACKUP_DIR/$DB_FILE\nrm $BACKUP_DIR/$DB_FILE\ngzip -9 $BACKUP_DIR/$FILE\n```\n\nRestaurer les donn\u00e9es dans la base\n----------------------------------\n\nEn partant du fichier `backup-2015-01-04.bak.sql.gz` g\u00e9n\u00e9r\u00e9 ci-dessus, on doit d'abord le d\u00e9compresser, puis importer le contenu dans la base SQL. Comme on a ajout\u00e9 l'option `--add-drop-table`, le drop s'effectue avant que l'import ne s'effectue, si la table existe d\u00e9j\u00e0. Par exemple : \n\n```\nDROP TABLE IF EXISTS `wp_commentmeta`;\n/*!40101 SET @saved_cs_client = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `wp_commentmeta` (\n\t`meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n\t`comment_id` bigint(20) unsigned NOT NULL DEFAULT '0',\n\t`meta_key` varchar(255) DEFAULT NULL,\n\t`meta_value` longtext,\n\tPRIMARY KEY (`meta_id`),\n\tKEY `comment_id` (`comment_id`),\n\tKEY `meta_key` (`meta_key`)\n) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8;\n```\n\nBref, on d\u00e9compresse le fichier, et on l'importe dans la db:\n\n``` \nmysql -h localhost -u <db_user> -p <db_name> < backup-2015-01-04.bak.sql\n# ex : mysql -h localhost -u wp_user -p wp_db < backup-2015-01-04.bak.sql\n```",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-01-07",
"title": "Title: Automatisation des sauvegardes Wordpress"
},
{
"category": "sys",
"content": "---\nTitle: /etc/skel/.bashrc\nDate: 2015-01-09\nSlug: etc-skel-bashrc\nTags: linux, bash\n---\n\n## What the skel?\n\nLe r\u00e9pertoire `/etc/skel/` contient les fichiers par d\u00e9faut qui seront copi\u00e9s lorsqu'un nouvel utilisateur sera cr\u00e9\u00e9. Sur ma ch'tite [Fedora](http://fedoraproject.org/) ador\u00e9e, ce dossier contient d\u00e9j\u00e0 les fichiers suivants :\n\n * **.bash_profile**, utilis\u00e9 lorsque l'utilisateur se connecte via un tty\n * **.bashrc**, utilis\u00e9 lorsque l'utilisateur lance connexion \u00e0 un terminal depuis une session d\u00e9j\u00e0 authentifi\u00e9e.\n * **.bash_logout**, vide (ouaip, par d\u00e9faut, il ne se passe rien; mais la modification de ce fichier permettrait d'ex\u00e9cuter un certain nombre d'actions lorsque l'utilisateur se d\u00e9connecte)\n\nSur [Antergos](http://antergos.com/) par contre, le dossier est compl\u00e8tement vide. On va remplir tout \u00e7a.\n\n## Message d'accueil\n\nPour que `bash` vous souhaite la bienvenue \u00e0 l'ouverture, passez par `fortune-mod`. C'est une application pr\u00e9sente sur la plupart des distributions, et qui sort un ensemble de citations de mani\u00e8re al\u00e9atoire. Par contre, l'installation de plugins suppl\u00e9mentaires (genre Calvin & Hobbes ou Chuck Norris) n\u00e9cessitera peut-\u00eatre de passer par une installation manuelle. Sous Arch, il y a [les Arch User Repositories](https://aur.archlinux.org/packages.php?O=0&L=0&C=0&K=fortune-mod&SeB=nd&PP=25&do_Search=Go) :)\n\n```\nsudo yaourt -S fortune-mod fortune-mod-calvin\n\nfred@gaw ~/Sources $ fortune\nThe more I know men the more I like my horse.\n\nfred@gaw ~/Sources $ fortune calvin\nCalvin: I think we have got enough information now, don't you?\nHobbes: All we have is one \"fact\" that you made up.\nCalvin: That's plenty. By the time we add an introduction, a few\n\t\tillustrations and a conclusion, it'll look like a graduate\n\t\tthesis.\n```\n\nApr\u00e8s, il suffit d'ajouter `fortune calvin` (ou le mod choisi) au d\u00e9but du fichier `.bashrc`. On peut \u00e9galement ajouter un appel \u00e0 `cowsay` ou `cowthink` avec un pipe depuis `fortune`, et on aura un beau message de login.\n\nBref, dans le fichier `.bashrc`, cela revient \u00e0 ajouter ceci :\n\n```\nif [ -x /usr/bin/fortune ]; then\n\tfortune calvin\nfi\n```\n\nOn teste que `fortune` existe, et si oui, on le lance au d\u00e9marrage de la session du shell.\n\n## Quelques couleurs et informations\n\nCe fichier, c'est d'abord l'emplacement pour associer un peu de couleurs au shell, en red\u00e9finissant la variable $PS1. Le [wiki d'ArchLinux](https://wiki.archlinux.org/index.php/Color_Bash_Prompt) est assez complet \u00e0 ce sujet. Ma config' pr\u00e9f\u00e9r\u00e9e reste cependant celle h\u00e9rit\u00e9e de [Gentoo](https://www.gentoo.org/):\n\n```\nif [[ ${EUID} == 0 ]] ; then\n\tPS1='\\[\\033[01;31m\\]\\h\\[\\033[01;34m\\] \\W \\$\\[\\033[00m\\] '\nelse\n\tPS1='\\[\\033[01;32m\\]\\u@\\h\\[\\033[01;34m\\] \\w \\$\\[\\033[00m\\] '\nfi\n```\n\nComme cette condition v\u00e9rifie si l'utilisateur courant est *root* ou non, il convient de la placer dans le bashrc global, et non au niveau de l'utilisateur courant. L'emplacement de ce fichier-ci d\u00e9pend vraiment de la distribution. Sous Arch par exemple, il se trouve dans `/etc/bash.bashrc`.\n\nUn autre truc int\u00e9ressant, c'est de pouvoir afficher la branche git sur laquelle on travaille, ainsi que l'environnement virtuel dans lequel on se trouve. Il existe normalement un fichier de compl\u00e9tion pour le shell, mais je n'ai pas r\u00e9ussi \u00e0 le faire fonctionner. Du coup, j'ai trouv\u00e9 [une autre solution](https://coderwall.com/p/fasnya). En combinant avec la variable $PS1 pr\u00e9c\u00e9dente, cela revient \u00e0 ceci :\n\n``` bash\nparse_git_branch() {\n\tgit branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/ (\\1)/'\n}\n\nexport PS1=\"\\[\\033[01;32m\\]\\u@\\h\\[\\033[01;34m\\] \\w\\[\\033[33m\\]\\$(parse_git_branch)\\[\\033[00m\\] $ \"\n```\n\nPour les environnements virtuels en Python, il suffit de passer par `virtualenvwrapper`.\n\n``` bash\nexport WORKON_HOME=$HOME/.virtualenvs\nexport PROJECT_HOME=$HOME/Sources\nsource /usr/bin/virtualenvwrapper.sh\n```\n\nLe nom de l'environnement s'ajoutera automatiquement au d\u00e9but de la ligne.\n\n## Quelques fonctions utiles\n\nBref, si on veut avoir un ensemble de fonctions pr\u00eate-\u00e0-utiliser, c'est le bon emplacement. Par exemple sur [SamEtMax](http://sametmax.com), on trouve un article intitul\u00e9 [`\u00e0 l'int\u00e9rieur de mon bashrc`](http://sametmax.com/a-linterieur-de-mon-bashrc/). Parmi les quelques fonctions exprim\u00e9es, on trouve par exemple:\n\n``` bash\nextract () {\nif [ -f $1 ]\n\tthen\n\t\tcase $1 in\n\t\t\t(*.7z) 7z x $1 ;;\n\t\t\t(*.lzma) unlzma $1 ;;\n\t\t\t(*.rar) unrar x $1 ;;\n\t\t\t(*.tar) tar xvf $1 ;;\n\t\t\t(*.tar.bz2) tar xvjf $1 ;;\n\t\t\t(*.bz2) bunzip2 $1 ;;\n\t\t\t(*.tar.gz) tar xvzf $1 ;;\n\t\t\t(*.gz) gunzip $1 ;;\n\t\t\t(*.tar.xz) tar Jxvf $1 ;;\n\t\t\t(*.xz) xz -d $1 ;;\n\t\t\t(*.tbz2) tar xvjf $1 ;;\n\t\t\t(*.tgz) tar xvzf $1 ;;\n\t\t\t(*.zip) unzip $1 ;;\n\t\t\t(*.Z) uncompress ;;\n\t\t\t(*) echo \"don't know how to extract '$1'...\" ;;\n\t\tesac\n\telse\n\t\techo \"Error: '$1' is not a valid file!\"\n\t\texit 0\n\tfi\n}\n```\n\n## Conclusion\n\nAu final, mon fichier .bashrc ressemble \u00e0 ceci:\n\n```bash\nif [ -x /usr/bin/fortune ]; then\n\tfortune calvin\nfi\n\nparse_git_branch() {\n\tgit branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/ (\\1)/'\n}\n\nexport PS1=\"\\[\\033[01;32m\\]\\u@\\h\\[\\033[01;34m\\] \\w\\[\\e[0;31m\\]\\$(parse_git_branch)\\[\\033[00m\\] $ \"\n\nexport WORKON_HOME=$HOME/.virtualenvs\nexport PROJECT_HOME=$HOME/Sources\nsource /usr/bin/virtualenvwrapper.sh\n```\n\nEt des fois que je me connecte en root, j'ai ajout\u00e9 ceci dans le fichier /etc/bash.bashrc:\n\n``` bash\nif [[ ${EUID} == 0 ]] ; then\n\tPS1='\\[\\033[01;31m\\]\\h\\[\\033[01;34m\\] \\W \\$\\[\\033[00m\\] '\nfi\n```\n\nLe contenu du fichier .bash_profile est assez simple. En r\u00e9sum\u00e9, il va v\u00e9rifier si un fichier .bashrc existe (ou non) et le charger.\n\n``` bash\n# Get the aliases and functions\nif [ -f ~/.bashrc ]; then\n\t. ~/.bashrc\nfi\n\n# User specific environment and startup programs\nPATH=$PATH:$HOME/.local/bin:$HOME/bin\nexport PATH\n```\n\n## Sources\n\n * http://sphericalcow.wordpress.com/2009/04/05/bashrc-by-example/\n * http://www.linfo.org/etc_skel.html\n * http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-01-09",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: rsync\nDate: 2015-01-17\n---\n\nPour transf\u00e9rer des fichiers de mani\u00e8re s\u00e9curis\u00e9, rien de mieux qu'SSH (ou qu'un disque externe coul\u00e9 dans du b\u00e9ton. Au choix). [SCP](|filename|2013-03-25 scp-basics.md) permet par exemple de transf\u00e9rer des fichiers au travers du protocole ssh, mais ne g\u00e8re pas la reprise d'un transfert \u00e9chou\u00e9. Pour plus de fonctionnalit\u00e9s, il existe [rsync](https://rsync.samba.org/), qui offre \u00e0 nos petits yeux \u00e9bahis plein de nouvelles fonctionnalit\u00e9s super utiles: la reprise de transfert en cas de foirage complet, la synchronisation de dossiers, ... C'est un outil de sauvegarde pratique, sur lequel se basent notamment [Duplicity](http://duplicity.nongnu.org/) et [Deja-Dup](https://launchpad.net/deja-dup).\n\nUtilisation\n-----------\n\n```\n$ rsync -r -P -e ssh login@server:path/ folder/\n```\n\nDans l'exemple ci-dessus, les param\u00e8tres sont:\n\n * `-r` pour un transfert r\u00e9cursif. Sans ce param\u00e8tre, seul les fichiers pr\u00e9sents dans le dossier racine seront transf\u00e9r\u00e9s.\n * `-P` pour avoir le m\u00eame effet que `--partial --progress`: une barre de progression s'affiche pour chaque fichier transf\u00e9r\u00e9, et le t\u00e9l\u00e9chargement de fichiers incomplets est repris \u00e0 l'endroit o\u00f9 il avait \u00e9t\u00e9 abandonn\u00e9.\n * `-e` pour sp\u00e9cifier le shell \u00e0 utiliser\n * Les deux derniers param\u00e8tres sont : `SOURCE` et `DESTINATION`. Ici, on va se connecter avec l'utilisateur `login` sur la machine `server` et rapatrier tous les dossiers qui se trouvent dans `path` vers le r\u00e9pertoire local qui s'appelle `folder`.\n\nParmi les autres param\u00e8tres int\u00e9ressants:\n\n * `-t` pour garder les informations de dates de modifications sur les fichiers\n * `-v` pour entrer dans un mode verbeux\n * `-u` pour synchroniser les dossiers, en prenant en compte les dates de modifications des fichiers pour savoir s'il doit envoyer une nouvelle version ou non. Attention que ce param\u00e8tre n'a pas d'int\u00e9r\u00eat si le transfert pr\u00e9c\u00e9dent a \u00e9chou\u00e9: comme le fichier (a moiti\u00e9) transf\u00e9r\u00e9 a la m\u00eame heure et date de modification que le fichier qu'rsync tente d'envoyer, il sera simplement *skipp\u00e9*, alors qu'il aurait d\u00fb continuer le transfert gr\u00e2ce au param\u00e8tre `-P`. Pour une sauvegarde/copie, \u00e9vitez ce param\u00e8tre, sauf si vous \u00eates s\u00fbr que la copie pr\u00e9c\u00e9dente a r\u00e9ussi.\n * `--delete` pour supprimer les fichiers qui se trouvent dans la destination, mais pas dans la source\n * `-z` pour compresser les fichiers et gagner un peu au niveau du transfert.\n\nAttention \u00e9galement aux `/` apr\u00e8s les chemins vers les r\u00e9pertoires. Oubliez le, et cela cr\u00e9era un nouveau r\u00e9pertoire dans le r\u00e9pertoire cible. Ajoutez le pour ne synchroniser que le contenu.\n\nSynology\n--------\n\nSi vous comptez utiliser votre Synology comme r\u00e9pertoire de destination, il se peut que vous tombiez sur le message d'erreur suivant:\n\n```\nPermission denied, please try again.\nrsync: connection unexpectedly closed (0 bytes received so far) [sender]\nrsync error: error in rsync protocol data stream (code 12) at io.c(226) [sender=3.1.1]\n```\n\nSi c'est le cas, vous devrez activer un service sur le NAS:\n\n * Dans `Main Menu`, cliquez sur `Backup & Replication` et s\u00e9lectionnez `Backup Services`.\n * Dans cet onglet, cochez l'option `Enable network backup service`.\n\nA pr\u00e9sent, vous pourrez utiliser `rsync` pour transf\u00e9rer vos documents vers le NAS.\n\nMon but ici est de synchroniser mon profil utilisateur (`~/` en gros). De nouveau, avec la commande ci-dessus, cela va synchroniser **tous** mes documents et fichiers. Probl\u00e8me: cela embarque \u00e9galement les `dot files`. Une solution pour ceci est d'ajouter le param\u00e8tre `--exclude \".*\"`.\n\nFinalement\n----------\n\nEn combinant tous les param\u00e8tres, ma commande rsync ressemble est la suivante:\n\n```\nrsync -rtv -P -e \"ssh -p 11111\" my_folder/ login@server:path/ --exclude \".*\" --delete\n```\n\nSources\n-------\n\n * [StackOverflow](http://stackoverflow.com/questions/20860896/is-there-a-way-to-continue-broken-scp-secure-copy-command-process-in-linux)\n * [Rsync: Permission Denied @ Synology](http://forum.synology.com/enu/viewtopic.php?t=92627)\n * [Synchronizing folders with rsync](http://www.jveweb.net/en/archives/2010/11/synchronizing-folders-with-rsync.html)\n * [rsync non standard ssh port](http://mike-hostetler.com/blog/2007/12/08/rsync-non-standard-ssh-port/)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-01-17",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: GitWeb\nDate: 2015-01-22\nSlug: gitweb\nTags: git, web, serveur\n---\n\n[GitWeb](http://git-scm.com/docs/gitweb.html) est un frontend Web permettant de visualiser des d\u00e9p\u00f4ts Git. En gros (et apr\u00e8s traduction), ses principales fonctions sont les suivantes:\n\n * Visualiser plusieurs d\u00e9p\u00f4ts ayant la m\u00eame racine\n * Parcourir toutes les r\u00e9visions d'un d\u00e9p\u00f4t donn\u00e9\n * Visualiser le contenu des fichiers du d\u00e9p\u00f4t (\u00e0 partir de n'importe quelle r\u00e9vision)\n * Visualiser les logs\n * G\u00e9n\u00e9rer un flux RSS/Atom pour tous les commits d'une branche\n * ...\n\nBref, sans atteindre les fonctionnalit\u00e9s d'un [GitHub](http://github.com) ou d'un [GitLab](https://about.gitlab.com/), GitWeb fera tr\u00e8s bien son boulot.\n\nCommencez par cr\u00e9er l'utilisateur `git`, gr\u00e2ce \u00e0 la commande `sudo adduser git`. Ceci va (normalement) cr\u00e9er le r\u00e9pertoire `/home/git` et tous les droits qui lui sont associ\u00e9s. Les d\u00e9p\u00f4ts seront alors stock\u00e9s dans le r\u00e9pertoire `/home/git/repositories`.\n\nPour Nginx, voici un exemple de configuration:\n\n```\nlocation /git/ {\n\talias /usr/share/gitweb/;\n\tfastcgi_param SCRIPT_FILENAME /usr/share/gitweb/index.cgi;\n\tinclude fastcgi_params;\n\tgzip off;\n\tfastcgi_param GITWEB_CONFIG /etc/gitweb.conf;\n\tfastcgi_pass unix:/var/run/fcgiwrap.socket;\n}\n```\n\nEt finalement, comme le th\u00e8me par d\u00e9faut est peut-\u00eatre un peu aust\u00e8re, il est possible de le modifier facilement en suivant les \u00e9tapes d\u00e9finies [ici](https://github.com/kogakure/gitweb-theme).\n\nSources\n-------\n\n * [Git-scm.com](http://git-scm.com/book/en/Git-on-the-Server-GitWeb)\n * [GitWeb & Nginx](https://misterpinchy.wordpress.com/2012/11/01/gitweb-and-nginx/)\n * [Running GitWeb in fast-cgi mode](https://sixohthree.com/1402/running-gitweb-in-fastcgi-mode)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-01-22",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Virtual Private Server\nDate: 2015-02-07\nSlug: virtual-private-server\n---\n\nJ'ai ouvert un compte chez [WebFaction](http://webfaction.com/) en f\u00e9vrier 2012, suite \u00e0 une promotion qu'ils faisaient. Pour ~180\u20ac pay\u00e9s, je recevais en fait un cr\u00e9dit de plus de 225\u20ac, ce qui revenait plus ou moins \u00e0 6,50$ / mois pour un serveur partag\u00e9 chez eux; c\u00e0d\n\n * 512 Mo de RAM\n * 100 Go d'espace disque\n\nCet abonnement arrivant \u00e0 terme (et ayant envie de changer un peu, et de profiter d'un serveur plus complet qu'un shared server), je me dirige vers l'offre VPS Classic d'OVH. Plusieurs raisons :\n\n * Impossible de trouver un [kimsufi](http://www.kimsufi.com/fr/) KS-1. La version KS-2 est dispo par contre, mais co\u00fbte quasiment le double pour quelque chose dont je n'aurai sans doute pas besoin.\n * Les offres SoYouStart sont hyper tentantes, mais ne r\u00e9pondent sans doute pas non plus \u00e0 ce que je souhaiterais/aurais besoin\n * Idem pour les offres Online.net ([Dedibox et co.](http://www.online.net/en/dedicated-server/dedibox-classic)).\n\n=> Pour me faire la main sur de l'h\u00e9bergement de sites php/python, bases de donn\u00e9es (MySQL/MongoDB/Redis) et un peu de stockage de fichiers ([Seafile](https://www.seafile.com/en/home/)), je me suis pris l'offre la plus basique au niveau des VPS Classic: 1 vCore, 1Go de RAM et 10Go d'espace disque. Quand on disait basique... :)\n\nAu niveau de l'installation, on a le choix parmi plusieurs distributions. Apr\u00e8s un petit essai avec une Ubuntu 14.04, je me tente une Debian 7. Quelques points \u00e0 voir apr\u00e8s l'installation de l'OS:\n\n * La S\u00e9curit\u00e9 et la configuration de base du serveur : cr\u00e9ation d'un utilisateur (ou plusieurs) utilisateurs pour la connexion SSH, d\u00e9sactivation du login root, installation de fail2ban.\n * La configuration : installation d'nginx, varnish et memcache. Puis installation de Mysql (mariadb?) pour la DB \u00e0 utiliser avec Wordpress.\n * le ReverseProxy : utilisation d'un nom de domaine achet\u00e9 chez Gandi :)\n\n# S\u00e9curit\u00e9 et configuration de base\n\nUn article sur le [forum de Clubic](http://www.clubic.com/forum/hardware-general/raspberry-pi-ze-topic-id877239-page1.html#1802451955) donne plein de conseils en prenant le raspberry pi comme base.\n\n# Configuration\n\nPour nginx, il existe un script d'installation chez [Nicolargo](https://raw.githubusercontent.com/nicolargo/debianpostinstall/master/nginxautoinstall.sh). Pour le t\u00e9l\u00e9choper, utilisez `wget https://raw.githubusercontent.com/nicolargo/debianpostinstall/master/nginxautoinstall.sh --no-check-certificate`. \nL'installation consiste entre autre \u00e0 t\u00e9l\u00e9charger les d\u00e9pendances pour la compilation d'nginx, \u00e0 ajouter le r\u00e9pertoire [dotdeb](http://www.dotdeb.org/), installer PHP5-FPM, les outils de d\u00e9veloppement et MemCache.\n\nApr\u00e8s ex\u00e9cution du script, on a un petit r\u00e9capitulatif d'installation : \n\n```\n\tNGinx configuration folder: /etc/nginx\n\tNGinx default site configuration: /etc/nginx/sites-enabled/default-site\n\tNGinx default HTML root: /var/www\n\tRead this to configure Naxsi: https://github.com/nbs-system/naxsi/wiki/basicsetup\n\tPageSpeed cache directory: /var/ngx_pagespeed_cache\n\tRead this to configure PageSpeed: https://developers.google.com/speed/pagespeed/module/configuration\n\t\n\tInstallation script log file: /tmp/nginxautoinstall-20141019201236.log\n```\n\nPlacez un fichier `index.html` dans le r\u00e9pertoire `/var/www/` et acc\u00e9der \u00e0 votre instance *via* son URL. Vous devriez vous le contenu.\n\nVoir aussi [ici](http://stackoverflow.com/questions/21524373/nginx-connect-failed-111-connection-refused-while-connecting-to-upstream) apr\u00e8s l'installation.\n\nLes logs se trouvent dans `/var/log/nginx/[access|error].log`. La configuration (sur Debian & Ubuntu) se fait gr\u00e2ce \u00e0 `service [start|stop|restart|status] nginx`.\n\nPour que Wordpress fonctionne, il faut installer `php5-fpm`. Ce service doit ensuite \u00eatre d\u00e9marr\u00e9 s'il ne l'est pas d\u00e9j\u00e0 (`service php5-fpm start`).\n\n# Reverse Proxy\n\nPour le reverse proxy, le plus simple est d'\u00e9diter le fichier de zone chez Gandi pour y associer l'adresse ip du VPS \u00e0 un nom de domaine ou \u00e0 un sous-domaine. La propagation des informations peut prendre quelques heures. Ensuite, il suffit de sp\u00e9cifier ce domaine ou sous-domaine directement dans le fichier de configuration Nginx.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-02-07",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Owncloud from scratch\nDate: 2015-03-02\nTags: owncloud, nginx, https\n---\n\n[Owncloud](https://owncloud.org/) est un service de cloud personnel, facile \u00e0 d\u00e9ployer, accessible et fonctionnel.\nL'installation est relativement simple. La seule grosse difficult\u00e9 pourrait venir de la mani\u00e8re dont vous allez configurer l'h\u00e9bergement: si c'est dans un sous-r\u00e9pertoire sur votre serveur, sachez que c'est relativement complexe (avec des r\u00e8gles de r\u00e9\u00e9criture et autres joyeuset\u00e9s); dans la mesure du possible, partez pour un sous-domaine. \n\nParmi les pr\u00e9requis, on a:\n\n * Un serveur Web (Nginx ou Apache, au choix)\n * Une base de donn\u00e9es et l'extension qui-va-bien pour PHP (php5-mysql ou php5-sqlite)\n * php5-gd\n * php5-curl\n\nSi Nginx n'est pas encore install\u00e9, suivez le tuto. Configurez ensuite un server block sp\u00e9cifique pour Owncloud:\n\n\n``` shell\nupstream php-handler {\n #server 127.0.0.1:9000;\n server unix:/var/run/php5-fpm.sock;\n}\n\nserver {\n listen 80;\n server_name <your_server>;\n return 301 https://$server_name$request_uri;\n}\n\nserver {\n listen 443 ssl;\n server_name <your_server>;\n\n ssl_certificate /etc/letsencrypt/live/<your_server>/fullchain.pem;\n ssl_certificate_key /etc/letsencrypt/live/<your_server>/privkey.pem;\n\n root /var/www/<your_server>/;\n client_max_body_size 10G;\n fastcgi_buffers 64 4K;\n\n # Disable gzip to avoid the removal of the ETag header\n gzip off;\n\n rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;\n rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;\n rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;\n\n index index.php;\n error_page 403 /core/templates/403.php;\n error_page 404 /core/templates/404.php;\n\n location = /robots.txt {\n allow all;\n log_not_found off;\n access_log off;\n }\n\n location ~ ^/(?:\\.htaccess|data|config|db_structure\\.xml|README){\n deny all;\n }\n\n location / {\n # The following 2 rules are only needed with webfinger\n rewrite ^/.well-known/host-meta /public.php?service=host-meta last;\n rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;\n\n rewrite ^/.well-known/carddav /remote.php/carddav/ redirect;\n rewrite ^/.well-known/caldav /remote.php/caldav/ redirect;\n\n rewrite ^(/core/doc/[^\\/]+/)$ $1/index.html;\n\n try_files $uri $uri/ /index.php;\n }\n\n location ~ \\.php(?:$|/) {\n fastcgi_split_path_info ^(.+\\.php)(/.+)$;\n include fastcgi_params;\n fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n fastcgi_param PATH_INFO $fastcgi_path_info;\n fastcgi_param HTTPS on;\n fastcgi_pass php-handler;\n }\n\n # Optional: set long EXPIRES header on static assets\n location ~* \\.(?:jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {\n expires 30d;\n # Optional: Don't log access to assets\n access_log off;\n }\n}\n```\n\nPour l'installer, le plus simple est de t\u00e9l\u00e9charger le fichier `setup-owncloud.php`, de le d\u00e9placer sur votre serveur et de lancer la configuration.\nUn message peut aussi survenir lors de l'installation. Une petite modification dans le fichier `/etc/php/fpm/php.ini` fera l'affaire.\n\n``` shell\nPHP is configured to populate raw post data. Since PHP 5.6 this will lead to PHP throwing notices for perfectly valid code.\n\nTo fix this issue set always_populate_raw_post_data to -1 in your php.ini\n```\n\nPendant l'installation, vous devrez cr\u00e9er un administrateur, configurer l'acc\u00e8s \u00e0 la base de donn\u00e9es. Vous aurez ensuite acc\u00e8s \u00e0 l'instance :-)\nApr\u00e8s cela : \n\n 1. [Connectez votre calendrier](http://doc.owncloud.org/server/8.0/go.php?to=user-sync-calendars)\n 2. [Connectez vos contacts](http://doc.owncloud.org/server/8.0/go.php?to=user-sync-contacts)\n 3. [Acc\u00e9dez \u00e0 vos fichiers *via* WebDAV](http://doc.owncloud.org/server/8.0/go.php?to=user-webdav)\n\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-03-02",
"title": "---"
},
{
"category": "sys",
"content": "\ufeff---\nTitle: cgit\nDate: 2015-03-07\nTags: git, cgit, server\n---\n\n[Cgit](https://git.zx2c4.com/cgit/) se pr\u00e9sente comme *A hyperfast web frontend for git repositories written in C. Jason A. Donenfeld: about summary refs log tree commit diff stats*. Il se trouve normalement dans les d\u00e9p\u00f4ts de votre distribution. Sous Debian, un petit `aptitude install cgit` fera l'affaire. Le paquet viendra avec `liblua` comme d\u00e9pendance, mais ce sera tout. Pour l'ex\u00e9cuter au travers d'Nginx, vous devrez \u00e9galement installer `fcgiwrap`, puis le d\u00e9marrer (`systemctl start fcgiwrap.socket`).\n\nMa configuration Nginx est la suivante. J'ai plac\u00e9 `cgit` \u00e0 l'url `/cgit`. Il est n\u00e9cessaire d'ajouter un deuxi\u00e8me emplacement pour les fichiers statiques, qui seront accessibles depuis `/cgit-web`:\n\n``` shell\nlocation /cgit {\n\tinclude fastcgi_params;\n\tfastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;\n\tfastcgi_pass unix:/run/fcgiwrap.socket;\n\tfastcgi_split_path_info ^(/cgit/?)(.+)$;\n\tfastcgi_param PATH_INFO $fastcgi_path_info;\n\tfastcgi_param QUERY_STRING $args;\n}\n\nlocation /cgit-web {\n\trewrite ^/cgit-web(/.*)$ $1 break;\n\troot /usr/share/cgit;\n}\n```\n\nEn ayant fait l'installation par le *package maneger* de Debian, les fichiers seront plac\u00e9s dans le r\u00e9pertoire `/usr/share/cgit/`, \u00e0 l'exception du fichier de configuration, accessible depuis le chemin `/etc/cgit/cgitrc`. C'est \u00e0 cet endroit-l\u00e0 que vous renseignerez notamment les d\u00e9p\u00f4ts \u00e0 afficher, ainsi que l'url \u00e0 utiliser pour acc\u00e9der aux fichiers de style (dans la conf' nginx, on a sp\u00e9cifi\u00e9 `cgit-web` alors que le fichier `cgitrc` param\u00e8tre par d\u00e9faut le chemin vers `cgit-css`. A vous de voir, mais faites correspondre les deux).\n\nPour ajouter des d\u00e9p\u00f4ts, le plus simple est d'ajouter la ligne `scan-path=<path>`. L'autre solution est de les ajouter \u00e0 la main, en utilisant les propri\u00e9t\u00e9s `url`, `path` et `desc`, comme propos\u00e9 sur le [Wiki d'ArchLinux](https://wiki.archlinux.org/index.php/Cgit):\n\n``` shell\n#\n# List of repositories.\n# This list could be kept in a different file (e.g. '/etc/cgitrepos')\n# and included like this:\n# include=/etc/cgitrepos\n#\n\nrepo.url=MyRepo\nrepo.path=/srv/git/MyRepo.git\nrepo.desc=This is my git repository\n\nrepo.url=MyOtherRepo\nrepo.path=/srv/git/MyOtherRepo.git\nrepo.desc=That's my other git repository\n``` \n\nL'utilisateur sous lequel tourne nginx doit cependant avoir acc\u00e8s en lecture aux d\u00e9p\u00f4ts. Pour faciliter les choses, j'ai modifi\u00e9 les permissions pour donner acc\u00e8s en lecture au groupe `www-data`, tout en gardant la propri\u00e9t\u00e9 avec mon compte utilisateur: `sudo chown -R fred:www-data <path>`.\n\nAjoutez-y une petite description avec l'attribut `root-desc`, ainsi qu'un titre \u00e9loquent avec `root-title`, et vous aurez une petite interface pratique, rapide et lisible. Elle n'offrira sans doute pas autant de fonctionnalit\u00e9s qu'un [GitWeb](https://git.wiki.kernel.org/index.php/Gitweb) avec http-backend.\n\n``` shell\n#\n# cgit config\n# see cgitrc(5) for details\n\ncss=/cgit-web/cgit.css\nlogo=/cgit-web/cgit.png\n\nroot-title=Git repositories\nroot-desc=\n\nscan-path=/home/fred/git/\n```\n\nSources:\n\n * [http://wiki.archlinux.org](https://wiki.archlinux.org/index.php/Cgit)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-03-07",
"title": "\ufeff---"
},
{
"category": "sys",
"content": "---\nTitle: SSMTP\nDate: 2015-03-07\nSlug: ssmtp\nTags: mails, sendmail, smtp\n---\n\nPour envoyer des mails depuis une application, la solution la plus simple consiste \u00e0 passer par [ssmtp](https://doc.ubuntu-fr.org/ssmtp). Cela permet de configurer facilement l'envoi de mails sans se farcir la configuration d'un serveur SMTP complet (postfix, exim, ...).\n\nPour l'installation, on passe par apt, comme d'hab: `apt install ssmtp`. On modifie ensuite le fichier `/etc/ssmtp/ssmtp.conf`. La configuration ci-dessous fonctionne pour une adresse h\u00e9berg\u00e9e chez Gandi.\n\n```shell\n#\n# Config file for sSMTP sendmail\n#\n# The person who gets all mail for userids < 1000\n# Make this empty to disable rewriting.\nroot=admin@grimbox.be\n\n# The place where the mail goes. The actual machine name is required no\n# MX records are consulted. Commonly mailhosts are named mail.domain.com\nmailhub=mail.gandi.net:587\n\n# Where will the mail seem to come from?\nrewriteDomain=grimbox.be\n\n# The full hostname\nhostname=grimbox.be\n\n# Are users allowed to set their own From: address?\n# YES - Allow the user to specify their own From: address\n# NO - Use the system generated From: address\nFromLineOverride=YES\n\nUseSTARTTLS=YES\n\nAuthUser=<smtp_username>\nAuthPass=<smtp_password>\n```\n\nPour tester:\n\n```shell\n$ mail -s \"Test\" destinataire@example.org < /dev/null\nNull message body; hope thats ok\n```\n\nVous devriez recevoir le message (relativement) rapidement.",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-03-07",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Installation de Python sous CentOS\nDate: 2015-03-09\nSlug: install-python-on-centos\n---\n\nOn installe les d\u00e9pendances: `sudo yum install zlib-devel bzip2-devel openssl-devel ncurses-devel`.\n\nPuis on proc\u00e8de \u00e0 l'installation:\n\n```\ncd /opt\nwget http://python.org/ftp/python/2.7.9/Python-2.7.9.tgz\ntar xvfz Python-2.7.9.tgz\ncd Python-2.7.9\n./configure --prefix=/usr/local --enable-unicode=ucs4 --enable-shared LDFLAGS=\"-Wl,-rpath /usr/local/lib\"\nmake && make altinstall\n```\n\nLa partie `LDFLAGS` permet d'identifier le chemin vers lequel les librairies partag\u00e9es seront install\u00e9es. Sans cette option, on risque de tomber sur une erreur de type `error while loading shared libraries: libpython2.7.so.1.0`. L'autre partie hyper importante est d'utiliser `make altinstall` (et non pas `make install`): cela installera la nouvelle version de Python \u00e0 c\u00f4t\u00e9 de l'ancienne, sans tout casser (*a priori*, c'est toujours mieux de laisser l'OS g\u00e9rer lui-m\u00eame les d\u00e9pendances dont il a besoin...).\n\nSources\n-------\n\n * http://toomuchdata.com/2014/02/16/how-to-install-python-on-centos/\n * http://sametmax.com/installer-python-2-7-x-sur-centos-6-x-les-doigts-dans-le-nez/",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-03-09",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: OVH Public Cloud\nDate: 2015-06-24\nSlug: ovh-public-cloud\nTags: ovh, cloud, server\n---\n\nApr\u00e8s quelques d\u00e9boires avec un VPS Classic 1, puis un VPS basique sur Digital Ocean, je me laisse tenter par la nouvelle offre OVH. Les commentaires semblent aller dans le bon sens et le prix est abordable pour un payement mensuel (6\u20ac HTVA).\n\nDans l'ordre, j'ai cr\u00e9\u00e9 un nouveau serveur en choisissant le mod\u00e8le (KS-2), puis une cl\u00e9 SSH pour s'y connecter. Contrairement aux autres serveurs, l'OS est d\u00e9j\u00e0 un brin configur\u00e9: sur une Debian 8, `sudo` est d\u00e9j\u00e0 pr\u00e9sent et l'utilisateur principal (admin) doit obligatoirement se connecter en fournissant la cl\u00e9 priv\u00e9e pour s'authentifier. Je n'ai pas encore trouv\u00e9 comment associer une nouvelle cl\u00e9 \u00e0 une instance existante... On va donc \u00e9viter de la perdre :-).\n\nUne fois connect\u00e9, j'ai suivi les \u00e9tapes habituelles:\n\n 1. Mise \u00e0 jour du syst\u00e8me (`apt-get update` et `apt-get upgrade`)\n 2. Cr\u00e9ation d'un nouvel utilisateur avec `sudo adduser fred`\n\nEn vrac\n-------\n\nPour ce test, j'ai utilis\u00e9 le script [Curl Speedtest](http://dl.getipaddr.net/), dispo sur [Github](https://raw.github.com/blackdotsh/curl-speedtest). \n\nLe processeur est un Intel Xeon E12xx (un seul coeur), 4Go de RAM, 20Go d'espace disque. La copie d'un fichier d'1Go a \u00e9t\u00e9 faite a une vitesse de 395Mo/s. Je suppose qu'il s'agit juste d'un bourrage d'octets en vrac. Cela ne concerne donc clairement pas la lecture ou l'\u00e9criture de petits fichiers de moins de 4Ko. Le calcul des 5000 premi\u00e8res d\u00e9cimales de Pi a pris 0m19.507.\n\nEn substance, cela donne ceci une vitesse de download en fonction du serveur distant (mais en arrivant facilement \u00e0 plus de 10Mo/s), et une vitesse d'upload \u00e9quivalente.",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-06-24",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: screen\nDate: 2015-07-01\nSlug: screen\n---\n\n[Screen](https://www.gnu.org/software/screen/) permet *grosso modo* de g\u00e9rer plusieurs terminaux au sein d'une seule et m\u00eame instance. Cela permet par exemple d'ouvrir une connexion SSH et d'ouvrir plusieurs onglets depuis cette seule connexion.\n\nLes commandes principales pour bien d\u00e9marrer sont les suivantes:\n\n * `screen` pour *ouvrir* le gestionnaire\n * `ctrl-a, c` pour ouvrir un nouveau shell dans cette instance de Screen\n * `ctrl-a, w` pour lister les shells ouverts par Screen\n * `ctrl-a, n` pour aller au prochain shell\n * `ctrl-a, N` pour aller au pr\u00e9c\u00e9dent shell\n\nHistoire de s'y retrouver un peu, copiez/collez le contenu suivant dans le fichier `~/.screenrc` (Source:??):\n\n``` shell\n\n startup_message off\n caption always\n # Caption JCK (met en \u00e9vidence %{=b kg} le screen actif [%n %t]\n # puis la liste des autres screen %{=s ky}%W\n # affich\u00e9 \u00e0 droite %=\n # le nom de la machine %{=b}%H\n # et l'heure %{=s}%c sont affich\u2592s\n caption string \"%{=b kg} [%n %t] %{=s ky}%W %= %{=b}%H %{=s}%c \"\n\n # Better vim intergration\n term \"screen-256color\"\n\n```\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-07-01",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Xpra\nDate: 2015-08-11\nSlug: xpra\n---\n\n[Xpra](http://xpra.org/) permet de faire tourner des applications X sur une machine distante, un peu \u00e0 la mani\u00e8re d'un X-Forwarding, avec un avantage sur les algorithmes de compression d'informations (h264, vp9, png, webp, ...) et la possibilit\u00e9 de transporter le son et la vid\u00e9o. Son fonctionnement consiste \u00e0 lancer le serveur sur un poste, puis \u00e0 y acc\u00e9der depuis une machine cliente (distante) au travers d'une connexion ouverte (SSH, TCP, TCP+AES). \n\nDepuis le serveur, installez `xpra` gr\u00e2ce aux d\u00e9p\u00f4ts [Winswitch](https://winswitch.org/downloads/). Apr\u00e8s l'ajout du d\u00e9p\u00f4t et des cl\u00e9s, \u00e9vitez juste la derni\u00e8re \u00e9tape qui consiste \u00e0 installer `winswitch`: installez juste `xpra`, \u00e0 moins que vous n'ayez besoin de plus.\n\nUne fois que c'est fait, lancez un terminal, et lancez les commandes suivantes: \n\n * `xpra start :100`\n * `export DISPLAY=:100`\n\nEn gros, on cr\u00e9e un affichage pour `xpra`, qui porte l'identifiant 100.\n\nDepuis la machine distance, installez le client [xpra](http://xpra.org/); vous aurez ensuite deux choix: soit passer par le client graphique, soit lancer xpra depuis une console. Sous Windows, cela ressemble \u00e0 ceci:\n\n```\ncd C:\\Program Files (x86)\\xpra\nxpra_cmd.exe attach ssh:<ip>:<display>\n```\n\nUne fen\u00eatre vous demandera votre login et votre mot de passe; ensuite, toute application graphique lanc\u00e9e depuis le serveur dans le terminal sera export\u00e9e vers le poste client.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-08-11",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Informations sur un fichier en CLI\nDate: 2015-08-13\nSlug: informations-sur-un-fichier-en-cli\n---\n\nPour conna\u00eetre des informations sur un fichier, dans un terminal:\n\n```shell\n[fred@aerys ~]$ file -i entries/conf/rsync.md\nentries/conf/rsync.md: text/plain; charset=iso-8859-1\n```\n\nPour encoder un fichier dans un autre format:\n\n```shell\nfred@aerys ~]$ iconv -f iso-8859-1 -t utf-8 entries/conf/rsync.md > entries/conf/rsync2.md\n```\n\nAttention \u00e0 bien rediriger la sortie vers un fichier qui n'est pas le m\u00eame que la source... Sans quoi, vous vous retrouverez avec un beau fichier vide.\n\nEn recommen\u00e7ant la premi\u00e8re op\u00e9ration, le `charset` aura normalement \u00e9t\u00e9 modifi\u00e9:\n\n```shell\n[fred@aerys ~]$ file -i entries/conf/rsync.md\nentries/conf/rsync.md: text/plain; charset=utf-8\n```\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-08-13",
"title": "---"
},
{
"category": "sys",
"content": "\ufeff---\nTitle: Quelques commandes MySQL de base\nDate: 2015-09-10\nSlug: quelques-commandes-mysql-de-base\nTags: mysql, database\n---\n\n## Connexion au shell\n\nPour se connecter sur le shell MySQL : `$ mysql -u root -p`.\nDes fois que vous ayez oubli\u00e9 les utilisateurs d\u00e9finis dans la DB:\n\n```\n\tmysql> select host, user, password from mysql.user;\n\t+-----------+------------------+-------------------------------------------+\n\t| host | user | password |\n\t+-----------+------------------+-------------------------------------------+\n\t| localhost | root | *AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |\n\t| localhost | wordpressuser | *BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB |\n\t| 127.0.0.1 | root | *CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC |\n\t| ::1 | root | *CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC |\n\t| localhost | debian-sys-maint | *DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD |\n\t+-----------+------------------+-------------------------------------------+\n\t5 rows in set (0.17 sec)\n```\n\n## Actions sur les tables\n\nPour lister les bases de donn\u00e9es enregistr\u00e9es:\n\n```\n\tmysql> show databases;\n\t+--------------------+\n\t| Database |\n\t+--------------------+\n\t| information_schema |\n\t| xxx |\n\t| mysql |\n\t| performance_schema |\n\t+--------------------+\n\t4 rows in set (0.05 sec)\n```\n\nEt pour supprimer une des bases, c'est gr\u00e2ce \u00e0:\n\n```\n\tmysql> drop database if exists wordpress;\n\tQuery OK, 0 rows affected (0.04 sec)\n```\n\n(on peut laisser tomber le `if exists`, mais cela jettera une erreur si la db n'existe pas.\n\nIl est aussi possible de [lister les tables appartenant \u00e0 une base en particulier](http://dev.mysql.com/doc/refman/5.0/en/show-tables.html):\n\n```\n\tmysql> show tables from reader;\n\t+--------------------------+\n\t| Tables_in_reader |\n\t+--------------------------+\n\t| access_keys |\n\t| archived_feeds |\n\t| cat_counters_cache |\n\t| counters_cache |\n\t| enclosures |\n\t| entries |\n\t| entry_comments |\n\t| error_log |\n\t| feed_categories |\n\t| feedbrowser_cache |\n\t| feeds |\n\t| ...\t\t\t\t\t |\n\t+--------------------------+\n\t31 rows in set (0.00 sec)\n```\n\n## Dump et restore\n\nPour *dumper* les donn\u00e9es d'une base en particulier, utilisez le petit script ci-dessous:\n\n```shell\nNOW=$(date +\"%Y-%m-%d-%H%M\")\n\nDB_USER=\"\"\nDB_PASS=\"\"\nDB_NAME=\"\"\nDB_FILE=\"$DB_NAME.db.$NOW.sql\"\nmysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $DB_FILE\n```\n\nEt pour restaurer les donn\u00e9es vers une base, le principe est de rediriger le contenu d'un fichier vers la connexion de la base de donn\u00e9es. Ce qu'on a fait juste au dessus, pour le dump, c'est d'utiliser une redirection **vers** un fichier `>`. Ici, c'est l'inverse: `<`.\n\n```\nmysql -u $DB_USER -p$DB_PASS $DB_NAME < fichier.sql\n```\n\n## Cr\u00e9ation d'un nouvel utilisateur\n\nCommencez par lancer `mysql -u root -p` pour entrer dans le shell MySQL.\nLa commande ci-dessous va cr\u00e9er un nouvel utilisateur, `newuser`, dont le mot de passe sera `password`. Le champ `localhost` peut rester tel quel.\n\n```sql\nCREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';\n```\n\nUne fois que le nouvel utilisateur est cr\u00e9\u00e9, il faut encore lui accorder des privil\u00e8ges. Pour cela, choisissez la base sur laquelle vous comptez lui donner un acc\u00e8s. Si elle n'existe pas encore, cr\u00e9ez la:\n\n```sql\nCREATE DATABASE IF NOT EXISTS database_name;\n```\n\nEt finalement, on accorde les privil\u00e8ges \u00e0 l'utilisateur `newuser` sur la base `database_name`:\n\n```sql\nGRANT ALL PRIVILEGES ON database_name.* TO 'newuser'@'localhost';\nFLUSH PRIVILEGES;\n```\n\n## Permissions\n\nPlut\u00f4t que d'accorder un petit `Grant All Privileges`, il y a [plusieurs niveaux de privil\u00e8ges](https://www.digitalocean.com/community/tutorials/how-to-create-a-new-user-and-grant-permissions-in-mysql):\n\n * **ALL PRIVILEGES** - attribue l'ensemble des privil\u00e8ges ci-dessous \u00e0 l'utilisateur, pour une base de donn\u00e9es sp\u00e9cifi\u00e9e. Si aucune base de donn\u00e9es n'est sp\u00e9cifi\u00e9e, les privil\u00e8ges seront attribu\u00e9s au niveau du syst\u00e8me.\n * **CREATE** - permet \u00e0 l'utilisateur de cr\u00e9er de nouvelles tables ou bases de donn\u00e9es\n * **DROP** - autorise la suppression de tables ou de bases de donn\u00e9es\n * **DELETE** - autorise la suppression d'enregistrements dans une table\n * **INSERT** - autorise l'insertion d'enregistrements dans une table\n * **SELECT** - autorise la s\u00e9lection de donn\u00e9es pr\u00e9sentes dans la base\n * **UPDATE** - autorise la mise \u00e0 jour d'enregistrements pr\u00e9sents dans une table\n * **GRANT OPTION** - autorise la gestion des privil\u00e8ges pour d'autres utilisateurs.",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2015-09-10",
"title": "\ufeff---"
},
{
"category": "sys",
"content": "---\nTitle: Installation et configuration basique de Postgresql\nDate: 2016-02-12\nSlug: installation-configuration-basique-postgresql\nTags: db, pgsql, sql\n---\n\nDans ma petite t\u00eate de d\u00e9veloppeur, [Postgresql](http://www.postgresql.org/) se trouve dans le haut du panier. Je n'ai clairement pas autant l'occasion de jouer avec que je le souhaiterais, \u00e0 cause d'un employeur un tantinet orient\u00e9 Oracle/MSSQL, mais les quelques fois o\u00f9 j'ai pu la tripoter, c'\u00e9tait un petit plaisir.\n\nBref, pour ceux qui d\u00e9sireraient se lancer dans l'aventure (ou essayer autre chose qu'un [MariaDB](https://mariadb.org/) packag\u00e9 par d\u00e9faut pour du PHP), un petit tuto est disponible ici: [doc.fedora-fr.org](http://doc.fedora-fr.org/wiki/Installation_et_configuration_de_PostgreSQL). Il couvre l'installation du service, la cr\u00e9ation d'un utilisateur, la s\u00e9curisation et l'utilisation d'un client ([pgadmin](https://launchpad.net/pgadmin).\n\n## Installation et initialisation\n\nCommencez par chercher un paquet qui ressemble \u00e0 `postgresql-server` *via* votre gestionnaire pr\u00e9f\u00e9r\u00e9. Apr\u00e8s l'installation, vous pourrez initialiser cette nouvelle instance avec la commande suivante: `sudo postgresql-setup --initdb`:\n\n```shell\n* Initializing database in '/var/lib/pgsql/data'\n* Initialized, logs are in /var/lib/pgsql/initdb_postgresql.log\n```\n\nOn d\u00e9marre ensuite le service si ce n'est pas d\u00e9j\u00e0 fait:\n\n```shell\n$ sudo systemctl start postgresql && sudo systemctl status postgresql\n[...]\nFeb 12 21:13:09 aerys systemd[1]: Started PostgreSQL database server.\n```\n\nApr\u00e8s tout ceci, un utilisateur `postgres` a \u00e9t\u00e9 cr\u00e9\u00e9 au niveau syst\u00e8me -- donc au m\u00eame titre que votre utilisateur \u00e0 vous - il ne s'agit pas d'un compte interne \u00e0 la base de donn\u00e9es, mais bien d'un compte avec lequel vous pouvez **vous connecter**. Comme expliqu\u00e9 dans la [doc](http://doc.fedora-fr.org/wiki/Installation_et_configuration_de_PostgreSQL) et au niveau de la base de donn\u00e9es, il s'agit de l'\u00e9quivalent au super-utilisateur `root`. En gros, super-pouvoir, super-responsabilit\u00e9s et super-gaffes si vous ne faites pas un minimum attention. Allez zou, maintenant qu'on sait qu'il ne faut rien supprimer, on peut s'y connecter. On passe en `root` pour l'impersonnification, puis on se connecte avec le compte `postgres` avant de se connecter \u00e0 la db avec la commande `psql`:\n\n```\nsudo su - postgres\n[sudo] password for fred:\n-bash-4.3$ psql\npsql (9.4.5)\nType \"help\" for help.\n\npostgres=#\npostgres=# ALTER USER postgres WITH PASSWORD 'mot_de_passe';\n```\n\nDans la mesure du possible, tapez les commandes ci-dessus plut\u00f4t que de passer par un copi\u00e9/coll\u00e9: `psql` semble avoir une tendance un peu prononc\u00e9e pour l'interpr\u00e9tation foireuse des donn\u00e9es copi\u00e9es. Pour la s\u00e9curisation du mot de passe, il est conseill\u00e9 de modifier la m\u00e9thode d'identification `ident` en `md5` dans le fichier `/var/lib/pgsql/pg_hba.conf`.\n\n## Documentation en rab'\n\n * `Pgsql en fran\u00e7ais <http://docs.postgresqlfr.org/>`_\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-02-12",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Lynis\nDate: 2016-06-01\nTags: audit, securit\u00e9, server\nSlug: lynis\n---\n\n[Lynis](https://cisofy.com/lynis/) permet de faire un audit du syst\u00e8me. Il s'installe et se lance tr\u00e8s facilement (mais aura besoin d'un acc\u00e8s `root`) et vous proposera un ensemble de suggestions, de param\u00e8tres \u00e0 modifier et la liste des choses en ordre.\n\n```shell\nsudo aptitude install lynis\nsudo lynis --check-all\n```\n\n```shell\n[+] Initializing program\n------------------------------------\n- Detecting OS... [ DONE ]\n- Clearing log file (/var/log/lynis.log)... [ DONE ]\n\n---------------------------------------------------\nProgram version: 1.6.3\nOperating system: Linux\nOperating system name: Debian\nOperating system version: 8.4\nKernel version: 4.5.1\nHardware platform: x86_64\nProfile: /etc/lynis/default.prf\nLog file: /var/log/lynis.log\nReport file: /var/log/lynis-report.dat\nReport version: 1.0\nPlugin directory: /etc/lynis/plugins\n```\n\nAu final, vous recevrez la liste des avertissements, erreurs et suggestions, accompagn\u00e9s de liens permettent leur correction ou prise en charge :)",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-06-01",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Auto-update d'un site statique avec Pelican\nDate: 2016-06-05\nSlug: auto-update-site-pelican-git\nTags: http, nginx, git, pelican, amazon, s3\n---\n\nPetite mise \u00e0 jour du script [du 26 juillet 2013]({filename}2013-07-26-pelican-webfaction.md), puisque j'ai d\u00e9m\u00e9nag\u00e9 le serveur [depuis un petit temps]({filename}../server/2015-12-29-scaleway.md) et que je passe dor\u00e9navant par [Nginx]({filename}../server/2015-04-03-nginx.md). Du workflow, je conserve le lien avec Git et la centralisation dans un Gitlab. Pour la publication, je garde la g\u00e9n\u00e9ration automatique, mais uniquement si le d\u00e9p\u00f4t a \u00e9t\u00e9 mis \u00e0 jour.\n\nBon, \u00e0 un moment, j'ai pens\u00e9 d\u00e9placer le contenu statique vers `Amazon S3 <https://aws.amazon.com/fr/s3/>`_, avec un petit pointeur DNS vers le bon noeud. Il y a pas mal de ressources utiles sur ce point, je vous laisse donc faire votre shopping, mais ayant un serveur \u00e0 disposition, j'ai +/- laiss\u00e9 tomber. Vous trouverez d\u00e9j\u00e0 tous les liens rassembl\u00e9s ci-dessous:\n\n * `Matt McManus - How I set up, designed, and published this website <http://www.mamcmanus.com/posts/how-i-built-this-site>`_\n * `Matt McManus - Setting up a Pelican site under your own domain using Amazon S3 <http://www.mamcmanus.com/posts/amazon-s3-pelican-site>`_\n * `Better Pelican hosting with Amazon S3 and CloudFront <https://pmac.io/2014/06/pelican-s3-cloudfront/>`_\n * `Setting Up a blog with Pelican and Amazon S3 <http://lexual.com/blog/setup-pelican-blog-on-s3/>`_\n * `Moving to Amazon S3 <http://cbudjan.com/2013/06/amazon-s3/>`_\n * `Amazon S3 Versioning - What, how and why? <https://linuxacademy.com/blog/amazon-web-services-2/amazon-s3-versioning-what-how-why/>`_\n\nLe script ressemble \u00e0 ceci:\n\n``` shell\n#! /usr/bin/env bash\n\ngit fetch origin\nreslog=$(git log HEAD..origin/master --oneline)\n\nif [[ \"${reslog}\" != \"\" ]] ; then\n echo \"Updating pelican-site\"\n git merge origin/master\n virtualenv -p /usr/bin/python3 .\n source bin/activate\n pip install -r requirements/base.txt\n pelican\nfi\n```\n\nPour son ex\u00e9cution, j'ai ajout\u00e9 une ligne dans Cron:\n\n``` shell\n30 * * * * /var/www/{site_name}/update_site.sh\n```\n\nNginx pointe alors vers le r\u00e9pertoire `output`, qui sera g\u00e9n\u00e9r\u00e9 par [Pelican](https://getpelican.com).\n\nSources\n-------\n\n * [Check if pull is needed](http://stackoverflow.com/questions/3258243/check-if-pull-needed-in-git/12791408#12791408)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-06-05",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Certbot\nDate: 2016-06-13\nSlug: certbot\nTags: eff, nginx, letsencrypt, certificats\n---\n\n> Certbot, previously the Let's Encrypt Client, is EFF's tool to obtain certs from Let's Encrypt, and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.\n\nMa commande [Certbot-auto](https://github.com/certbot/certbot) pour la cr\u00e9ation et la prolongation des certificats sur mes serveurs:\n\n``` shell\n\n ./certbot-auto certonly --standalone --standalone-supported-challenges http-01 --email me@grimbox.be -d grimbox.be\n\n```\n\nSi n\u00e9cessaire, n'h\u00e9sitez pas \u00e0 ajouter les sous-domaines \u00e0 la suite: `-d grimbox.be -d boulet.grimbox.be -d blabla.grimbox.be`...\nLes certificats seront plac\u00e9s dans le r\u00e9pertoire ``/etc/letsencrypt/live/<nom_du_domaine>/``, et devront \u00eatre r\u00e9f\u00e9renc\u00e9s de la mani\u00e8re suivante dans Nginx:\n\n``` shell\n\n server {\n listen 80;\n listen [::]80;\n server_name <nom_du_domaine>;\n return 301 https://$server_name$request_uri;\n }\n\n server {\n listen 443 ssl;\n listen [::]:443 ssl;\n\n server_name <nom_du_domaine>;\n ssl_certificate /etc/letsencrypt/live/<nom_du_domaine>/fullchain.pem;\n ssl_certificate_key /etc/letsencrypt/live/<nom_du_domaine>/privkey.pem;\n\n [...]\n }\n\n```\n\nTodos\n=====\n\n * Visiblement, il existe [un paquet dans les backports pour Jessie](https://certbot.eff.org/#debianjessie-nginx).\n * Puis ajouter une \u00e9l\u00e9vation de privil\u00e8ges pour arr\u00eater/d\u00e9marrer Nginx.",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-06-13",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Fail2ban\nDate: 2016-06-13\nSlug: fail2ban\n\n---\n\nDans la cat\u00e9gorie des petits outils top biches, on a [fail2ban](http://www.fail2ban.org/wiki/index.php/Main_Page), qui est un *framework de pr\u00e9vention contre les intrusions*. Il permet par exemple de d\u00e9tecter un trop grand nombre de tentative de connexion. Fail2Ban est ensuite utilis\u00e9 pour modifier les r\u00e8gles du pare-feu, pour rejeter par d\u00e9faut l'adresse IP incrimin\u00e9e.\n\nPar exemple, juste apr\u00e8s son installation, on peut trouver ceci parmi les logs:\n\n``` shell\n\n 2016-06-13 05:23:40,337 fail2ban.actions[4160]: WARNING [ssh] Ban 5.39.218.148\n 2016-06-13 05:33:41,022 fail2ban.actions[4160]: WARNING [ssh] Unban 5.39.218.148\n 2016-06-13 05:33:47,040 fail2ban.actions[4160]: WARNING [ssh] Ban 5.39.218.148\n 2016-06-13 05:43:47,717 fail2ban.actions[4160]: WARNING [ssh] Unban 5.39.218.148\n 2016-06-13 05:43:50,732 fail2ban.actions[4160]: WARNING [ssh] Ban 5.39.218.148\n 2016-06-13 05:53:51,398 fail2ban.actions[4160]: WARNING [ssh] Unban 5.39.218.148\n 2016-06-13 05:53:56,415 fail2ban.actions[4160]: WARNING [ssh] Ban 5.39.218.148\n 2016-06-13 06:03:57,097 fail2ban.actions[4160]: WARNING [ssh] Unban 5.39.218.148\n 2016-06-13 06:04:01,113 fail2ban.actions[4160]: WARNING [ssh] Ban 5.39.218.148\n 2016-06-13 06:14:01,807 fail2ban.actions[4160]: WARNING [ssh] Unban 5.39.218.148\n 2016-06-13 06:14:07,825 fail2ban.actions[4160]: WARNING [ssh] Ban 5.39.218.148\n 2016-06-13 06:24:08,516 fail2ban.actions[4160]: WARNING [ssh] Unban 5.39.218.148\n\n```\n\nOn voit clairement qu'il s'agit d'une tentative de connexion malicieuse: toujours la m\u00eame adresse IP, \u00e0 des heures pas franchement folichonnes. Ici, Fail2Ban est configur\u00e9 pour *rel\u00e2cher* une IP apr\u00e8s une dizaine de minutes.\n\nPour modifier ce comportement, on va ajouter un m\u00e9canisme de *jails*: ouvrez le fichier `/etc/fail2ban/jail.conf`. La section `[DEFAULT]` reprend des param\u00e8tres classiques (*bantime* de 10 minutes, nombre maximal de tentatives \u00e0 6, ...). Il est possible de sp\u00e9cifier ces *jails*, en prenant par exemple la configuration pour `SSH`:\n\n``` shell\n\n [ssh]\n\n enabled = true\n port = ssh\n filter = sshd\n logpath = /var/log/auth.log\n maxretry = 3\n bantime = 3600\n\n```\n\nEt voila! Ban d'1h, nombre max de tentatives: 3. On red\u00e9marre ensuite Fail2Ban *via* `/etc/init.d/fail2ban restart`.\n\nDeux-trois liens suppl\u00e9mentaires:\n\n * [How to protect SSH with Fail2ban on Ubuntu 14.04](https://www.digitalocean.com/community/tutorials/how-to-protect-ssh-with-fail2ban-on-ubuntu-14-04)\n * [How to protect Nginx with Fail2ban on Ubuntu 14.04](https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04) (parce que oui, on peut aussi monitorer les tentatives de connexion foireuses directement *via* Nginx).",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-06-13",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Owncloud -> Nextcloud\nDate: 2016-07-08\nSlug: from-owncloud-to-nextcloud\nTags: http, nginx, conf, server, owncloud, nextcloud\n---\n\nSuite aux derni\u00e8res annonces concernant Owncloud, je suis fra\u00eechement pass\u00e9 sur son fork, Nextcloud. Apr\u00e8s l'installation, qui a consist\u00e9 en gros \u00e0\n\n 1. Copier les donn\u00e9es et le fichier de conf',\n 2. Ecraser sauvagement tous les fichiers pr\u00e9sents,\n 3. remettre les donn\u00e9es et le fichier `config.php` (et oui, cela fonctionne),\n\nil restait deux-trois probl\u00e8mes li\u00e9s \u00e0 la configuration du serveur-m\u00eame. Tous ces avertissements sont dispos en grands, gras, gros et large sur n'importe quelle page d'administration. Il suffit juste de creuser un peu la documentation pour trouver la solution.\n\nPour ma part:\n\n> php ne semble pas \u00eatre configur\u00e9 de mani\u00e8re \u00e0 r\u00e9cup\u00e9rer les valeurs des variables d\u2019environnement. Le test de la commande getenv(\"PATH\") retourne seulement une r\u00e9ponse vide.\n\nIl suffit de modifier le fichier `/etc/php5/fpm/pool.d/www.conf` et de suivre [les recommandations](https://docs.nextcloud.org/server/9.0/admin_manual/installation/source_installation.html#php-fpm-configuration-notes).\n\n> L'en-t\u00eate HTTP \"X-Download-Options\" n'est pas configur\u00e9e pour \u00eatre \u00e9gale \u00e0 \"noopen\" cr\u00e9ant potentiellement un risque reli\u00e9 \u00e0 la s\u00e9curit\u00e9 et \u00e0 la vie priv\u00e9e. Il est donc recommand\u00e9 d'ajuster ce param\u00e8tre.\n\nOn ajoute simplement `add_header X-Download-Options noopen;` dans la conf' Nginx.\n\n> L'en-t\u00eate HTTP \"X-Permitted-Cross-Domain-Policies\" n'est pas configur\u00e9e pour \u00eatre \u00e9gale \u00e0 \"none\" cr\u00e9ant potentiellement un risque reli\u00e9 \u00e0 la s\u00e9curit\u00e9 et \u00e0 la vie priv\u00e9e. Il est donc recommand\u00e9 d'ajuster ce param\u00e8tre.\n\nIdem que ci-dessus: on ajoute `add_header X-Permitted-Cross-Domain-Policies none;`.\n\n> Des fichiers n'ont pas pass\u00e9 la v\u00e9rification d\u2019int\u00e9grit\u00e9. Consultez la documentation pour avoir plus d'informations sur comment r\u00e9soudre ce probl\u00e8me.\n\nIci, c'\u00e9tait un peu plus con: deux fichiers n'\u00e9taient pas conformes. En fait, le probl\u00e8me \u00e9tait identique pour les deux: la commande `cp -r <origine> <destination>` ne copie pas les *dotfiles*. J'avais donc un fichier avec le mauvais hash (`.htaccess`) et un fichier manquant (`.user.ini`).\n\n> Aucun cache m\u00e9moire n'est configur\u00e9. Si possible, configurez un cache pour augmenter les performances. Consultez la documentation pour avoir plus d'informations \u00e0 ce sujet.\n\nL\u00e0, par contre, [l'installation de memcache](https://docs.nextcloud.org/server/9.0/admin_manual/configuration_server/oc_server_tuning.html) sera pour plus tard ;)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-07-08",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Docker\nDate: \"2016-08-21\"\nSlug: docker\nCategory: \"Ops\"\nTags: docker, env, dev, virtualisation, container\n---\n\nL'id\u00e9e derri\u00e8re [Docker](https://www.docker.com/) est juste g\u00e9niale (en plus d'avoir mis une baleine comme logo, je veux dire): une simplification de la virtualisation pour faire tourner des processus dans des simili-machines virtuelles, c'est le bien. Jusqu'\u00e0 pr\u00e9sent, je n'ai jamais r\u00e9ellement eu l'occasion ou l'envie de me pencher sur le sujet... et puis la r\u00e9v\u00e9lation: pour un test de [django-haystack](http://haystacksearch.org/), j'ai besoin d'un environnement [ElasticSearch](https://www.elastic.co/). Voire [MongoDB](https://www.mongodb.com/) ou [Solr](https://lucene.apache.org/solr/). Bref, vous voyez l'id\u00e9e: on a un besoin, et on n'a pas envie de s'en farcir l'installation ou la configuration. On veut juste que *it works!* (si possible du premier coup). Alors, clairement, je ne le ferais pas en prod', mais pour un environnement de dev', c'est top. Ce que [Gitlab](filename}articles/dev/python/2016-08-05 framagit-continuous-integration.rst) en fait est juste g\u00e9nial aussi: les *runners* tournent dans un environnement *sandbox* bas\u00e9 sur une image Docker.\n\nPour d\u00e9marrer, c'est super simple:\n\n```shell\n# dnf install docker\n# systemctl start docker\n# docker run -d elasticsearch\n```\n\nEnsuite, pour obtenir l'adresse IP \u00e0 laquelle le container r\u00e9pond, on regarde *via* ``systemctl status docker``.\n\nEt finalement, on ouvre son navigateur pr\u00e9f\u00e9r\u00e9 (Firefox, what else) pour se rendre \u00e0 l'adresse http://172.17.0.2:9200. On obtient ceci:\n\n```json\n{\n \"name\" : \"Yellowjacket\",\n \"cluster_name\" : \"elasticsearch\",\n \"version\" : {\n \"number\" : \"2.3.5\",\n \"build_hash\" : \"90f439ff60a3c0f497f91663701e64ccd01edbb4\",\n \"build_timestamp\" : \"2016-07-27T10:36:52Z\",\n \"build_snapshot\" : false,\n \"lucene_version\" : \"5.5.0\"\n },\n \"tagline\" : \"You Know, for Search\"\n}\n```\n\nMagique :)\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-08-21",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: DSM 6.0\nDate: 2016-09-20\nSlug: dsm-6-0\n---\n\nDepuis quelques jours, je tripatouille un peu la derni\u00e8re version de [DSM](https://www.synology.com/fr-fr/dsm/). J'utilise principalement mon NAS pour la gestion de ma m\u00e9diath\u00e8que et pour les backups. Il est configur\u00e9 en RAID 5 sur quatre disques; le cinqui\u00e8me disque n'est pas utilis\u00e9, il servira (peut-\u00eatre) si un des disques durs principaux claque.\n\nAu programme des applications install\u00e9es, je n'ai activ\u00e9 que les d\u00e9p\u00f4ts officiels: j'y trouve la suite DS* (Audio, Video, Note et Cloud). Mes diff\u00e9rentes machines utilisent Cloud Backup pour cracher leurs fichiers directement dans un r\u00e9pertoire de sauvegarde dans le *home directory* de l'utilisateur. Cela fonctionne bien, mais cela ne conserve que la derni\u00e8re version des donn\u00e9es connues. Une option permet cependant d'emp\u00eacher la suppression si le fichier n'est plus pr\u00e9sent \u00e0 la source. Je ne sais pas si cette option est r\u00e9ellement une bonne solution, puisqu'on fini par avoir un *melting-pot* de fichiers... Et je suppose que si un nouveau fichier est nomm\u00e9 de la m\u00eame mani\u00e8re qu'un ancien, cette derni\u00e8re version ne sera plus jamais accessible puisqu'\u00e9cras\u00e9e par la nouvelle... Du coup, c'est bien: \u00e7a duplique les donn\u00e9es de mani\u00e8re plus ou moins transparente, mais ce n'est pas une solution bullet-proof.\n\nAu niveau des services et du partage, idem: je n'ai activ\u00e9 que le strict minimum: SMB, NFS, r\u00e9pertoires utilisateurs et rien d'autre.\n\nSo far, so good... :) quoique je me demande si un [HP Gen8](https://www.amazon.fr/Microsvr-Gen8-G1610t-Entry-Nhp/dp/B013UBCHVU/ref=sr_1_1?ie=UTF8&qid=1471722661&sr=8-1&keywords=hp+gen+8) ne me conviendrait pas: la diff\u00e9rence de prix avec un Synology est relativement importante; la faute \u00e0 DSM et \u00e0 l'int\u00e9gration des services disponibles. Je ne connais pas suffisament [OpenMediaVault](http://www.openmediavault.org/) ou [FreeNAS](http://www.freenas.org/) que pour \u00e9mettre un avis sur ces deux syst\u00e8mes. La prochaine fois, sans doute :)",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-09-20",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: M\u00e9mo pour cl\u00f4turer des issues au travers de commits dans Gitlab\nDate: 2016-09-26\nTags: git, gitlab, issues\nSlug: close-gitlab-issue-within-git-commit\n---\n\nJuste un m\u00e9mo pour les mots-cl\u00e9s g\u00e9r\u00e9s par GitLab et Github permettant de cl\u00f4turer une issue au moment du commit:\n\n```\nclose\ncloses\nclosed\nfix\nfixes\nfixed\nresolve\nresolves\nresolved\n```\n\nAu moment du commit, il suffit de r\u00e9f\u00e9rencer l'issue gr\u00e2ce \u00e0 `#<issue_number>`, en plus d'utiliser l'un des mots-cl\u00e9s ci-dessus.\n\nSource: https://help.github.com/articles/closing-issues-via-commit-messages/\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-09-26",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Une semaine avec Solus\nSlug: a-week-with-solus\nTags: beid, linux, gnu, distro, solus\nDate: 2016-11-07\n---\n\nJe m'\u00e9tais promis que ma derni\u00e8re installation de Fedora (22?) serait la derni\u00e8re, qu'\u00e0 pr\u00e9sent j'avais grandis et que je pouvais finalement, pass\u00e9 30 ans, me poser un peu sur le syst\u00e8me \u00e0 utiliser. Bah non. L'appel de la nouveaut\u00e9 et le go\u00fbt d'un syst\u00e8me instable m'ont de nouveau fait plonger dans les m\u00e9andres des distributions Linux \u00e0 installer sur mon mat\u00e9riel...\n\nApr\u00e8s avoir un peu fouill\u00e9 [distrowatch](http://distrowatch.com), je pensais repasser sur Arch gr\u00e2ce \u00e0 [Arch-Anywhere](https://arch-anywhere.org/), pour une installation d'ArchLinux en 30 secondes-montre-en-main (en vrai, c'est plus proche de 45-50 minutes, surtout quand on a explos\u00e9 son quota de t\u00e9l\u00e9chargement chez son FAI ador\u00e9 et qu'on se retrouve limit\u00e9 \u00e0 300kB/s).\n\nBon. En fait, je n'ai plus l'\u00e2ge de tripatouiller une distribution de barbu: ArchLinux, c'est pass\u00e9. Apr\u00e8s l'installation, [Slim](https://wiki.archlinux.org/index.php/SLiM) m'annon\u00e7ait une disposition clavier en `en-US` avec un KDE derri\u00e8re en `fr-BE`. Pas envie de chipoter, je voulais un truc qui \"juste marche\".\n\nBref, Solus. En fait, c'est 'achement rafra\u00eechissant: le syst\u00e8me est hyper r\u00e9actif (mais vraiment hein: \u00e7a boot en 2 secondes apr\u00e8s que Grub se soit charg\u00e9, sur du mat\u00e9riel relativement r\u00e9cent).\n\n## Outils et programmation\n\nSi vous devez installer un environnement de d\u00e9veloppement, pensez toujours \u00e0 ajouter `*-devel` \u00e0 l'installation; par exemple `python-devel` ou `ruby-devel`, sans quoi vous n'aurez pas les librairies, et *a priori*, il y aura peu de choses qui fonctionneront... :)\n\nPour Ruby, on doit aller un chouia plus loin, puisque l'installation des *Development Tools* se fait gr\u00e2ce \u00e0 la commande `sudo gem update --system`. Apr\u00e8s cela, aucun soucis pour installer `compass` avec `gem install compass`.\n\nAutres bonnes nouvelles: [vscode](https://code.visualstudio.com/) et [atom](https://atom.io/) sont int\u00e9gr\u00e9s directement dans les d\u00e9p\u00f4ts de la distribution. Parmi les *third parties*, on trouve \u00e9galement [Android Studio](https://developer.android.com/studio/index.html), [Idea](https://www.jetbrains.com/idea/), [SublimeText3](https://www.sublimetext.com/3) et [PyCharm](https://www.jetbrains.com/pycharm/). Le choix est l\u00e0, et c'est le top.\n\n## Carte d'identit\u00e9 \u00e9lectronique\n\nEn Belgique, on a une carte d'identit\u00e9 \u00e9lectronique, avec une puce, un code PIN, et on peut faire plein [plein de choses super utiles](http://www.belgium.be/fr) avec (comme remplir sa d\u00e9claration d'imp\u00f4ts). Il y a deux paquets \u00e0 prendre en compte pour cela (le middleware et le viewer); tout est expliqu\u00e9 sur la page d'accueil du projet pour les principales distributions. Pour les autres, il y a les sources :) Solus faisant partie \"des autres\", il y a quelques d\u00e9pendances \u00e0 r\u00e9soudre avant d'arriver \u00e0 compiler le n\u00e9cessaire:\n\n```shell\nsudo pisi install pcsc-lite-devel libusb-devel libgtk-3-devel openjdk-8\n./configure\nmake\nsudo make install\n```\n\nOn a aussi besoin des drivers `ccid`, qui ne sont pas dispos dans les d\u00e9p\u00f4ts. On peut les t\u00e9l\u00e9charger [ici](https://alioth.debian.org/frs/?group_id=30105#title_ccid), et les installer en suivant la mani\u00e8re classique (`./configure; make; sudo make install`). L'installation nous informe qu'il ne faut **surtout** pas oublier de copier le fichier `src/92_pcscd_ccid.rules` dans le r\u00e9pertoire `/etc/udev/rules.d/`. A l'occasion, il faudra que je creuse pourquoi cette \u00e9tape n'est pas effectu\u00e9e en m\u00eame temps que l'installation...\n\nD\u00e9marrez ensuite `pcscd` en mode *foreground* avec les traces de debug avec les options `-f -d`. Cela vous permettra de v\u00e9rifier et valider que votre lecteur USB est correctement d\u00e9tect\u00e9. Si cela coince, vous devrez vous d\u00e9brouillez pour trouver les pilotes ccid compatible avec votre mat\u00e9riel. Par exemple avec un lecteur `ACR38`en USB: `dmesg` le d\u00e9tecte bien, mais `pcscd` ne comprend que dalle. Il suffit alors de t\u00e9l\u00e9charger le pilote ccid sur le site du constructeur, de l'installer, et de red\u00e9marrer les d\u00e9mons:\n\n```shell\n$ dmesg\n\n[ 710.951271] usb 2-3: new full-speed USB device number 8 using xhci_hcd\n[ 711.122192] usb 2-3: New USB device found, idVendor=072f, idProduct=9000\n[ 711.122194] usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0\n[ 711.122196] usb 2-3: Product: ACR38 USB Reader\n[ 711.122197] usb 2-3: Manufacturer: ACS\n```\n\n```shell\n$ sudo pcscd -f -d\n\nccid_usb.c:313:OpenUSBByName() Using: /usr/lib64/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist\nccid_usb.c:331:OpenUSBByName() ifdManufacturerString: Advanced Card Systems Ltd.\nccid_usb.c:332:OpenUSBByName() ifdProductString: ACS CCID driver\nccid_usb.c:333:OpenUSBByName() Copyright: This driver is protected by terms of the GNU Lesser General Public License version 2.1, or (at your option) any later\nccid_usb.c:706:OpenUSBByName() Found Vendor/Product: 072F/9000 (ACS ACR38U)\nccid_usb.c:708:OpenUSBByName() Using USB bus/device: 2/9\nacr38cmd.c:519:ACR38_SetCardVoltage() cardVoltage: 0\nacr38cmd.c:600:ACR38_SetCardType() cardType: 0\nccid.c:728:ccid_open_hack_post() Firmware: ACR38-1100\n```\n\nEt voil\u00e0! Un peu plus compliqu\u00e9 que sur une autre distribution, mais cela fonctionne :)\n\nLe pilote Firefox fonctionnera (pour peu que vous l'ayez install\u00e9, forc\u00e9ment). Par contre, avec les traces de `pcscd`, on a vraiment l'impression que ce module consomme \u00e9norm\u00e9ment. Quand vous ne l'utilisez pas, il peut \u00eatre int\u00e9ressant de le d\u00e9sactiver compl\u00e8tement. On perdrait en confort ce qu'on gagnerait en performances.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-11-07",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Rune Audio\nDate: 2016-12-16\nTags: raspberry, rune_audio, dac, audio\nSlug: rune-audio\n---\n\nQu'est-ce qu'on peut faire avec un vieux Raspberry Pi qui traine au fond d'un tiroir? *A priori*, plein de choses: un serveur [YunoHost](), une [sonde de temp\u00e9rature](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/temperature/), une [dashcam](https://pidashcam.blogspot.be/), ... Ou un serveur [MPD](https://fr.wikipedia.org/wiki/Music_Player_Daemon) :)\n\nSi cela vous tente, il existe plusieurs distributions qui vous aideront \u00e0 atteindre cet objectif:\n\n * [Volumio](https://fr.wikipedia.org/wiki/Music_Player_Daemon)\n * [Rune Audio](http://www.runeaudio.com/)\n * [OSMC](https://osmc.tv/) avec du Kodi dedans\n * [Moode](http://moodeaudio.org/).\n\n\nJ'ai pris la premi\u00e8re option. Apr\u00e8s avoir copi\u00e9 le contenu sur la carte SD en utilisant la commande `dd` (comme d'hab'), on plug le tout dans le Raspberry, on lui enfiche un c\u00e2ble RJ45, la prise d'alimentation et c'est parti!\n\nSi sa d\u00e9tection n'est pas automatique, regardez les logs du routeur pour trouver son adresse IP; sinon, rendez-vous sur l'adresse [http://runeaudio.local](http://runeaudio.local) et ajoutez simplement une source (NAS, disque USB, Jamendo, Drible, Spotify ou une Webradio).\n\nQuelques remarques:\n\n * Je n'ai pas r\u00e9ussi \u00e0 configurer le partage par NFS (alors qu'il fonctionne parfaitement sur Kodi, sur le second Raspberry)\n * Pour contr\u00f4ler le bouzin, passez soit par le client Web sur le r\u00e9seau local, soit par une application. Sur Android, l'appli [MPDroid](https://f-droid.org/repository/browse/?fdid=com.namelessdev.mpdroid) est top et tr\u00e8s simple: on parcourt les sources (avec r\u00e9cup\u00e9ration automatique des m\u00e9tadonn\u00e9es et des jaquettes) et on lance (soit directement, soit \u00e0 la suite). Sur iOS, je n'ai pas encore trouv\u00e9 mon bonheur; je me limite donc \u00e0 un raccourci du serveur sur la page d'accueil :)\n\nPour aller plus loin et si vous poss\u00e9dez un bon ampli, pensez \u00e0 passer sur un [HifiBerry](https://www.hifiberry.com/) ou un [autre DAC](http://raspi.tv/2016/dac-review).",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2016-12-16",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Connexion d'un utilisateur sans mot de passe\nSummary: Juste avec sa cl\u00e9 ED25519, sa bite et son couteau.\nCategory: S\u00e9curit\u00e9\n---\n\nVoir [ici](https://wiki.archlinux.org/index.php/SSH_keys#ECDSA) pour revoir la syntaxe de cr\u00e9ation d'une cl\u00e9 ECDSA.\nPour info, le wiki d'[ArchLinux](https://wiki.archlinux.org/index.php/SSH_keys#ECDSA) l'explique relativement bien:\n\n```shell\nssh-keygen -t ed25519\n```\n\nPour une explication plus compl\u00e8te sur le fonctionnement des algorithmes \u00e0 courbes elliptiques, voir sur le [blog de Mozilla](https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/].\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2017-07-12",
"title": "---"
},
{
"category": "sys",
"content": "Title: Activer la connexion automatique sous Windows\nDate: 2017-07-27\nTags: windows, autologin\n\n\non tapote `control userpasswords2` apr\u00e8s avoir appuyr\u00e9 sur Super+R, et on active (ou un d\u00e9sactive) la connexion automatique d'un des utilisateurs.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2017-07-27",
"title": "Title: Activer la connexion automatique sous Windows"
},
{
"category": "sys",
"content": "---\nTitle: De la diff\u00e9rence entre rsync, scp et sftp\nSummary: rsync, scp et sftp sont dans un bateau. Le serveur plante.\nTags: rsync, security, ssh, scp, sftp\nDate: 2017-08-08\n---\n\nJ'ai encore appris un truc \u00e0 la noix aujourd'hui: [SCP](https://fr.wikipedia.org/wiki/Secure_copy) et [SFTP](https://fr.wikipedia.org/wiki/SFTP) ne sont pas du tout \u00e9quivalents pour l'envoi de documents sur un serveur en se connectant avec SSH. La mani\u00e8re de se connecter, oui; la m\u00e9thode de transfert, non! SCP ne fait que copier les fichiers; SFTP permet de g\u00e9rer plus finement (en mode interactif, si besoin) les fichiers et d'explorer l'arborescence si besoin.\n\nSFTP doit \u00eatre activ\u00e9 manuellement dans le fichier `/etc/ssh/sshd_config` alors qu'SCP pourra \u00eatre utilis\u00e9 d\u00e8s qu'une connexion SSH sera fonctionnelle.\n\nLe truc \u00e0 savoir, c'est qu'il est possible d'autoriser une connexion SSH, emp\u00eacher l'utilisation d'un shell, et autoriser malgr\u00e9 tout le protocole SFTP. En gros, on peut donc renvoyer l'utilisateur chez lui s'il se connecte au shell, mais l'autoriser s'il s'agit uniquement d'un transfert de fichiers (et oui: SCP ne sert qu'au transfert de fichiers... Mais comme la connexion semble \u00eatre ouverte, le serveur vous enverra dans les ronces).\n\nPour passer SFTP en mode non-interactif, on peut proc\u00e9der [comme ceci](www.unix.com/ubuntu/156681-i-want-upload-file-remote-machine-noninteractive-mode-through-sftp.html) (SCP l'est d'office, lui, en non-interactif):\n\n```shell\nsftp <HOST> -b <<EOF\nput file1\nput file2\nEOF\n```\n\nVoir aussi [ici](https://wiki.archlinux.org/index.php/SCP_and_SFTP) pour les d\u00e9tails d'installation du service SFTP complet.\n\nEt pour [simplifier](https://unix.stackexchange.com/questions/8707/whats-the-difference-between-sftp-scp-and-fish-protocols):\n\n```\nSFTP = SSH + SFTP-server on server\nSCP = SSH + `scp` on server side\nFISH = SSH + `dd` (and some other basic Unix utilities on the server side only)\n```",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2017-08-08",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Sortie de TinyTinyRSS et passage \u00e0 FreshRSS\nDate: 2017-08-17\nTags: rss, applis, auto-h\u00e9bergement\n---\n\nJ'ai plus ou moins d\u00e9marr\u00e9 l'auto-h\u00e9bergement avec une instance de [TinyTinyRSS](https://tt-rss.org/). Depuis quelques semaines et apr\u00e8s une ou deux mises-\u00e0-jour depuis le d\u00e9p\u00f4t Git, l'instance commen\u00e7ait \u00e0 battre de l'aile: messages d'avertissements libpng suite au passage vers [Debian 9](https://wiki.debian.org/DebianStretch), les ic\u00f4nes des flux qui ne correspondaient pas, ... Zou, passage \u00e0 [FreshRSS](https://github.com/FreshRSS/FreshRSS).\n\nDe prime abord, c'est un peu flou:\n\n * Le site officiel indique encore la version 1.2 comme \u00e9tant la derni\u00e8re release stable, alors que le compte Gihtub propose d\u00e9j\u00e0 la 1.7;\n * L'installation par l'archive .zip partait du principe que tout se trouvait dans une base SQLite.\n * L'installation *via* le d\u00e9p\u00f4t Git n'a pos\u00e9 aucun probl\u00e8me...\n * Il y a quelques trous dans la documentation.\n\nRestait alors \u00e0 trouver une application Android: [EasyRSS](https://f-droid.org/packages/org.freshrss.easyrss/). Ici aussi, la configuration est un peu louche:\n\n * Rendez-vous dans la section **Authentification** des param\u00e8tres et activez l'option `Autoriser l'acc\u00e8s par l'API`\n * V\u00e9rifiez votre fichier Nginx. Il doit notamment mapper la location ` ~ ^.+?\\.php(/.*)?$` et ajouter la ligne `fastcgi_param PATH_INFO $fastcgi_path_info`. A voir dans la documentation (mais cela m\u00e9riterait presque d'\u00eatre plus mis en avant).\n * L'URL \u00e0 configurer dans EasyRSS devra pointer vers `/api/greader.php` (voire `/p/api/greader.php`, \u00e0 nouveau en fonction de votre configuration).\n * EasyRSS pour Android ne permet pas de s'abonner \u00e0 un flux.\n\nA part ces deux-trois bricoles \u00e0 l'installation, le reste de l'appli est top! Th\u00e8mes \u00e0 jour, interface intuitive, r\u00e9activit\u00e9, plein d'options partout. Bref, c'est joli et fonctionnel. La mise \u00e0 jour automatique des flux m\u00e9riterait peut-\u00eatre d'\u00eatre un rien plus pratique (soit *via* un token, soit par un script PHP - mais il faut alors un peu jongler avec les t\u00e2ches CRON et l'utilisateur sous lequel tourne le serveur Web).\n\nPour t\u00e9l\u00e9charger automatiquement le fichier OPML, je passe par la proc\u00e9dure suivante:\n\n```shell\nNOW=$(date +\"%Y-%m-%d-%H%M\")\nFILE=\"freshrss.$NOW.opml\"\n/var/www/reader.grimbox.be/cli/export-opml-for-user.php --user Fred > $FILE\n```",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2017-08-17",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Copier le fichier le plus r\u00e9cent vers un r\u00e9pertoire\nTags: xcopy, windows, bat\nDate: 2017-08-27\n---\n\nQuand on veut cracher des fichiers de logs sans se pr\u00e9occuper de la gestion de leur emplacement, il y a [logrotate](https://linux.die.net/man/8/logrotate). Le machin qui dit \"Ok, j'ai ton fichier dans `/var/log/bidule.log`, je t'en garde trois semaines, un nouveau fichier par semaine et je te d\u00e9gage les plus anciens. Cool.\n\nSinon, il y a des applications qui s'amusent \u00e0 dumper des sauvegardes directement suffix\u00e9es avec la date. Une plaie pour savoir quoi sauvegarder, puisqu'on se retrouve __tr\u00e8s__ rapidement \u00e0 avoir 236GB de backups dans un r\u00e9pertoire. Pour \u00e9viter d'avoir \u00e0 sauvegarder cette quantit\u00e9 monstrueuse par SSH, j'ai fouill\u00e9 pour sortir un petit script permettant d'isoler le fichier le plus r\u00e9cent. De cette mani\u00e8re, je conserve dans un r\u00e9pertoire la derni\u00e8re version des donn\u00e9es, et il me suffit d'envoyer ce r\u00e9pertoire-l\u00e0 pour avoir une copie distante (cela ne g\u00e8re par contre pas le fait que les fichiers continuent \u00e0 s'amonceler nonchalement \u00e0 un endroit que je souhaiterais garder propre).\n\n```bat\n@echo off\n\nfor /F \"delims=\" %%a in ('dir /b /od \"*.bak\"') do set Youngest=%%a\nxcopy /y /F \"%Youngest%\" \"E:\\Backups\\latest.bak\"\n```\n\nLes arguments pass\u00e9s \u00e0 `xcopy` permettent de confirmer toute question (genre */y : \"Pas grave si cela \u00e9crase un fichier existant\"* (c'est m\u00eame le but) et */F: La destination est un fichier et pas un r\u00e9pertoire*\").\n\nSources: https://stackoverflow.com/questions/19152609/batch-file-to-copy-the-most-recent-file-created#19152899 et https://duckduckgo.com/?q=ccopy+latest+file+youngest&t=ffab&atb=v69-4_z&ia=qa.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2017-08-27",
"title": "---"
},
{
"category": "sys",
"content": "---\nTitle: Ghost.org, la plateforme de publication en Node.JS\nTags: blog, engine\nDate: 2017-12-05\n---\n\n[Ghost](https://ghost.org) est une tr\u00e8s chouette plateforme de r\u00e9daction et de publication, qui a ses petits d\u00e9fauts de jeunesse malgr\u00e9 tout.\n\nL'installation s'est franchement am\u00e9lior\u00e9e depuis les premi\u00e8res versions: on installe Node (de pr\u00e9f\u00e9rence *via* les d\u00e9p\u00f4ts officiels et non pas ceux de la distribution):\n\n```shell\ncurl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -\nsudo apt-get install -y nodejs\n```\n\nEnsuite, on passe par l'installation de Ghost-cli gr\u00e2ce \u00e0 npm et on d\u00e9marre l'installation qui pose les bonnes questions, jusqu'\u00e0 la cr\u00e9ation d'un certificat Let's Encrypt.",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2017-12-05",
"title": "---"
},
{
"category": "sys",
"content": "J'ai un peu chipot\u00e9 pour avoir un MTA fonctionnel.\n\nLe nom de domaine se trouve chez Gandi, le serveur chez Scaleway et j'ai install\u00e9 ssmtp comme MTA.\n\nPremier petit pi\u00e8ge, il y a un default security group directement au niveau de l'interface de scaleway. Par d\u00e9faut, ce groupe bloque la sortie SMTP.\n\n![scaleway-security-group-smtp](/blog/content/images/2018/01/scaleway-security-group-smtp.png)\n\nAu besoin, il est possible d'avoir un acc\u00e8s interactif au serveur SMTP en l'interrogeant en Telnet. Si n\u00e9cessaire, installez telnet et pr\u00e9parer l'encodage en [base64](https://www.ndchost.com/wiki/mail/test-smtp-auth-telnet) de vos identifiants pour pouvoir les lui envoyer lorsqu'ils seront demand\u00e9s:\n\n```shell\nperl -MMIME::Base64 -e 'print encode_base64(\"<username>\");'\n\ntelnet mail.gandi.net 587\nEHLO mail.gandi.net\n<user en base64>\n<password en base64>\n```\n\nSi la connexion plante d\u00e9j\u00e0 \u00e0 ce moment-ci, c'est peut-\u00eatre un soucis du pare-feu. Si n\u00e9cessaire, ouvrez le port 587/tcp depuis ufw avec la commande `ufw allow out 587/tcp`. Une contrainte peut \u00eatre li\u00e9e \u00e0 l'\u00e9chappement des caract\u00e8res sp\u00e9ciaux du mot de passe; si cela ne passe pas, conservez un mot de passe fort, mais d\u00e9gagez les caract\u00e8res types `@`, `!` et `=`.\n\nApr\u00e8s l'installation d'ssmtp, vous pouvez modifier le contenu du fichier `/etc/ssmtp/ssmtp.conf` avec quelque chose de similaire:\n\n```ini\n## Config file for sSMTP sendmail\n## The person who gets all mail for userids < 1000\n## Make this empty to disable rewriting.\n\nroot=admin@<nom_de_domaine>\nmailhub=mail.gandi.net:587\nhostname=\nFromLineOverride=YES\nUseSTARTTLS=YES\nAuthUser=<user@nom_de_domaine>\nAuthPass=<mot_de_passe_de_user@nom_de_domaine>\n```\n\nSi vous souhaitez d\u00e9finir l'adresse email utilis\u00e9e par un compte sp\u00e9cifique, il suffira de d\u00e9finir cette association dans le fichier `/etc/ssmtp/revaliases`.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2018-01-09",
"title": "J'ai un peu chipot\u00e9 pour avoir un MTA fonctionnel."
},
{
"category": "sys",
"content": "Hello Gitea\n===========\n\n[Gitea](https://gitea.io/fr-fr) se pr\u00e9sente comme un service d'h\u00e9bergement et d'acc\u00e8s \u00e0 des d\u00e9p\u00f4ts [Git](https://git-scm.com/), le tout sans douleur.\n\n**Spoiler alert**: C'est quand m\u00eame un peu douloureux. Mais moins que pour un service [Gitlab](https://about.gitlab.com/) qui n\u00e9cessite ses scripts [Chef](https://www.chef.io/), parce que trop compliqu\u00e9.\n\nInstallation\n------------\n\nPour l'installation, l'article le plus complet que j'ai trouv\u00e9 (et sur lequel je me suis bas\u00e9 :-)) est disponible [ici](https://jeremyverda.net/installing-gitea-on-debian/).\n\nL'installation est relativement simple; le plus compliqu\u00e9 a \u00e9t\u00e9 de d\u00e9couvrir certaines sp\u00e9cificit\u00e9s et de rendre le service disponible depuis un sous-r\u00e9pertoire sur Nginx.\n\n```shell\nadduser --disabled-login --gecos 'gitea' git\nsu - git\n```\n\nComme le rappelle `man adduser` (et aussi le [forum AskUbuntu](https://askubuntu.com/questions/420784/what-do-the-disabled-login-and-gecos-options-of-adduser-command-stand)):\n\n```text\n--disabled-login\n Do not run passwd to set the password. The user won't be able\n to use her account until the password is set.\n\n--gecos GECOS\n Set the gecos field for the new entry generated. adduser will\n not ask for finger information if this option is given.\n```\n\nVoir [ici](https://en.wikipedia.org/wiki/Gecos_field) pour la signification de `GECOS` (TL;DR: on s'attend \u00e0 avoir le nom, le b\u00e2timent/la chambre, le num\u00e9ro de t\u00e9l\u00e9phone pro, le num\u00e9ro de t\u00e9l\u00e9phone priv\u00e9 et toute autre information, s\u00e9par\u00e9es par des virgules).\n\nT\u00e9l\u00e9chargez ensuite la bonne version de l'application en fonction de votre architecture, sur la [page de t\u00e9l\u00e9chargement](https://dl.gitea.io/) et rendez le ex\u00e9cutable.\nAttention donc que pour un serveur ARM type Raspberry-Pi, vous ne devrez surtout pas prendre les fichiers type `amd64`. Oui, \u00e7a a l'air logique, mais sur le coup, en suivant [le tuto d'installation](https://docs.gitea.io/en-us/install-from-binary/) pas-\u00e0-pas, \u00e7a l'est moins.\n\nApr\u00e8s l'installation, et au premier d\u00e9marrage, Gitea cr\u00e9era un fichier de configuration sp\u00e9cifique qu'il placera \u00e0 l'emplacement `custom/conf/app.ini`. Cr\u00e9ez d\u00e9j\u00e0 les r\u00e9pertoires de stockage pour les donn\u00e9es: `mkdir -p custom/conf data`, puis d\u00e9marrer l'application via `./gitea web`.\n\nSi vous souhaitez d\u00e9marrer Gitea dans un sous-r\u00e9pertoire du domaine, coupez le service, modifiez le fichier afin d'y ajouter `[server] ROOT_URL = /git/` et red\u00e9marrez-le ensuite.\n\n### Configuration Nginx\n\n```shell\nserver {\n listen 443 ssl;\n ssl_protocols TLSv1.1 TLSv1.2;\n\n [...]\n\n location /git/ {\n proxy_pass http://localhost:3000/;\n client_max_body_size 100M;\n }\n\n [...]\n```\n\nEt d\u00e9marrez le service \u00e0 la main: `./gitea web`. Vous pourrez ensuite passer \u00e0 l'installation, en vous rendant sur la bonne page.\n\nUne fois que tout sera correctement install\u00e9, on peut passer \u00e0 la (re)configuration via le fichier `custom/conf/app.ini`. Le seul changement que j'ai appliqu\u00e9 consiste \u00e0 modifier la section `[server]`:\n\n```ini\n[server]\nPROTOCOL = http\nROOT_URL = https://grimbox.be/git/\nSSH_DOMAIN = grimbox.be\nDOMAIN = grimbox.be\nHTTP_PORT = 3000\nHTTP_ADDR = 0.0.0.0\nDISABLE_SSH = false\nSSH_PORT = 22\nLFS_START_SERVER = true\n```\n\n### Configuration Supervisord\n\nLa documentation conseille de passer par [systemd](https://freedesktop.org/wiki/Software/systemd/), mais le tuto conseille plut\u00f4t de passer par [supervisor](http://supervisord.org/), ce qui revient +/- au m\u00eame:\n\n```shell\napt install supervisor\nmkdir /var/log/gitea\nvim /etc/supervisor/conf.d/gitea.conf\n```\n\nEt copiez le contenu ci-dessous:\n\n```ini\n[program:gitea]\ndirectory=/home/git/\ncommand=/home/git/gitea web\nautostart=true\nautorestart=true\nstartsecs=10\nstdout_logfile=/var/log/gitea/stdout.log\nstdout_logfile_maxbytes=1MB\nstdout_logfile_backups=10\nstdout_capture_maxbytes=1MB\nstderr_logfile=/var/log/gitea/stderr.log\nstderr_logfile_maxbytes=1MB\nstderr_logfile_backups=10\nstderr_capture_maxbytes=1MB\nenvironment = HOME=\"/home/git\", USER=\"git\"\n```\n\nEt on termine par `supervisorctl start gitea` (apr\u00e8s avoir arr\u00eat\u00e9 l'instance qui tourne d\u00e9j\u00e0 en manuel :-)).\n\n### Arborescence finale\n\n```shell\ngit@dagger:~$ tree .\n.\n\u251c\u2500\u2500 custom\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 conf\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 app.ini\n\u251c\u2500\u2500 data\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 avatars\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 9ffb88df5ac2a65fbad9a981cd1b949a\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 gitea.db\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 indexers\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 issues.bleve\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 index_meta.json\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 store\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 lfs\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 sessions\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 ...\n\u251c\u2500\u2500 gitea\n\u251c\u2500\u2500 gitea-repositories\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 <user>\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 <repo1>.git\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 branches\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 config\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 description\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 HEAD\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 hooks\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 ...\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 info\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 ...\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 objects\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 ...\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 refs\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 heads\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 master\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 tags\n\u2514\u2500\u2500 log\n \u251c\u2500\u2500 gitea.log\n \u251c\u2500\u2500 hooks\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 post-receive.log\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 pre-receive.log\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 update.log\n \u251c\u2500\u2500 http.log\n \u251c\u2500\u2500 serv.log\n \u251c\u2500\u2500 xorm.log\n \u2514\u2500\u2500 xorm.log.2018-07-04.001\n```\n\nBackup\n------\n\nToute la magie tient dans une seule commande: `./gitea dump`.\n\nCela cr\u00e9era une archive ~timestamp\u00e9e~ ~horodat\u00e9e~ avec un indice. G\u00e9n\u00e9r\u00e9e le 04/07/2018 \u00e0 13h16, elle porte par exemple l'indice 1530702980.\nAjoutez donc ce dump dans un crontab, et envoyez le tout vers votre d\u00e9p\u00f4t Borg pr\u00e9f\u00e9r\u00e9 :-)\n\nRestore\n-------\n\nVous pouvez d\u00e9zipper l'archive g\u00e9n\u00e9r\u00e9e ci-dessus, mais la structure sera diff\u00e9rente de l'arborescence des fichiers attendus par Gitea. Les r\u00e9pertoires `custom` et `data` se trouveront aux bons endroits, mais la base de donn\u00e9es devra \u00eatre reconfigur\u00e9e en fonction de votre configuration (avec du SQLite, c'est plus simple...).\n\nIdem pour les d\u00e9p\u00f4ts: ils sont archiv\u00e9s dans un fichier `gitea-repo.zip` \u00e0 l'int\u00e9rieur du dump r\u00e9alis\u00e9 ci-dessus.\n\nComme l'indique la [documentation](https://docs.gitea.io/en-us/backup-and-restore/), il n'y a donc pas de processus automatique.\n\nPush derr\u00e8re un proxy d'entreprise\n----------------------------------\n\nSi vous obtenez une erreur d'authentification (401) lors d'un push, il est possible que vous deviez passer par un tunnel, afin de vous identifier correctement par rapport \u00e0 votre proxy. Pour cela, dans la configuration de [cntlm](./cntlm.md), ajoutez un tunnel de type `Tunnel 12222:<server_url>:22` afin de mapper un port interne (ici, le 12222) sur le port d'\u00e9coute du serveur externe.\n\nOn peut ensuite configurer son d\u00e9p\u00f4t local avec l'URL suivante: `url = ssh://git@localhost:12222/<repo_url>.git`.\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2018-07-04",
"title": "Hello Gitea"
},
{
"category": "sys",
"content": "# Comparaison de quelques VPS/Baremetal\n\nUtilisation de `Sysbench <https://wiki.gentoo.org/wiki/Sysbench>`_ pour les tests.\n\nLes serveurs compar\u00e9s sont les suivants:\n\n * Un VPS Cloud chez OVH: 4Go de Ram, single-core et SSD de 20Go.\n * Un C1 chez Scaleway: 2Go de RAM, quad-core ARMv7 et SSD de 50Go.\n * Un Kimsufi KS-1: Atom @ 1.86Ghz (2 coeurs, 4 threads), 2Go de RAM et 500 de disque.\n * Un ARM64 2GB chez Scaleway\n * Un VPS x86-64 2GB de RAM et SSD Nvme de chez Scaleway (les nouveaux mod\u00e8les de 2018 :-) )\n\nAu niveau des tests, j'ai compar\u00e9 les performances des CPU en utilisant `sysbench`. J'ai ensuite d\u00e9marr\u00e9 un test de lecture/\u00e9criture compl\u00e8tement biais\u00e9 *via* la commande `dd`, comme expliqu\u00e9 [ici](http://www.stevefortuna.com/check-disk-speed-quickly-and-easily-in-linux/). Cette \u00e9tape permet juste de simuler une \u00e9criture sur le disque, dans des conditions id\u00e9ales.\n\n## En r\u00e9sum\u00e9\n\n```shell\nsysbench --test=cpu --cpu-max-prime=20000 run\nsysbench --test=cpu --cpu-max-prime=20000 --num-threads=4 run\ndd if=/dev/zero of=test bs=1048576 count=2048\ndd if=test of=/dev/null bs=1048576\n```\n\n| | VPS Cloud | C1 | KS-1 | Start-1S | ARM64-2G |\n|-------------------|-------------|-----------|-----------|--------------|--------------|\n| CPU | 29.8127s | 686.8824s | 209.6545s | **20.8311s** | 29.9709s |\n| CPU multithreaded | 27.9756s | 171.3275s | 86.2656s | 10.4649s | **7.5875s** |\n| Read | **2.3Go/s** | 97.6 MB/s | 145Mo/s | 1.1GB/s | 387 MB/s |\n| Write | 514Mo/s | 96.2 MB/s | 143Mo/s | **587 MB/s** | 210 MB/s |\n\nA titre de comparaison, un Rapsberry Pi 3 obtient respectivement les valeurs suivantes:\n\n* CPU: 370.1484s\n* CPU MT: 93.0836s\n* Disk read: 17,8 MB/s\n* Disk write: 11,2 MB/s\n\nEt pour un Raspberry Pi B+ dans les m\u00eames conditions, on obtient ceci:\n\n* CPU: 874.7016s\n* CPU MT: 876.7125s\n* Disk read: 21,6 MB/s\n* Disk write: 7,2 MB/s\n\nEn conclusion, et en se basant sur ces r\u00e9sultats (th\u00e9oriques), l'ARM64 semble \u00eatre une option valable pour un petit serveur h\u00e9bergeant quelques applications.\nSurtout en prenant le prix en consid\u00e9ration; \u00e0 3.67\u20ac TVAC le petit processeur, 2Go de RAM et 50Go de SSD, c'est une offre qui semble plut\u00f4t sympa.\nSi les besoins en espace de stockage sont grands, il vaudra peut-\u00eatre mieux s'orienter vers un Kimsufi (pour peu qu'ils soient disponibles...).\n\nReste \u00e0 v\u00e9rifier quelques points:\n\n* La disponibilit\u00e9 des noyaux pour ces archis un peu h\u00e9t\u00e9roclites - le C1 tourne toujours avec un noyau en 4.3.5.\n* Le support IPv6 qu'on dit bancal ou partiel (pas v\u00e9rifi\u00e9).\n",
"keywords": [],
"path": "articles\\sys",
"publication_date": "2018-08-27",
"title": "# Comparaison de quelques VPS/Baremetal"
}
],
"categories": {},
"keywords": {}
}