[{"data":1,"prerenderedAt":46930},["ShallowReactive",2],{"category-programmation":3},[4,333,1768,6020,13521,15661,21590,24666,28700,30568,31460,32929,34766,36091,39211,40423,42098,44596,45778,46822],{"id":5,"title":6,"author":7,"body":8,"category":300,"categorySlug":301,"date":302,"description":14,"excerpt":303,"extension":317,"location":318,"meta":319,"navigation":320,"path":321,"published":320,"seo":322,"slug":323,"stem":324,"tags":325,"timeToRead":331,"__hash__":332},"posts\u002Fposts\u002FProgrammation\u002F2026-01-29-sportequipement-vibe-coding.md","SportEquipement - Application de suivi de matériel sportif avec Vibe Coding","Ulrich Vandenhekke",{"type":9,"value":10,"toc":290},"minimark",[11,15,18,21,24,32,37,40,43,59,63,66,75,78,81,88,91,94,101,112,116,119,122,136,139,164,167,170,177,180,183,186,189,192,195,199,202,205,208,213,216,219,222,225,229,232,235,238,241,248,252,255,258,261,268,275,278,281,284,287],[12,13,14],"p",{},"Bonjour à tous,",[12,16,17],{},"Pour ceux qui me connaissent, vous savez que je fais un peu de vélo. Et comme tout cycliste moderne, j'utilise Strava.\nC'est l'outil de référence pour suivre ses sorties, comparer ses segments et analyser sa forme. Strava propose bien une\nfonctionnalité de \"Suivi d'équipement\" (pour savoir combien de kilomètres ont vos chaussures ou votre cadre), mais...\nc'est sommaire.",[12,19,20],{},"Si la version Web permet d'ajouter des composants (chaîne, cassette, etc.), l'application mobile a tout simplement\n\"oublié\" cette fonctionnalité.",[12,22,23],{},"J'ai eu quelques problèmes avec ma chaîne qui s'use en 2 000 km ou des plaquettes de frein à changer. Bref j'avais envie\nd'avoir des stats un peu précises sur le suivi de mon matériel. De la même manière je cours régulièrement et je voulais\nsavoir quand mes baskets atteignaient leur durée de vie maximale (ça, ça marche bien sur Strava).",[12,25,26,27,31],{},"Pour améliorer ce suivi j'ai décidé de créer ma propre solution : ",[28,29,30],"strong",{},"SportEquipement",".",[33,34,36],"h2",{"id":35},"sportequipement-cest-quoi","SportEquipement : C'est quoi ?",[12,38,39],{},"L'idée est simple : une application mobile, connectée à Strava et à Android Health Connect, qui récupère mes activités\net incrémente l'usure de chaque composant défini.",[12,41,42],{},"Pour la première version, je voulais aussi qu'elle soit \"Local First\". L'application tourne entièrement sur le téléphone.\nPas de serveur, application open source, et mes données restent chez moi. (Bon, j'ajouterai peut-être dans un futur un\nserveur pour synchroniser mes différents appareils et sécuriser les tokens Strava, mais chaque chose en son temps).",[12,44,45,46,53,54,31],{},"L'application est d'ailleurs disponible sur le ",[47,48,52],"a",{"href":49,"rel":50},"https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=org.shadoware.sportequipment&hl=fr",[51],"nofollow","Play Store"," et le code source est sur mon ",[47,55,58],{"href":56,"rel":57},"https:\u002F\u002Fgogs.shadoware.org\u002FShadowareOrg\u002FSportsEquipment",[51],"Gitea perso",[33,60,62],{"id":61},"quelques-écrans","Quelques écrans",[12,64,65],{},"Cet écran montre la liste des équipements qui ont été ajoutés. On peut voir l'état d'usure de chaque équipement et si\nl'équipement est usé ou un de ces composants est usé on a une alerte visuelle.",[12,67,68],{},[69,70],"img",{"alt":71,"className":72,"src":74},"Liste des équipements",[73],"img-center","\u002FProgrammation\u002Fsportequipement\u002Fimage1.png",[12,76,77],{},"Sur l'écran détail d'un équipement, on y voit les informations détaillées de l'équipement mais aussi la liste des\ncomposants et l'usure des composants.",[12,79,80],{},"Un composant peut être usé par le kilométrage (ex: chaîne, pneu) ou par le temps (ex: liquide de frein).",[12,82,83],{},[69,84],{"alt":85,"className":86,"src":87},"Liste des composants \u002F Détail",[73],"\u002FProgrammation\u002Fsportequipement\u002Fimage2.png",[12,89,90],{},"Sur l'écran d'activité on récupère la liste des activités synchronisées depuis Strava ou Health Connect (pour l'instant\nune fois par jour). On peut créer des activités manuellement aussi si besoin. C'est l'ajout ou la suppression d'une activité\nqui impacte l'usure des équipements.",[12,92,93],{},"Les activités sont rattachées aux équipements via des types d'activités (l'équipement est attaché à un type d'activité,\net l'activité aussi).",[12,95,96],{},[69,97],{"alt":98,"className":99,"src":100},"Liste des activités",[73],"\u002FProgrammation\u002Fsportequipement\u002Fimage3.png",[12,102,103,104,108,109,31],{},"Mais si je vous écris aujourd'hui, ce n'est pas seulement pour vous présenter l'outil. C'est surtout pour vous raconter\n",[105,106,107],"em",{},"comment"," je l'ai développé. J'ai voulu tester le fameux ",[28,110,111],{},"\"Vibe Coding\"",[33,113,115],{"id":114},"développement-en-vibe-coding","Développement en Vibe Coding",[12,117,118],{},"Je souhaitais développer mon application rapidement. Je voulais également avoir ce que les agents IA avaient dans leurs\nneurones. En effet, j'ai une licence Github Copilot que j'utilisais principalement en mode auto-completion de code, un\npeu pour discuter, et parfois pour modifier du code sur un projet déjà existant. J'ai déjà \"Vibe Codé\" des scripts sans\nimpact dont le but était de faire des exécutions one-shot.",[12,120,121],{},"Sur ce projet, je me suis dit :",[123,124,125,133],"blockquote",{},[12,126,127,128,132],{},"Je ne suis plus développeur, je suis le chef de projet et le product owner. Je décris la fonctionnalité que je veux, et\nl'IA code pour moi. Je teste et si ça ne compile pas ou si ça ne marche pas comme je veux je fais un retour ",[129,130,131],"del",{},"au\ndeveloppeur"," à l'IA.",[12,134,135],{},"A la fin je regarderai le code généré et je verrai ce que l'IA vaut.",[12,137,138],{},"J'ai donc commencé à mettre différents types d'instructions :",[140,141,142,150,157],"ul",{},[143,144,145],"li",{},[47,146,149],{"href":147,"rel":148},"https:\u002F\u002Fgogs.shadoware.org\u002FShadowareOrg\u002FSportsEquipment\u002Fsrc\u002Fbranch\u002Fmain\u002F.github\u002Fcopilot-instructions.md",[51],"Expert en Kotlin et développement Android",[143,151,152],{},[47,153,156],{"href":154,"rel":155},"https:\u002F\u002Fgogs.shadoware.org\u002FShadowareOrg\u002FSportsEquipment\u002Fsrc\u002Fbranch\u002Fmain\u002F.github\u002Fprompts\u002Fui_ux.prompt.md",[51],"Agent expert en UI\u002FUX",[143,158,159],{},[47,160,163],{"href":161,"rel":162},"https:\u002F\u002Fgogs.shadoware.org\u002FShadowareOrg\u002FSportsEquipment\u002Fsrc\u002Fbranch\u002Fmain\u002F.github\u002Fprompts\u002Fdocumentation.prompt.md",[51],"Expert en documentation technique",[12,165,166],{},"Ces différents experts sont inspirés de prompts trouvés sur Internet et adaptés, modifiés et\u002Fou générés à l'aide de Github\nCopilot également.",[12,168,169],{},"Ensuite j'ai décrit mon projet en quelques lignes dans le prompt. Je lui ai demandé de me faire un plan, puis de le\ndévelopper.",[12,171,172,173,176],{},"Les deux premières semaines ont été grisantes. J'ai développé ",[28,174,175],{},"80% du logiciel"," en un temps record. Je regardais l'IA\ncoder, je cliquais sur le bouton continuer ou approuver (les outils MCP, le build, ...) et je jouais aux jeux vidéo pendant ce\ntemps.",[12,178,179],{},"Pour info les MCP c'est \"Model Context Protocol\", cela permet à Github Copilot d'accéder à des outils comme\nl'execution des commandes, la recherche sur internet, ...",[12,181,182],{},"Ma routine était simple : je demandais une fonctionnalité, l'IA générait le code, je compilais (pendant ce temps je\nfaisais autre chose : jeux vidéos, un autre programme ...). Une fois terminé, je lançais android studio, je compilais,\nje testais.",[12,184,185],{},"Si ça marchait, je passais à la fonctionnalité suivante. Si ça ne marchait pas, je donnais un retour à l'IA en lui\nexpliquant le problème (erreur de compilation, bug, comportement non conforme) et c'était reparti pour un tour.",[12,187,188],{},"Régulièrement je devais réinitialiser la conversation, je demandais donc à l'IA de mettre à jour le plan pour reprendre\ndans une nouvelle conversation. Généralement, je faisais cela quand l'IA commençait à faire n'importe quoi (oubli de ce\nsur quoi on travaillait initialement, pataugeait dans la semoule, ...). Les prémisses du pétage de plombs de l'IA passaient\nsouvent par un passage du français à l'anglais dans les réponses. La signification était probablement la perte du\ncontexte initial et des instructions de démarrage.",[12,190,191],{},"Au début, Copilot m'a pondu une architecture logicielle complexe, découpée en couches bien distinctes. Sur le papier,\nc'était beau (ça vient des instructions expert en développement kotlin qui demande une Clean architecture avec une\nséparation : Domain, Data, Feature, Core).",[12,193,194],{},"De mon coté, pour un projet perso, si j'avais dû développer le projet moi-même de zéro, j'aurais probablement fait\nbeaucoup plus simple et direct. Probablement une application avec des vues, une couche service et une couche DAO dans le\nmême projet. Mais là, c'était l'IA qui gérait l'architecture, donc je laissais faire. J'avançais à l'aveugle.",[33,196,198],{"id":197},"et-là-cest-le-drame","Et là, c'est le drame",[12,200,201],{},"Au bout de deux semaines, patatras. Je reçois une notification : je n'ai plus de crédits GitHub Copilot pour les\nrequêtes premium. Panne sèche.",[12,203,204],{},"J'ai bien tenté de reprendre avec un GPT4.1 ou GPT4o qui sont inclus en illimité, mais quand on a testé Gemini 3 ou\nClaude Sonnet 4.... qu'est que GPT4 est con....",[12,206,207],{},"Je me retrouve seul face à mon IDE, sans l'aide de copilot. J'étais le 15 du mois et il me restait 2 semaines avant le\nrenouvellement. Je me suis dit :",[123,209,210],{},[12,211,212],{},"Bon, c'est l'occasion de regarder un peu ce qu'il m'a écrit en détail et de faire une revue de code.",[12,214,215],{},"J'ai ouvert les fichiers. Et là... j'ai eu du sang qui m'a coulé des yeux, la cervelle qui m'est sortie par les oreilles ...",[12,217,218],{},"Le MCD (Modèle Conceptuel de Données) était inutilement complexe. Il y avait de la duplication de code partout. Pour\nfaire la même chose, l'IA avait parfois utilisé trois méthodes différentes à trois endroits du code, sans aucune\ncohérence globale. Il y avait du code mort, des variables inutilisées, des détours techniques incompréhensibles.",[12,220,221],{},"C'était fonctionnel, oui. Mais c'était sale. Très sale.",[12,223,224],{},"J'ai donc commencé à lister tous les problèmes architecturaux que j'ai vus dans le code (et attention il y en a\nprobablement d'autres). La suppression du code mort, je l'ai faite moi-même car à chaque fois l'IA n'était pas capable\nde le détecter si je ne lui donne pas le nom de la méthode.",[33,226,228],{"id":227},"le-grand-nettoyage","Le grand nettoyage",[12,230,231],{},"Dès que mes crédits ont été renouvelés, j'ai voulu tout nettoyer et donner à l'IA l'ensemble de ma revue de code.\nOptimiste, j'ai donné le grand listing de tout ce qui n'allait pas et de demander à l'IA une correction globale.",[12,233,234],{},"Échec total. C'était trop pour elle. Elle se perdait dans les corrections, me disait que tout était fait, mais seule une\npartie était terminée....",[12,236,237],{},"J'ai dû changer de stratégie. J'ai repris mon \"Vibe Coding\", mais cette fois-ci pour réparer les dégâts, problème par\nproblème, couche par couche (domaine, puis data, puis feature, puis core).",[12,239,240],{},"Puis je suis repassé en mode petite itération pour terminer les dernières fonctionnalités, corriger les derniers bugs. Et\nj'ai parfois dû mettre les mains dans le cambouis moi-même pour corriger des problèmes que l'IA n'arrivait pas à\nrésoudre.",[12,242,243,244,247],{},"Résultat des courses : j'avais fait 80% du projet (le prototype sale) en 2 semaines. Il m'a fallu ",[28,245,246],{},"un mois entier","\npour faire les 20% restants et nettoyer la base de code pour la rendre un peu plus propre.",[33,249,251],{"id":250},"conclusion","Conclusion",[12,253,254],{},"Aujourd'hui, l'application est sur le store Google, elle fonctionne bien, et elle répond à mon besoin initial.",[12,256,257],{},"Mais je ressors de cette expérience avec un sentiment mitigé. J'ai un étrange détachement vis-à-vis de ce projet.",[12,259,260],{},"J'ai l'impression d'avoir codé avec un stagiaire qui a de très bonnes connaissances théoriques sur l'architecture logicielle\nmais qui sans contrôle te crée une dette technique immense. Par contre il a l'avantage d'écrire très vite. Ce projet qui\na été fait en un mois - un mois et demi, m'aurait pris beaucoup plus de temps (sachant que je ne développe en perso que\nle soir et le week-end).",[12,262,263,264,267],{},"D'habitude, quand je code un logiciel, c'est mon \"bébé\". Je connais chaque ligne, chaque astuce, chaque défaut. Là...\nj'ai l'impression que ce n'est pas ",[28,265,266],{},"mon"," projet. Je me sens comme le Chef de Projet ou le client qui a passé commande.",[12,269,270,271,274],{},"Pour les petits scripts, les projets ",[28,272,273],{},"utilitaires",", l'intelligence artificielle est super pratique. Elle permet de\nconstruire rapidement un prototype fonctionnel. Mais sans maîtrise, le code n'est pas maintenable dans le temps (même\npar l'IA elle-même). Et je ne parle pas non plus des problématiques de sécurité, si j'avais un serveur sur cette\napplication.",[12,276,277],{},"Pour les projets de passionnés, ceux qu'on fait \"pour l'art\" ou pour le plaisir d'apprendre, je ne suis pas sûr de\nréitérer l'expérience aussi poussée. J'aime développer et c'est important pour moi de toucher la ligne de code.",[12,279,280],{},"J'ai aussi une autre inquiétude par rapport à l'avenir du métier de développeur. Un bon développeur pour l'instant est\ntoujours nécessaire pour superviser l'intelligence artificielle.",[12,282,283],{},"Mais les juniors qui arrivent sur le marché du travail vont-ils apprendre les bonnes pratiques de développement s'ils\nse reposent trop sur l'IA pour coder à leur place ? Est-ce que les juniors vont trouver du travail, même s'ils sont\ncompétents ?",[12,285,286],{},"Actuellement un développeur qui n'utilise pas l'IA risque de se retrouver à un moment dépassé sur le marché du travail.\nCe que j'aimais avec le développement c'est qu'avant n'importe qui pouvait faire du développement avec n'importe quel\nPC. Il y avait un coût d'apprentissage, tout le monde n'est pas fait pour faire du développement, mais c'était accessible\nfinancièrement aux personnes motivées.",[12,288,289],{},"Maintenant, il faut soit une très grosse carte graphique (et même là ce ne sont pas des modèles ultra performants), ou\nun abonnement payant. Il y a quelques versions gratuites mais elles sont là pour attirer. L'IA rend le développement plus\naccessible au niveau apprentissage, mais moins accessible financièrement et surtout dépendant d'un fournisseur.",{"title":291,"searchDepth":292,"depth":292,"links":293},"",2,[294,295,296,297,298,299],{"id":35,"depth":292,"text":36},{"id":61,"depth":292,"text":62},{"id":114,"depth":292,"text":115},{"id":197,"depth":292,"text":198},{"id":227,"depth":292,"text":228},{"id":250,"depth":292,"text":251},"Programmation","programmation","2026-01-29",{"type":9,"value":304},[305,307,309,311,313],[12,306,14],{},[12,308,17],{},[12,310,20],{},[12,312,23],{},[12,314,26,315,31],{},[28,316,30],{},"md","Lille, France",{"planet":320},true,"\u002Fpost\u002Fsportequipement-vibe-coding",{"title":6,"description":14},"sportequipement-vibe-coding","posts\u002FProgrammation\u002F2026-01-29-sportequipement-vibe-coding",[326,327,328,329,330],"developpement","ia","vibe coding","rex","android",10,"UjPK0msj1uJoiDCVdG4PiDDZUq_PLpB0i2SzFIOesPI",{"id":334,"title":335,"author":7,"body":336,"category":300,"categorySlug":301,"date":1618,"description":14,"excerpt":1619,"extension":317,"location":318,"meta":1759,"navigation":320,"path":1760,"published":320,"seo":1761,"slug":1762,"stem":1763,"tags":1764,"timeToRead":489,"__hash__":1767},"posts\u002Fposts\u002FProgrammation\u002F2024-06-14-max-old-space.md","Quelle est la valeur par défaut de max-old-space-size dans NodeJS ?",{"type":9,"value":337,"toc":1616},[338,340,348,351,533,536,542,557,560,563,599,602,607,616,619,622,633,848,858,867,1037,1045,1187,1203,1500,1503,1529,1535,1538,1541,1544,1609,1612],[12,339,14],{},[12,341,342,343,347],{},"Lors de nos développements en NodeJS, il arrive parfois que l'on se retrouve confronté à des erreurs. Certaines de ces\nerreurs ne se reproduisent pas en local, mais uniquement sur un environnement distant. C'est ce qui nous est arrivé\nrécemment lors de l'exécution de la commande ",[344,345,346],"code",{},"npm ci"," sur la chaîne de déploiement continue.",[12,349,350],{},"L'erreur que nous avons rencontrée est la suivante :",[352,353,357],"pre",{"className":354,"code":355,"language":356,"meta":291,"style":291},"language-shell shiki shiki-themes one-dark-pro","\u003C--- Last few GCs --->\n\n[14040:0x56930a0]    96150 ms: Mark-Compact 2012.5 (2093.0) -> 2011.8 (2092.0) MB, 902.72 \u002F 17.13 ms  (average mu = 0.416, current mu = 0.217) allocation failure; scavenge might not succeed\n[14040:0x56930a0]    97002 ms: Mark-Compact 2019.6 (2092.0) -> 2019.1 (2112.8) MB, 843.10 \u002F 0.00 ms  (average mu = 0.251, current mu = 0.011) allocation failure; scavenge might not succeed\n\n\u003C--- JS stacktrace --->\n\nFATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory\n","shell",[344,358,359,368,373,431,476,481,487,492],{"__ignoreMap":291},[360,361,364],"span",{"class":362,"line":363},"line",1,[360,365,367],{"class":366},"sn6KH","\u003C--- Last few GCs --->\n",[360,369,370],{"class":362,"line":292},[360,371,372],{"emptyLinePlaceholder":320},"\n",[360,374,376,379,383,386,389,392,395,399,402,405,408,410,412,416,419,422,425,428],{"class":362,"line":375},3,[360,377,378],{"class":366},"[14040:0x56930a0]    96150 ms: Mark-Compact 2012.5 (",[360,380,382],{"class":381},"sVbv2","2093.0",[360,384,385],{"class":366},") -> 2011.8 (",[360,387,388],{"class":381},"2092.0",[360,390,391],{"class":366},") MB, 902.72 \u002F 17.13 ms  (",[360,393,394],{"class":381},"average",[360,396,398],{"class":397},"subq3"," mu",[360,400,401],{"class":397}," =",[360,403,404],{"class":397}," 0.416,",[360,406,407],{"class":397}," current",[360,409,398],{"class":397},[360,411,401],{"class":397},[360,413,415],{"class":414},"sVC51"," 0.217",[360,417,418],{"class":366},") allocation failure; ",[360,420,421],{"class":381},"scavenge",[360,423,424],{"class":397}," might",[360,426,427],{"class":397}," not",[360,429,430],{"class":397}," succeed\n",[360,432,434,437,439,442,445,448,450,452,454,457,459,461,463,466,468,470,472,474],{"class":362,"line":433},4,[360,435,436],{"class":366},"[14040:0x56930a0]    97002 ms: Mark-Compact 2019.6 (",[360,438,388],{"class":381},[360,440,441],{"class":366},") -> 2019.1 (",[360,443,444],{"class":381},"2112.8",[360,446,447],{"class":366},") MB, 843.10 \u002F 0.00 ms  (",[360,449,394],{"class":381},[360,451,398],{"class":397},[360,453,401],{"class":397},[360,455,456],{"class":397}," 0.251,",[360,458,407],{"class":397},[360,460,398],{"class":397},[360,462,401],{"class":397},[360,464,465],{"class":414}," 0.011",[360,467,418],{"class":366},[360,469,421],{"class":381},[360,471,424],{"class":397},[360,473,427],{"class":397},[360,475,430],{"class":397},[360,477,479],{"class":362,"line":478},5,[360,480,372],{"emptyLinePlaceholder":320},[360,482,484],{"class":362,"line":483},6,[360,485,486],{"class":366},"\u003C--- JS stacktrace --->\n",[360,488,490],{"class":362,"line":489},7,[360,491,372],{"emptyLinePlaceholder":320},[360,493,495,498,501,504,507,510,513,516,519,522,524,527,530],{"class":362,"line":494},8,[360,496,497],{"class":381},"FATAL",[360,499,500],{"class":397}," ERROR:",[360,502,503],{"class":397}," Reached",[360,505,506],{"class":397}," heap",[360,508,509],{"class":397}," limit",[360,511,512],{"class":397}," Allocation",[360,514,515],{"class":397}," failed",[360,517,518],{"class":397}," -",[360,520,521],{"class":397}," JavaScript",[360,523,506],{"class":397},[360,525,526],{"class":397}," out",[360,528,529],{"class":397}," of",[360,531,532],{"class":397}," memory\n",[12,534,535],{},"Cette erreur se produit lorsque la mémoire allouée pour NodeJS est insuffisante (le garbage collector de NodeJS n'arrive\npas à nettoyer la mémoire). Pour résoudre ce problème, l'une des possibilités est d'augmenter la mémoire allouée à NodeJS.",[12,537,538,539,541],{},"Une autre possibilité est de comprendre pourquoi le programme a besoin d'autant de mémoire et de le corriger, car\nle problème peut venir d'une fuite de mémoire. Dans notre cas, c'est la commande ",[344,540,346],{}," qui est en cause. Et la\nconsommation de mémoire dépend du nombre de paquets que nous avons en dépendance (et qui eux-mêmes en ont).",[12,543,544,545,548,549,552,553,556],{},"Pour augmenter la mémoire allouée à NodeJS, il faut ajouter l'option ",[344,546,547],{},"--max-old-space-size"," à la commande ",[344,550,551],{},"node",".\nOn peut également modifier la variable d'environnement ",[344,554,555],{},"NODE_OPTIONS"," pour définir la taille de la mémoire allouée à\nNodeJS.",[12,558,559],{},"Lors de la modification de la mémoire allouée à NodeJS, il est important de prendre en compte la mémoire disponible sur\nla machine et la mémoire utilisée par les autres processus.",[12,561,562],{},"Voici un exemple pour augmenter la mémoire allouée à NodeJS à 4 Go :",[352,564,568],{"className":565,"code":566,"language":567,"meta":291,"style":291},"language-bash shiki shiki-themes one-dark-pro","export NODE_OPTIONS=--max-old-space-size=4096\nnpm ci\n","bash",[344,569,570,591],{"__ignoreMap":291},[360,571,572,576,580,584,586,588],{"class":362,"line":363},[360,573,575],{"class":574},"seHd6","export",[360,577,579],{"class":578},"sVyAn"," NODE_OPTIONS",[360,581,583],{"class":582},"sjrmR","=",[360,585,547],{"class":578},[360,587,583],{"class":582},[360,589,590],{"class":414},"4096\n",[360,592,593,596],{"class":362,"line":292},[360,594,595],{"class":381},"npm",[360,597,598],{"class":397}," ci\n",[12,600,601],{},"Mais avant d'augmenter la mémoire allouée à NodeJS, nous allons nous poser une question :",[123,603,604],{},[12,605,606],{},"Pourquoi ai-je le problème sur la chaîne de déploiement et pas sur mon poste en local, malgré le fait que la version\nde NodeJS soit identique ?",[12,608,609,610,615],{},"Pour répondre à cette question, nous avons commencé par une petite recherche sur le grand réseau. Nous avons trouvé un\narticle très intéressant sur le site ",[47,611,614],{"href":612,"rel":613},"https:\u002F\u002Fmedium.com\u002Fgeekculture\u002Fnode-js-default-memory-settings-3c0fe8a9ba1",[51],"Medium",".\nDans cet article, une expérimentation a été faite pour déterminer la mémoire allouée par défaut à NodeJS en fonction de\nla version de NodeJS.",[12,617,618],{},"Cela montre que dans la version de NodeJS 20 que nous utilisons, la limite devrait être de 4Go par défaut. Mais\npourquoi avons-nous cette erreur, sachant que dans le message d'erreur, la mémoire allouée est de 2Go ?",[12,620,621],{},"Pour trouver plus d'informations, nous avons dû nous plonger dans le code source de NodeJS, qui embarque lui-même le code\nsource du moteur V8. Nous allons nous concentrer sur la dernière version de NodeJS.",[12,623,624,625,628,629,632],{},"Pour trouver plus d'informations, nous avons essayé de rechercher dans le code les endroits qui parlent de max_old_space_size. Cette\nrecherche m'a amené à la fonction ",[344,626,627],{},"MaxOldGenerationSize"," dans le fichier ",[344,630,631],{},"deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap.cc"," :",[352,634,638],{"className":635,"code":636,"language":637,"meta":291,"style":291},"language-cpp shiki shiki-themes one-dark-pro","\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap.cc\n\n\u002F\u002F line 362\nsize_t Heap::MaxOldGenerationSize(uint64_t physical_memory) {\n  size_t max_size = V8HeapTrait::kMaxSize;\n  \u002F\u002F Increase the heap size from 2GB to 4GB for 64-bit systems with physical\n  \u002F\u002F memory at least 16GB. The theshold is set to 15GB to accomodate for some\n  \u002F\u002F memory being reserved by the hardware.\n  constexpr bool x64_bit = Heap::kHeapLimitMultiplier >= 2;\n  if (v8_flags.huge_max_old_generation_size && x64_bit &&\n      (physical_memory \u002F GB) >= 15) {\n    DCHECK_EQ(max_size \u002F GB, 2u);\n    max_size *= 2;\n  }\n  return std::min(max_size, AllocatorLimitOnMaxOldGenerationSize());\n}\n","cpp",[344,639,640,646,650,655,682,695,700,705,710,736,760,779,802,815,821,842],{"__ignoreMap":291},[360,641,642],{"class":362,"line":363},[360,643,645],{"class":644},"sV9Aq","\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap.cc\n",[360,647,648],{"class":362,"line":292},[360,649,372],{"emptyLinePlaceholder":320},[360,651,652],{"class":362,"line":375},[360,653,654],{"class":644},"\u002F\u002F line 362\n",[360,656,657,660,664,667,669,672,675,679],{"class":362,"line":433},[360,658,659],{"class":574},"size_t",[360,661,663],{"class":662},"sU0A5"," Heap",[360,665,666],{"class":366},"::",[360,668,627],{"class":381},[360,670,671],{"class":366},"(",[360,673,674],{"class":574},"uint64_t",[360,676,678],{"class":677},"s_ZVi"," physical_memory",[360,680,681],{"class":366},") {\n",[360,683,684,687,690,692],{"class":362,"line":478},[360,685,686],{"class":574},"  size_t",[360,688,689],{"class":366}," max_size ",[360,691,583],{"class":574},[360,693,694],{"class":366}," V8HeapTrait::kMaxSize;\n",[360,696,697],{"class":362,"line":483},[360,698,699],{"class":644},"  \u002F\u002F Increase the heap size from 2GB to 4GB for 64-bit systems with physical\n",[360,701,702],{"class":362,"line":489},[360,703,704],{"class":644},"  \u002F\u002F memory at least 16GB. The theshold is set to 15GB to accomodate for some\n",[360,706,707],{"class":362,"line":494},[360,708,709],{"class":644},"  \u002F\u002F memory being reserved by the hardware.\n",[360,711,713,716,719,722,724,727,730,733],{"class":362,"line":712},9,[360,714,715],{"class":574},"  constexpr",[360,717,718],{"class":574}," bool",[360,720,721],{"class":366}," x64_bit ",[360,723,583],{"class":574},[360,725,726],{"class":366}," Heap::kHeapLimitMultiplier ",[360,728,729],{"class":574},">=",[360,731,732],{"class":414}," 2",[360,734,735],{"class":366},";\n",[360,737,738,741,744,747,749,752,755,757],{"class":362,"line":331},[360,739,740],{"class":574},"  if",[360,742,743],{"class":366}," (",[360,745,746],{"class":662},"v8_flags",[360,748,31],{"class":366},[360,750,751],{"class":578},"huge_max_old_generation_size",[360,753,754],{"class":582}," &&",[360,756,721],{"class":366},[360,758,759],{"class":582},"&&\n",[360,761,763,766,769,772,774,777],{"class":362,"line":762},11,[360,764,765],{"class":366},"      (physical_memory ",[360,767,768],{"class":574},"\u002F",[360,770,771],{"class":366}," GB) ",[360,773,729],{"class":574},[360,775,776],{"class":414}," 15",[360,778,681],{"class":366},[360,780,782,785,788,790,793,796,799],{"class":362,"line":781},12,[360,783,784],{"class":381},"    DCHECK_EQ",[360,786,787],{"class":366},"(max_size ",[360,789,768],{"class":574},[360,791,792],{"class":366}," GB, ",[360,794,795],{"class":414},"2",[360,797,798],{"class":578},"u",[360,800,801],{"class":366},");\n",[360,803,805,808,811,813],{"class":362,"line":804},13,[360,806,807],{"class":366},"    max_size ",[360,809,810],{"class":574},"*=",[360,812,732],{"class":414},[360,814,735],{"class":366},[360,816,818],{"class":362,"line":817},14,[360,819,820],{"class":366},"  }\n",[360,822,824,827,830,833,836,839],{"class":362,"line":823},15,[360,825,826],{"class":574},"  return",[360,828,829],{"class":366}," std::",[360,831,832],{"class":381},"min",[360,834,835],{"class":366},"(max_size, ",[360,837,838],{"class":381},"AllocatorLimitOnMaxOldGenerationSize",[360,840,841],{"class":366},"());\n",[360,843,845],{"class":362,"line":844},16,[360,846,847],{"class":366},"}\n",[12,849,850,851,854,855,31],{},"Pour pouvoir rassembler les morceaux, nous devons donc connaître ",[344,852,853],{},"V8HeapTrait::kMaxSize"," et ",[344,856,857],{},"Heap::kHeapLimitMultiplier",[12,859,860,861,863,864,632],{},"La valeur de ",[344,862,853],{}," est définie dans le fichier ",[344,865,866],{},"deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap-controller.h",[352,868,870],{"className":635,"code":869,"language":637,"meta":291,"style":291},"\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap-controller.h\n\n\u002F\u002F line 16\nstruct BaseControllerTrait {\n  static constexpr size_t kMinSize = 128u * Heap::kHeapLimitMultiplier * MB;\n  static constexpr size_t kMaxSize = 1024u * Heap::kHeapLimitMultiplier * MB;\n\n  static constexpr double kMinGrowingFactor = 1.1;\n  static constexpr double kMaxGrowingFactor = 4.0;\n  static constexpr double kConservativeGrowingFactor = 1.3;\n  static constexpr double kTargetMutatorUtilization = 0.97;\n};\n",[344,871,872,877,881,886,897,929,955,959,978,996,1014,1032],{"__ignoreMap":291},[360,873,874],{"class":362,"line":363},[360,875,876],{"class":644},"\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap-controller.h\n",[360,878,879],{"class":362,"line":292},[360,880,372],{"emptyLinePlaceholder":320},[360,882,883],{"class":362,"line":375},[360,884,885],{"class":644},"\u002F\u002F line 16\n",[360,887,888,891,894],{"class":362,"line":433},[360,889,890],{"class":574},"struct",[360,892,893],{"class":662}," BaseControllerTrait",[360,895,896],{"class":366}," {\n",[360,898,899,902,905,908,911,913,916,918,921,923,926],{"class":362,"line":478},[360,900,901],{"class":574},"  static",[360,903,904],{"class":574}," constexpr",[360,906,907],{"class":574}," size_t",[360,909,910],{"class":366}," kMinSize ",[360,912,583],{"class":574},[360,914,915],{"class":414}," 128",[360,917,798],{"class":578},[360,919,920],{"class":574}," *",[360,922,726],{"class":366},[360,924,925],{"class":574},"*",[360,927,928],{"class":366}," MB;\n",[360,930,931,933,935,937,940,942,945,947,949,951,953],{"class":362,"line":483},[360,932,901],{"class":574},[360,934,904],{"class":574},[360,936,907],{"class":574},[360,938,939],{"class":366}," kMaxSize ",[360,941,583],{"class":574},[360,943,944],{"class":414}," 1024",[360,946,798],{"class":578},[360,948,920],{"class":574},[360,950,726],{"class":366},[360,952,925],{"class":574},[360,954,928],{"class":366},[360,956,957],{"class":362,"line":489},[360,958,372],{"emptyLinePlaceholder":320},[360,960,961,963,965,968,971,973,976],{"class":362,"line":494},[360,962,901],{"class":574},[360,964,904],{"class":574},[360,966,967],{"class":574}," double",[360,969,970],{"class":366}," kMinGrowingFactor ",[360,972,583],{"class":574},[360,974,975],{"class":414}," 1.1",[360,977,735],{"class":366},[360,979,980,982,984,986,989,991,994],{"class":362,"line":712},[360,981,901],{"class":574},[360,983,904],{"class":574},[360,985,967],{"class":574},[360,987,988],{"class":366}," kMaxGrowingFactor ",[360,990,583],{"class":574},[360,992,993],{"class":414}," 4.0",[360,995,735],{"class":366},[360,997,998,1000,1002,1004,1007,1009,1012],{"class":362,"line":331},[360,999,901],{"class":574},[360,1001,904],{"class":574},[360,1003,967],{"class":574},[360,1005,1006],{"class":366}," kConservativeGrowingFactor ",[360,1008,583],{"class":574},[360,1010,1011],{"class":414}," 1.3",[360,1013,735],{"class":366},[360,1015,1016,1018,1020,1022,1025,1027,1030],{"class":362,"line":762},[360,1017,901],{"class":574},[360,1019,904],{"class":574},[360,1021,967],{"class":574},[360,1023,1024],{"class":366}," kTargetMutatorUtilization ",[360,1026,583],{"class":574},[360,1028,1029],{"class":414}," 0.97",[360,1031,735],{"class":366},[360,1033,1034],{"class":362,"line":781},[360,1035,1036],{"class":366},"};\n",[12,1038,1039,1040,863,1042,632],{},"Enfin, la valeur de ",[344,1041,857],{},[344,1043,1044],{},"deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap.h",[352,1046,1048],{"className":635,"code":1047,"language":637,"meta":291,"style":291},"\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap.h\n\n\u002F\u002F line 306\n#if V8_OS_ANDROID\n  \u002F\u002F Don't apply pointer multiplier on Android since it has no swap space and\n  \u002F\u002F should instead adapt it's heap size based on available physical memory.\n  static const int kPointerMultiplier = 1;\n  static const int kHeapLimitMultiplier = 1;\n#else\n  static const int kPointerMultiplier = kTaggedSize \u002F 4;\n  \u002F\u002F The heap limit needs to be computed based on the system pointer size\n  \u002F\u002F because we want a pointer-compressed heap to have larger limit than\n  \u002F\u002F an ordinary 32-bit which that is constrained by 2GB virtual address space.\n  static const int kHeapLimitMultiplier = kSystemPointerSize \u002F 4;\n#endif\n",[344,1049,1050,1055,1059,1064,1072,1077,1082,1102,1119,1124,1146,1151,1156,1161,1182],{"__ignoreMap":291},[360,1051,1052],{"class":362,"line":363},[360,1053,1054],{"class":644},"\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fheap\u002Fheap.h\n",[360,1056,1057],{"class":362,"line":292},[360,1058,372],{"emptyLinePlaceholder":320},[360,1060,1061],{"class":362,"line":375},[360,1062,1063],{"class":644},"\u002F\u002F line 306\n",[360,1065,1066,1069],{"class":362,"line":433},[360,1067,1068],{"class":574},"#if",[360,1070,1071],{"class":381}," V8_OS_ANDROID\n",[360,1073,1074],{"class":362,"line":478},[360,1075,1076],{"class":644},"  \u002F\u002F Don't apply pointer multiplier on Android since it has no swap space and\n",[360,1078,1079],{"class":362,"line":483},[360,1080,1081],{"class":644},"  \u002F\u002F should instead adapt it's heap size based on available physical memory.\n",[360,1083,1084,1086,1089,1092,1095,1097,1100],{"class":362,"line":489},[360,1085,901],{"class":574},[360,1087,1088],{"class":574}," const",[360,1090,1091],{"class":574}," int",[360,1093,1094],{"class":366}," kPointerMultiplier ",[360,1096,583],{"class":574},[360,1098,1099],{"class":414}," 1",[360,1101,735],{"class":366},[360,1103,1104,1106,1108,1110,1113,1115,1117],{"class":362,"line":494},[360,1105,901],{"class":574},[360,1107,1088],{"class":574},[360,1109,1091],{"class":574},[360,1111,1112],{"class":366}," kHeapLimitMultiplier ",[360,1114,583],{"class":574},[360,1116,1099],{"class":414},[360,1118,735],{"class":366},[360,1120,1121],{"class":362,"line":712},[360,1122,1123],{"class":574},"#else\n",[360,1125,1126,1128,1130,1132,1134,1136,1139,1141,1144],{"class":362,"line":331},[360,1127,901],{"class":574},[360,1129,1088],{"class":574},[360,1131,1091],{"class":574},[360,1133,1094],{"class":366},[360,1135,583],{"class":574},[360,1137,1138],{"class":366}," kTaggedSize ",[360,1140,768],{"class":574},[360,1142,1143],{"class":414}," 4",[360,1145,735],{"class":366},[360,1147,1148],{"class":362,"line":762},[360,1149,1150],{"class":644},"  \u002F\u002F The heap limit needs to be computed based on the system pointer size\n",[360,1152,1153],{"class":362,"line":781},[360,1154,1155],{"class":644},"  \u002F\u002F because we want a pointer-compressed heap to have larger limit than\n",[360,1157,1158],{"class":362,"line":804},[360,1159,1160],{"class":644},"  \u002F\u002F an ordinary 32-bit which that is constrained by 2GB virtual address space.\n",[360,1162,1163,1165,1167,1169,1171,1173,1176,1178,1180],{"class":362,"line":817},[360,1164,901],{"class":574},[360,1166,1088],{"class":574},[360,1168,1091],{"class":574},[360,1170,1112],{"class":366},[360,1172,583],{"class":574},[360,1174,1175],{"class":366}," kSystemPointerSize ",[360,1177,768],{"class":574},[360,1179,1143],{"class":414},[360,1181,735],{"class":366},[360,1183,1184],{"class":362,"line":823},[360,1185,1186],{"class":574},"#endif\n",[12,1188,860,1189,1192,1193,1196,1197,1200,1201,632],{},[344,1190,1191],{},"kHeapLimitMultiplier"," dépend elle-même de ",[344,1194,1195],{},"kSystemPointerSize",", qui n'est pas définie dans ce fichier. C'est\ndans le fichier ",[344,1198,1199],{},"deps\u002Fv8\u002Fsrc\u002Fbase\u002Fplatform\u002Fplatform.h"," que nous allons trouver la valeur de ",[344,1202,1195],{},[352,1204,1206],{"className":635,"code":1205,"language":637,"meta":291,"style":291},"\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fbase\u002Fplatform\u002Fplatform.h\n\n\u002F\u002F line 84\nV8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index) {\n  const intptr_t kTibInlineTlsOffset = 0xE10;\n  const intptr_t kTibExtraTlsOffset = 0xF94;\n  const intptr_t kMaxInlineSlots = 64;\n  const intptr_t kMaxSlots = kMaxInlineSlots + 1024;\n  const intptr_t kSystemPointerSize = sizeof(void*);\n  DCHECK(0 \u003C= index && index \u003C kMaxSlots);\n  USE(kMaxSlots);\n  if (index \u003C kMaxInlineSlots) {\n    return static_cast\u003Cintptr_t>(\n        __readfsdword(kTibInlineTlsOffset + kSystemPointerSize * index));\n  }\n  intptr_t extra = static_cast\u003Cintptr_t>(__readfsdword(kTibExtraTlsOffset));\n  if (!extra) return 0;\n  return *reinterpret_cast\u003Cintptr_t*>(extra + kSystemPointerSize *\n                                                  (index - kMaxInlineSlots));\n}\n",[344,1207,1208,1213,1217,1222,1240,1261,1279,1295,1315,1335,1362,1370,1382,1396,1413,1417,1439,1460,1483,1495],{"__ignoreMap":291},[360,1209,1210],{"class":362,"line":363},[360,1211,1212],{"class":644},"\u002F\u002F deps\u002Fv8\u002Fsrc\u002Fbase\u002Fplatform\u002Fplatform.h\n",[360,1214,1215],{"class":362,"line":292},[360,1216,372],{"emptyLinePlaceholder":320},[360,1218,1219],{"class":362,"line":375},[360,1220,1221],{"class":644},"\u002F\u002F line 84\n",[360,1223,1224,1227,1230,1233,1235,1237],{"class":362,"line":433},[360,1225,1226],{"class":366},"V8_INLINE ",[360,1228,1229],{"class":574},"intptr_t",[360,1231,1232],{"class":381}," InternalGetExistingThreadLocal",[360,1234,671],{"class":366},[360,1236,1229],{"class":574},[360,1238,1239],{"class":366}," index) {\n",[360,1241,1242,1245,1248,1251,1253,1256,1259],{"class":362,"line":478},[360,1243,1244],{"class":574},"  const",[360,1246,1247],{"class":574}," intptr_t",[360,1249,1250],{"class":366}," kTibInlineTlsOffset ",[360,1252,583],{"class":574},[360,1254,1255],{"class":578}," 0x",[360,1257,1258],{"class":414},"E10",[360,1260,735],{"class":366},[360,1262,1263,1265,1267,1270,1272,1274,1277],{"class":362,"line":483},[360,1264,1244],{"class":574},[360,1266,1247],{"class":574},[360,1268,1269],{"class":366}," kTibExtraTlsOffset ",[360,1271,583],{"class":574},[360,1273,1255],{"class":578},[360,1275,1276],{"class":414},"F94",[360,1278,735],{"class":366},[360,1280,1281,1283,1285,1288,1290,1293],{"class":362,"line":489},[360,1282,1244],{"class":574},[360,1284,1247],{"class":574},[360,1286,1287],{"class":366}," kMaxInlineSlots ",[360,1289,583],{"class":574},[360,1291,1292],{"class":414}," 64",[360,1294,735],{"class":366},[360,1296,1297,1299,1301,1304,1306,1308,1311,1313],{"class":362,"line":494},[360,1298,1244],{"class":574},[360,1300,1247],{"class":574},[360,1302,1303],{"class":366}," kMaxSlots ",[360,1305,583],{"class":574},[360,1307,1287],{"class":366},[360,1309,1310],{"class":574},"+",[360,1312,944],{"class":414},[360,1314,735],{"class":366},[360,1316,1317,1319,1321,1323,1325,1328,1330,1333],{"class":362,"line":712},[360,1318,1244],{"class":574},[360,1320,1247],{"class":574},[360,1322,1175],{"class":366},[360,1324,583],{"class":574},[360,1326,1327],{"class":574}," sizeof",[360,1329,671],{"class":366},[360,1331,1332],{"class":574},"void*",[360,1334,801],{"class":366},[360,1336,1337,1340,1342,1345,1348,1351,1354,1356,1359],{"class":362,"line":331},[360,1338,1339],{"class":381},"  DCHECK",[360,1341,671],{"class":366},[360,1343,1344],{"class":414},"0",[360,1346,1347],{"class":574}," \u003C=",[360,1349,1350],{"class":366}," index ",[360,1352,1353],{"class":582},"&&",[360,1355,1350],{"class":366},[360,1357,1358],{"class":574},"\u003C",[360,1360,1361],{"class":366}," kMaxSlots);\n",[360,1363,1364,1367],{"class":362,"line":762},[360,1365,1366],{"class":381},"  USE",[360,1368,1369],{"class":366},"(kMaxSlots);\n",[360,1371,1372,1374,1377,1379],{"class":362,"line":781},[360,1373,740],{"class":574},[360,1375,1376],{"class":366}," (index ",[360,1378,1358],{"class":574},[360,1380,1381],{"class":366}," kMaxInlineSlots) {\n",[360,1383,1384,1387,1390,1393],{"class":362,"line":804},[360,1385,1386],{"class":574},"    return",[360,1388,1389],{"class":366}," static_cast",[360,1391,1392],{"class":574},"\u003Cintptr_t>",[360,1394,1395],{"class":366},"(\n",[360,1397,1398,1401,1404,1406,1408,1410],{"class":362,"line":817},[360,1399,1400],{"class":381},"        __readfsdword",[360,1402,1403],{"class":366},"(kTibInlineTlsOffset ",[360,1405,1310],{"class":574},[360,1407,1175],{"class":366},[360,1409,925],{"class":574},[360,1411,1412],{"class":366}," index));\n",[360,1414,1415],{"class":362,"line":823},[360,1416,820],{"class":366},[360,1418,1419,1422,1425,1427,1429,1431,1433,1436],{"class":362,"line":844},[360,1420,1421],{"class":574},"  intptr_t",[360,1423,1424],{"class":366}," extra ",[360,1426,583],{"class":574},[360,1428,1389],{"class":366},[360,1430,1392],{"class":574},[360,1432,671],{"class":366},[360,1434,1435],{"class":381},"__readfsdword",[360,1437,1438],{"class":366},"(kTibExtraTlsOffset));\n",[360,1440,1442,1444,1446,1449,1452,1455,1458],{"class":362,"line":1441},17,[360,1443,740],{"class":574},[360,1445,743],{"class":366},[360,1447,1448],{"class":582},"!",[360,1450,1451],{"class":366},"extra) ",[360,1453,1454],{"class":574},"return",[360,1456,1457],{"class":414}," 0",[360,1459,735],{"class":366},[360,1461,1463,1465,1467,1470,1473,1476,1478,1480],{"class":362,"line":1462},18,[360,1464,826],{"class":574},[360,1466,920],{"class":574},[360,1468,1469],{"class":366},"reinterpret_cast",[360,1471,1472],{"class":574},"\u003Cintptr_t*>",[360,1474,1475],{"class":366},"(extra ",[360,1477,1310],{"class":574},[360,1479,1175],{"class":366},[360,1481,1482],{"class":574},"*\n",[360,1484,1486,1489,1492],{"class":362,"line":1485},19,[360,1487,1488],{"class":366},"                                                  (index ",[360,1490,1491],{"class":574},"-",[360,1493,1494],{"class":366}," kMaxInlineSlots));\n",[360,1496,1498],{"class":362,"line":1497},20,[360,1499,847],{"class":366},[12,1501,1502],{},"Nous avons ainsi tous les éléments pour reconstituer le puzzle :",[140,1504,1505,1510,1519],{},[143,1506,1507,1509],{},[344,1508,1195],{}," permet de définir la taille d'un pointeur. Sur un système 64 bits, la taille d'un pointeur est\nde 8 octets, alors que sur un système 32 bits, la taille d'un pointeur est de 4 octets.",[143,1511,1512,1514,1515,1518],{},[344,1513,1191],{}," possède la valeur de 1 sur Android, mais pour les autres systèmes, la valeur est de\n",[344,1516,1517],{},"kSystemPointerSize \u002F 4",", soit 2 sur un système 64 bits et 1 sur un système 32 bits.",[143,1520,1521,1524,1525,1528],{},[344,1522,1523],{},"kMaxSize"," vaut ",[344,1526,1527],{},"1024 * kHeapLimitMultiplier * MB",", soit 1024 MB sur un système 32 bits et 2048 MB sur un système 64\nbits.",[12,1530,1531,1532,1534],{},"Enfin, en lisant le code de la fonction ",[344,1533,627],{},", on comprend que la mémoire allouée à NodeJS est de 2Go\npar défaut.",[12,1536,1537],{},"Mais si le système est un système 64 bits (pointeur de 8 octets) et que la mémoire disponible sur la machine est\nsupérieure à 15Go, alors la mémoire allouée est multipliée par 2, soit 4Go.",[12,1539,1540],{},"Cela explique pourquoi sur nos postes de développement surpuissants, nous n'avons pas l'erreur car la mémoire allouée est de\n4Go par défaut. Mais sur la chaîne de déploiement, la mémoire allouée est de 2Go par défaut, car la machine ne possède\nque 8Go (ce qui est largement suffisant).",[12,1542,1543],{},"Voici un petit tableau récapitulatif:",[1545,1546,1547,1566],"table",{},[1548,1549,1550],"thead",{},[1551,1552,1553,1557,1560,1563],"tr",{},[1554,1555,1556],"th",{},"Système",[1554,1558,1559],{},"Taille du pointeur",[1554,1561,1562],{},"Mémoire disponible",[1554,1564,1565],{},"Mémoire allouée par défaut",[1567,1568,1569,1584,1597],"tbody",{},[1551,1570,1571,1575,1578,1581],{},[1572,1573,1574],"td",{},"32 bits",[1572,1576,1577],{},"4 octets",[1572,1579,1580],{},"OSEF",[1572,1582,1583],{},"2Go",[1551,1585,1586,1589,1592,1595],{},[1572,1587,1588],{},"64 bits",[1572,1590,1591],{},"8 octets",[1572,1593,1594],{},"\u003C 15Go",[1572,1596,1583],{},[1551,1598,1599,1601,1603,1606],{},[1572,1600,1588],{},[1572,1602,1591],{},[1572,1604,1605],{},">= 15Go",[1572,1607,1608],{},"4Go",[12,1610,1611],{},"J'espère que cet article vous a permis de faire un petit voyage dans le code source de NodeJS et de\ncomprendre comment est calculée la valeur par défaut de max-old-space-size.",[1613,1614,1615],"style",{},"html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}",{"title":291,"searchDepth":292,"depth":292,"links":1617},[],"2024-06-14",{"type":9,"value":1620},[1621,1623,1627,1629,1757],[12,1622,14],{},[12,1624,342,1625,347],{},[344,1626,346],{},[12,1628,350],{},[352,1630,1631],{"className":354,"code":355,"language":356,"meta":291,"style":291},[344,1632,1633,1637,1641,1679,1717,1721,1725,1729],{"__ignoreMap":291},[360,1634,1635],{"class":362,"line":363},[360,1636,367],{"class":366},[360,1638,1639],{"class":362,"line":292},[360,1640,372],{"emptyLinePlaceholder":320},[360,1642,1643,1645,1647,1649,1651,1653,1655,1657,1659,1661,1663,1665,1667,1669,1671,1673,1675,1677],{"class":362,"line":375},[360,1644,378],{"class":366},[360,1646,382],{"class":381},[360,1648,385],{"class":366},[360,1650,388],{"class":381},[360,1652,391],{"class":366},[360,1654,394],{"class":381},[360,1656,398],{"class":397},[360,1658,401],{"class":397},[360,1660,404],{"class":397},[360,1662,407],{"class":397},[360,1664,398],{"class":397},[360,1666,401],{"class":397},[360,1668,415],{"class":414},[360,1670,418],{"class":366},[360,1672,421],{"class":381},[360,1674,424],{"class":397},[360,1676,427],{"class":397},[360,1678,430],{"class":397},[360,1680,1681,1683,1685,1687,1689,1691,1693,1695,1697,1699,1701,1703,1705,1707,1709,1711,1713,1715],{"class":362,"line":433},[360,1682,436],{"class":366},[360,1684,388],{"class":381},[360,1686,441],{"class":366},[360,1688,444],{"class":381},[360,1690,447],{"class":366},[360,1692,394],{"class":381},[360,1694,398],{"class":397},[360,1696,401],{"class":397},[360,1698,456],{"class":397},[360,1700,407],{"class":397},[360,1702,398],{"class":397},[360,1704,401],{"class":397},[360,1706,465],{"class":414},[360,1708,418],{"class":366},[360,1710,421],{"class":381},[360,1712,424],{"class":397},[360,1714,427],{"class":397},[360,1716,430],{"class":397},[360,1718,1719],{"class":362,"line":478},[360,1720,372],{"emptyLinePlaceholder":320},[360,1722,1723],{"class":362,"line":483},[360,1724,486],{"class":366},[360,1726,1727],{"class":362,"line":489},[360,1728,372],{"emptyLinePlaceholder":320},[360,1730,1731,1733,1735,1737,1739,1741,1743,1745,1747,1749,1751,1753,1755],{"class":362,"line":494},[360,1732,497],{"class":381},[360,1734,500],{"class":397},[360,1736,503],{"class":397},[360,1738,506],{"class":397},[360,1740,509],{"class":397},[360,1742,512],{"class":397},[360,1744,515],{"class":397},[360,1746,518],{"class":397},[360,1748,521],{"class":397},[360,1750,506],{"class":397},[360,1752,526],{"class":397},[360,1754,529],{"class":397},[360,1756,532],{"class":397},[1613,1758,1615],{},{"planet":320},"\u002Fpost\u002Fmax-old-space",{"title":335,"description":14},"max-old-space","posts\u002FProgrammation\u002F2024-06-14-max-old-space",[1765,1766],"javascript","nodejs","rKoBJuRBkLYyVgc8etB7XZPEzRbfpMzHtNOUEWqjpL8",{"id":1769,"title":1770,"author":7,"body":1771,"category":300,"categorySlug":301,"date":5992,"description":5993,"excerpt":5994,"extension":317,"location":318,"meta":6010,"navigation":320,"path":6011,"published":320,"seo":6012,"slug":6013,"stem":6014,"tags":6015,"timeToRead":3224,"__hash__":6019},"posts\u002Fposts\u002FWoodstock\u002F2024-03-14_pr_backuppc_pool.md","Woodstock Backup - Reverse engineering de BackupPC",{"type":9,"value":1772,"toc":5974},[1773,1782,1785,1788,1794,1798,1801,1810,1818,1827,1835,1838,1841,1844,1847,1850,1853,1856,1860,1866,1875,1891,1900,1905,1908,1973,1977,1980,1988,1991,1995,2011,2018,2026,2029,2038,2041,2048,2051,2058,2061,2064,2068,2075,2078,2081,2086,2089,2093,2106,2112,2321,2324,2333,2339,2348,2351,2354,2617,2636,2644,2669,2932,2935,3586,3608,3614,3628,4098,4104,4293,4297,4300,4303,4318,4686,4693,4700,4703,4707,4710,4729,4737,4740,4744,4747,4755,4758,4761,4775,4784,4794,4854,4857,4928,4931,5219,5229,5236,5368,5375,5522,5531,5534,5541,5544,5551,5554,5738,5741,5745,5748,5757,5760,5764,5771,5780,5903,5909,5912,5923,5926,5942,5946,5949,5957,5963,5966,5968,5971],[12,1774,1775,1776,1781],{},"Une partie de cet article a été publiée sur ",[47,1777,1780],{"href":1778,"rel":1779},"https:\u002F\u002Flinuxfr.org\u002Fusers\u002Fsan_guickoo\u002Fjournaux\u002Fpullrequest-d-une-application-en-rust",[51],"LinuxFR",".\nAprès avoir reçu quelques retours, j'ai décidé de publier une version modifiée et améliorée de cet article sur mon blog.",[12,1783,1784],{},"Je remercie donc la communauté de LinuxFR pour ses retours. 😄",[12,1786,1787],{},"Les commentaires sur le code ou sur l'article sont les bienvenus.",[12,1789,1790],{},[69,1791],{"src":1792,"alt":291,"className":1793},"\u002FWoodstock\u002Fhdd_unsplash.jpg",[73],[33,1795,1797],{"id":1796},"le-commencement","Le commencement",[12,1799,1800],{},"Actuellement, j'utilise BackupPC pour sauvegarder mes données. BackupPC est un logiciel de sauvegarde qui se connecte à\ndifférents ordinateurs via SSH et utilise rsync pour sauvegarder les données. Il fonctionne parfaitement avec des\nordinateurs Linux et un peu moins bien sur des ordinateurs Windows où il faut installer un rsyncd\u002FCygwin (les données ne\nsont pas protégées par SSH dans ce cas).",[12,1802,1803,1804,1809],{},"Par ailleurs, je développe ",[47,1805,1808],{"href":1806,"rel":1807},"https:\u002F\u002Fshadoware.org\u002Fpost\u002Fwoodstock",[51],"mon propre logiciel de sauvegarde",". C'est un défi\npersonnel que je me suis lancé pour répondre à mes propres besoins (et aussi pour le plaisir).",[12,1811,1812,1813,31],{},"Mon premier prototype est écrit en TypeScript et utilise rsync couplé avec Btrfs pour faire des sauvegardes\nincrémentales. Malheureusement, quelques problèmes liés à l'utilisation de Btrfs m'ont fait abandonner ce prototype\n(problème avec la création d'un grand nombre de snapshots et un système de fichier un peu trop plein). J'en parle dans\n",[47,1814,1817],{"href":1815,"rel":1816},"https:\u002F\u002Fshadoware.org\u002Fpost\u002Fwoodstock_brtfs",[51],"un article sur mon blog",[12,1819,1820,1821,1826],{},"Je me suis donc orienté vers l'écriture de mon propre pool de stockage de données. L'écriture dans ce pool de stockage\nm'oblige à écrire mon propre logiciel de synchronisation. BackupPC a fait le choix de rester sur rsync et donc à créer\nun ",[47,1822,1825],{"href":1823,"rel":1824},"https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Frsync-bpc",[51],"fork de rsync"," capable de se connecter en rsync sur les machines à\nsauvegarder, tout en étant capable d'écrire le résultat dans le pool de backuppc, au format de backuppc. Pour ma part,\nj'ai choisi de développer mon protocole basé sur GRPC (et donc HTTP\u002F2).",[12,1828,1829,1830,31],{},"J'ai donc fait un second prototype, toujours en TypeScript, pour tester mon idée. Je suis satisfait du résultat, mais\nles limites du moteur JavaScript font de ce prototype un simple prototype. Là aussi, j'en parle dans\n",[47,1831,1834],{"href":1832,"rel":1833},"https:\u002F\u002Fshadoware.org\u002Fpost\u002Fwoodstock_rust",[51],"un autre article de mon blog",[12,1836,1837],{},"Je vais donc réécrire la partie la plus importante de ce programme en Rust. Pourquoi Rust ? Dans ma jeunesse (enfin,\nj'avais entre 20 et 30 ans), j'adorais programmer en C\u002FC++. Je me souviens d'avoir programmé un petit IDE en C++ avec\nQt. Lors du développement en C++, il m'arrivait parfois de me retrouver avec des fuites de mémoire, des erreurs de\nsegmentation, ainsi que des problèmes de concurrence d'accès aux données.",[12,1839,1840],{},"C++ m'a beaucoup appris sur le fonctionnement d'une machine, la gestion de la mémoire, la gestion du multithreading,\netc. Tout le monde devrait commencer par ce langage 😄.",[12,1842,1843],{},"Rust est un langage qui a été conçu pour éviter ces problèmes. Après avoir lu la documentation, j'ai adoré le concept.\nDu coup, j'ai décidé que ce serait une très bonne idée d'apprendre à l'utiliser. (Surtout qu'on en entend beaucoup\nparler en ce moment).",[12,1845,1846],{},"Vous trouvez que je digresse beaucoup ? C'est possible.",[12,1848,1849],{},"Revenons à notre programme.",[12,1851,1852],{},"Je me suis dit qu'avant d'écrire la gestion de mon pool de stockage en Rust, je voulais faire un script qui me permette\nde migrer le contenu de mon pool de stockage de BackupPC vers mon nouveau pool de stockage. Et de le faire en Rust.",[12,1854,1855],{},"Pour cela, j'ai besoin de comprendre comment fonctionne le pool de stockage de BackupPC. Le faire avec le code source\nde BackupPC sera amusant et pas trop compliqué.",[33,1857,1859],{"id":1858},"description-du-pool-de-stockage-de-backuppc","Description du pool de stockage de BackupPC",[12,1861,1862],{},[69,1863],{"src":1864,"alt":1865},"https:\u002F\u002Fbackuppc.github.io\u002Fbackuppc\u002Fimages\u002Flogos\u002Flogo.svg","BackupPC Logo",[12,1867,1868,1869,1874],{},"La ",[47,1870,1873],{"href":1871,"rel":1872},"https:\u002F\u002Fbackuppc.github.io\u002Fbackuppc\u002FBackupPC.html",[51],"documentation de BackupPC"," décrit déjà pas mal de choses :",[140,1876,1877,1884],{},[143,1878,1879],{},[47,1880,1883],{"href":1881,"rel":1882},"https:\u002F\u002Fbackuppc.github.io\u002Fbackuppc\u002FBackupPC.html#Storage-layout",[51],"Comment sont stockés les fichiers dans le pool de stockage ?",[143,1885,1886],{},[47,1887,1890],{"href":1888,"rel":1889},"https:\u002F\u002Fbackuppc.github.io\u002Fbackuppc\u002FBackupPC.html#Compressed-file-format",[51],"Une description succincte du format des fichiers compressés",[12,1892,1893,1894,1899],{},"Ensuite, pour obtenir les détails, il faut aller lire le ",[47,1895,1898],{"href":1896,"rel":1897},"https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs",[51],"code source en C"," qui\nsert de liaison avec le code en Perl. BackupPC est originellement écrit en Perl (entièrement, si je ne me trompe pas,\npour la version 3). La version 4 a été partiellement réécrite en C pour la partie qui gère le pool de stockage. Cette\npartie est utilisée par le rsync modifié et par la partie Perl à travers la bibliothèque de bindings.",[1901,1902,1904],"h3",{"id":1903},"la-constitution-du-pool","La constitution du pool",[12,1906,1907],{},"Le pool de stockage de BackupPC est principalement constitué de plusieurs dossiers :",[140,1909,1910,1958,1964],{},[143,1911,1912,1915,1916],{},[344,1913,1914],{},"pc"," : Ce dossier répertorie les sauvegardes des différentes machines, organisées par machine puis par sauvegarde.\n",[140,1917,1918,1923],{},[143,1919,1920],{},[344,1921,1922],{},"host1",[143,1924,1925,1928,1929,1931,1932],{},[344,1926,1927],{},"host2"," : Le dossier de la machine ",[344,1930,1927],{},".\n",[140,1933,1934,1940,1946,1950,1955],{},[143,1935,1936,1939],{},[344,1937,1938],{},"backups"," : Un fichier au format TSV (Tab Separated Values) qui liste les sauvegardes de la machine avec leurs\ninformations.",[143,1941,1942,1945],{},[344,1943,1944],{},"1"," : La sauvegarde où les dossiers sont représentés à l'aide du système de fichiers, et les fichiers sont listés\ndans des fichiers d'attributs. Le hash du fichier d'attribut dans le pool est contenu dans le nom du fichier\n(exemple : attrib_33fe8f9ae2f5cedbea63b9d3ea767ac0).",[143,1947,1948],{},[344,1949,795],{},[143,1951,1952],{},[344,1953,1954],{},"3",[143,1956,1957],{},"...",[143,1959,1960,1963],{},[344,1961,1962],{},"pool"," : Dans ce dossier, les fichiers sont stockés en utilisant leur hash MD5. Les fichiers sont répartis sur deux\nniveaux dans 128 dossiers dont le nom est constitué des 7 premiers bits des deux premiers octets. Si deux fichiers ont\nle même MD5, un nombre est accolé au hash pour les différencier.",[143,1965,1966,1969,1970,1972],{},[344,1967,1968],{},"cpool"," : La structure de ce dossier est la même que celle du dossier ",[344,1971,1962],{},". Il s'agit d'un pool de stockage\ncompressé.",[1901,1974,1976],{"id":1975},"le-format-des-fichiers-compressés","Le format des fichiers compressés",[12,1978,1979],{},"Voici la description du fichier compressé selon la documentation (traduction libre) :",[123,1981,1982,1985],{},[12,1983,1984],{},"Le format de fichier compressé est généré par Compress::Zlib::deflate avec une modification mineure, mais\nimportante. Comme Compress::Zlib::inflate gonfle entièrement son argument en mémoire, il pourrait consommer de\ngrandes quantités de mémoire s'il décompressait un fichier très compressé. Par exemple, un fichier de 200 Mo de 0x0\nbytes se compresse à environ 200 Ko. Si Compress::Zlib::inflate était appelé avec ce seul tampon de 200 Ko, il\naurait besoin d'allouer 200 Mo de mémoire pour retourner le résultat.",[12,1986,1987],{},"BackupPC surveille l'efficacité de la compression d'un fichier. Si un gros fichier a un taux de compression très élevé\n(ce qui signifie qu'il utilisera beaucoup de mémoire lorsqu'il sera décompressé), BackupPC appelle la méthode flush(), qui\ntermine proprement la compression en cours. BackupPC commence alors une nouvelle section et ajoute simplement le\nfichier de sortie. Ainsi, le format de fichier compressé de BackupPC est une ou plusieurs sections\u002Fflushes\nconcaténées. Les ratios spécifiques que BackupPC utilise sont que si un morceau de 6 Mo se compresse à moins de 64\nKo, alors un flush sera effectué.",[12,1989,1990],{},"Donc, dans notre cas, nous devons être capables de lire un fichier compressé comme une suite de fichiers compressés\nconcaténés les uns après les autres.",[1901,1992,1994],{"id":1993},"le-format-des-fichiers-dattributs","Le format des fichiers d'attributs",[12,1996,1997,2002,2003,2006,2007,2010],{},[47,1998,2001],{"href":1999,"rel":2000},"https:\u002F\u002Fbackuppc.github.io\u002Fbackuppc\u002FBackupPC.html#Attribute-file-format",[51],"Dans la documentation",", il est expliqué que\ndans la version 4, on retrouve un fichier ",[344,2004,2005],{},"attrib_33fe8f9ae2f5cedbea63b9d3ea767ac0"," dans les différents dossiers de la\nmachine (",[344,2008,2009],{},"__TOPDIR__\u002Fpc\u002Fhost1",").\nLe nom du fichier contient le hash du fichier d'attributs que l'on peut retrouver dans le pool de stockage.",[12,2012,2013,2014,2017],{},"Pour accéder à un fichier du pool de stockage, il faut aller dans le dossier ",[344,2015,2016],{},"__TOPDIR__\u002Fpc"," et lire le nom du fichier\nd'attribut pour retrouver le hash du fichier compressé correspondant au nom du dossier que l'on veut lire. Enfin, il\nfaut lire le fichier compressé pour obtenir les données.",[12,2019,2020,2021,31],{},"Le contenu du fichier d'attribut n'est pas décrit. Cependant, on peut le retrouver dans le fichier\n",[47,2022,2025],{"href":2023,"rel":2024},"https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs\u002Fblob\u002Fmaster\u002Fbpc_attrib.c#L626",[51],"bpc_attribs.c",[12,2027,2028],{},"Le fichier d'attribut est encodé en binaire. Il s'agit d'une suite de varint (entier encodé sur un nombre variable\nd'octets).",[12,2030,2031,2032,2037],{},"Un ",[47,2033,2036],{"href":2034,"rel":2035},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVariable-length_quantity",[51],"Varint"," est un entier qui est encodé sur un nombre variable\nd'octets. Le premier bit de chaque octet indique si l'entier est terminé ou s'il faut lire un autre octet. Le reste des\nbits de l'octet représente l'entier.",[12,2039,2040],{},"Voici une représentation d'un Varint depuis Wikipedia :",[12,2042,2043],{},[69,2044],{"src":2045,"alt":2046,"className":2047},"https:\u002F\u002Fupload.wikimedia.org\u002Fwikipedia\u002Fcommons\u002Fthumb\u002Fc\u002Fc6\u002FUintvar_coding.svg\u002F1920px-Uintvar_coding.svg.png","Image représentant un Varint (Source : Wikipedia)",[73],[12,2049,2050],{},"D'après le code source de BackupPC, le fichier d'attribut est encodé de la manière suivante :",[12,2052,2053,2054,2057],{},"Le fichier commence par un numéro magique ",[344,2055,2056],{},"0x17565353",". Ensuite, pour chaque fichier, on retrouve les attributs du\nfichier. Pour chaque attribut, on retrouve les xattrs.",[69,2059],{"src":2060},"https:\u002F\u002Fwww.plantuml.com\u002Fplantuml\u002Fpng\u002FXL8nJWCn4Epl5TC11H8eEf2kIa530HqIhHDlxbRosSUkVKgUb7VaOyW7KKWuGsLxPpIptjcbHYDnPtfNTMGiIOExxVrZ_L0lwaLbOXHUfQXD1TnYDC8-Dd31jucIm2RuqETZm-kEIIe0q2ZissOEEYhuqA-4OA_8HpdiIM49SJSGjjdpZ3kLBStgM1EfvD47ItXxVNul4HBR4jIMeMZOkQ8f--nw0g4cZTGQiOVz-GHu99FolzQX7uHKEVZ_naLmJ5unT3lbZqGAJG8tFvkVANL6kqlnLTfiSjuN6AvVdcgao8xriCSGlXo4eeGqai0QhxaoXE1k9gKfisQw_hac17SC_9jywg98-Ar6S0QZSST7KNEEioHlyxf_0W00",[12,2062,2063],{},"Il ne me reste donc plus qu'à reproduire tout cela en Rust.",[33,2065,2067],{"id":2066},"le-développement-en-rust","Le développement en Rust",[12,2069,2070],{},[69,2071],{"src":2072,"alt":2073,"className":2074},"\u002FWoodstock\u002Frust_unsplash.jpg","Rust",[73],[12,2076,2077],{},"Pour le développement de ce programme, j'ai établi certaines limites. Je me suis concentré uniquement sur la lecture des\nfichiers du pool qui sont en version 4. Ma version de BackupPC est la version 4, et j'ai migré l'intégralité du pool de\nstockage depuis la version 3.",[12,2079,2080],{},"Je n'ai donc pas de données en version 3 pour tester mon programme.",[12,2082,2083],{},[28,2084,2085],{},"Si vous souhaitez tester mon programme ou l'utiliser, sachez qu'il n'est pas compatible avec la version 3 de BackupPC,\nni avec la version 4 si votre pool est un mélange de versions V3 et V4.",[12,2087,2088],{},"Si le besoin se fait sentir plus tard, il sera toujours possible d'améliorer tout cela.",[1901,2090,2092],{"id":2091},"les-fichiers-compressés","Les fichiers compressés",[12,2094,2095,2096,2099,2100,2103,2104,31],{},"J'ai donc commencé par développer un programme qui, à partir d'un hash, est capable de décompresser un fichier de ce\npool. Pour décompresser un fichier BackupPC compressé avec ",[344,2097,2098],{},"zlib",", j'ai choisi d'utiliser la bibliothèque ",[344,2101,2102],{},"flate2",", qui\nest une alternative Rust à la bibliothèque standard ",[344,2105,2098],{},[12,2107,2108,2109,2111],{},"La bibliothèque ",[344,2110,2102],{}," permet de décompresser un fichier en utilisant la notion de BufReader en Rust. La version\nsimplifiée pour décompresser un fichier du pool est donc la suivante :",[352,2113,2117],{"className":2114,"code":2115,"language":2116,"meta":291,"style":291},"language-rust shiki shiki-themes one-dark-pro","use flate2::bufread::ZlibDecoder;\nuse std::fs::File;\n\nfn main() {\n    let f = File::open(\"33fe8f9ae2f5cedbea63b9d3ea767ac0\").unwrap();\n    let b = BufReader::new(f);\n    let mut z = ZlibEncoder::new(b);\n    let mut buffer = Vec::new();\n    z.read_to_end(&mut buffer).unwrap();\n    println!(\"{:?}\", buffer);\n}\n","rust",[344,2118,2119,2139,2158,2162,2173,2205,2229,2255,2275,2299,2317],{"__ignoreMap":291},[360,2120,2121,2124,2127,2129,2132,2134,2137],{"class":362,"line":363},[360,2122,2123],{"class":574},"use",[360,2125,2126],{"class":662}," flate2",[360,2128,666],{"class":366},[360,2130,2131],{"class":662},"bufread",[360,2133,666],{"class":366},[360,2135,2136],{"class":662},"ZlibDecoder",[360,2138,735],{"class":366},[360,2140,2141,2143,2146,2148,2151,2153,2156],{"class":362,"line":292},[360,2142,2123],{"class":574},[360,2144,2145],{"class":662}," std",[360,2147,666],{"class":366},[360,2149,2150],{"class":662},"fs",[360,2152,666],{"class":366},[360,2154,2155],{"class":662},"File",[360,2157,735],{"class":366},[360,2159,2160],{"class":362,"line":375},[360,2161,372],{"emptyLinePlaceholder":320},[360,2163,2164,2167,2170],{"class":362,"line":433},[360,2165,2166],{"class":574},"fn",[360,2168,2169],{"class":381}," main",[360,2171,2172],{"class":366},"() {\n",[360,2174,2175,2178,2181,2183,2186,2188,2191,2193,2196,2199,2202],{"class":362,"line":478},[360,2176,2177],{"class":574},"    let",[360,2179,2180],{"class":578}," f",[360,2182,401],{"class":582},[360,2184,2185],{"class":662}," File",[360,2187,666],{"class":366},[360,2189,2190],{"class":381},"open",[360,2192,671],{"class":366},[360,2194,2195],{"class":397},"\"33fe8f9ae2f5cedbea63b9d3ea767ac0\"",[360,2197,2198],{"class":366},").",[360,2200,2201],{"class":381},"unwrap",[360,2203,2204],{"class":366},"();\n",[360,2206,2207,2209,2212,2214,2217,2219,2222,2224,2227],{"class":362,"line":483},[360,2208,2177],{"class":574},[360,2210,2211],{"class":578}," b",[360,2213,401],{"class":582},[360,2215,2216],{"class":662}," BufReader",[360,2218,666],{"class":366},[360,2220,2221],{"class":381},"new",[360,2223,671],{"class":366},[360,2225,2226],{"class":578},"f",[360,2228,801],{"class":366},[360,2230,2231,2233,2236,2239,2241,2244,2246,2248,2250,2253],{"class":362,"line":489},[360,2232,2177],{"class":574},[360,2234,2235],{"class":574}," mut",[360,2237,2238],{"class":578}," z",[360,2240,401],{"class":582},[360,2242,2243],{"class":662}," ZlibEncoder",[360,2245,666],{"class":366},[360,2247,2221],{"class":381},[360,2249,671],{"class":366},[360,2251,2252],{"class":578},"b",[360,2254,801],{"class":366},[360,2256,2257,2259,2261,2264,2266,2269,2271,2273],{"class":362,"line":494},[360,2258,2177],{"class":574},[360,2260,2235],{"class":574},[360,2262,2263],{"class":578}," buffer",[360,2265,401],{"class":582},[360,2267,2268],{"class":662}," Vec",[360,2270,666],{"class":366},[360,2272,2221],{"class":381},[360,2274,2204],{"class":366},[360,2276,2277,2280,2282,2285,2288,2291,2293,2295,2297],{"class":362,"line":712},[360,2278,2279],{"class":578},"    z",[360,2281,31],{"class":366},[360,2283,2284],{"class":381},"read_to_end",[360,2286,2287],{"class":366},"(&",[360,2289,2290],{"class":574},"mut",[360,2292,2263],{"class":578},[360,2294,2198],{"class":366},[360,2296,2201],{"class":381},[360,2298,2204],{"class":366},[360,2300,2301,2304,2306,2309,2312,2315],{"class":362,"line":331},[360,2302,2303],{"class":381},"    println!",[360,2305,671],{"class":366},[360,2307,2308],{"class":397},"\"{:?}\"",[360,2310,2311],{"class":366},", ",[360,2313,2314],{"class":578},"buffer",[360,2316,801],{"class":366},[360,2318,2319],{"class":362,"line":762},[360,2320,847],{"class":366},[12,2322,2323],{},"Malheureusement, ce code ne fonctionne pas à tous les coups. Pour les plus petits fichiers de mon pool, cela fonctionne\ntrès bien, mais quand on se retrouve avec les fichiers volumineux que BackupPC a décidé de découper, cela ne fonctionne\nplus.",[12,2325,2326,2327,2332],{},"De plus, dans certains cas, BackupPC ",[47,2328,2331],{"href":2329,"rel":2330},"https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs\u002Fblob\u002Fmaster\u002Fbpc_fileZIO.c#L214",[51],"remplace certains octets","\npour indiquer que l'on est au début d'un nouveau bloc de données zlib, ou pour indiquer que l'on a ajouté à la fin une\nchecksum md4.",[12,2334,2335,2336,2338],{},"Comme certains fichiers peuvent être volumineux, je ne peux pas faire un ",[344,2337,2284],{}," pour lire le fichier en\nmémoire et le modifier.",[12,2340,2341,2342,2347],{},"Le fichier ",[47,2343,2346],{"href":2344,"rel":2345},"https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs\u002Fblob\u002Fmaster\u002Fbpc_fileZIO.c",[51],"bpc_fileZIO.c"," permet de comprendre\ncomment sont encodés les fichiers compressés.",[12,2349,2350],{},"Lors de la lecture d'un fichier compressé, si la lecture de la compression s'arrête et qu'il reste encore des octets\nà lire, alors il faut recommencer une nouvelle décompression.",[12,2352,2353],{},"On peut aussi voir le bout de code suivant :",[352,2355,2359],{"className":2356,"code":2357,"language":2358,"meta":291,"style":291},"language-c shiki shiki-themes one-dark-pro","\u002F\u002F https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs\u002Fblob\u002Fmaster\u002Fbpc_fileZIO.c#L219C15-L237C18\nif ( fd->strm.next_in[0] == 0xd6 || fd->strm.next_in[0] == 0xd7 ) {\n    \u002F*\n     * Flag 0xd6 or 0xd7 means this is a compressed file with\n     * appended md4 block checksums for rsync.  Change\n     * the first byte back to 0x78 and proceed.\n     *\u002F\n    fd->strm.next_in[0] = 0x78;\n} else if ( fd->strm.next_in[0] == 0xb3 ) {\n    \u002F*\n     * Flag 0xb3 means this is the start of the rsync\n     * block checksums, so consider this as EOF for\n     * the compressed file.  Also seek the file so\n     * it is positioned at the 0xb3.\n     *\u002F\n    fd->eof = 1;\n    \u002F* TODO: check return status *\u002F\n    lseek(fd->fd, -fd->strm.avail_in, SEEK_CUR);\n    fd->strm.avail_in = 0;\n}\n","c",[344,2360,2361,2366,2427,2432,2437,2442,2447,2452,2481,2515,2519,2524,2529,2534,2539,2543,2558,2563,2595,2613],{"__ignoreMap":291},[360,2362,2363],{"class":362,"line":363},[360,2364,2365],{"class":644},"\u002F\u002F https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs\u002Fblob\u002Fmaster\u002Fbpc_fileZIO.c#L219C15-L237C18\n",[360,2367,2368,2371,2374,2377,2380,2383,2386,2388,2391,2394,2396,2399,2402,2405,2407,2409,2411,2413,2415,2417,2419,2421,2424],{"class":362,"line":292},[360,2369,2370],{"class":574},"if",[360,2372,2373],{"class":366}," ( fd",[360,2375,2376],{"class":574},"->",[360,2378,2379],{"class":366},"strm.",[360,2381,2382],{"class":578},"next_in",[360,2384,2385],{"class":366},"[",[360,2387,1344],{"class":414},[360,2389,2390],{"class":366},"] ",[360,2392,2393],{"class":574},"==",[360,2395,1255],{"class":578},[360,2397,2398],{"class":414},"d6",[360,2400,2401],{"class":582}," ||",[360,2403,2404],{"class":366}," fd",[360,2406,2376],{"class":574},[360,2408,2379],{"class":366},[360,2410,2382],{"class":578},[360,2412,2385],{"class":366},[360,2414,1344],{"class":414},[360,2416,2390],{"class":366},[360,2418,2393],{"class":574},[360,2420,1255],{"class":578},[360,2422,2423],{"class":414},"d7",[360,2425,2426],{"class":366}," ) {\n",[360,2428,2429],{"class":362,"line":375},[360,2430,2431],{"class":644},"    \u002F*\n",[360,2433,2434],{"class":362,"line":433},[360,2435,2436],{"class":644},"     * Flag 0xd6 or 0xd7 means this is a compressed file with\n",[360,2438,2439],{"class":362,"line":478},[360,2440,2441],{"class":644},"     * appended md4 block checksums for rsync.  Change\n",[360,2443,2444],{"class":362,"line":483},[360,2445,2446],{"class":644},"     * the first byte back to 0x78 and proceed.\n",[360,2448,2449],{"class":362,"line":489},[360,2450,2451],{"class":644},"     *\u002F\n",[360,2453,2454,2457,2459,2462,2464,2466,2468,2470,2472,2474,2476,2479],{"class":362,"line":494},[360,2455,2456],{"class":662},"    fd",[360,2458,2376],{"class":366},[360,2460,2461],{"class":662},"strm",[360,2463,31],{"class":366},[360,2465,2382],{"class":578},[360,2467,2385],{"class":366},[360,2469,1344],{"class":414},[360,2471,2390],{"class":366},[360,2473,583],{"class":574},[360,2475,1255],{"class":578},[360,2477,2478],{"class":414},"78",[360,2480,735],{"class":366},[360,2482,2483,2486,2489,2492,2494,2496,2498,2500,2502,2504,2506,2508,2510,2513],{"class":362,"line":712},[360,2484,2485],{"class":366},"} ",[360,2487,2488],{"class":574},"else",[360,2490,2491],{"class":574}," if",[360,2493,2373],{"class":366},[360,2495,2376],{"class":574},[360,2497,2379],{"class":366},[360,2499,2382],{"class":578},[360,2501,2385],{"class":366},[360,2503,1344],{"class":414},[360,2505,2390],{"class":366},[360,2507,2393],{"class":574},[360,2509,1255],{"class":578},[360,2511,2512],{"class":414},"b3",[360,2514,2426],{"class":366},[360,2516,2517],{"class":362,"line":331},[360,2518,2431],{"class":644},[360,2520,2521],{"class":362,"line":762},[360,2522,2523],{"class":644},"     * Flag 0xb3 means this is the start of the rsync\n",[360,2525,2526],{"class":362,"line":781},[360,2527,2528],{"class":644},"     * block checksums, so consider this as EOF for\n",[360,2530,2531],{"class":362,"line":804},[360,2532,2533],{"class":644},"     * the compressed file.  Also seek the file so\n",[360,2535,2536],{"class":362,"line":817},[360,2537,2538],{"class":644},"     * it is positioned at the 0xb3.\n",[360,2540,2541],{"class":362,"line":823},[360,2542,2451],{"class":644},[360,2544,2545,2547,2549,2552,2554,2556],{"class":362,"line":844},[360,2546,2456],{"class":662},[360,2548,2376],{"class":366},[360,2550,2551],{"class":578},"eof",[360,2553,401],{"class":574},[360,2555,1099],{"class":414},[360,2557,735],{"class":366},[360,2559,2560],{"class":362,"line":1441},[360,2561,2562],{"class":644},"    \u002F* TODO: check return status *\u002F\n",[360,2564,2565,2568,2570,2573,2575,2577,2579,2581,2583,2585,2587,2589,2592],{"class":362,"line":1462},[360,2566,2567],{"class":381},"    lseek",[360,2569,671],{"class":366},[360,2571,2572],{"class":662},"fd",[360,2574,2376],{"class":366},[360,2576,2572],{"class":578},[360,2578,2311],{"class":366},[360,2580,1491],{"class":574},[360,2582,2572],{"class":662},[360,2584,2376],{"class":366},[360,2586,2461],{"class":662},[360,2588,31],{"class":366},[360,2590,2591],{"class":578},"avail_in",[360,2593,2594],{"class":366},", SEEK_CUR);\n",[360,2596,2597,2599,2601,2603,2605,2607,2609,2611],{"class":362,"line":1485},[360,2598,2456],{"class":662},[360,2600,2376],{"class":366},[360,2602,2461],{"class":662},[360,2604,31],{"class":366},[360,2606,2591],{"class":578},[360,2608,401],{"class":574},[360,2610,1457],{"class":414},[360,2612,735],{"class":366},[360,2614,2615],{"class":362,"line":1497},[360,2616,847],{"class":366},[12,2618,2619,2620,2623,2624,2627,2628,2631,2632,2635],{},"Si, en début de flux, on trouve ",[344,2621,2622],{},"0xd6"," ou ",[344,2625,2626],{},"0xd7",", il faut changer le premier octet en ",[344,2629,2630],{},"0x78"," et continuer la lecture. En\nfin de flux, si on trouve ",[344,2633,2634],{},"0xb3",", on considère que c'est la fin du fichier compressé. (De notre côté, nous ne nous\nintéresserons pas à la partie checksum md4).",[12,2637,2108,2638,2640,2641,2643],{},[344,2639,2102],{}," ne permet pas de faire cela simplement. J'ai donc dû lire le code de ",[344,2642,2102],{}," pour comprendre\ncomment je pouvais agir pour lire un fichier compressé de BackupPC.",[12,2645,2646,2653,2654,2656,2657,2660,2661,2664,2665,2668],{},[47,2647,2650,2651],{"href":2648,"rel":2649},"https:\u002F\u002Fgithub.com\u002Frust-lang\u002Fflate2-rs\u002Fblob\u002Fmain\u002Fsrc\u002Fbufreader.rs#L73",[51],"Le code suivant de la bibliothèque ",[344,2652,2102],{},"\npermet de voir que ",[344,2655,2102],{}," a besoin, dans son constructeur, d'un ",[344,2658,2659],{},"BufRead"," pour lire un fichier compressé. Il utilise\nla méthode ",[344,2662,2663],{},"fill_buf"," pour remplir un tampon et la méthode ",[344,2666,2667],{},"consume"," pour consommer le tampon.",[352,2670,2672],{"className":2114,"code":2671,"language":2116,"meta":291,"style":291},"\u002F\u002F https:\u002F\u002Fgithub.com\u002Frust-lang\u002Fflate2-rs\u002Fblob\u002Fmain\u002Fsrc\u002Fbufreader.rs#L73\nimpl\u003CR: Read> Read for BufReader\u003CR> {\n    fn read(&mut self, buf: &mut [u8]) -> io::Result\u003Cusize> {\n        \u002F\u002F If we don't have any buffered data and we're doing a massive read\n        \u002F\u002F (larger than our internal buffer), bypass our internal buffer\n        \u002F\u002F entirely.\n        if self.pos == self.cap && buf.len() >= self.buf.len() {\n            return self.inner.read(buf);\n        }\n        let nread = {\n            let mut rem = self.fill_buf()?;\n            rem.read(buf)?\n        };\n        self.consume(nread);\n        Ok(nread)\n    }\n}\n",[344,2673,2674,2679,2712,2761,2766,2771,2776,2817,2836,2841,2853,2874,2890,2895,2911,2923,2928],{"__ignoreMap":291},[360,2675,2676],{"class":362,"line":363},[360,2677,2678],{"class":644},"\u002F\u002F https:\u002F\u002Fgithub.com\u002Frust-lang\u002Fflate2-rs\u002Fblob\u002Fmain\u002Fsrc\u002Fbufreader.rs#L73\n",[360,2680,2681,2684,2686,2689,2692,2695,2698,2700,2703,2705,2707,2709],{"class":362,"line":292},[360,2682,2683],{"class":574},"impl",[360,2685,1358],{"class":366},[360,2687,2688],{"class":662},"R",[360,2690,2691],{"class":366},": ",[360,2693,2694],{"class":662},"Read",[360,2696,2697],{"class":366},"> ",[360,2699,2694],{"class":662},[360,2701,2702],{"class":574}," for",[360,2704,2216],{"class":662},[360,2706,1358],{"class":366},[360,2708,2688],{"class":662},[360,2710,2711],{"class":366},"> {\n",[360,2713,2714,2717,2720,2722,2724,2727,2729,2732,2735,2737,2740,2743,2746,2749,2751,2754,2756,2759],{"class":362,"line":375},[360,2715,2716],{"class":574},"    fn",[360,2718,2719],{"class":381}," read",[360,2721,2287],{"class":366},[360,2723,2290],{"class":574},[360,2725,2726],{"class":662}," self",[360,2728,2311],{"class":366},[360,2730,2731],{"class":578},"buf",[360,2733,2734],{"class":366},": &",[360,2736,2290],{"class":574},[360,2738,2739],{"class":366}," [",[360,2741,2742],{"class":662},"u8",[360,2744,2745],{"class":366},"]) -> ",[360,2747,2748],{"class":662},"io",[360,2750,666],{"class":366},[360,2752,2753],{"class":662},"Result",[360,2755,1358],{"class":366},[360,2757,2758],{"class":662},"usize",[360,2760,2711],{"class":366},[360,2762,2763],{"class":362,"line":433},[360,2764,2765],{"class":644},"        \u002F\u002F If we don't have any buffered data and we're doing a massive read\n",[360,2767,2768],{"class":362,"line":478},[360,2769,2770],{"class":644},"        \u002F\u002F (larger than our internal buffer), bypass our internal buffer\n",[360,2772,2773],{"class":362,"line":483},[360,2774,2775],{"class":644},"        \u002F\u002F entirely.\n",[360,2777,2778,2781,2783,2786,2788,2790,2793,2795,2798,2800,2803,2806,2808,2810,2813,2815],{"class":362,"line":489},[360,2779,2780],{"class":574},"        if",[360,2782,2726],{"class":662},[360,2784,2785],{"class":366},".pos ",[360,2787,2393],{"class":582},[360,2789,2726],{"class":662},[360,2791,2792],{"class":366},".cap ",[360,2794,1353],{"class":582},[360,2796,2797],{"class":578}," buf",[360,2799,31],{"class":366},[360,2801,2802],{"class":381},"len",[360,2804,2805],{"class":366},"() ",[360,2807,729],{"class":582},[360,2809,2726],{"class":662},[360,2811,2812],{"class":366},".buf.",[360,2814,2802],{"class":381},[360,2816,2172],{"class":366},[360,2818,2819,2822,2824,2827,2830,2832,2834],{"class":362,"line":494},[360,2820,2821],{"class":574},"            return",[360,2823,2726],{"class":662},[360,2825,2826],{"class":366},".inner.",[360,2828,2829],{"class":381},"read",[360,2831,671],{"class":366},[360,2833,2731],{"class":578},[360,2835,801],{"class":366},[360,2837,2838],{"class":362,"line":712},[360,2839,2840],{"class":366},"        }\n",[360,2842,2843,2846,2849,2851],{"class":362,"line":331},[360,2844,2845],{"class":574},"        let",[360,2847,2848],{"class":578}," nread",[360,2850,401],{"class":582},[360,2852,896],{"class":366},[360,2854,2855,2858,2860,2863,2865,2867,2869,2871],{"class":362,"line":762},[360,2856,2857],{"class":574},"            let",[360,2859,2235],{"class":574},[360,2861,2862],{"class":578}," rem",[360,2864,401],{"class":582},[360,2866,2726],{"class":662},[360,2868,31],{"class":366},[360,2870,2663],{"class":381},[360,2872,2873],{"class":366},"()?;\n",[360,2875,2876,2879,2881,2883,2885,2887],{"class":362,"line":781},[360,2877,2878],{"class":578},"            rem",[360,2880,31],{"class":366},[360,2882,2829],{"class":381},[360,2884,671],{"class":366},[360,2886,2731],{"class":578},[360,2888,2889],{"class":366},")?\n",[360,2891,2892],{"class":362,"line":804},[360,2893,2894],{"class":366},"        };\n",[360,2896,2897,2900,2902,2904,2906,2909],{"class":362,"line":817},[360,2898,2899],{"class":662},"        self",[360,2901,31],{"class":366},[360,2903,2667],{"class":381},[360,2905,671],{"class":366},[360,2907,2908],{"class":578},"nread",[360,2910,801],{"class":366},[360,2912,2913,2916,2918,2920],{"class":362,"line":823},[360,2914,2915],{"class":662},"        Ok",[360,2917,671],{"class":366},[360,2919,2908],{"class":578},[360,2921,2922],{"class":366},")\n",[360,2924,2925],{"class":362,"line":844},[360,2926,2927],{"class":366},"    }\n",[360,2929,2930],{"class":362,"line":1441},[360,2931,847],{"class":366},[12,2933,2934],{},"J'ai donc commencé par développer un adaptateur qui s'intercale entre le fichier et le décompresseur. Cet adaptateur\na pour objectif de reproduire le comportement de BackupPC et de remplacer les octets en début de fichier.",[352,2936,2938],{"className":2114,"code":2937,"language":2116,"meta":291,"style":291},"struct InterpretAdapter\u003CR: BufRead> {\n    inner: R,\n    first: bool,\n    temp: Option\u003CVec\u003Cu8>>,\n}\n\nimpl\u003CR: BufRead> InterpretAdapter\u003CR> {\n    fn new(inner: R) -> Self {\n        Self {\n            inner,\n            first: true,\n            temp: None,\n        }\n    }\n\n    fn reset(&mut self) {\n        self.first = true;\n        self.temp = None;\n    }\n}\n...\nimpl\u003CR: BufRead> BufRead for InterpretAdapter\u003CR> {\n    fn fill_buf(&mut self) -> io::Result\u003C&[u8]> {\n        if self.temp.is_none() {\n            let buf = self.inner.fill_buf()?;\n            let mut buf = buf.to_vec();\n\n            if self.first && !buf.is_empty() {\n                self.first = false;\n\n                if buf[0] == 0xd6 || buf[0] == 0xd7 {\n                    buf[0] = 0x78;\n                } else if buf[0] == 0xb3 {\n                    \u002F\u002F EOF\n                    buf = Vec::new();\n                }\n            }\n\n            self.temp = Some(buf);\n        }\n\n        Ok(self.temp.as_ref().unwrap())\n    }\n\n    fn consume(&mut self, amt: usize) {\n        if amt > 0 {\n            self.temp = None;\n            self.inner.consume(amt);\n        }\n    }\n}\n",[344,2939,2940,2957,2969,2981,3003,3007,3011,3034,3058,3065,3072,3084,3096,3100,3104,3108,3123,3137,3151,3155,3159,3165,3192,3222,3237,3254,3274,3279,3303,3318,3323,3359,3378,3403,3409,3424,3430,3436,3441,3460,3465,3470,3493,3498,3503,3528,3543,3556,3571,3576,3581],{"__ignoreMap":291},[360,2941,2942,2944,2947,2949,2951,2953,2955],{"class":362,"line":363},[360,2943,890],{"class":574},[360,2945,2946],{"class":662}," InterpretAdapter",[360,2948,1358],{"class":366},[360,2950,2688],{"class":662},[360,2952,2691],{"class":366},[360,2954,2659],{"class":662},[360,2956,2711],{"class":366},[360,2958,2959,2962,2964,2966],{"class":362,"line":292},[360,2960,2961],{"class":578},"    inner",[360,2963,2691],{"class":366},[360,2965,2688],{"class":662},[360,2967,2968],{"class":366},",\n",[360,2970,2971,2974,2976,2979],{"class":362,"line":375},[360,2972,2973],{"class":578},"    first",[360,2975,2691],{"class":366},[360,2977,2978],{"class":662},"bool",[360,2980,2968],{"class":366},[360,2982,2983,2986,2988,2991,2993,2996,2998,3000],{"class":362,"line":433},[360,2984,2985],{"class":578},"    temp",[360,2987,2691],{"class":366},[360,2989,2990],{"class":662},"Option",[360,2992,1358],{"class":366},[360,2994,2995],{"class":662},"Vec",[360,2997,1358],{"class":366},[360,2999,2742],{"class":662},[360,3001,3002],{"class":366},">>,\n",[360,3004,3005],{"class":362,"line":478},[360,3006,847],{"class":366},[360,3008,3009],{"class":362,"line":483},[360,3010,372],{"emptyLinePlaceholder":320},[360,3012,3013,3015,3017,3019,3021,3023,3025,3028,3030,3032],{"class":362,"line":489},[360,3014,2683],{"class":574},[360,3016,1358],{"class":366},[360,3018,2688],{"class":662},[360,3020,2691],{"class":366},[360,3022,2659],{"class":662},[360,3024,2697],{"class":366},[360,3026,3027],{"class":662},"InterpretAdapter",[360,3029,1358],{"class":366},[360,3031,2688],{"class":662},[360,3033,2711],{"class":366},[360,3035,3036,3038,3041,3043,3046,3048,3050,3053,3056],{"class":362,"line":494},[360,3037,2716],{"class":574},[360,3039,3040],{"class":381}," new",[360,3042,671],{"class":366},[360,3044,3045],{"class":578},"inner",[360,3047,2691],{"class":366},[360,3049,2688],{"class":662},[360,3051,3052],{"class":366},") -> ",[360,3054,3055],{"class":662},"Self",[360,3057,896],{"class":366},[360,3059,3060,3063],{"class":362,"line":712},[360,3061,3062],{"class":662},"        Self",[360,3064,896],{"class":366},[360,3066,3067,3070],{"class":362,"line":331},[360,3068,3069],{"class":578},"            inner",[360,3071,2968],{"class":366},[360,3073,3074,3077,3079,3082],{"class":362,"line":762},[360,3075,3076],{"class":578},"            first",[360,3078,2691],{"class":366},[360,3080,3081],{"class":414},"true",[360,3083,2968],{"class":366},[360,3085,3086,3089,3091,3094],{"class":362,"line":781},[360,3087,3088],{"class":578},"            temp",[360,3090,2691],{"class":366},[360,3092,3093],{"class":662},"None",[360,3095,2968],{"class":366},[360,3097,3098],{"class":362,"line":804},[360,3099,2840],{"class":366},[360,3101,3102],{"class":362,"line":817},[360,3103,2927],{"class":366},[360,3105,3106],{"class":362,"line":823},[360,3107,372],{"emptyLinePlaceholder":320},[360,3109,3110,3112,3115,3117,3119,3121],{"class":362,"line":844},[360,3111,2716],{"class":574},[360,3113,3114],{"class":381}," reset",[360,3116,2287],{"class":366},[360,3118,2290],{"class":574},[360,3120,2726],{"class":662},[360,3122,681],{"class":366},[360,3124,3125,3127,3130,3132,3135],{"class":362,"line":1441},[360,3126,2899],{"class":662},[360,3128,3129],{"class":366},".first ",[360,3131,583],{"class":582},[360,3133,3134],{"class":414}," true",[360,3136,735],{"class":366},[360,3138,3139,3141,3144,3146,3149],{"class":362,"line":1462},[360,3140,2899],{"class":662},[360,3142,3143],{"class":366},".temp ",[360,3145,583],{"class":582},[360,3147,3148],{"class":662}," None",[360,3150,735],{"class":366},[360,3152,3153],{"class":362,"line":1485},[360,3154,2927],{"class":366},[360,3156,3157],{"class":362,"line":1497},[360,3158,847],{"class":366},[360,3160,3162],{"class":362,"line":3161},21,[360,3163,3164],{"class":366},"...\n",[360,3166,3168,3170,3172,3174,3176,3178,3180,3182,3184,3186,3188,3190],{"class":362,"line":3167},22,[360,3169,2683],{"class":574},[360,3171,1358],{"class":366},[360,3173,2688],{"class":662},[360,3175,2691],{"class":366},[360,3177,2659],{"class":662},[360,3179,2697],{"class":366},[360,3181,2659],{"class":662},[360,3183,2702],{"class":574},[360,3185,2946],{"class":662},[360,3187,1358],{"class":366},[360,3189,2688],{"class":662},[360,3191,2711],{"class":366},[360,3193,3195,3197,3200,3202,3204,3206,3208,3210,3212,3214,3217,3219],{"class":362,"line":3194},23,[360,3196,2716],{"class":574},[360,3198,3199],{"class":381}," fill_buf",[360,3201,2287],{"class":366},[360,3203,2290],{"class":574},[360,3205,2726],{"class":662},[360,3207,3052],{"class":366},[360,3209,2748],{"class":662},[360,3211,666],{"class":366},[360,3213,2753],{"class":662},[360,3215,3216],{"class":366},"\u003C&[",[360,3218,2742],{"class":662},[360,3220,3221],{"class":366},"]> {\n",[360,3223,3225,3227,3229,3232,3235],{"class":362,"line":3224},24,[360,3226,2780],{"class":574},[360,3228,2726],{"class":662},[360,3230,3231],{"class":366},".temp.",[360,3233,3234],{"class":381},"is_none",[360,3236,2172],{"class":366},[360,3238,3240,3242,3244,3246,3248,3250,3252],{"class":362,"line":3239},25,[360,3241,2857],{"class":574},[360,3243,2797],{"class":578},[360,3245,401],{"class":582},[360,3247,2726],{"class":662},[360,3249,2826],{"class":366},[360,3251,2663],{"class":381},[360,3253,2873],{"class":366},[360,3255,3257,3259,3261,3263,3265,3267,3269,3272],{"class":362,"line":3256},26,[360,3258,2857],{"class":574},[360,3260,2235],{"class":574},[360,3262,2797],{"class":578},[360,3264,401],{"class":582},[360,3266,2797],{"class":578},[360,3268,31],{"class":366},[360,3270,3271],{"class":381},"to_vec",[360,3273,2204],{"class":366},[360,3275,3277],{"class":362,"line":3276},27,[360,3278,372],{"emptyLinePlaceholder":320},[360,3280,3282,3285,3287,3289,3291,3294,3296,3298,3301],{"class":362,"line":3281},28,[360,3283,3284],{"class":574},"            if",[360,3286,2726],{"class":662},[360,3288,3129],{"class":366},[360,3290,1353],{"class":582},[360,3292,3293],{"class":582}," !",[360,3295,2731],{"class":578},[360,3297,31],{"class":366},[360,3299,3300],{"class":381},"is_empty",[360,3302,2172],{"class":366},[360,3304,3306,3309,3311,3313,3316],{"class":362,"line":3305},29,[360,3307,3308],{"class":662},"                self",[360,3310,3129],{"class":366},[360,3312,583],{"class":582},[360,3314,3315],{"class":414}," false",[360,3317,735],{"class":366},[360,3319,3321],{"class":362,"line":3320},30,[360,3322,372],{"emptyLinePlaceholder":320},[360,3324,3326,3329,3331,3333,3335,3337,3339,3342,3344,3346,3348,3350,3352,3354,3357],{"class":362,"line":3325},31,[360,3327,3328],{"class":574},"                if",[360,3330,2797],{"class":578},[360,3332,2385],{"class":366},[360,3334,1344],{"class":414},[360,3336,2390],{"class":366},[360,3338,2393],{"class":582},[360,3340,3341],{"class":414}," 0xd6",[360,3343,2401],{"class":582},[360,3345,2797],{"class":578},[360,3347,2385],{"class":366},[360,3349,1344],{"class":414},[360,3351,2390],{"class":366},[360,3353,2393],{"class":582},[360,3355,3356],{"class":414}," 0xd7",[360,3358,896],{"class":366},[360,3360,3362,3365,3367,3369,3371,3373,3376],{"class":362,"line":3361},32,[360,3363,3364],{"class":578},"                    buf",[360,3366,2385],{"class":366},[360,3368,1344],{"class":414},[360,3370,2390],{"class":366},[360,3372,583],{"class":582},[360,3374,3375],{"class":414}," 0x78",[360,3377,735],{"class":366},[360,3379,3381,3384,3386,3388,3390,3392,3394,3396,3398,3401],{"class":362,"line":3380},33,[360,3382,3383],{"class":366},"                } ",[360,3385,2488],{"class":574},[360,3387,2491],{"class":574},[360,3389,2797],{"class":578},[360,3391,2385],{"class":366},[360,3393,1344],{"class":414},[360,3395,2390],{"class":366},[360,3397,2393],{"class":582},[360,3399,3400],{"class":414}," 0xb3",[360,3402,896],{"class":366},[360,3404,3406],{"class":362,"line":3405},34,[360,3407,3408],{"class":644},"                    \u002F\u002F EOF\n",[360,3410,3412,3414,3416,3418,3420,3422],{"class":362,"line":3411},35,[360,3413,3364],{"class":578},[360,3415,401],{"class":582},[360,3417,2268],{"class":662},[360,3419,666],{"class":366},[360,3421,2221],{"class":381},[360,3423,2204],{"class":366},[360,3425,3427],{"class":362,"line":3426},36,[360,3428,3429],{"class":366},"                }\n",[360,3431,3433],{"class":362,"line":3432},37,[360,3434,3435],{"class":366},"            }\n",[360,3437,3439],{"class":362,"line":3438},38,[360,3440,372],{"emptyLinePlaceholder":320},[360,3442,3444,3447,3449,3451,3454,3456,3458],{"class":362,"line":3443},39,[360,3445,3446],{"class":662},"            self",[360,3448,3143],{"class":366},[360,3450,583],{"class":582},[360,3452,3453],{"class":662}," Some",[360,3455,671],{"class":366},[360,3457,2731],{"class":578},[360,3459,801],{"class":366},[360,3461,3463],{"class":362,"line":3462},40,[360,3464,2840],{"class":366},[360,3466,3468],{"class":362,"line":3467},41,[360,3469,372],{"emptyLinePlaceholder":320},[360,3471,3473,3475,3477,3480,3482,3485,3488,3490],{"class":362,"line":3472},42,[360,3474,2915],{"class":662},[360,3476,671],{"class":366},[360,3478,3479],{"class":662},"self",[360,3481,3231],{"class":366},[360,3483,3484],{"class":381},"as_ref",[360,3486,3487],{"class":366},"().",[360,3489,2201],{"class":381},[360,3491,3492],{"class":366},"())\n",[360,3494,3496],{"class":362,"line":3495},43,[360,3497,2927],{"class":366},[360,3499,3501],{"class":362,"line":3500},44,[360,3502,372],{"emptyLinePlaceholder":320},[360,3504,3506,3508,3511,3513,3515,3517,3519,3522,3524,3526],{"class":362,"line":3505},45,[360,3507,2716],{"class":574},[360,3509,3510],{"class":381}," consume",[360,3512,2287],{"class":366},[360,3514,2290],{"class":574},[360,3516,2726],{"class":662},[360,3518,2311],{"class":366},[360,3520,3521],{"class":578},"amt",[360,3523,2691],{"class":366},[360,3525,2758],{"class":662},[360,3527,681],{"class":366},[360,3529,3531,3533,3536,3539,3541],{"class":362,"line":3530},46,[360,3532,2780],{"class":574},[360,3534,3535],{"class":578}," amt",[360,3537,3538],{"class":582}," >",[360,3540,1457],{"class":414},[360,3542,896],{"class":366},[360,3544,3546,3548,3550,3552,3554],{"class":362,"line":3545},47,[360,3547,3446],{"class":662},[360,3549,3143],{"class":366},[360,3551,583],{"class":582},[360,3553,3148],{"class":662},[360,3555,735],{"class":366},[360,3557,3559,3561,3563,3565,3567,3569],{"class":362,"line":3558},48,[360,3560,3446],{"class":662},[360,3562,2826],{"class":366},[360,3564,2667],{"class":381},[360,3566,671],{"class":366},[360,3568,3521],{"class":578},[360,3570,801],{"class":366},[360,3572,3574],{"class":362,"line":3573},49,[360,3575,2840],{"class":366},[360,3577,3579],{"class":362,"line":3578},50,[360,3580,2927],{"class":366},[360,3582,3584],{"class":362,"line":3583},51,[360,3585,847],{"class":366},[12,3587,3588,3589,3592,3593,3596,3597,3599,3600,3602,3603,854,3605,3607],{},"Cet adaptateur s'intercale entre le ",[344,3590,3591],{},"BufReader"," et le ",[344,3594,3595],{},"ZLibDecoder",". Du point de vue du ",[344,3598,3595],{},", il doit\nse comporter comme un ",[344,3601,3591],{}," et donc implémenter les méthodes ",[344,3604,2663],{},[344,3606,2667],{},". Dans ces méthodes, je dois\nretourner un tampon.",[12,3609,3610,3611,3613],{},"Je ne peux pas modifier directement le tampon du ",[344,3612,3591],{}," car ce dernier est une référence en lecture seule. Je\ncopie donc le contenu (je n'ai pas trouvé de meilleure manière de faire cela).",[12,3615,3616,3617,3620,3621,3624,3625,3627],{},"Enfin, on peut développer le ",[344,3618,3619],{},"Reader"," qui sera capable de lire les fichiers compressés. Pour cela, j'ai d'abord\nimplémenté une méthode ",[344,3622,3623],{},"read_some_bytes"," qui permet de lire un certain nombre d'octets. Si jamais on arrive à la fin\nd'une section, alors la méthode peut retourner moins que la taille du tampon. Généralement, cela arrive en fin de\nfichier. Quand j'ai utilisé directement cette méthode en tant que méthode ",[344,3626,2829],{},", je me suis retrouvé avec des\ncorruptions.",[352,3629,3631],{"className":2114,"code":3630,"language":2116,"meta":291,"style":291},"pub struct BackupPCReader\u003CR: Read> {\n    decoder: Option\u003CZlibDecoder\u003CInterpretAdapter\u003CBufReader\u003CR>>>>,\n}\n...\nfn read_some_bytes(&mut self, buf: &mut [u8]) -> io::Result\u003Cusize> {\n    loop {\n        let decoder = self.decoder.as_mut();\n        if decoder.is_none() {\n            return Ok(0);\n        }\n\n        let decoder_read_result = decoder.unwrap().read(buf);\n\n        let count = match decoder_read_result {\n            Ok(count) => {\n                count\n            }\n            Err(e) => {\n                return Err(e);\n            }\n        };\n\n        if count != 0 {\n            return Ok(count);\n        }\n\n        if count == 0 {\n            let decoder = self.decoder.take();\n            if let Some(decoder) = decoder {\n                let mut reader = decoder.into_inner();\n                \u002F\u002F S'il reste encore des octets à lire dans reader alors on continue, sinon on s'arrête\n                if reader.fill_buf()?.is_empty() {\n                    return Ok(0);\n                }\n                reader.reset();\n\n                self.decoder = Some(ZlibDecoder::new(reader));\n            }\n        }\n    }\n}\n",[344,3632,3633,3654,3682,3686,3690,3729,3736,3755,3767,3780,3784,3788,3813,3817,3833,3846,3851,3855,3867,3881,3885,3889,3893,3906,3918,3922,3926,3939,3956,3979,4000,4005,4022,4035,4039,4051,4055,4082,4086,4090,4094],{"__ignoreMap":291},[360,3634,3635,3638,3641,3644,3646,3648,3650,3652],{"class":362,"line":363},[360,3636,3637],{"class":574},"pub",[360,3639,3640],{"class":574}," struct",[360,3642,3643],{"class":662}," BackupPCReader",[360,3645,1358],{"class":366},[360,3647,2688],{"class":662},[360,3649,2691],{"class":366},[360,3651,2694],{"class":662},[360,3653,2711],{"class":366},[360,3655,3656,3659,3661,3663,3665,3667,3669,3671,3673,3675,3677,3679],{"class":362,"line":292},[360,3657,3658],{"class":578},"    decoder",[360,3660,2691],{"class":366},[360,3662,2990],{"class":662},[360,3664,1358],{"class":366},[360,3666,2136],{"class":662},[360,3668,1358],{"class":366},[360,3670,3027],{"class":662},[360,3672,1358],{"class":366},[360,3674,3591],{"class":662},[360,3676,1358],{"class":366},[360,3678,2688],{"class":662},[360,3680,3681],{"class":366},">>>>,\n",[360,3683,3684],{"class":362,"line":375},[360,3685,847],{"class":366},[360,3687,3688],{"class":362,"line":433},[360,3689,3164],{"class":366},[360,3691,3692,3694,3697,3699,3701,3703,3705,3707,3709,3711,3713,3715,3717,3719,3721,3723,3725,3727],{"class":362,"line":478},[360,3693,2166],{"class":574},[360,3695,3696],{"class":381}," read_some_bytes",[360,3698,2287],{"class":366},[360,3700,2290],{"class":574},[360,3702,2726],{"class":662},[360,3704,2311],{"class":366},[360,3706,2731],{"class":578},[360,3708,2734],{"class":366},[360,3710,2290],{"class":574},[360,3712,2739],{"class":366},[360,3714,2742],{"class":662},[360,3716,2745],{"class":366},[360,3718,2748],{"class":662},[360,3720,666],{"class":366},[360,3722,2753],{"class":662},[360,3724,1358],{"class":366},[360,3726,2758],{"class":662},[360,3728,2711],{"class":366},[360,3730,3731,3734],{"class":362,"line":483},[360,3732,3733],{"class":574},"    loop",[360,3735,896],{"class":366},[360,3737,3738,3740,3743,3745,3747,3750,3753],{"class":362,"line":489},[360,3739,2845],{"class":574},[360,3741,3742],{"class":578}," decoder",[360,3744,401],{"class":582},[360,3746,2726],{"class":662},[360,3748,3749],{"class":366},".decoder.",[360,3751,3752],{"class":381},"as_mut",[360,3754,2204],{"class":366},[360,3756,3757,3759,3761,3763,3765],{"class":362,"line":494},[360,3758,2780],{"class":574},[360,3760,3742],{"class":578},[360,3762,31],{"class":366},[360,3764,3234],{"class":381},[360,3766,2172],{"class":366},[360,3768,3769,3771,3774,3776,3778],{"class":362,"line":712},[360,3770,2821],{"class":574},[360,3772,3773],{"class":662}," Ok",[360,3775,671],{"class":366},[360,3777,1344],{"class":414},[360,3779,801],{"class":366},[360,3781,3782],{"class":362,"line":331},[360,3783,2840],{"class":366},[360,3785,3786],{"class":362,"line":762},[360,3787,372],{"emptyLinePlaceholder":320},[360,3789,3790,3792,3795,3797,3799,3801,3803,3805,3807,3809,3811],{"class":362,"line":781},[360,3791,2845],{"class":574},[360,3793,3794],{"class":578}," decoder_read_result",[360,3796,401],{"class":582},[360,3798,3742],{"class":578},[360,3800,31],{"class":366},[360,3802,2201],{"class":381},[360,3804,3487],{"class":366},[360,3806,2829],{"class":381},[360,3808,671],{"class":366},[360,3810,2731],{"class":578},[360,3812,801],{"class":366},[360,3814,3815],{"class":362,"line":804},[360,3816,372],{"emptyLinePlaceholder":320},[360,3818,3819,3821,3824,3826,3829,3831],{"class":362,"line":817},[360,3820,2845],{"class":574},[360,3822,3823],{"class":578}," count",[360,3825,401],{"class":582},[360,3827,3828],{"class":574}," match",[360,3830,3794],{"class":578},[360,3832,896],{"class":366},[360,3834,3835,3838,3840,3843],{"class":362,"line":823},[360,3836,3837],{"class":662},"            Ok",[360,3839,671],{"class":366},[360,3841,3842],{"class":578},"count",[360,3844,3845],{"class":366},") => {\n",[360,3847,3848],{"class":362,"line":844},[360,3849,3850],{"class":578},"                count\n",[360,3852,3853],{"class":362,"line":1441},[360,3854,3435],{"class":366},[360,3856,3857,3860,3862,3865],{"class":362,"line":1462},[360,3858,3859],{"class":662},"            Err",[360,3861,671],{"class":366},[360,3863,3864],{"class":578},"e",[360,3866,3845],{"class":366},[360,3868,3869,3872,3875,3877,3879],{"class":362,"line":1485},[360,3870,3871],{"class":574},"                return",[360,3873,3874],{"class":662}," Err",[360,3876,671],{"class":366},[360,3878,3864],{"class":578},[360,3880,801],{"class":366},[360,3882,3883],{"class":362,"line":1497},[360,3884,3435],{"class":366},[360,3886,3887],{"class":362,"line":3161},[360,3888,2894],{"class":366},[360,3890,3891],{"class":362,"line":3167},[360,3892,372],{"emptyLinePlaceholder":320},[360,3894,3895,3897,3899,3902,3904],{"class":362,"line":3194},[360,3896,2780],{"class":574},[360,3898,3823],{"class":578},[360,3900,3901],{"class":582}," !=",[360,3903,1457],{"class":414},[360,3905,896],{"class":366},[360,3907,3908,3910,3912,3914,3916],{"class":362,"line":3224},[360,3909,2821],{"class":574},[360,3911,3773],{"class":662},[360,3913,671],{"class":366},[360,3915,3842],{"class":578},[360,3917,801],{"class":366},[360,3919,3920],{"class":362,"line":3239},[360,3921,2840],{"class":366},[360,3923,3924],{"class":362,"line":3256},[360,3925,372],{"emptyLinePlaceholder":320},[360,3927,3928,3930,3932,3935,3937],{"class":362,"line":3276},[360,3929,2780],{"class":574},[360,3931,3823],{"class":578},[360,3933,3934],{"class":582}," ==",[360,3936,1457],{"class":414},[360,3938,896],{"class":366},[360,3940,3941,3943,3945,3947,3949,3951,3954],{"class":362,"line":3281},[360,3942,2857],{"class":574},[360,3944,3742],{"class":578},[360,3946,401],{"class":582},[360,3948,2726],{"class":662},[360,3950,3749],{"class":366},[360,3952,3953],{"class":381},"take",[360,3955,2204],{"class":366},[360,3957,3958,3960,3963,3965,3967,3970,3973,3975,3977],{"class":362,"line":3305},[360,3959,3284],{"class":574},[360,3961,3962],{"class":574}," let",[360,3964,3453],{"class":662},[360,3966,671],{"class":366},[360,3968,3969],{"class":578},"decoder",[360,3971,3972],{"class":366},") ",[360,3974,583],{"class":582},[360,3976,3742],{"class":578},[360,3978,896],{"class":366},[360,3980,3981,3984,3986,3989,3991,3993,3995,3998],{"class":362,"line":3320},[360,3982,3983],{"class":574},"                let",[360,3985,2235],{"class":574},[360,3987,3988],{"class":578}," reader",[360,3990,401],{"class":582},[360,3992,3742],{"class":578},[360,3994,31],{"class":366},[360,3996,3997],{"class":381},"into_inner",[360,3999,2204],{"class":366},[360,4001,4002],{"class":362,"line":3325},[360,4003,4004],{"class":644},"                \u002F\u002F S'il reste encore des octets à lire dans reader alors on continue, sinon on s'arrête\n",[360,4006,4007,4009,4011,4013,4015,4018,4020],{"class":362,"line":3361},[360,4008,3328],{"class":574},[360,4010,3988],{"class":578},[360,4012,31],{"class":366},[360,4014,2663],{"class":381},[360,4016,4017],{"class":366},"()?.",[360,4019,3300],{"class":381},[360,4021,2172],{"class":366},[360,4023,4024,4027,4029,4031,4033],{"class":362,"line":3380},[360,4025,4026],{"class":574},"                    return",[360,4028,3773],{"class":662},[360,4030,671],{"class":366},[360,4032,1344],{"class":414},[360,4034,801],{"class":366},[360,4036,4037],{"class":362,"line":3405},[360,4038,3429],{"class":366},[360,4040,4041,4044,4046,4049],{"class":362,"line":3411},[360,4042,4043],{"class":578},"                reader",[360,4045,31],{"class":366},[360,4047,4048],{"class":381},"reset",[360,4050,2204],{"class":366},[360,4052,4053],{"class":362,"line":3426},[360,4054,372],{"emptyLinePlaceholder":320},[360,4056,4057,4059,4062,4064,4066,4068,4070,4072,4074,4076,4079],{"class":362,"line":3432},[360,4058,3308],{"class":662},[360,4060,4061],{"class":366},".decoder ",[360,4063,583],{"class":582},[360,4065,3453],{"class":662},[360,4067,671],{"class":366},[360,4069,2136],{"class":662},[360,4071,666],{"class":366},[360,4073,2221],{"class":381},[360,4075,671],{"class":366},[360,4077,4078],{"class":578},"reader",[360,4080,4081],{"class":366},"));\n",[360,4083,4084],{"class":362,"line":3438},[360,4085,3435],{"class":366},[360,4087,4088],{"class":362,"line":3443},[360,4089,2840],{"class":366},[360,4091,4092],{"class":362,"line":3462},[360,4093,2927],{"class":366},[360,4095,4096],{"class":362,"line":3467},[360,4097,847],{"class":366},[12,4099,4100,4101,4103],{},"J'ai donc rédigé une méthode ",[344,4102,2829],{}," qui remplit le tampon tant que le nombre d'octets lus est inférieur à la taille du\ntampon. On ne retourne 0 que dans le cas où la lecture du fichier est terminée.",[352,4105,4107],{"className":2114,"code":4106,"language":2116,"meta":291,"style":291},"fn read(&mut self, buf: &mut [u8]) -> io::Result\u003Cusize> {\n    let mut total_bytes_read = 0;\n\n    while total_bytes_read \u003C buf.len() {\n        let bytes_to_read = &mut buf[total_bytes_read..];\n        let bytes_read = self.read_some_bytes(bytes_to_read)?;\n        total_bytes_read += bytes_read;\n\n        if bytes_read == 0 {\n            break;\n        }\n    }\n\n    Ok(total_bytes_read)\n}\n",[344,4108,4109,4147,4162,4166,4184,4208,4231,4243,4247,4259,4266,4270,4274,4278,4289],{"__ignoreMap":291},[360,4110,4111,4113,4115,4117,4119,4121,4123,4125,4127,4129,4131,4133,4135,4137,4139,4141,4143,4145],{"class":362,"line":363},[360,4112,2166],{"class":574},[360,4114,2719],{"class":381},[360,4116,2287],{"class":366},[360,4118,2290],{"class":574},[360,4120,2726],{"class":662},[360,4122,2311],{"class":366},[360,4124,2731],{"class":578},[360,4126,2734],{"class":366},[360,4128,2290],{"class":574},[360,4130,2739],{"class":366},[360,4132,2742],{"class":662},[360,4134,2745],{"class":366},[360,4136,2748],{"class":662},[360,4138,666],{"class":366},[360,4140,2753],{"class":662},[360,4142,1358],{"class":366},[360,4144,2758],{"class":662},[360,4146,2711],{"class":366},[360,4148,4149,4151,4153,4156,4158,4160],{"class":362,"line":292},[360,4150,2177],{"class":574},[360,4152,2235],{"class":574},[360,4154,4155],{"class":578}," total_bytes_read",[360,4157,401],{"class":582},[360,4159,1457],{"class":414},[360,4161,735],{"class":366},[360,4163,4164],{"class":362,"line":375},[360,4165,372],{"emptyLinePlaceholder":320},[360,4167,4168,4171,4173,4176,4178,4180,4182],{"class":362,"line":433},[360,4169,4170],{"class":574},"    while",[360,4172,4155],{"class":578},[360,4174,4175],{"class":582}," \u003C",[360,4177,2797],{"class":578},[360,4179,31],{"class":366},[360,4181,2802],{"class":381},[360,4183,2172],{"class":366},[360,4185,4186,4188,4191,4193,4196,4198,4200,4202,4205],{"class":362,"line":478},[360,4187,2845],{"class":574},[360,4189,4190],{"class":578}," bytes_to_read",[360,4192,401],{"class":582},[360,4194,4195],{"class":366}," &",[360,4197,2290],{"class":574},[360,4199,2797],{"class":578},[360,4201,2385],{"class":366},[360,4203,4204],{"class":578},"total_bytes_read",[360,4206,4207],{"class":366},"..];\n",[360,4209,4210,4212,4215,4217,4219,4221,4223,4225,4228],{"class":362,"line":483},[360,4211,2845],{"class":574},[360,4213,4214],{"class":578}," bytes_read",[360,4216,401],{"class":582},[360,4218,2726],{"class":662},[360,4220,31],{"class":366},[360,4222,3623],{"class":381},[360,4224,671],{"class":366},[360,4226,4227],{"class":578},"bytes_to_read",[360,4229,4230],{"class":366},")?;\n",[360,4232,4233,4236,4239,4241],{"class":362,"line":489},[360,4234,4235],{"class":578},"        total_bytes_read",[360,4237,4238],{"class":582}," +=",[360,4240,4214],{"class":578},[360,4242,735],{"class":366},[360,4244,4245],{"class":362,"line":494},[360,4246,372],{"emptyLinePlaceholder":320},[360,4248,4249,4251,4253,4255,4257],{"class":362,"line":712},[360,4250,2780],{"class":574},[360,4252,4214],{"class":578},[360,4254,3934],{"class":582},[360,4256,1457],{"class":414},[360,4258,896],{"class":366},[360,4260,4261,4264],{"class":362,"line":331},[360,4262,4263],{"class":574},"            break",[360,4265,735],{"class":366},[360,4267,4268],{"class":362,"line":762},[360,4269,2840],{"class":366},[360,4271,4272],{"class":362,"line":781},[360,4273,2927],{"class":366},[360,4275,4276],{"class":362,"line":804},[360,4277,372],{"emptyLinePlaceholder":320},[360,4279,4280,4283,4285,4287],{"class":362,"line":817},[360,4281,4282],{"class":662},"    Ok",[360,4284,671],{"class":366},[360,4286,4204],{"class":578},[360,4288,2922],{"class":366},[360,4290,4291],{"class":362,"line":823},[360,4292,847],{"class":366},[1901,4294,4296],{"id":4295},"les-fichiers-dattributs","Les fichiers d'attributs",[12,4298,4299],{},"Les fichiers d'attributs sont d'abord des fichiers compressés en utilisant la méthode décrite précédemment. J'ai donc\nutilisé le Reader que j'ai écrit précédemment pour décompresser les fichiers au fur et à mesure de leur lecture.",[12,4301,4302],{},"Je me suis ensuite attaqué au décodage des fichiers d'attributs. En réécrivant le code, j'ai découvert que certains\nnombres étaient mal encodés, ce qui provoquait des erreurs de décodage que j'ai dû gérer avec plus de flexibilité.",[12,4304,4305,4306,4308,4309,4311,4312,4317],{},"Pour lire un ",[344,4307,2036],{},", j'ai ajouté un trait au trait ",[344,4310,2694],{},". Je me suis basé sur le ",[47,4313,4316],{"href":4314,"rel":4315},"https:\u002F\u002Fgithub.com\u002Fbackuppc\u002Fbackuppc-xs\u002Fblob\u002Fmaster\u002Fbpc_attrib.c#L548",[51],"code C de BackupPC",",\ntout en modifiant la philosophie pour répondre au fonctionnement d'un Reader Rust.",[352,4319,4321],{"className":2114,"code":4320,"language":2116,"meta":291,"style":291},"pub trait VarintRead: Read {\n    fn read_varint(&mut self) -> io::Result\u003Cu64> {\n        let mut result = 0;\n        let mut shift = 0;\n\n        loop {\n            let mut buf: [u8; 1] = [0u8; 1];\n            self.read_exact(&mut buf)?;\n\n            let byte = buf[0];\n            let val = (byte & 0x7F) as u64;\n            if shift >= 64 || val \u003C\u003C shift >> shift != val {\n                eprintln!(\"Varint too large: probably corrupted data\");\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    \"Varint too large: probably corrupted data\",\n                ));\n            }\n\n            result |= val \u003C\u003C shift;\n            if byte & 0x80 == 0 {\n                return Ok(result);\n            }\n            shift += 7;\n        }\n    }\n}\n",[344,4322,4323,4339,4367,4382,4397,4401,4408,4443,4460,4464,4481,4511,4542,4554,4575,4592,4599,4604,4608,4612,4628,4645,4658,4662,4674,4678,4682],{"__ignoreMap":291},[360,4324,4325,4327,4330,4333,4335,4337],{"class":362,"line":363},[360,4326,3637],{"class":574},[360,4328,4329],{"class":574}," trait",[360,4331,4332],{"class":662}," VarintRead",[360,4334,2691],{"class":366},[360,4336,2694],{"class":662},[360,4338,896],{"class":366},[360,4340,4341,4343,4346,4348,4350,4352,4354,4356,4358,4360,4362,4365],{"class":362,"line":292},[360,4342,2716],{"class":574},[360,4344,4345],{"class":381}," read_varint",[360,4347,2287],{"class":366},[360,4349,2290],{"class":574},[360,4351,2726],{"class":662},[360,4353,3052],{"class":366},[360,4355,2748],{"class":662},[360,4357,666],{"class":366},[360,4359,2753],{"class":662},[360,4361,1358],{"class":366},[360,4363,4364],{"class":662},"u64",[360,4366,2711],{"class":366},[360,4368,4369,4371,4373,4376,4378,4380],{"class":362,"line":375},[360,4370,2845],{"class":574},[360,4372,2235],{"class":574},[360,4374,4375],{"class":578}," result",[360,4377,401],{"class":582},[360,4379,1457],{"class":414},[360,4381,735],{"class":366},[360,4383,4384,4386,4388,4391,4393,4395],{"class":362,"line":433},[360,4385,2845],{"class":574},[360,4387,2235],{"class":574},[360,4389,4390],{"class":578}," shift",[360,4392,401],{"class":582},[360,4394,1457],{"class":414},[360,4396,735],{"class":366},[360,4398,4399],{"class":362,"line":478},[360,4400,372],{"emptyLinePlaceholder":320},[360,4402,4403,4406],{"class":362,"line":483},[360,4404,4405],{"class":574},"        loop",[360,4407,896],{"class":366},[360,4409,4410,4412,4414,4416,4419,4421,4424,4426,4428,4430,4432,4434,4436,4438,4440],{"class":362,"line":489},[360,4411,2857],{"class":574},[360,4413,2235],{"class":574},[360,4415,2797],{"class":578},[360,4417,4418],{"class":366},": [",[360,4420,2742],{"class":662},[360,4422,4423],{"class":366},"; ",[360,4425,1944],{"class":414},[360,4427,2390],{"class":366},[360,4429,583],{"class":582},[360,4431,2739],{"class":366},[360,4433,1344],{"class":414},[360,4435,2742],{"class":662},[360,4437,4423],{"class":366},[360,4439,1944],{"class":414},[360,4441,4442],{"class":366},"];\n",[360,4444,4445,4447,4449,4452,4454,4456,4458],{"class":362,"line":494},[360,4446,3446],{"class":662},[360,4448,31],{"class":366},[360,4450,4451],{"class":381},"read_exact",[360,4453,2287],{"class":366},[360,4455,2290],{"class":574},[360,4457,2797],{"class":578},[360,4459,4230],{"class":366},[360,4461,4462],{"class":362,"line":712},[360,4463,372],{"emptyLinePlaceholder":320},[360,4465,4466,4468,4471,4473,4475,4477,4479],{"class":362,"line":331},[360,4467,2857],{"class":574},[360,4469,4470],{"class":578}," byte",[360,4472,401],{"class":582},[360,4474,2797],{"class":578},[360,4476,2385],{"class":366},[360,4478,1344],{"class":414},[360,4480,4442],{"class":366},[360,4482,4483,4485,4488,4490,4492,4495,4498,4501,4503,4506,4509],{"class":362,"line":762},[360,4484,2857],{"class":574},[360,4486,4487],{"class":578}," val",[360,4489,401],{"class":582},[360,4491,743],{"class":366},[360,4493,4494],{"class":578},"byte",[360,4496,4497],{"class":366}," & ",[360,4499,4500],{"class":414},"0x7F",[360,4502,3972],{"class":366},[360,4504,4505],{"class":574},"as",[360,4507,4508],{"class":662}," u64",[360,4510,735],{"class":366},[360,4512,4513,4515,4517,4520,4522,4524,4526,4529,4531,4534,4536,4538,4540],{"class":362,"line":781},[360,4514,3284],{"class":574},[360,4516,4390],{"class":578},[360,4518,4519],{"class":582}," >=",[360,4521,1292],{"class":414},[360,4523,2401],{"class":582},[360,4525,4487],{"class":578},[360,4527,4528],{"class":582}," \u003C\u003C",[360,4530,4390],{"class":578},[360,4532,4533],{"class":582}," >>",[360,4535,4390],{"class":578},[360,4537,3901],{"class":582},[360,4539,4487],{"class":578},[360,4541,896],{"class":366},[360,4543,4544,4547,4549,4552],{"class":362,"line":804},[360,4545,4546],{"class":381},"                eprintln!",[360,4548,671],{"class":366},[360,4550,4551],{"class":397},"\"Varint too large: probably corrupted data\"",[360,4553,801],{"class":366},[360,4555,4556,4558,4560,4562,4564,4566,4569,4571,4573],{"class":362,"line":817},[360,4557,3871],{"class":574},[360,4559,3874],{"class":662},[360,4561,671],{"class":366},[360,4563,2748],{"class":662},[360,4565,666],{"class":366},[360,4567,4568],{"class":662},"Error",[360,4570,666],{"class":366},[360,4572,2221],{"class":381},[360,4574,1395],{"class":366},[360,4576,4577,4580,4582,4585,4587,4590],{"class":362,"line":823},[360,4578,4579],{"class":662},"                    io",[360,4581,666],{"class":366},[360,4583,4584],{"class":662},"ErrorKind",[360,4586,666],{"class":366},[360,4588,4589],{"class":662},"InvalidData",[360,4591,2968],{"class":366},[360,4593,4594,4597],{"class":362,"line":844},[360,4595,4596],{"class":397},"                    \"Varint too large: probably corrupted data\"",[360,4598,2968],{"class":366},[360,4600,4601],{"class":362,"line":1441},[360,4602,4603],{"class":366},"                ));\n",[360,4605,4606],{"class":362,"line":1462},[360,4607,3435],{"class":366},[360,4609,4610],{"class":362,"line":1485},[360,4611,372],{"emptyLinePlaceholder":320},[360,4613,4614,4617,4620,4622,4624,4626],{"class":362,"line":1497},[360,4615,4616],{"class":578},"            result",[360,4618,4619],{"class":582}," |=",[360,4621,4487],{"class":578},[360,4623,4528],{"class":582},[360,4625,4390],{"class":578},[360,4627,735],{"class":366},[360,4629,4630,4632,4634,4636,4639,4641,4643],{"class":362,"line":3161},[360,4631,3284],{"class":574},[360,4633,4470],{"class":578},[360,4635,4497],{"class":366},[360,4637,4638],{"class":414},"0x80",[360,4640,3934],{"class":582},[360,4642,1457],{"class":414},[360,4644,896],{"class":366},[360,4646,4647,4649,4651,4653,4656],{"class":362,"line":3167},[360,4648,3871],{"class":574},[360,4650,3773],{"class":662},[360,4652,671],{"class":366},[360,4654,4655],{"class":578},"result",[360,4657,801],{"class":366},[360,4659,4660],{"class":362,"line":3194},[360,4661,3435],{"class":366},[360,4663,4664,4667,4669,4672],{"class":362,"line":3224},[360,4665,4666],{"class":578},"            shift",[360,4668,4238],{"class":582},[360,4670,4671],{"class":414}," 7",[360,4673,735],{"class":366},[360,4675,4676],{"class":362,"line":3239},[360,4677,2840],{"class":366},[360,4679,4680],{"class":362,"line":3256},[360,4681,2927],{"class":366},[360,4683,4684],{"class":362,"line":3276},[360,4685,847],{"class":366},[12,4687,4688,4689,4692],{},"Au cours de mes tests pour lire les fichiers d'attributs du pool, j'ai rencontré de nombreuses erreurs de décodage (avec\nle message ci-dessus : ",[105,4690,4691],{},"Varint too large: probably corrupted data","). Ce qui est rassurant, c'est que cela n'est pas lié\nà mon algorithme. BackupPC rencontre le même problème lors du décodage de ses propres fichiers (ce qui se traduit dans\nson cas par une date en janvier 1970) :",[12,4694,4695],{},[69,4696],{"src":4697,"alt":4698,"className":4699},"\u002FWoodstock\u002F2024-03-14_pr_backuppc_pool_1.png","Fichier corrompu",[73],[12,4701,4702],{},"La question est donc : mes données sont-elles corrompues ou s'agit-il d'un bug de BackupPC ? Je ne vais pas obtenir de\nréponse à cette question.",[1901,4704,4706],{"id":4705},"la-lecture-des-machines-et-des-sauvegardes","La lecture des machines et des sauvegardes",[12,4708,4709],{},"La partie la plus ardue est terminée.",[140,4711,4712,4717,4723],{},[143,4713,4714,4715,31],{},"Pour lister les machines, il suffit de lister les dossiers du répertoire ",[344,4716,2016],{},[143,4718,4719,4720,31],{},"Pour lister les sauvegardes, il faut lire le fichier texte (tsv) ",[344,4721,4722],{},"__TOPDIR__\u002Fpc\u002F\u003Cmachine>\u002Fbackups",[143,4724,4725,4726,31],{},"Pour lister les dossiers partagés, il faut lister les dossiers du répertoire ",[344,4727,4728],{},"__TOPDIR__\u002Fpc\u002F\u003Cmachine>\u002F\u003Cbackup>",[12,4730,4731,4732,31],{},"J'ai écrit ces trois méthodes dans ce fichier, que je vous invite à consulter. Il n'est pas très complexe : ",[47,4733,4736],{"href":4734,"rel":4735},"https:\u002F\u002Fgogs.shadoware.org\u002Fphoenix\u002Fbackuppc_pool\u002Fsrc\u002Fbranch\u002Fmaster\u002Fsrc\u002Fhosts.rs",[51],"hosts.rs",[12,4738,4739],{},"Je peux donc affirmer que j'ai réussi à lire les fichiers du pool de BackupPC. Pour mieux visualiser le résultat, j'ai\ndécidé de me lancer un défi supplémentaire : écrire un pilote FUSE pour visualiser le pool de stockage.",[1901,4741,4743],{"id":4742},"le-driver-fuse","Le driver FUSE",[12,4745,4746],{},"L'étape suivante consiste donc à développer un pilote FUSE qui intègre tout cela. Il s'agit de lire les fichiers\nd'attributs pour reconstituer la structure du système de fichiers (qui sont dans le pool et compressés), et de lire les\nfichiers compressés pour les données.",[12,4748,4749,4750,31],{},"Pour gérer la partie du système de fichiers, j'ai utilisé la bibliothèque ",[47,4751,4754],{"href":4752,"rel":4753},"https:\u002F\u002Fdocs.rs\u002Ffuser\u002Flatest\u002Ffuser\u002Findex.html",[51],"fuser",[12,4756,4757],{},"Le cœur du système ayant été développé, la partie système de fichiers consiste principalement à décoder le chemin fourni\npar FUSE, à décompressé et lire le fichier d'attributs. Dans le cas où l'utilisateur souhaite lire le contenu d'un\nfichier, il faut décompresser le fichier compressé.",[12,4759,4760],{},"J'ai donc la partie système de fichiers qui gère les requêtes FUSE et les transmet à la partie vue (avec un système de\ncache), et la partie vue qui prend un chemin et le transforme dans le format suivant en appelant les différentes\nméthodes précédentes :",[140,4762,4763,4766,4769,4772],{},[143,4764,4765],{},"nom de l'hôte",[143,4767,4768],{},"numéro de sauvegarde",[143,4770,4771],{},"chemin du partage",[143,4773,4774],{},"chemin",[12,4776,4777,4778,4783],{},"Le décodage est réalisé dans le fichier ",[47,4779,4782],{"href":4780,"rel":4781},"https:\u002F\u002Fgogs.shadoware.org\u002Fphoenix\u002Fbackuppc_pool\u002Fsrc\u002Fbranch\u002Fmaster\u002Fsrc\u002Fview.rs",[51],"view.rs",".\nPour cette partie, j'ai ajouté des tests unitaires. Ces tests unitaires m'ont permis d'itérer plus rapidement pour\nconstruire le système de fichiers (sans avoir à monter ce dernier à chaque fois).",[12,4785,4786,4787,4789,4790,4793],{},"On appelle la méthode avec le chemin découpé à chaque ",[344,4788,768],{}," pour obtenir les différents éléments du chemin (sous forme de\n",[344,4791,4792],{},"&[&str]",").:",[352,4795,4797],{"className":2114,"code":4796,"language":2116,"meta":291,"style":291},"pub fn list(&self, path: &[&str]) -> Result\u003CVec\u003CFileAttributes>> {\n    match path.len() {\n",[344,4798,4799,4840],{"__ignoreMap":291},[360,4800,4801,4803,4806,4809,4811,4813,4815,4818,4821,4824,4826,4828,4830,4832,4834,4837],{"class":362,"line":363},[360,4802,3637],{"class":574},[360,4804,4805],{"class":574}," fn",[360,4807,4808],{"class":381}," list",[360,4810,2287],{"class":366},[360,4812,3479],{"class":662},[360,4814,2311],{"class":366},[360,4816,4817],{"class":578},"path",[360,4819,4820],{"class":366},": &[&",[360,4822,4823],{"class":662},"str",[360,4825,2745],{"class":366},[360,4827,2753],{"class":662},[360,4829,1358],{"class":366},[360,4831,2995],{"class":662},[360,4833,1358],{"class":366},[360,4835,4836],{"class":662},"FileAttributes",[360,4838,4839],{"class":366},">> {\n",[360,4841,4842,4845,4848,4850,4852],{"class":362,"line":292},[360,4843,4844],{"class":574},"    match",[360,4846,4847],{"class":578}," path",[360,4849,31],{"class":366},[360,4851,2802],{"class":381},[360,4853,2172],{"class":366},[12,4855,4856],{},"On commence d'abord par examiner le nombre d'éléments dans le chemin. Si nous n'avons aucun élément, cela signifie que\nnous sommes à la racine et que nous souhaitons obtenir la liste des machines.",[352,4858,4860],{"className":2114,"code":4859,"language":2116,"meta":291,"style":291},"        0 => {\n            let hosts = self.hosts.list_hosts()?;\n            Ok(hosts.into_iter().map(FileAttributes::from_host).collect())\n        }\n",[344,4861,4862,4870,4889,4924],{"__ignoreMap":291},[360,4863,4864,4867],{"class":362,"line":363},[360,4865,4866],{"class":414},"        0",[360,4868,4869],{"class":366}," => {\n",[360,4871,4872,4874,4877,4879,4881,4884,4887],{"class":362,"line":292},[360,4873,2857],{"class":574},[360,4875,4876],{"class":578}," hosts",[360,4878,401],{"class":582},[360,4880,2726],{"class":662},[360,4882,4883],{"class":366},".hosts.",[360,4885,4886],{"class":381},"list_hosts",[360,4888,2873],{"class":366},[360,4890,4891,4893,4895,4898,4900,4903,4905,4908,4910,4912,4914,4917,4919,4922],{"class":362,"line":375},[360,4892,3837],{"class":662},[360,4894,671],{"class":366},[360,4896,4897],{"class":578},"hosts",[360,4899,31],{"class":366},[360,4901,4902],{"class":381},"into_iter",[360,4904,3487],{"class":366},[360,4906,4907],{"class":381},"map",[360,4909,671],{"class":366},[360,4911,4836],{"class":662},[360,4913,666],{"class":366},[360,4915,4916],{"class":578},"from_host",[360,4918,2198],{"class":366},[360,4920,4921],{"class":381},"collect",[360,4923,3492],{"class":366},[360,4925,4926],{"class":362,"line":433},[360,4927,2840],{"class":366},[12,4929,4930],{},"Si nous avons un seul élément, alors c'est le nom de la machine. Nous souhaitons donc récupérer la liste des sauvegardes\nassociées à cette machine.",[352,4932,4934],{"className":2114,"code":4933,"language":2116,"meta":291,"style":291},"        1 => {\n            let backups = self.hosts.list_backups(path[0]);\n            match backups {\n                Ok(backups) => Ok(backups\n                    .into_iter()\n                    .map(|a| FileAttributes::from_backup(&a))\n                    .collect()),\n                Err(err) => {\n                    \u002F\u002F If the file isn't found, it's because we should return empty vec\n                    if let Some(io_err) = err.downcast_ref::\u003Cstd::io::Error>() {\n                        if io_err.kind() == std::io::ErrorKind::NotFound {\n                            Ok(Vec::new())\n                        } else {\n                            Err(err)\n                        }\n                    } else {\n                        Err(err)\n                    }\n                }\n            }\n        }\n",[344,4935,4936,4943,4970,4979,4999,5009,5039,5048,5060,5065,5108,5142,5157,5166,5177,5182,5191,5202,5207,5211,5215],{"__ignoreMap":291},[360,4937,4938,4941],{"class":362,"line":363},[360,4939,4940],{"class":414},"        1",[360,4942,4869],{"class":366},[360,4944,4945,4947,4950,4952,4954,4956,4959,4961,4963,4965,4967],{"class":362,"line":292},[360,4946,2857],{"class":574},[360,4948,4949],{"class":578}," backups",[360,4951,401],{"class":582},[360,4953,2726],{"class":662},[360,4955,4883],{"class":366},[360,4957,4958],{"class":381},"list_backups",[360,4960,671],{"class":366},[360,4962,4817],{"class":578},[360,4964,2385],{"class":366},[360,4966,1344],{"class":414},[360,4968,4969],{"class":366},"]);\n",[360,4971,4972,4975,4977],{"class":362,"line":375},[360,4973,4974],{"class":574},"            match",[360,4976,4949],{"class":578},[360,4978,896],{"class":366},[360,4980,4981,4984,4986,4988,4991,4994,4996],{"class":362,"line":433},[360,4982,4983],{"class":662},"                Ok",[360,4985,671],{"class":366},[360,4987,1938],{"class":578},[360,4989,4990],{"class":366},") => ",[360,4992,4993],{"class":662},"Ok",[360,4995,671],{"class":366},[360,4997,4998],{"class":578},"backups\n",[360,5000,5001,5004,5006],{"class":362,"line":478},[360,5002,5003],{"class":366},"                    .",[360,5005,4902],{"class":381},[360,5007,5008],{"class":366},"()\n",[360,5010,5011,5013,5015,5017,5020,5022,5024,5027,5029,5032,5034,5036],{"class":362,"line":483},[360,5012,5003],{"class":366},[360,5014,4907],{"class":381},[360,5016,671],{"class":366},[360,5018,5019],{"class":582},"|",[360,5021,47],{"class":578},[360,5023,5019],{"class":582},[360,5025,5026],{"class":662}," FileAttributes",[360,5028,666],{"class":366},[360,5030,5031],{"class":381},"from_backup",[360,5033,2287],{"class":366},[360,5035,47],{"class":578},[360,5037,5038],{"class":366},"))\n",[360,5040,5041,5043,5045],{"class":362,"line":489},[360,5042,5003],{"class":366},[360,5044,4921],{"class":381},[360,5046,5047],{"class":366},"()),\n",[360,5049,5050,5053,5055,5058],{"class":362,"line":494},[360,5051,5052],{"class":662},"                Err",[360,5054,671],{"class":366},[360,5056,5057],{"class":578},"err",[360,5059,3845],{"class":366},[360,5061,5062],{"class":362,"line":712},[360,5063,5064],{"class":644},"                    \u002F\u002F If the file isn't found, it's because we should return empty vec\n",[360,5066,5067,5070,5072,5074,5076,5079,5081,5083,5086,5088,5091,5094,5097,5099,5101,5103,5105],{"class":362,"line":331},[360,5068,5069],{"class":574},"                    if",[360,5071,3962],{"class":574},[360,5073,3453],{"class":662},[360,5075,671],{"class":366},[360,5077,5078],{"class":578},"io_err",[360,5080,3972],{"class":366},[360,5082,583],{"class":582},[360,5084,5085],{"class":578}," err",[360,5087,31],{"class":366},[360,5089,5090],{"class":381},"downcast_ref",[360,5092,5093],{"class":366},"::\u003C",[360,5095,5096],{"class":662},"std",[360,5098,666],{"class":366},[360,5100,2748],{"class":662},[360,5102,666],{"class":366},[360,5104,4568],{"class":662},[360,5106,5107],{"class":366},">() {\n",[360,5109,5110,5113,5116,5118,5121,5123,5125,5127,5129,5131,5133,5135,5137,5140],{"class":362,"line":762},[360,5111,5112],{"class":574},"                        if",[360,5114,5115],{"class":578}," io_err",[360,5117,31],{"class":366},[360,5119,5120],{"class":381},"kind",[360,5122,2805],{"class":366},[360,5124,2393],{"class":582},[360,5126,2145],{"class":662},[360,5128,666],{"class":366},[360,5130,2748],{"class":662},[360,5132,666],{"class":366},[360,5134,4584],{"class":662},[360,5136,666],{"class":366},[360,5138,5139],{"class":662},"NotFound",[360,5141,896],{"class":366},[360,5143,5144,5147,5149,5151,5153,5155],{"class":362,"line":781},[360,5145,5146],{"class":662},"                            Ok",[360,5148,671],{"class":366},[360,5150,2995],{"class":662},[360,5152,666],{"class":366},[360,5154,2221],{"class":381},[360,5156,3492],{"class":366},[360,5158,5159,5162,5164],{"class":362,"line":804},[360,5160,5161],{"class":366},"                        } ",[360,5163,2488],{"class":574},[360,5165,896],{"class":366},[360,5167,5168,5171,5173,5175],{"class":362,"line":817},[360,5169,5170],{"class":662},"                            Err",[360,5172,671],{"class":366},[360,5174,5057],{"class":578},[360,5176,2922],{"class":366},[360,5178,5179],{"class":362,"line":823},[360,5180,5181],{"class":366},"                        }\n",[360,5183,5184,5187,5189],{"class":362,"line":844},[360,5185,5186],{"class":366},"                    } ",[360,5188,2488],{"class":574},[360,5190,896],{"class":366},[360,5192,5193,5196,5198,5200],{"class":362,"line":1441},[360,5194,5195],{"class":662},"                        Err",[360,5197,671],{"class":366},[360,5199,5057],{"class":578},[360,5201,2922],{"class":366},[360,5203,5204],{"class":362,"line":1462},[360,5205,5206],{"class":366},"                    }\n",[360,5208,5209],{"class":362,"line":1485},[360,5210,3429],{"class":366},[360,5212,5213],{"class":362,"line":1497},[360,5214,3435],{"class":366},[360,5216,5217],{"class":362,"line":3161},[360,5218,2840],{"class":366},[12,5220,5221,5222,5225,5226,5228],{},"Si nous avons plus de deux éléments, alors nous souhaitons retourner au moins le partage, voire les fichiers à\nsauvegarder. Le problème est que le nom du partage ",[344,5223,5224],{},"share"," peut lui-même contenir des ",[344,5227,768],{},". Il peut donc être composé de\nplusieurs éléments.",[12,5230,5231,5232,5235],{},"Le but de la méthode ",[344,5233,5234],{},"list_shares_of"," est de retourner le partage si ce dernier est un partage valide, ainsi que la\npartie du chemin qui suit le partage.",[352,5237,5239],{"className":2114,"code":5238,"language":2116,"meta":291,"style":291},"        _ => {\n            let (shares, selected_share, share_size) =\n                self.list_shares_of(path[0], path[1].parse::\u003Cu32>().unwrap_or(0), &path[2..])?;\n\n            let shares = shares.into_iter().map(FileAttributes::from_share).collect();\n",[344,5240,5241,5248,5272,5330,5334],{"__ignoreMap":291},[360,5242,5243,5246],{"class":362,"line":363},[360,5244,5245],{"class":578},"        _",[360,5247,4869],{"class":366},[360,5249,5250,5252,5254,5257,5259,5262,5264,5267,5269],{"class":362,"line":292},[360,5251,2857],{"class":574},[360,5253,743],{"class":366},[360,5255,5256],{"class":578},"shares",[360,5258,2311],{"class":366},[360,5260,5261],{"class":578},"selected_share",[360,5263,2311],{"class":366},[360,5265,5266],{"class":578},"share_size",[360,5268,3972],{"class":366},[360,5270,5271],{"class":582},"=\n",[360,5273,5274,5276,5278,5280,5282,5284,5286,5288,5291,5293,5295,5297,5300,5303,5305,5308,5311,5314,5316,5318,5321,5323,5325,5327],{"class":362,"line":375},[360,5275,3308],{"class":662},[360,5277,31],{"class":366},[360,5279,5234],{"class":381},[360,5281,671],{"class":366},[360,5283,4817],{"class":578},[360,5285,2385],{"class":366},[360,5287,1344],{"class":414},[360,5289,5290],{"class":366},"], ",[360,5292,4817],{"class":578},[360,5294,2385],{"class":366},[360,5296,1944],{"class":414},[360,5298,5299],{"class":366},"].",[360,5301,5302],{"class":381},"parse",[360,5304,5093],{"class":366},[360,5306,5307],{"class":662},"u32",[360,5309,5310],{"class":366},">().",[360,5312,5313],{"class":381},"unwrap_or",[360,5315,671],{"class":366},[360,5317,1344],{"class":414},[360,5319,5320],{"class":366},"), &",[360,5322,4817],{"class":578},[360,5324,2385],{"class":366},[360,5326,795],{"class":414},[360,5328,5329],{"class":366},"..])?;\n",[360,5331,5332],{"class":362,"line":433},[360,5333,372],{"emptyLinePlaceholder":320},[360,5335,5336,5338,5341,5343,5345,5347,5349,5351,5353,5355,5357,5359,5362,5364,5366],{"class":362,"line":478},[360,5337,2857],{"class":574},[360,5339,5340],{"class":578}," shares",[360,5342,401],{"class":582},[360,5344,5340],{"class":578},[360,5346,31],{"class":366},[360,5348,4902],{"class":381},[360,5350,3487],{"class":366},[360,5352,4907],{"class":381},[360,5354,671],{"class":366},[360,5356,4836],{"class":662},[360,5358,666],{"class":366},[360,5360,5361],{"class":578},"from_share",[360,5363,2198],{"class":366},[360,5365,4921],{"class":381},[360,5367,2204],{"class":366},[12,5369,5370,5371,5374],{},"Une fois que nous avons le nom de la machine, le numéro de la sauvegarde et le partage, nous pouvons appeler la méthode\n",[344,5372,5373],{},"list_file_from_dir"," pour récupérer les fichiers du sous-dossier du partage.",[352,5376,5378],{"className":2114,"code":5377,"language":2116,"meta":291,"style":291},"            match selected_share {\n                None => Ok(shares),\n                Some(selected_share) => self.list_file_from_dir(\n                    path[0],\n                    path[1].parse::\u003Cu32>().unwrap_or(0),\n                    &selected_share,\n                    &path[(2 + share_size)..].join(\"\u002F\"),\n                ),\n            }\n        }\n    }\n}\n",[344,5379,5380,5389,5406,5425,5437,5463,5472,5501,5506,5510,5514,5518],{"__ignoreMap":291},[360,5381,5382,5384,5387],{"class":362,"line":363},[360,5383,4974],{"class":574},[360,5385,5386],{"class":578}," selected_share",[360,5388,896],{"class":366},[360,5390,5391,5394,5397,5399,5401,5403],{"class":362,"line":292},[360,5392,5393],{"class":662},"                None",[360,5395,5396],{"class":366}," => ",[360,5398,4993],{"class":662},[360,5400,671],{"class":366},[360,5402,5256],{"class":578},[360,5404,5405],{"class":366},"),\n",[360,5407,5408,5411,5413,5415,5417,5419,5421,5423],{"class":362,"line":375},[360,5409,5410],{"class":662},"                Some",[360,5412,671],{"class":366},[360,5414,5261],{"class":578},[360,5416,4990],{"class":366},[360,5418,3479],{"class":662},[360,5420,31],{"class":366},[360,5422,5373],{"class":381},[360,5424,1395],{"class":366},[360,5426,5427,5430,5432,5434],{"class":362,"line":433},[360,5428,5429],{"class":578},"                    path",[360,5431,2385],{"class":366},[360,5433,1344],{"class":414},[360,5435,5436],{"class":366},"],\n",[360,5438,5439,5441,5443,5445,5447,5449,5451,5453,5455,5457,5459,5461],{"class":362,"line":478},[360,5440,5429],{"class":578},[360,5442,2385],{"class":366},[360,5444,1944],{"class":414},[360,5446,5299],{"class":366},[360,5448,5302],{"class":381},[360,5450,5093],{"class":366},[360,5452,5307],{"class":662},[360,5454,5310],{"class":366},[360,5456,5313],{"class":381},[360,5458,671],{"class":366},[360,5460,1344],{"class":414},[360,5462,5405],{"class":366},[360,5464,5465,5468,5470],{"class":362,"line":483},[360,5466,5467],{"class":366},"                    &",[360,5469,5261],{"class":578},[360,5471,2968],{"class":366},[360,5473,5474,5476,5478,5481,5483,5486,5488,5491,5494,5496,5499],{"class":362,"line":489},[360,5475,5467],{"class":366},[360,5477,4817],{"class":578},[360,5479,5480],{"class":366},"[(",[360,5482,795],{"class":414},[360,5484,5485],{"class":366}," + ",[360,5487,5266],{"class":578},[360,5489,5490],{"class":366},")..].",[360,5492,5493],{"class":381},"join",[360,5495,671],{"class":366},[360,5497,5498],{"class":397},"\"\u002F\"",[360,5500,5405],{"class":366},[360,5502,5503],{"class":362,"line":494},[360,5504,5505],{"class":366},"                ),\n",[360,5507,5508],{"class":362,"line":712},[360,5509,3435],{"class":366},[360,5511,5512],{"class":362,"line":331},[360,5513,2840],{"class":366},[360,5515,5516],{"class":362,"line":762},[360,5517,2927],{"class":366},[360,5519,5520],{"class":362,"line":781},[360,5521,847],{"class":366},[12,5523,5524,5525,5530],{},"Enfin, pour la partie FUSE, je vous invite à consulter le fichier ",[47,5526,5529],{"href":5527,"rel":5528},"https:\u002F\u002Fgogs.shadoware.org\u002Fphoenix\u002Fbackuppc_pool\u002Fsrc\u002Fbranch\u002Fmaster\u002Fsrc\u002Ffilesystem.rs",[51],"filesystem.rs",".\nCe fichier fait simplement le lien entre la partie FUSE et la partie vue.",[12,5532,5533],{},"Sur la partie FUSE, j'ai ajouté un cache pour éviter de lire plusieurs fois le même fichier (d'attributs) dans le pool.",[12,5535,5536,5537,5540],{},"Une fois le système de fichiers construit, il était nécessaire de le tester avec des tests réels. Le premier test a\nconsisté à parcourir l'ensemble du système de fichiers pour vérifier si la partie attribut fonctionnait correctement.\nPour cela, j'ai utilisé le programme ",[344,5538,5539],{},"filelight",". Ce programme permet de parcourir le système de fichiers et de\nvisualiser la taille des fichiers.",[12,5542,5543],{},"Voici un exemple sur une partie de la sauvegarde :",[12,5545,5546],{},[69,5547],{"src":5548,"alt":5549,"className":5550},"\u002FWoodstock\u002Ffilelight_localhost.png","Filelight",[73],[12,5552,5553],{},"Enfin, pour tester la capacité du programme à lire tous les fichiers du système de fichiers, j'ai écrit un petit script\nshell.",[352,5555,5557],{"className":565,"code":5556,"language":567,"meta":291,"style":291},"#!\u002Fbin\u002Fbash\n\n# Fichiers de sortie\noutput_file=\"md5sums.txt\"\nerror_file=\"errors.txt\"\n\n# Parcourir tous les fichiers du système de fichiers\nfind \u002Fhome\u002Fphoenix\u002Ftmp\u002Ftest -type f -print0 | while IFS= read -r -d '' file; do\n    # Essayer de calculer le hash MD5 du fichier\n    if md5sum \"$file\" >> \"$output_file\"; then\n        echo \"Processed $file\"\n    else\n        # Si le fichier ne peut pas être lu, écrire le nom du fichier dans le fichier d'erreur\n        echo \"Failed to process $file\" >> \"$error_file\"\n    fi\ndone\n",[344,5558,5559,5564,5568,5573,5583,5593,5597,5602,5648,5653,5685,5698,5703,5708,5728,5733],{"__ignoreMap":291},[360,5560,5561],{"class":362,"line":363},[360,5562,5563],{"class":644},"#!\u002Fbin\u002Fbash\n",[360,5565,5566],{"class":362,"line":292},[360,5567,372],{"emptyLinePlaceholder":320},[360,5569,5570],{"class":362,"line":375},[360,5571,5572],{"class":644},"# Fichiers de sortie\n",[360,5574,5575,5578,5580],{"class":362,"line":433},[360,5576,5577],{"class":578},"output_file",[360,5579,583],{"class":582},[360,5581,5582],{"class":397},"\"md5sums.txt\"\n",[360,5584,5585,5588,5590],{"class":362,"line":478},[360,5586,5587],{"class":578},"error_file",[360,5589,583],{"class":582},[360,5591,5592],{"class":397},"\"errors.txt\"\n",[360,5594,5595],{"class":362,"line":483},[360,5596,372],{"emptyLinePlaceholder":320},[360,5598,5599],{"class":362,"line":489},[360,5600,5601],{"class":644},"# Parcourir tous les fichiers du système de fichiers\n",[360,5603,5604,5607,5610,5613,5615,5618,5621,5624,5627,5629,5631,5634,5637,5640,5643,5645],{"class":362,"line":494},[360,5605,5606],{"class":381},"find",[360,5608,5609],{"class":397}," \u002Fhome\u002Fphoenix\u002Ftmp\u002Ftest",[360,5611,5612],{"class":414}," -type",[360,5614,2180],{"class":397},[360,5616,5617],{"class":414}," -print0",[360,5619,5620],{"class":366}," | ",[360,5622,5623],{"class":574},"while",[360,5625,5626],{"class":578}," IFS",[360,5628,583],{"class":582},[360,5630,2719],{"class":582},[360,5632,5633],{"class":414}," -r",[360,5635,5636],{"class":414}," -d",[360,5638,5639],{"class":397}," ''",[360,5641,5642],{"class":397}," file",[360,5644,4423],{"class":366},[360,5646,5647],{"class":574},"do\n",[360,5649,5650],{"class":362,"line":712},[360,5651,5652],{"class":644},"    # Essayer de calculer le hash MD5 du fichier\n",[360,5654,5655,5658,5661,5664,5667,5670,5673,5675,5678,5680,5682],{"class":362,"line":331},[360,5656,5657],{"class":574},"    if",[360,5659,5660],{"class":381}," md5sum",[360,5662,5663],{"class":397}," \"",[360,5665,5666],{"class":578},"$file",[360,5668,5669],{"class":397},"\"",[360,5671,5672],{"class":366}," >> ",[360,5674,5669],{"class":397},[360,5676,5677],{"class":578},"$output_file",[360,5679,5669],{"class":397},[360,5681,4423],{"class":366},[360,5683,5684],{"class":574},"then\n",[360,5686,5687,5690,5693,5695],{"class":362,"line":762},[360,5688,5689],{"class":582},"        echo",[360,5691,5692],{"class":397}," \"Processed ",[360,5694,5666],{"class":578},[360,5696,5697],{"class":397},"\"\n",[360,5699,5700],{"class":362,"line":781},[360,5701,5702],{"class":574},"    else\n",[360,5704,5705],{"class":362,"line":804},[360,5706,5707],{"class":644},"        # Si le fichier ne peut pas être lu, écrire le nom du fichier dans le fichier d'erreur\n",[360,5709,5710,5712,5715,5717,5719,5721,5723,5726],{"class":362,"line":817},[360,5711,5689],{"class":582},[360,5713,5714],{"class":397}," \"Failed to process ",[360,5716,5666],{"class":578},[360,5718,5669],{"class":397},[360,5720,5672],{"class":366},[360,5722,5669],{"class":397},[360,5724,5725],{"class":578},"$error_file",[360,5727,5697],{"class":397},[360,5729,5730],{"class":362,"line":823},[360,5731,5732],{"class":574},"    fi\n",[360,5734,5735],{"class":362,"line":844},[360,5736,5737],{"class":574},"done\n",[12,5739,5740],{},"J'ai récemment commencé à développer un autre programme en Rust qui utilise la notion de multithreading.",[1901,5742,5744],{"id":5743},"les-avantages-de-rust","Les avantages de Rust",[12,5746,5747],{},"En travaillant sur ce petit programme Rust, j'ai apprécié plusieurs aspects du langage. Rust offre la possibilité\nd'écrire du code de bas niveau sans avoir à gérer la mémoire comme en C, ce qui m'a procuré un sentiment de sécurité. De\nplus, la documentation de Rust est bien conçue et m'a permis de progresser rapidement.",[12,5749,5750,5751,5756],{},"J'ai également trouvé la syntaxe de Rust très lisible, à condition de ne pas utiliser les durées de vie. La présence de\nnombreux packages (crates) sur ",[47,5752,5755],{"href":5753,"rel":5754},"https:\u002F\u002Fcrates.io\u002F",[51],"crates.io"," facilite le développement rapide de fonctionnalités.",[12,5758,5759],{},"Clippy, un outil de vérification du code Rust, m'a été très utile. Il donne des conseils pour améliorer le code, ce qui\nm'a aidé à progresser, même s'il me reste encore du chemin à parcourir.",[1901,5761,5763],{"id":5762},"les-défis-rencontrés-avec-rust","Les défis rencontrés avec Rust",[12,5765,5766,5767,5770],{},"Malgré ces avantages, j'ai rencontré quelques difficultés, probablement dues à ma méconnaissance du langage Rust. Par\nexemple, pour certaines parties du code, je me suis retrouvé avec du code contenant le mot ",[105,5768,5769],{},"unsafe",". J'ai refusé de\nl'utiliser, ce qui a rendu mon code plus complexe.",[12,5772,5773,5774,5777,5778,632],{},"J'ai un cas particulier pour lequel je n'ai pas trouvé de solution. Dans mon logiciel de sauvegarde, je lis des noms de\nfichier que je stocke en tant que ",[344,5775,5776],{},"[u8]"," en Protobuf dans un fichier. Si je traite ces noms de fichier en tant que\nchaîne de caractères, je me retrouve avec des erreurs potentielles de conversion si le nom de fichier n'est pas en UTF-8\nsous Linux et en UTF-16 sous Windows. Pour stocker donc sous forme d'octet, j'utilise ces méthodes qui m'obligent à\nutiliser ",[344,5779,5769],{},[352,5781,5783],{"className":2114,"code":5782,"language":2116,"meta":291,"style":291},"#[must_use]\npub fn osstr_to_vec(path: &OsStr) -> Vec\u003Cu8> {\n    path.as_encoded_bytes().to_vec()\n}\n\n#[must_use]\npub fn vec_to_osstr(vec: &[u8]) -> OsString {\n    unsafe { OsString::from_encoded_bytes_unchecked(vec.to_owned()) }\n}\n",[344,5784,5785,5790,5818,5834,5838,5842,5846,5872,5899],{"__ignoreMap":291},[360,5786,5787],{"class":362,"line":363},[360,5788,5789],{"class":366},"#[must_use]\n",[360,5791,5792,5794,5796,5799,5801,5803,5805,5808,5810,5812,5814,5816],{"class":362,"line":292},[360,5793,3637],{"class":574},[360,5795,4805],{"class":574},[360,5797,5798],{"class":381}," osstr_to_vec",[360,5800,671],{"class":366},[360,5802,4817],{"class":578},[360,5804,2734],{"class":366},[360,5806,5807],{"class":662},"OsStr",[360,5809,3052],{"class":366},[360,5811,2995],{"class":662},[360,5813,1358],{"class":366},[360,5815,2742],{"class":662},[360,5817,2711],{"class":366},[360,5819,5820,5823,5825,5828,5830,5832],{"class":362,"line":375},[360,5821,5822],{"class":578},"    path",[360,5824,31],{"class":366},[360,5826,5827],{"class":381},"as_encoded_bytes",[360,5829,3487],{"class":366},[360,5831,3271],{"class":381},[360,5833,5008],{"class":366},[360,5835,5836],{"class":362,"line":433},[360,5837,847],{"class":366},[360,5839,5840],{"class":362,"line":478},[360,5841,372],{"emptyLinePlaceholder":320},[360,5843,5844],{"class":362,"line":483},[360,5845,5789],{"class":366},[360,5847,5848,5850,5852,5855,5857,5860,5863,5865,5867,5870],{"class":362,"line":489},[360,5849,3637],{"class":574},[360,5851,4805],{"class":574},[360,5853,5854],{"class":381}," vec_to_osstr",[360,5856,671],{"class":366},[360,5858,5859],{"class":578},"vec",[360,5861,5862],{"class":366},": &[",[360,5864,2742],{"class":662},[360,5866,2745],{"class":366},[360,5868,5869],{"class":662},"OsString",[360,5871,896],{"class":366},[360,5873,5874,5877,5880,5882,5884,5887,5889,5891,5893,5896],{"class":362,"line":494},[360,5875,5876],{"class":574},"    unsafe",[360,5878,5879],{"class":366}," { ",[360,5881,5869],{"class":662},[360,5883,666],{"class":366},[360,5885,5886],{"class":381},"from_encoded_bytes_unchecked",[360,5888,671],{"class":366},[360,5890,5859],{"class":578},[360,5892,31],{"class":366},[360,5894,5895],{"class":381},"to_owned",[360,5897,5898],{"class":366},"()) }\n",[360,5900,5901],{"class":362,"line":712},[360,5902,847],{"class":366},[12,5904,5905,5906,5908],{},"Le problème est que dans l'interface, des noms Windows ou Linux peuvent être affichés. Je ne souhaite pas que le\nprogramme plante, mais qu'au pire des cas, il affiche un nom de fichier incorrect. Je ne suis pas sûr que le code écrit\nsoit la meilleure solution. (D'après mes tests, il fonctionne). Une meilleure solution pour convertir un ",[344,5907,5807],{}," en\nString en fonction de l'encodage actuel (la variable d'environnement LANG sous Linux) aurait été pratique.",[12,5910,5911],{},"La gestion de la mémoire, bien que semblant simple au premier abord, devient rapidement complexe lorsqu'on veut faire du\nmultithreading. On se retrouve à mettre des structures dans des Box, des Mutex et des Arc, ce qui complique la syntaxe.",[12,5913,5914,5915,5918,5919,5922],{},"L'introduction de dynamisme, notamment pour la gestion des erreurs, nécessite l'utilisation du mot-clé ",[344,5916,5917],{},"dyn",", ce qui\npeut également devenir complexe. Je me retrouve avec presque toutes mes méthodes qui retournent un\n",[344,5920,5921],{},"Result\u003C???, Box\u003Cdyn Error>>",". Là aussi, je me demande si c'est une bonne pratique.",[12,5924,5925],{},"De plus, Rust semble souvent nous obliger à cloner des objets, alors que j'aurais parfois préféré utiliser simplement la\nréférence de l'objet. Mais comme potentiellement Rust n'arrive pas à déterminer si dans un cas de multithreading la\nvariable sera toujours valide, on doit la cloner. Parfois dans ces cas, je me dis qu'en C, je sais quand j'alloue, quand\nje désalloue, qui a le droit de lire et d'écrire. De mes souvenirs du C et du C++, j'avais plus de contrôle, le code me\nparaissait plus facile à écrire. Maintenant, le moindre oubli, petite erreur, peut être fatal, et Rust nous protège de\ncela. Bref, je pense simplement que je dois encore prendre le temps de me familiariser avec la philosophie de Rust.",[12,5927,5928,5929,2311,5932,2311,5935,2623,5938,5941],{},"Enfin, les erreurs de compilation ont été un gros défi. J'ai passé des heures à essayer de comprendre certaines erreurs,\nà ajuster les durées de vie ou à ajouter ",[344,5930,5931],{},"static",[344,5933,5934],{},"Send",[344,5936,5937],{},"Sync",[344,5939,5940],{},"Clone"," sans savoir quelle était la bonne façon de\nfaire.",[1901,5943,5945],{"id":5944},"les-tests-unitaires","Les tests unitaires",[12,5947,5948],{},"J'ai réalisé des tests unitaires pour une partie du développement. Cependant, l'écriture de ces tests a été difficile,\nsurtout en comparaison avec des bibliothèques comme Jest en JavaScript.",[12,5950,5951,5952,31],{},"La création de mocks pour les interfaces et les autres fichiers n'est pas native à Rust et n'est pas une tâche simple.\nJ'ai dû utiliser une bibliothèque dédiée, ",[47,5953,5956],{"href":5954,"rel":5955},"https:\u002F\u002Fdocs.rs\u002Fmockall\u002Flatest\u002Fmockall\u002F",[51],"mockall",[12,5958,5959,5960,31],{},"L'utilisation de mocks m'a contraint à créer des structures, alors qu'initialement j'avais des méthodes. J'ai commencé\navec des méthodes statiques, mais leur gestion avec les mocks ne permet pas de réaliser des tests unitaires en\nparallèle. Pour exécuter les tests unitaires, j'ai dû lancer un test à la fois avec la commande\n",[344,5961,5962],{},"RUST_TEST_THREADS=1 cargo test",[12,5964,5965],{},"Cependant, j'ai réussi à modifier les tests unitaires pour qu'ils puissent s'exécuter en parallèle sans supprimer les\nméthodes statiques.",[33,5967,251],{"id":250},[12,5969,5970],{},"Maintenant que j'ai écrit ce petit programme, je vais pouvoir créer mon propre pool de stockage. De votre côté,\nn'hésitez pas à me faire des retours sur le programme. Je suis ouvert à toutes les critiques. De plus, si vous utilisez\nBackupPC (en version 4 uniquement et avec un pool de stockage en version 4), vous pouvez tester mon programme et\nl'utiliser.",[1613,5972,5973],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}",{"title":291,"searchDepth":292,"depth":292,"links":5975},[5976,5977,5982,5991],{"id":1796,"depth":292,"text":1797},{"id":1858,"depth":292,"text":1859,"children":5978},[5979,5980,5981],{"id":1903,"depth":375,"text":1904},{"id":1975,"depth":375,"text":1976},{"id":1993,"depth":375,"text":1994},{"id":2066,"depth":292,"text":2067,"children":5983},[5984,5985,5986,5987,5988,5989,5990],{"id":2091,"depth":375,"text":2092},{"id":4295,"depth":375,"text":4296},{"id":4705,"depth":375,"text":4706},{"id":4742,"depth":375,"text":4743},{"id":5743,"depth":375,"text":5744},{"id":5762,"depth":375,"text":5763},{"id":5944,"depth":375,"text":5945},{"id":250,"depth":292,"text":251},"2024-05-07","Une partie de cet article a été publiée sur LinuxFR.\nAprès avoir reçu quelques retours, j'ai décidé de publier une version modifiée et améliorée de cet article sur mon blog.",{"type":9,"value":5995},[5996,6001,6003,6005],[12,5997,1775,5998,1781],{},[47,5999,1780],{"href":1778,"rel":6000},[51],[12,6002,1784],{},[12,6004,1787],{},[12,6006,6007],{},[69,6008],{"src":1792,"alt":291,"className":6009},[73],{"planet":320},"\u002Fpost\u002Fpr_backuppc_pool",{"title":1770,"description":5993},"pr_backuppc_pool","posts\u002FWoodstock\u002F2024-03-14_pr_backuppc_pool",[6016,6017,6018,1765,1766],"woodstock","backup","sauvegarde","JVBo68qbMHY70AJ8I83XDPaOAeqZhhqQNzs8jDhZhvY",{"id":6021,"title":6022,"author":7,"body":6023,"category":300,"categorySlug":301,"date":13505,"description":291,"excerpt":13506,"extension":317,"location":318,"meta":13514,"navigation":320,"path":13515,"published":320,"seo":13516,"slug":13517,"stem":13518,"tags":13519,"timeToRead":1441,"__hash__":13520},"posts\u002Fposts\u002FWoodstock\u002F2023-05-10_woodstock_rust.md","Woodstock Backup - Optimiser la consommation mémoire de Node.js avec Rust",{"type":9,"value":6024,"toc":13495},[6025,6029,6032,6035,6039,6042,7522,7525,7528,7596,7599,7602,7606,7613,7616,7619,7622,7720,7723,7783,7789,7793,7796,7806,9717,9720,9780,9783,9786,9789,9793,9796,9799,9802,9805,9812,9815,9818,9821,11390,11393,11738,11741,11779,11782,11788,11791,11799,11802,11810,13045,13051,13422,13425,13428,13467,13470,13473,13476,13479,13481,13484,13492],[33,6026,6028],{"id":6027},"introduction","Introduction",[12,6030,6031],{},"Node.js est un environnement d'exécution JavaScript côté serveur qui repose sur le moteur JavaScript V8 de Google. Il\nest utilisé pour développer des applications serveur en back-end d'une application web, des outils en ligne de commande\net des applications desktop. Cependant, la consommation de mémoire peut être un problème pour certaines applications\nNode.js, en particulier celles qui manipulent de grandes quantités de données ou des données volumineuses.",[12,6033,6034],{},"Dans cet article, nous allons voir comment optimiser la consommation de mémoire d'une application Node.js en le couplant\navec Rust. Rust est un langage de programmation système qui offre des performances similaires à celles du C++, tout en\noffrant une sécurité de mémoire à la compilation. Rust peut être utilisé pour écrire des bibliothèques C\u002FC++ natives\npour Node.js.",[33,6036,6038],{"id":6037},"problématique","Problématique",[12,6040,6041],{},"J'ai développé un logiciel de sauvegarde appelé Woodstock Backup, écrit en TypeScript. Lors du lancement des\nsauvegardes, il crée une représentation du système de fichier en mémoire et nécessite une grande quantité de mémoire.\nPour illustrer cela, nous avons reproduit notre cas avec le code suivant :",[352,6043,6047],{"className":6044,"code":6045,"language":6046,"meta":291,"style":291},"language-js shiki shiki-themes one-dark-pro","const filesize = require(\"filesize.js\");\nconst fs = require(\"fs\");\n\u002F\u002F Utilisation des méthodes de sérialisation et de désérialisation du moteur V8\nconst { serialize, deserialize } = require(\"v8\");\n\n\u002F\u002F Méthode pour générer une chaîne de caractère contenant des caractères aléatoires\nfunction randomString(size) {\n  const buffer = Buffer.alloc(size);\n  for (let i = 0; i \u003C size; i++) {\n    buffer[i] = Math.floor(Math.random() * 256);\n  }\n  return buffer;\n}\n\n\u002F\u002F Méthode pour générer un nombre aléatoire de la taille d'un nombre de 53 bits\nfunction randomNumber() {\n  return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);\n}\n\n\u002F\u002F Création d'un objet de test en javascript contenant que des données aléatoires\nconst testObject = () => ({\n  path: randomString(100),\n  stats: {\n    ownerId: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    groupId: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    size: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    compressedSize: {\n      low: randomNumber(),\n      high: randomNumber(),\n      unsigned: true,\n    },\n    lastRead: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    lastModified: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    created: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    mode: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    dev: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    rdev: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    ino: { low: randomNumber(), high: randomNumber(), unsigned: true },\n    nlink: { low: randomNumber(), high: randomNumber(), unsigned: true },\n  },\n  chunks: [randomString(32), randomString(32), randomString(32)],\n  sha256: randomString(32),\n});\n\n\u002F\u002F Lancement du GC pour s'assurer que la mémoire utilisé ne contient que les objets de test\nglobal.gc();\n\u002F\u002F On recupère la mémoire utilisé avant le test\nconst memoryBefore = process.memoryUsage().heapUsed;\n\u002F\u002F On recupère le temps avant le test (pour mesurer le temps de traitement)\nconst time = Date.now();\n\n\u002F\u002F Création des objets. J'ai du lancer plusieurs fois le script pour trouver une valeur qui ne causé pas de crash de \n\u002F\u002F Node.JS pour cause de manque de mémoire\nconst nbObjects = 1_300_000;\nconst testArray = new Array(nbObjects);\nfor (let i = 0; i \u003C nbObjects; i++) {\n  testArray[i] = testObject();\n}\n\n\u002F\u002F Combien de temps à pris la création des objets\nconsole.log(\"Creation time: \", Date.now() - time);\n\u002F\u002F Lancement du GC pour s'assurer que nous n'avons pas d'autres reliquats\nglobal.gc();\n\u002F\u002F Récupération de la mémoire après le test\nconst memoryAfter = process.memoryUsage().heapUsed;\n\nconsole.log(\"Memory consumption: \", filesize.default(memoryAfter - memoryBefore));\nconsole.log(\"Memory consumption by objects: \", filesize.default((memoryAfter - memoryBefore) \u002F nbObjects));\n\n\u002F\u002F Dans la suite on va écrire un fichier contenant le contenu de la mémoire. Cela a été fait initiallement pour \n\u002F\u002F s'assurer que le GC ne supprime pas mes objets car non utilisés.\nconst time2 = Date.now();\n\n\u002F\u002F Remove test file if exist\ntry {\n  fs.unlinkSync(\"test\");\n} catch (e) {}\n\nconst stream = fs.createWriteStream(\"test\");\n\n\u002F\u002F C'est moche, mais c'est pour tester\nstream.on(\"close\", () => {\n  console.log(\"Write to file time: \", Date.now() - time2);\n  \u002F\u002F Size of file test on disk\n  const stats = fs.statSync(\"test\");\n  console.log(\"Size of file on disk: \", filesize.default(stats.size));\n  console.log(\n    \"Size of object in the file\",\n    filesize.default(stats.size \u002F nbObjects)\n  );\n});\n\nfor (const obj of testArray) {\n  stream.write(serialize(obj));\n}\nstream.end();\n","js",[344,6048,6049,6069,6087,6092,6120,6124,6129,6144,6166,6202,6242,6246,6254,6258,6262,6267,6276,6304,6308,6312,6317,6335,6352,6360,6398,6429,6460,6467,6479,6490,6501,6506,6537,6568,6599,6630,6661,6692,6723,6754,6759,6793,6808,6813,6817,6822,6834,6839,6863,6868,6887,6891,6897,6903,6918,6940,6972,6990,6995,7000,7006,7039,7045,7056,7062,7084,7089,7124,7163,7168,7174,7180,7198,7203,7209,7217,7235,7250,7255,7278,7283,7289,7312,7343,7349,7372,7405,7416,7424,7449,7455,7460,7465,7483,7505,7510],{"__ignoreMap":291},[360,6050,6051,6054,6057,6059,6062,6064,6067],{"class":362,"line":363},[360,6052,6053],{"class":574},"const",[360,6055,6056],{"class":662}," filesize",[360,6058,401],{"class":582},[360,6060,6061],{"class":381}," require",[360,6063,671],{"class":366},[360,6065,6066],{"class":397},"\"filesize.js\"",[360,6068,801],{"class":366},[360,6070,6071,6073,6076,6078,6080,6082,6085],{"class":362,"line":292},[360,6072,6053],{"class":574},[360,6074,6075],{"class":662}," fs",[360,6077,401],{"class":582},[360,6079,6061],{"class":381},[360,6081,671],{"class":366},[360,6083,6084],{"class":397},"\"fs\"",[360,6086,801],{"class":366},[360,6088,6089],{"class":362,"line":375},[360,6090,6091],{"class":644},"\u002F\u002F Utilisation des méthodes de sérialisation et de désérialisation du moteur V8\n",[360,6093,6094,6096,6098,6101,6103,6106,6109,6111,6113,6115,6118],{"class":362,"line":433},[360,6095,6053],{"class":574},[360,6097,5879],{"class":366},[360,6099,6100],{"class":662},"serialize",[360,6102,2311],{"class":366},[360,6104,6105],{"class":662},"deserialize",[360,6107,6108],{"class":366}," } ",[360,6110,583],{"class":582},[360,6112,6061],{"class":381},[360,6114,671],{"class":366},[360,6116,6117],{"class":397},"\"v8\"",[360,6119,801],{"class":366},[360,6121,6122],{"class":362,"line":478},[360,6123,372],{"emptyLinePlaceholder":320},[360,6125,6126],{"class":362,"line":483},[360,6127,6128],{"class":644},"\u002F\u002F Méthode pour générer une chaîne de caractère contenant des caractères aléatoires\n",[360,6130,6131,6134,6137,6139,6142],{"class":362,"line":489},[360,6132,6133],{"class":574},"function",[360,6135,6136],{"class":381}," randomString",[360,6138,671],{"class":366},[360,6140,6141],{"class":677},"size",[360,6143,681],{"class":366},[360,6145,6146,6148,6150,6152,6155,6157,6160,6162,6164],{"class":362,"line":494},[360,6147,1244],{"class":574},[360,6149,2263],{"class":662},[360,6151,401],{"class":582},[360,6153,6154],{"class":662}," Buffer",[360,6156,31],{"class":366},[360,6158,6159],{"class":381},"alloc",[360,6161,671],{"class":366},[360,6163,6141],{"class":578},[360,6165,801],{"class":366},[360,6167,6168,6171,6173,6176,6179,6181,6183,6185,6188,6190,6193,6195,6197,6200],{"class":362,"line":712},[360,6169,6170],{"class":574},"  for",[360,6172,743],{"class":366},[360,6174,6175],{"class":574},"let",[360,6177,6178],{"class":578}," i",[360,6180,401],{"class":582},[360,6182,1457],{"class":414},[360,6184,4423],{"class":366},[360,6186,6187],{"class":578},"i",[360,6189,4175],{"class":582},[360,6191,6192],{"class":578}," size",[360,6194,4423],{"class":366},[360,6196,6187],{"class":578},[360,6198,6199],{"class":582},"++",[360,6201,681],{"class":366},[360,6203,6204,6207,6209,6211,6213,6215,6218,6220,6223,6225,6228,6230,6233,6235,6237,6240],{"class":362,"line":331},[360,6205,6206],{"class":578},"    buffer",[360,6208,2385],{"class":366},[360,6210,6187],{"class":578},[360,6212,2390],{"class":366},[360,6214,583],{"class":582},[360,6216,6217],{"class":662}," Math",[360,6219,31],{"class":366},[360,6221,6222],{"class":381},"floor",[360,6224,671],{"class":366},[360,6226,6227],{"class":662},"Math",[360,6229,31],{"class":366},[360,6231,6232],{"class":381},"random",[360,6234,2805],{"class":366},[360,6236,925],{"class":582},[360,6238,6239],{"class":414}," 256",[360,6241,801],{"class":366},[360,6243,6244],{"class":362,"line":762},[360,6245,820],{"class":366},[360,6247,6248,6250,6252],{"class":362,"line":781},[360,6249,826],{"class":574},[360,6251,2263],{"class":578},[360,6253,735],{"class":366},[360,6255,6256],{"class":362,"line":804},[360,6257,847],{"class":366},[360,6259,6260],{"class":362,"line":817},[360,6261,372],{"emptyLinePlaceholder":320},[360,6263,6264],{"class":362,"line":823},[360,6265,6266],{"class":644},"\u002F\u002F Méthode pour générer un nombre aléatoire de la taille d'un nombre de 53 bits\n",[360,6268,6269,6271,6274],{"class":362,"line":844},[360,6270,6133],{"class":574},[360,6272,6273],{"class":381}," randomNumber",[360,6275,2172],{"class":366},[360,6277,6278,6280,6282,6284,6286,6288,6290,6292,6294,6296,6298,6301],{"class":362,"line":1441},[360,6279,826],{"class":574},[360,6281,6217],{"class":662},[360,6283,31],{"class":366},[360,6285,6222],{"class":381},[360,6287,671],{"class":366},[360,6289,6227],{"class":662},[360,6291,31],{"class":366},[360,6293,6232],{"class":381},[360,6295,2805],{"class":366},[360,6297,925],{"class":582},[360,6299,6300],{"class":662}," Number",[360,6302,6303],{"class":366},".MAX_SAFE_INTEGER);\n",[360,6305,6306],{"class":362,"line":1462},[360,6307,847],{"class":366},[360,6309,6310],{"class":362,"line":1485},[360,6311,372],{"emptyLinePlaceholder":320},[360,6313,6314],{"class":362,"line":1497},[360,6315,6316],{"class":644},"\u002F\u002F Création d'un objet de test en javascript contenant que des données aléatoires\n",[360,6318,6319,6321,6324,6326,6329,6332],{"class":362,"line":3161},[360,6320,6053],{"class":574},[360,6322,6323],{"class":381}," testObject",[360,6325,401],{"class":582},[360,6327,6328],{"class":366}," () ",[360,6330,6331],{"class":574},"=>",[360,6333,6334],{"class":366}," ({\n",[360,6336,6337,6340,6342,6345,6347,6350],{"class":362,"line":3167},[360,6338,6339],{"class":578},"  path",[360,6341,2691],{"class":366},[360,6343,6344],{"class":381},"randomString",[360,6346,671],{"class":366},[360,6348,6349],{"class":414},"100",[360,6351,5405],{"class":366},[360,6353,6354,6357],{"class":362,"line":3194},[360,6355,6356],{"class":578},"  stats",[360,6358,6359],{"class":366},": {\n",[360,6361,6362,6365,6368,6371,6373,6376,6379,6382,6384,6386,6388,6391,6393,6395],{"class":362,"line":3224},[360,6363,6364],{"class":578},"    ownerId",[360,6366,6367],{"class":366},": { ",[360,6369,6370],{"class":578},"low",[360,6372,2691],{"class":366},[360,6374,6375],{"class":381},"randomNumber",[360,6377,6378],{"class":366},"(), ",[360,6380,6381],{"class":578},"high",[360,6383,2691],{"class":366},[360,6385,6375],{"class":381},[360,6387,6378],{"class":366},[360,6389,6390],{"class":578},"unsigned",[360,6392,2691],{"class":366},[360,6394,3081],{"class":414},[360,6396,6397],{"class":366}," },\n",[360,6399,6400,6403,6405,6407,6409,6411,6413,6415,6417,6419,6421,6423,6425,6427],{"class":362,"line":3239},[360,6401,6402],{"class":578},"    groupId",[360,6404,6367],{"class":366},[360,6406,6370],{"class":578},[360,6408,2691],{"class":366},[360,6410,6375],{"class":381},[360,6412,6378],{"class":366},[360,6414,6381],{"class":578},[360,6416,2691],{"class":366},[360,6418,6375],{"class":381},[360,6420,6378],{"class":366},[360,6422,6390],{"class":578},[360,6424,2691],{"class":366},[360,6426,3081],{"class":414},[360,6428,6397],{"class":366},[360,6430,6431,6434,6436,6438,6440,6442,6444,6446,6448,6450,6452,6454,6456,6458],{"class":362,"line":3256},[360,6432,6433],{"class":578},"    size",[360,6435,6367],{"class":366},[360,6437,6370],{"class":578},[360,6439,2691],{"class":366},[360,6441,6375],{"class":381},[360,6443,6378],{"class":366},[360,6445,6381],{"class":578},[360,6447,2691],{"class":366},[360,6449,6375],{"class":381},[360,6451,6378],{"class":366},[360,6453,6390],{"class":578},[360,6455,2691],{"class":366},[360,6457,3081],{"class":414},[360,6459,6397],{"class":366},[360,6461,6462,6465],{"class":362,"line":3276},[360,6463,6464],{"class":578},"    compressedSize",[360,6466,6359],{"class":366},[360,6468,6469,6472,6474,6476],{"class":362,"line":3281},[360,6470,6471],{"class":578},"      low",[360,6473,2691],{"class":366},[360,6475,6375],{"class":381},[360,6477,6478],{"class":366},"(),\n",[360,6480,6481,6484,6486,6488],{"class":362,"line":3305},[360,6482,6483],{"class":578},"      high",[360,6485,2691],{"class":366},[360,6487,6375],{"class":381},[360,6489,6478],{"class":366},[360,6491,6492,6495,6497,6499],{"class":362,"line":3320},[360,6493,6494],{"class":578},"      unsigned",[360,6496,2691],{"class":366},[360,6498,3081],{"class":414},[360,6500,2968],{"class":366},[360,6502,6503],{"class":362,"line":3325},[360,6504,6505],{"class":366},"    },\n",[360,6507,6508,6511,6513,6515,6517,6519,6521,6523,6525,6527,6529,6531,6533,6535],{"class":362,"line":3361},[360,6509,6510],{"class":578},"    lastRead",[360,6512,6367],{"class":366},[360,6514,6370],{"class":578},[360,6516,2691],{"class":366},[360,6518,6375],{"class":381},[360,6520,6378],{"class":366},[360,6522,6381],{"class":578},[360,6524,2691],{"class":366},[360,6526,6375],{"class":381},[360,6528,6378],{"class":366},[360,6530,6390],{"class":578},[360,6532,2691],{"class":366},[360,6534,3081],{"class":414},[360,6536,6397],{"class":366},[360,6538,6539,6542,6544,6546,6548,6550,6552,6554,6556,6558,6560,6562,6564,6566],{"class":362,"line":3380},[360,6540,6541],{"class":578},"    lastModified",[360,6543,6367],{"class":366},[360,6545,6370],{"class":578},[360,6547,2691],{"class":366},[360,6549,6375],{"class":381},[360,6551,6378],{"class":366},[360,6553,6381],{"class":578},[360,6555,2691],{"class":366},[360,6557,6375],{"class":381},[360,6559,6378],{"class":366},[360,6561,6390],{"class":578},[360,6563,2691],{"class":366},[360,6565,3081],{"class":414},[360,6567,6397],{"class":366},[360,6569,6570,6573,6575,6577,6579,6581,6583,6585,6587,6589,6591,6593,6595,6597],{"class":362,"line":3405},[360,6571,6572],{"class":578},"    created",[360,6574,6367],{"class":366},[360,6576,6370],{"class":578},[360,6578,2691],{"class":366},[360,6580,6375],{"class":381},[360,6582,6378],{"class":366},[360,6584,6381],{"class":578},[360,6586,2691],{"class":366},[360,6588,6375],{"class":381},[360,6590,6378],{"class":366},[360,6592,6390],{"class":578},[360,6594,2691],{"class":366},[360,6596,3081],{"class":414},[360,6598,6397],{"class":366},[360,6600,6601,6604,6606,6608,6610,6612,6614,6616,6618,6620,6622,6624,6626,6628],{"class":362,"line":3411},[360,6602,6603],{"class":578},"    mode",[360,6605,6367],{"class":366},[360,6607,6370],{"class":578},[360,6609,2691],{"class":366},[360,6611,6375],{"class":381},[360,6613,6378],{"class":366},[360,6615,6381],{"class":578},[360,6617,2691],{"class":366},[360,6619,6375],{"class":381},[360,6621,6378],{"class":366},[360,6623,6390],{"class":578},[360,6625,2691],{"class":366},[360,6627,3081],{"class":414},[360,6629,6397],{"class":366},[360,6631,6632,6635,6637,6639,6641,6643,6645,6647,6649,6651,6653,6655,6657,6659],{"class":362,"line":3426},[360,6633,6634],{"class":578},"    dev",[360,6636,6367],{"class":366},[360,6638,6370],{"class":578},[360,6640,2691],{"class":366},[360,6642,6375],{"class":381},[360,6644,6378],{"class":366},[360,6646,6381],{"class":578},[360,6648,2691],{"class":366},[360,6650,6375],{"class":381},[360,6652,6378],{"class":366},[360,6654,6390],{"class":578},[360,6656,2691],{"class":366},[360,6658,3081],{"class":414},[360,6660,6397],{"class":366},[360,6662,6663,6666,6668,6670,6672,6674,6676,6678,6680,6682,6684,6686,6688,6690],{"class":362,"line":3432},[360,6664,6665],{"class":578},"    rdev",[360,6667,6367],{"class":366},[360,6669,6370],{"class":578},[360,6671,2691],{"class":366},[360,6673,6375],{"class":381},[360,6675,6378],{"class":366},[360,6677,6381],{"class":578},[360,6679,2691],{"class":366},[360,6681,6375],{"class":381},[360,6683,6378],{"class":366},[360,6685,6390],{"class":578},[360,6687,2691],{"class":366},[360,6689,3081],{"class":414},[360,6691,6397],{"class":366},[360,6693,6694,6697,6699,6701,6703,6705,6707,6709,6711,6713,6715,6717,6719,6721],{"class":362,"line":3438},[360,6695,6696],{"class":578},"    ino",[360,6698,6367],{"class":366},[360,6700,6370],{"class":578},[360,6702,2691],{"class":366},[360,6704,6375],{"class":381},[360,6706,6378],{"class":366},[360,6708,6381],{"class":578},[360,6710,2691],{"class":366},[360,6712,6375],{"class":381},[360,6714,6378],{"class":366},[360,6716,6390],{"class":578},[360,6718,2691],{"class":366},[360,6720,3081],{"class":414},[360,6722,6397],{"class":366},[360,6724,6725,6728,6730,6732,6734,6736,6738,6740,6742,6744,6746,6748,6750,6752],{"class":362,"line":3443},[360,6726,6727],{"class":578},"    nlink",[360,6729,6367],{"class":366},[360,6731,6370],{"class":578},[360,6733,2691],{"class":366},[360,6735,6375],{"class":381},[360,6737,6378],{"class":366},[360,6739,6381],{"class":578},[360,6741,2691],{"class":366},[360,6743,6375],{"class":381},[360,6745,6378],{"class":366},[360,6747,6390],{"class":578},[360,6749,2691],{"class":366},[360,6751,3081],{"class":414},[360,6753,6397],{"class":366},[360,6755,6756],{"class":362,"line":3462},[360,6757,6758],{"class":366},"  },\n",[360,6760,6761,6764,6766,6768,6770,6773,6776,6778,6780,6782,6784,6786,6788,6790],{"class":362,"line":3467},[360,6762,6763],{"class":578},"  chunks",[360,6765,4418],{"class":366},[360,6767,6344],{"class":381},[360,6769,671],{"class":366},[360,6771,6772],{"class":414},"32",[360,6774,6775],{"class":366},"), ",[360,6777,6344],{"class":381},[360,6779,671],{"class":366},[360,6781,6772],{"class":414},[360,6783,6775],{"class":366},[360,6785,6344],{"class":381},[360,6787,671],{"class":366},[360,6789,6772],{"class":414},[360,6791,6792],{"class":366},")],\n",[360,6794,6795,6798,6800,6802,6804,6806],{"class":362,"line":3472},[360,6796,6797],{"class":578},"  sha256",[360,6799,2691],{"class":366},[360,6801,6344],{"class":381},[360,6803,671],{"class":366},[360,6805,6772],{"class":414},[360,6807,5405],{"class":366},[360,6809,6810],{"class":362,"line":3495},[360,6811,6812],{"class":366},"});\n",[360,6814,6815],{"class":362,"line":3500},[360,6816,372],{"emptyLinePlaceholder":320},[360,6818,6819],{"class":362,"line":3505},[360,6820,6821],{"class":644},"\u002F\u002F Lancement du GC pour s'assurer que la mémoire utilisé ne contient que les objets de test\n",[360,6823,6824,6827,6829,6832],{"class":362,"line":3530},[360,6825,6826],{"class":662},"global",[360,6828,31],{"class":366},[360,6830,6831],{"class":381},"gc",[360,6833,2204],{"class":366},[360,6835,6836],{"class":362,"line":3545},[360,6837,6838],{"class":644},"\u002F\u002F On recupère la mémoire utilisé avant le test\n",[360,6840,6841,6843,6846,6848,6851,6853,6856,6858,6861],{"class":362,"line":3558},[360,6842,6053],{"class":574},[360,6844,6845],{"class":662}," memoryBefore",[360,6847,401],{"class":582},[360,6849,6850],{"class":662}," process",[360,6852,31],{"class":366},[360,6854,6855],{"class":381},"memoryUsage",[360,6857,3487],{"class":366},[360,6859,6860],{"class":578},"heapUsed",[360,6862,735],{"class":366},[360,6864,6865],{"class":362,"line":3573},[360,6866,6867],{"class":644},"\u002F\u002F On recupère le temps avant le test (pour mesurer le temps de traitement)\n",[360,6869,6870,6872,6875,6877,6880,6882,6885],{"class":362,"line":3578},[360,6871,6053],{"class":574},[360,6873,6874],{"class":662}," time",[360,6876,401],{"class":582},[360,6878,6879],{"class":662}," Date",[360,6881,31],{"class":366},[360,6883,6884],{"class":381},"now",[360,6886,2204],{"class":366},[360,6888,6889],{"class":362,"line":3583},[360,6890,372],{"emptyLinePlaceholder":320},[360,6892,6894],{"class":362,"line":6893},52,[360,6895,6896],{"class":644},"\u002F\u002F Création des objets. J'ai du lancer plusieurs fois le script pour trouver une valeur qui ne causé pas de crash de \n",[360,6898,6900],{"class":362,"line":6899},53,[360,6901,6902],{"class":644},"\u002F\u002F Node.JS pour cause de manque de mémoire\n",[360,6904,6906,6908,6911,6913,6916],{"class":362,"line":6905},54,[360,6907,6053],{"class":574},[360,6909,6910],{"class":662}," nbObjects",[360,6912,401],{"class":582},[360,6914,6915],{"class":414}," 1_300_000",[360,6917,735],{"class":366},[360,6919,6921,6923,6926,6928,6930,6933,6935,6938],{"class":362,"line":6920},55,[360,6922,6053],{"class":574},[360,6924,6925],{"class":662}," testArray",[360,6927,401],{"class":582},[360,6929,3040],{"class":574},[360,6931,6932],{"class":381}," Array",[360,6934,671],{"class":366},[360,6936,6937],{"class":578},"nbObjects",[360,6939,801],{"class":366},[360,6941,6943,6946,6948,6950,6952,6954,6956,6958,6960,6962,6964,6966,6968,6970],{"class":362,"line":6942},56,[360,6944,6945],{"class":574},"for",[360,6947,743],{"class":366},[360,6949,6175],{"class":574},[360,6951,6178],{"class":578},[360,6953,401],{"class":582},[360,6955,1457],{"class":414},[360,6957,4423],{"class":366},[360,6959,6187],{"class":578},[360,6961,4175],{"class":582},[360,6963,6910],{"class":578},[360,6965,4423],{"class":366},[360,6967,6187],{"class":578},[360,6969,6199],{"class":582},[360,6971,681],{"class":366},[360,6973,6975,6978,6980,6982,6984,6986,6988],{"class":362,"line":6974},57,[360,6976,6977],{"class":578},"  testArray",[360,6979,2385],{"class":366},[360,6981,6187],{"class":578},[360,6983,2390],{"class":366},[360,6985,583],{"class":582},[360,6987,6323],{"class":381},[360,6989,2204],{"class":366},[360,6991,6993],{"class":362,"line":6992},58,[360,6994,847],{"class":366},[360,6996,6998],{"class":362,"line":6997},59,[360,6999,372],{"emptyLinePlaceholder":320},[360,7001,7003],{"class":362,"line":7002},60,[360,7004,7005],{"class":644},"\u002F\u002F Combien de temps à pris la création des objets\n",[360,7007,7009,7012,7014,7017,7019,7022,7024,7027,7029,7031,7033,7035,7037],{"class":362,"line":7008},61,[360,7010,7011],{"class":662},"console",[360,7013,31],{"class":366},[360,7015,7016],{"class":381},"log",[360,7018,671],{"class":366},[360,7020,7021],{"class":397},"\"Creation time: \"",[360,7023,2311],{"class":366},[360,7025,7026],{"class":662},"Date",[360,7028,31],{"class":366},[360,7030,6884],{"class":381},[360,7032,2805],{"class":366},[360,7034,1491],{"class":582},[360,7036,6874],{"class":578},[360,7038,801],{"class":366},[360,7040,7042],{"class":362,"line":7041},62,[360,7043,7044],{"class":644},"\u002F\u002F Lancement du GC pour s'assurer que nous n'avons pas d'autres reliquats\n",[360,7046,7048,7050,7052,7054],{"class":362,"line":7047},63,[360,7049,6826],{"class":662},[360,7051,31],{"class":366},[360,7053,6831],{"class":381},[360,7055,2204],{"class":366},[360,7057,7059],{"class":362,"line":7058},64,[360,7060,7061],{"class":644},"\u002F\u002F Récupération de la mémoire après le test\n",[360,7063,7065,7067,7070,7072,7074,7076,7078,7080,7082],{"class":362,"line":7064},65,[360,7066,6053],{"class":574},[360,7068,7069],{"class":662}," memoryAfter",[360,7071,401],{"class":582},[360,7073,6850],{"class":662},[360,7075,31],{"class":366},[360,7077,6855],{"class":381},[360,7079,3487],{"class":366},[360,7081,6860],{"class":578},[360,7083,735],{"class":366},[360,7085,7087],{"class":362,"line":7086},66,[360,7088,372],{"emptyLinePlaceholder":320},[360,7090,7092,7094,7096,7098,7100,7103,7105,7108,7110,7113,7115,7118,7120,7122],{"class":362,"line":7091},67,[360,7093,7011],{"class":662},[360,7095,31],{"class":366},[360,7097,7016],{"class":381},[360,7099,671],{"class":366},[360,7101,7102],{"class":397},"\"Memory consumption: \"",[360,7104,2311],{"class":366},[360,7106,7107],{"class":662},"filesize",[360,7109,31],{"class":366},[360,7111,7112],{"class":381},"default",[360,7114,671],{"class":366},[360,7116,7117],{"class":578},"memoryAfter",[360,7119,518],{"class":582},[360,7121,6845],{"class":578},[360,7123,4081],{"class":366},[360,7125,7127,7129,7131,7133,7135,7138,7140,7142,7144,7146,7149,7151,7153,7155,7157,7159,7161],{"class":362,"line":7126},68,[360,7128,7011],{"class":662},[360,7130,31],{"class":366},[360,7132,7016],{"class":381},[360,7134,671],{"class":366},[360,7136,7137],{"class":397},"\"Memory consumption by objects: \"",[360,7139,2311],{"class":366},[360,7141,7107],{"class":662},[360,7143,31],{"class":366},[360,7145,7112],{"class":381},[360,7147,7148],{"class":366},"((",[360,7150,7117],{"class":578},[360,7152,518],{"class":582},[360,7154,6845],{"class":578},[360,7156,3972],{"class":366},[360,7158,768],{"class":582},[360,7160,6910],{"class":578},[360,7162,4081],{"class":366},[360,7164,7166],{"class":362,"line":7165},69,[360,7167,372],{"emptyLinePlaceholder":320},[360,7169,7171],{"class":362,"line":7170},70,[360,7172,7173],{"class":644},"\u002F\u002F Dans la suite on va écrire un fichier contenant le contenu de la mémoire. Cela a été fait initiallement pour \n",[360,7175,7177],{"class":362,"line":7176},71,[360,7178,7179],{"class":644},"\u002F\u002F s'assurer que le GC ne supprime pas mes objets car non utilisés.\n",[360,7181,7183,7185,7188,7190,7192,7194,7196],{"class":362,"line":7182},72,[360,7184,6053],{"class":574},[360,7186,7187],{"class":662}," time2",[360,7189,401],{"class":582},[360,7191,6879],{"class":662},[360,7193,31],{"class":366},[360,7195,6884],{"class":381},[360,7197,2204],{"class":366},[360,7199,7201],{"class":362,"line":7200},73,[360,7202,372],{"emptyLinePlaceholder":320},[360,7204,7206],{"class":362,"line":7205},74,[360,7207,7208],{"class":644},"\u002F\u002F Remove test file if exist\n",[360,7210,7212,7215],{"class":362,"line":7211},75,[360,7213,7214],{"class":574},"try",[360,7216,896],{"class":366},[360,7218,7220,7223,7225,7228,7230,7233],{"class":362,"line":7219},76,[360,7221,7222],{"class":662},"  fs",[360,7224,31],{"class":366},[360,7226,7227],{"class":381},"unlinkSync",[360,7229,671],{"class":366},[360,7231,7232],{"class":397},"\"test\"",[360,7234,801],{"class":366},[360,7236,7238,7240,7243,7245,7247],{"class":362,"line":7237},77,[360,7239,2485],{"class":366},[360,7241,7242],{"class":574},"catch",[360,7244,743],{"class":366},[360,7246,3864],{"class":578},[360,7248,7249],{"class":366},") {}\n",[360,7251,7253],{"class":362,"line":7252},78,[360,7254,372],{"emptyLinePlaceholder":320},[360,7256,7258,7260,7263,7265,7267,7269,7272,7274,7276],{"class":362,"line":7257},79,[360,7259,6053],{"class":574},[360,7261,7262],{"class":662}," stream",[360,7264,401],{"class":582},[360,7266,6075],{"class":662},[360,7268,31],{"class":366},[360,7270,7271],{"class":381},"createWriteStream",[360,7273,671],{"class":366},[360,7275,7232],{"class":397},[360,7277,801],{"class":366},[360,7279,7281],{"class":362,"line":7280},80,[360,7282,372],{"emptyLinePlaceholder":320},[360,7284,7286],{"class":362,"line":7285},81,[360,7287,7288],{"class":644},"\u002F\u002F C'est moche, mais c'est pour tester\n",[360,7290,7292,7295,7297,7300,7302,7305,7308,7310],{"class":362,"line":7291},82,[360,7293,7294],{"class":662},"stream",[360,7296,31],{"class":366},[360,7298,7299],{"class":381},"on",[360,7301,671],{"class":366},[360,7303,7304],{"class":397},"\"close\"",[360,7306,7307],{"class":366},", () ",[360,7309,6331],{"class":574},[360,7311,896],{"class":366},[360,7313,7315,7318,7320,7322,7324,7327,7329,7331,7333,7335,7337,7339,7341],{"class":362,"line":7314},83,[360,7316,7317],{"class":662},"  console",[360,7319,31],{"class":366},[360,7321,7016],{"class":381},[360,7323,671],{"class":366},[360,7325,7326],{"class":397},"\"Write to file time: \"",[360,7328,2311],{"class":366},[360,7330,7026],{"class":662},[360,7332,31],{"class":366},[360,7334,6884],{"class":381},[360,7336,2805],{"class":366},[360,7338,1491],{"class":582},[360,7340,7187],{"class":578},[360,7342,801],{"class":366},[360,7344,7346],{"class":362,"line":7345},84,[360,7347,7348],{"class":644},"  \u002F\u002F Size of file test on disk\n",[360,7350,7352,7354,7357,7359,7361,7363,7366,7368,7370],{"class":362,"line":7351},85,[360,7353,1244],{"class":574},[360,7355,7356],{"class":662}," stats",[360,7358,401],{"class":582},[360,7360,6075],{"class":662},[360,7362,31],{"class":366},[360,7364,7365],{"class":381},"statSync",[360,7367,671],{"class":366},[360,7369,7232],{"class":397},[360,7371,801],{"class":366},[360,7373,7375,7377,7379,7381,7383,7386,7388,7390,7392,7394,7396,7399,7401,7403],{"class":362,"line":7374},86,[360,7376,7317],{"class":662},[360,7378,31],{"class":366},[360,7380,7016],{"class":381},[360,7382,671],{"class":366},[360,7384,7385],{"class":397},"\"Size of file on disk: \"",[360,7387,2311],{"class":366},[360,7389,7107],{"class":662},[360,7391,31],{"class":366},[360,7393,7112],{"class":381},[360,7395,671],{"class":366},[360,7397,7398],{"class":662},"stats",[360,7400,31],{"class":366},[360,7402,6141],{"class":578},[360,7404,4081],{"class":366},[360,7406,7408,7410,7412,7414],{"class":362,"line":7407},87,[360,7409,7317],{"class":662},[360,7411,31],{"class":366},[360,7413,7016],{"class":381},[360,7415,1395],{"class":366},[360,7417,7419,7422],{"class":362,"line":7418},88,[360,7420,7421],{"class":397},"    \"Size of object in the file\"",[360,7423,2968],{"class":366},[360,7425,7427,7430,7432,7434,7436,7438,7440,7442,7445,7447],{"class":362,"line":7426},89,[360,7428,7429],{"class":662},"    filesize",[360,7431,31],{"class":366},[360,7433,7112],{"class":381},[360,7435,671],{"class":366},[360,7437,7398],{"class":662},[360,7439,31],{"class":366},[360,7441,6141],{"class":578},[360,7443,7444],{"class":582}," \u002F",[360,7446,6910],{"class":578},[360,7448,2922],{"class":366},[360,7450,7452],{"class":362,"line":7451},90,[360,7453,7454],{"class":366},"  );\n",[360,7456,7458],{"class":362,"line":7457},91,[360,7459,6812],{"class":366},[360,7461,7463],{"class":362,"line":7462},92,[360,7464,372],{"emptyLinePlaceholder":320},[360,7466,7468,7470,7472,7474,7477,7479,7481],{"class":362,"line":7467},93,[360,7469,6945],{"class":574},[360,7471,743],{"class":366},[360,7473,6053],{"class":574},[360,7475,7476],{"class":662}," obj",[360,7478,529],{"class":574},[360,7480,6925],{"class":578},[360,7482,681],{"class":366},[360,7484,7486,7489,7491,7494,7496,7498,7500,7503],{"class":362,"line":7485},94,[360,7487,7488],{"class":662},"  stream",[360,7490,31],{"class":366},[360,7492,7493],{"class":381},"write",[360,7495,671],{"class":366},[360,7497,6100],{"class":381},[360,7499,671],{"class":366},[360,7501,7502],{"class":578},"obj",[360,7504,4081],{"class":366},[360,7506,7508],{"class":362,"line":7507},95,[360,7509,847],{"class":366},[360,7511,7513,7515,7517,7520],{"class":362,"line":7512},96,[360,7514,7294],{"class":662},[360,7516,31],{"class":366},[360,7518,7519],{"class":381},"end",[360,7521,2204],{"class":366},[12,7523,7524],{},"En estimant rapidement la mémoire que la taille de l'objet aurait dû prendre, je l'estime à environ 432 octets (12\nnombres de 2*64 bits + 1 octet de boolean + 128 caractères pour les chunks et 100 caractères pour le nom).",[12,7526,7527],{},"Le code n'est pas le plus propre, mais le but est ici d'illustrer rapidement la problématique. Voici le résultat de ce\ntest :",[1545,7529,7530,7538],{},[1548,7531,7532],{},[1551,7533,7534,7536],{},[1554,7535],{},[1554,7537],{},[1567,7539,7540,7548,7556,7564,7572,7580,7588],{},[1551,7541,7542,7545],{},[1572,7543,7544],{},"Nombre d'objets créés",[1572,7546,7547],{},"1 300 000",[1551,7549,7550,7553],{},[1572,7551,7552],{},"Temps de création",[1572,7554,7555],{},"15 secondes",[1551,7557,7558,7561],{},[1572,7559,7560],{},"Consommation mémoire",[1572,7562,7563],{},"2,8 Go",[1551,7565,7566,7569],{},[1572,7567,7568],{},"Consommation moyenne par objet",[1572,7570,7571],{},"2,2 Ko",[1551,7573,7574,7577],{},[1572,7575,7576],{},"Temps d'écriture dans le fichier",[1572,7578,7579],{},"91 secondes",[1551,7581,7582,7585],{},[1572,7583,7584],{},"Taille du fichier sur le disque",[1572,7586,7587],{},"1,1 Go",[1551,7589,7590,7593],{},[1572,7591,7592],{},"Taille moyenne d'un objet dans le fichier",[1572,7594,7595],{},"903 octets",[12,7597,7598],{},"Avec ce premier exemple, on peut déjà constater que la consommation mémoire est très importante. En effet, on est à\n2,2Ko par objet au lieu des 432 estimés (soit 5 fois plus). La taille des objets dans le fichier est déjà un peu plus\nraisonnable.",[12,7600,7601],{},"La seule explication au fait que la consommation mémoire soit aussi importante est, je pense, liée au fait que dans V8,\nles structures sont toutes des objets avec des méthodes par défaut et une structure minimaliste (les Buffers également).",[33,7603,7605],{"id":7604},"test-avec-un-bigint","Test avec un BigInt",[12,7607,7608,7609,7612],{},"La question que l'on peut se poser est : pourquoi utiliser la structure ",[344,7610,7611],{},"{ low: Number, high: Number, unsigned: Bool }"," ?",[12,7614,7615],{},"J'utilise cette structure car pour la persistance, j'utilise la librairie protobuf.js qui ne supporte pas les BigInt,\nmais qui utilise à la place la librairie long.js qui utilise cette structure.",[12,7617,7618],{},"J'ai donc effectué un test en remplaçant chaque objet complexe par le nouveau type BigInt de Node.js. Voici le code :",[12,7620,7621],{},"Pour générer le nombre aléatoire, je me base sur un entier de 2*53 bits.",[352,7623,7625],{"className":6044,"code":7624,"language":6046,"meta":291,"style":291},"function randomNumber() {\n  return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);\n}\n\nfunction randomBigInt() {\n  return (BigInt(randomNumber()) \u003C\u003C 53n) + BigInt(randomNumber());\n}\n",[344,7626,7627,7635,7661,7665,7669,7678,7716],{"__ignoreMap":291},[360,7628,7629,7631,7633],{"class":362,"line":363},[360,7630,6133],{"class":574},[360,7632,6273],{"class":381},[360,7634,2172],{"class":366},[360,7636,7637,7639,7641,7643,7645,7647,7649,7651,7653,7655,7657,7659],{"class":362,"line":292},[360,7638,826],{"class":574},[360,7640,6217],{"class":662},[360,7642,31],{"class":366},[360,7644,6222],{"class":381},[360,7646,671],{"class":366},[360,7648,6227],{"class":662},[360,7650,31],{"class":366},[360,7652,6232],{"class":381},[360,7654,2805],{"class":366},[360,7656,925],{"class":582},[360,7658,6300],{"class":662},[360,7660,6303],{"class":366},[360,7662,7663],{"class":362,"line":375},[360,7664,847],{"class":366},[360,7666,7667],{"class":362,"line":433},[360,7668,372],{"emptyLinePlaceholder":320},[360,7670,7671,7673,7676],{"class":362,"line":478},[360,7672,6133],{"class":574},[360,7674,7675],{"class":381}," randomBigInt",[360,7677,2172],{"class":366},[360,7679,7680,7682,7684,7687,7689,7691,7694,7697,7700,7703,7705,7707,7710,7712,7714],{"class":362,"line":483},[360,7681,826],{"class":574},[360,7683,743],{"class":366},[360,7685,7686],{"class":381},"BigInt",[360,7688,671],{"class":366},[360,7690,6375],{"class":381},[360,7692,7693],{"class":366},"()) ",[360,7695,7696],{"class":582},"\u003C\u003C",[360,7698,7699],{"class":414}," 53",[360,7701,7702],{"class":574},"n",[360,7704,3972],{"class":366},[360,7706,1310],{"class":582},[360,7708,7709],{"class":381}," BigInt",[360,7711,671],{"class":366},[360,7713,6375],{"class":381},[360,7715,841],{"class":366},[360,7717,7718],{"class":362,"line":489},[360,7719,847],{"class":366},[12,7721,7722],{},"Le résultat est le suivant:",[1545,7724,7725,7733],{},[1548,7726,7727],{},[1551,7728,7729,7731],{},[1554,7730],{},[1554,7732],{},[1567,7734,7735,7741,7748,7755,7762,7769,7776],{},[1551,7736,7737,7739],{},[1572,7738,7544],{},[1572,7740,7547],{},[1551,7742,7743,7745],{},[1572,7744,7552],{},[1572,7746,7747],{},"14 secondes",[1551,7749,7750,7752],{},[1572,7751,7560],{},[1572,7753,7754],{},"2,1 Go",[1551,7756,7757,7759],{},[1572,7758,7568],{},[1572,7760,7761],{},"1,7 Ko",[1551,7763,7764,7766],{},[1572,7765,7576],{},[1572,7767,7768],{},"40 secondes",[1551,7770,7771,7773],{},[1572,7772,7584],{},[1572,7774,7775],{},"747,8 Mo",[1551,7777,7778,7780],{},[1572,7779,7592],{},[1572,7781,7782],{},"603 octets",[12,7784,7785,7786,7788],{},"L'utilisation de ",[344,7787,7686],{}," permet de réduire la consommation mémoire de 25% et la taille des objets dans le fichier de\n33%. La taille des objets sur le disque est acceptable. En revanche, la consommation mémoire de Node.js reste trop\nimportante.",[33,7790,7792],{"id":7791},"ecriture-du-même-code-en-rust","Ecriture du même code en Rust",[12,7794,7795],{},"Il est possible d'optimiser certaines parties de l'application grâce à la notion de node_modules natifs. Habituellement,\nces modules sont écrits en C++ en utilisant N-API. Il existe des bindings pour Rust, ce qui permet d'écrire une partie\nde l'application en Rust et de l'utiliser dans Node.JS.",[12,7797,7798,7799,7802,7803,31],{},"Pour comparer les performances de Rust et de Node.js, j'ai écrit le même code en Rust. Pour les nombres, je me suis basé\nsur des entiers de 64 bits et pour le nom de fichier, sur un ",[344,7800,7801],{},"Vec\u003Cu8>",". Je me suis basé sur une table de 32 caractères\npour le ",[344,7804,7805],{},"Sha256",[352,7807,7809],{"className":2114,"code":7808,"language":2116,"meta":291,"style":291},"use humansize::{format_size, make_format, DECIMAL};\nuse procinfo::pid;\nuse rand::{rngs::ThreadRng, Rng};\nuse serde::{Deserialize, Serialize};\nuse std::io::BufWriter;\n\n#[derive(Serialize, Deserialize, Debug)]\nstruct Stats {\n    owner_id: u64,\n    group_id: u64,\n    size: u64,\n    compressed_size: u64,\n    last_read: u64,\n    last_modified: u64,\n    created: u64,\n    mode: u64,\n    dev: u64,\n    rdev: u64,\n    ino: u64,\n    nlink: u64,\n}\n\n#[derive(Serialize, Deserialize, Debug)]\nstruct Sha256 {\n    data: [u8; 32],\n}\n\n#[derive(Serialize, Deserialize, Debug)]\nstruct TestObject {\n    #[serde(with = \"serde_bytes\")]\n    path: Vec\u003Cu8>,\n    stats: Stats,\n\n    chunks: Vec\u003CSha256>,\n    sha256: Sha256,\n}\n\nfn generate_random_number(rng: &mut ThreadRng) -> u64 {\n    rng.gen()\n}\n\nfn generate_random_vect(rng: &mut ThreadRng, size: usize) -> Vec\u003Cu8> {\n    let mut vect: Vec\u003Cu8> = Vec::with_capacity(size);\n    for _ in 0..size {\n        vect.push(rng.gen());\n    }\n    vect\n}\n\nfn generate_random_sha256(rng: &mut ThreadRng) -> Sha256 {\n    let mut sha256 = Sha256 { data: [0; 32] };\n    for i in 0..32 {\n        sha256.data[i] = rng.gen();\n    }\n    sha256\n}\n\nfn main() {\n    let formatter = make_format(DECIMAL);\n    let mut rng = rand::thread_rng();\n    \u002F\u002F Get the memory consumption of the current process\n    let memory = pid::statm_self().unwrap();\n    \u002F\u002F Get the current time in ms\n    let now = std::time::SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .unwrap()\n        .as_millis();\n\n    \u002F\u002F Create a vector with 1_300_000 elements of type TestObject\n    let nb_object = 1_300_000;\n    let mut test_objects: Vec\u003CTestObject> = Vec::with_capacity(nb_object);\n    for _ in 0..nb_object {\n        test_objects.push(TestObject {\n            path: generate_random_vect(&mut rng, 100),\n            stats: Stats {\n                owner_id: generate_random_number(&mut rng),\n                group_id: generate_random_number(&mut rng),\n                size: generate_random_number(&mut rng),\n                compressed_size: generate_random_number(&mut rng),\n                last_read: generate_random_number(&mut rng),\n                last_modified: generate_random_number(&mut rng),\n                created: generate_random_number(&mut rng),\n                mode: generate_random_number(&mut rng),\n                dev: generate_random_number(&mut rng),\n                rdev: generate_random_number(&mut rng),\n                ino: generate_random_number(&mut rng),\n                nlink: generate_random_number(&mut rng),\n            },\n            chunks: vec![\n                generate_random_sha256(&mut rng),\n                generate_random_sha256(&mut rng),\n                generate_random_sha256(&mut rng),\n            ],\n            sha256: generate_random_sha256(&mut rng),\n        });\n    }\n\n    let now_after_creation = std::time::SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .unwrap()\n        .as_millis();\n    \u002F\u002F Calculate the creation time\n    println!(\"Creation time: {} ms\", now_after_creation - now);\n\n    \u002F\u002F Get the memory consumption of the current process\n    let memory_after_creation = pid::statm_self().unwrap();\n    \u002F\u002F Show memory consumption\n    println!(\n        \"Memory consumption after creation: {}\",\n        formatter((memory_after_creation.size - memory.size) * 4096)\n    );\n    \u002F\u002F Show average memory consumption per object\n    println!(\n        \"Average memory consumption per object: {}\",\n        formatter(((memory_after_creation.size - memory.size) * 4096) \u002F nb_object)\n    );\n\n    \u002F\u002F Remove the file test.bin if it exists\n    match std::fs::remove_file(\"test.bin\") {\n        Ok(_) => {}\n        Err(_) => {}\n    }\n\n    \u002F\u002F Serialize all the objects in a file\n    let file = std::fs::File::create(\"test.bin\").unwrap();\n    let mut buffile = BufWriter::new(file);\n    for test_object in test_objects.iter() {\n        bincode::serialize_into(&mut buffile, test_object).unwrap();\n    }\n\n    \u002F\u002F Show time to write\n    let now_after_serialization = std::time::SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .unwrap()\n        .as_millis();\n\n    println!(\n        \"Write to file time: {} ms\",\n        now_after_serialization - now_after_creation\n    );\n\n    \u002F\u002F Get the file size and the average object size in file\n    let metadata = std::fs::metadata(\"test.bin\").unwrap();\n    println!(\n        \"Size of file on disk: {}\",\n        format_size(metadata.len(), DECIMAL)\n    );\n    println!(\n        \"Size of object in the file: {}\",\n        format_size(metadata.len() \u002F nb_object as u64, DECIMAL)\n    );\n}\n",[344,7810,7811,7826,7836,7861,7880,7897,7901,7920,7929,7940,7951,7961,7972,7983,7994,8004,8014,8024,8034,8044,8054,8058,8062,8078,8087,8102,8106,8110,8126,8135,8147,8162,8174,8178,8193,8204,8208,8212,8237,8249,8253,8257,8292,8326,8346,8366,8370,8375,8379,8383,8406,8435,8451,8474,8478,8483,8487,8491,8499,8517,8536,8541,8564,8569,8596,8619,8627,8636,8640,8645,8658,8693,8709,8724,8746,8757,8775,8792,8809,8826,8843,8860,8877,8894,8911,8928,8945,8962,8967,8980,8993,9005,9017,9022,9040,9045,9049,9054,9080,9101,9110,9119,9125,9147,9152,9157,9179,9185,9192,9200,9225,9231,9237,9244,9252,9277,9282,9287,9293,9316,9329,9341,9346,9351,9357,9391,9417,9436,9464,9469,9474,9480,9506,9527,9536,9545,9550,9557,9565,9576,9581,9586,9592,9623,9630,9638,9658,9663,9670,9678,9707,9712],{"__ignoreMap":291},[360,7812,7813,7815,7818,7821,7824],{"class":362,"line":363},[360,7814,2123],{"class":574},[360,7816,7817],{"class":662}," humansize",[360,7819,7820],{"class":366},"::{format_size, make_format, ",[360,7822,7823],{"class":662},"DECIMAL",[360,7825,1036],{"class":366},[360,7827,7828,7830,7833],{"class":362,"line":292},[360,7829,2123],{"class":574},[360,7831,7832],{"class":662}," procinfo",[360,7834,7835],{"class":366},"::pid;\n",[360,7837,7838,7840,7843,7846,7849,7851,7854,7856,7859],{"class":362,"line":375},[360,7839,2123],{"class":574},[360,7841,7842],{"class":662}," rand",[360,7844,7845],{"class":366},"::{",[360,7847,7848],{"class":662},"rngs",[360,7850,666],{"class":366},[360,7852,7853],{"class":662},"ThreadRng",[360,7855,2311],{"class":366},[360,7857,7858],{"class":662},"Rng",[360,7860,1036],{"class":366},[360,7862,7863,7865,7868,7870,7873,7875,7878],{"class":362,"line":433},[360,7864,2123],{"class":574},[360,7866,7867],{"class":662}," serde",[360,7869,7845],{"class":366},[360,7871,7872],{"class":662},"Deserialize",[360,7874,2311],{"class":366},[360,7876,7877],{"class":662},"Serialize",[360,7879,1036],{"class":366},[360,7881,7882,7884,7886,7888,7890,7892,7895],{"class":362,"line":478},[360,7883,2123],{"class":574},[360,7885,2145],{"class":662},[360,7887,666],{"class":366},[360,7889,2748],{"class":662},[360,7891,666],{"class":366},[360,7893,7894],{"class":662},"BufWriter",[360,7896,735],{"class":366},[360,7898,7899],{"class":362,"line":483},[360,7900,372],{"emptyLinePlaceholder":320},[360,7902,7903,7906,7908,7910,7912,7914,7917],{"class":362,"line":489},[360,7904,7905],{"class":366},"#[derive(",[360,7907,7877],{"class":662},[360,7909,2311],{"class":366},[360,7911,7872],{"class":662},[360,7913,2311],{"class":366},[360,7915,7916],{"class":662},"Debug",[360,7918,7919],{"class":366},")]\n",[360,7921,7922,7924,7927],{"class":362,"line":494},[360,7923,890],{"class":574},[360,7925,7926],{"class":662}," Stats",[360,7928,896],{"class":366},[360,7930,7931,7934,7936,7938],{"class":362,"line":712},[360,7932,7933],{"class":578},"    owner_id",[360,7935,2691],{"class":366},[360,7937,4364],{"class":662},[360,7939,2968],{"class":366},[360,7941,7942,7945,7947,7949],{"class":362,"line":331},[360,7943,7944],{"class":578},"    group_id",[360,7946,2691],{"class":366},[360,7948,4364],{"class":662},[360,7950,2968],{"class":366},[360,7952,7953,7955,7957,7959],{"class":362,"line":762},[360,7954,6433],{"class":578},[360,7956,2691],{"class":366},[360,7958,4364],{"class":662},[360,7960,2968],{"class":366},[360,7962,7963,7966,7968,7970],{"class":362,"line":781},[360,7964,7965],{"class":578},"    compressed_size",[360,7967,2691],{"class":366},[360,7969,4364],{"class":662},[360,7971,2968],{"class":366},[360,7973,7974,7977,7979,7981],{"class":362,"line":804},[360,7975,7976],{"class":578},"    last_read",[360,7978,2691],{"class":366},[360,7980,4364],{"class":662},[360,7982,2968],{"class":366},[360,7984,7985,7988,7990,7992],{"class":362,"line":817},[360,7986,7987],{"class":578},"    last_modified",[360,7989,2691],{"class":366},[360,7991,4364],{"class":662},[360,7993,2968],{"class":366},[360,7995,7996,7998,8000,8002],{"class":362,"line":823},[360,7997,6572],{"class":578},[360,7999,2691],{"class":366},[360,8001,4364],{"class":662},[360,8003,2968],{"class":366},[360,8005,8006,8008,8010,8012],{"class":362,"line":844},[360,8007,6603],{"class":578},[360,8009,2691],{"class":366},[360,8011,4364],{"class":662},[360,8013,2968],{"class":366},[360,8015,8016,8018,8020,8022],{"class":362,"line":1441},[360,8017,6634],{"class":578},[360,8019,2691],{"class":366},[360,8021,4364],{"class":662},[360,8023,2968],{"class":366},[360,8025,8026,8028,8030,8032],{"class":362,"line":1462},[360,8027,6665],{"class":578},[360,8029,2691],{"class":366},[360,8031,4364],{"class":662},[360,8033,2968],{"class":366},[360,8035,8036,8038,8040,8042],{"class":362,"line":1485},[360,8037,6696],{"class":578},[360,8039,2691],{"class":366},[360,8041,4364],{"class":662},[360,8043,2968],{"class":366},[360,8045,8046,8048,8050,8052],{"class":362,"line":1497},[360,8047,6727],{"class":578},[360,8049,2691],{"class":366},[360,8051,4364],{"class":662},[360,8053,2968],{"class":366},[360,8055,8056],{"class":362,"line":3161},[360,8057,847],{"class":366},[360,8059,8060],{"class":362,"line":3167},[360,8061,372],{"emptyLinePlaceholder":320},[360,8063,8064,8066,8068,8070,8072,8074,8076],{"class":362,"line":3194},[360,8065,7905],{"class":366},[360,8067,7877],{"class":662},[360,8069,2311],{"class":366},[360,8071,7872],{"class":662},[360,8073,2311],{"class":366},[360,8075,7916],{"class":662},[360,8077,7919],{"class":366},[360,8079,8080,8082,8085],{"class":362,"line":3224},[360,8081,890],{"class":574},[360,8083,8084],{"class":662}," Sha256",[360,8086,896],{"class":366},[360,8088,8089,8092,8094,8096,8098,8100],{"class":362,"line":3239},[360,8090,8091],{"class":578},"    data",[360,8093,4418],{"class":366},[360,8095,2742],{"class":662},[360,8097,4423],{"class":366},[360,8099,6772],{"class":414},[360,8101,5436],{"class":366},[360,8103,8104],{"class":362,"line":3256},[360,8105,847],{"class":366},[360,8107,8108],{"class":362,"line":3276},[360,8109,372],{"emptyLinePlaceholder":320},[360,8111,8112,8114,8116,8118,8120,8122,8124],{"class":362,"line":3281},[360,8113,7905],{"class":366},[360,8115,7877],{"class":662},[360,8117,2311],{"class":366},[360,8119,7872],{"class":662},[360,8121,2311],{"class":366},[360,8123,7916],{"class":662},[360,8125,7919],{"class":366},[360,8127,8128,8130,8133],{"class":362,"line":3305},[360,8129,890],{"class":574},[360,8131,8132],{"class":662}," TestObject",[360,8134,896],{"class":366},[360,8136,8137,8140,8142,8145],{"class":362,"line":3320},[360,8138,8139],{"class":366},"    #[serde(with ",[360,8141,583],{"class":582},[360,8143,8144],{"class":397}," \"serde_bytes\"",[360,8146,7919],{"class":366},[360,8148,8149,8151,8153,8155,8157,8159],{"class":362,"line":3325},[360,8150,5822],{"class":578},[360,8152,2691],{"class":366},[360,8154,2995],{"class":662},[360,8156,1358],{"class":366},[360,8158,2742],{"class":662},[360,8160,8161],{"class":366},">,\n",[360,8163,8164,8167,8169,8172],{"class":362,"line":3361},[360,8165,8166],{"class":578},"    stats",[360,8168,2691],{"class":366},[360,8170,8171],{"class":662},"Stats",[360,8173,2968],{"class":366},[360,8175,8176],{"class":362,"line":3380},[360,8177,372],{"emptyLinePlaceholder":320},[360,8179,8180,8183,8185,8187,8189,8191],{"class":362,"line":3405},[360,8181,8182],{"class":578},"    chunks",[360,8184,2691],{"class":366},[360,8186,2995],{"class":662},[360,8188,1358],{"class":366},[360,8190,7805],{"class":662},[360,8192,8161],{"class":366},[360,8194,8195,8198,8200,8202],{"class":362,"line":3411},[360,8196,8197],{"class":578},"    sha256",[360,8199,2691],{"class":366},[360,8201,7805],{"class":662},[360,8203,2968],{"class":366},[360,8205,8206],{"class":362,"line":3426},[360,8207,847],{"class":366},[360,8209,8210],{"class":362,"line":3432},[360,8211,372],{"emptyLinePlaceholder":320},[360,8213,8214,8216,8219,8221,8224,8226,8228,8231,8233,8235],{"class":362,"line":3438},[360,8215,2166],{"class":574},[360,8217,8218],{"class":381}," generate_random_number",[360,8220,671],{"class":366},[360,8222,8223],{"class":578},"rng",[360,8225,2734],{"class":366},[360,8227,2290],{"class":574},[360,8229,8230],{"class":662}," ThreadRng",[360,8232,3052],{"class":366},[360,8234,4364],{"class":662},[360,8236,896],{"class":366},[360,8238,8239,8242,8244,8247],{"class":362,"line":3443},[360,8240,8241],{"class":578},"    rng",[360,8243,31],{"class":366},[360,8245,8246],{"class":381},"gen",[360,8248,5008],{"class":366},[360,8250,8251],{"class":362,"line":3462},[360,8252,847],{"class":366},[360,8254,8255],{"class":362,"line":3467},[360,8256,372],{"emptyLinePlaceholder":320},[360,8258,8259,8261,8264,8266,8268,8270,8272,8274,8276,8278,8280,8282,8284,8286,8288,8290],{"class":362,"line":3472},[360,8260,2166],{"class":574},[360,8262,8263],{"class":381}," generate_random_vect",[360,8265,671],{"class":366},[360,8267,8223],{"class":578},[360,8269,2734],{"class":366},[360,8271,2290],{"class":574},[360,8273,8230],{"class":662},[360,8275,2311],{"class":366},[360,8277,6141],{"class":578},[360,8279,2691],{"class":366},[360,8281,2758],{"class":662},[360,8283,3052],{"class":366},[360,8285,2995],{"class":662},[360,8287,1358],{"class":366},[360,8289,2742],{"class":662},[360,8291,2711],{"class":366},[360,8293,8294,8296,8298,8301,8303,8305,8307,8309,8311,8313,8315,8317,8320,8322,8324],{"class":362,"line":3495},[360,8295,2177],{"class":574},[360,8297,2235],{"class":574},[360,8299,8300],{"class":578}," vect",[360,8302,2691],{"class":366},[360,8304,2995],{"class":662},[360,8306,1358],{"class":366},[360,8308,2742],{"class":662},[360,8310,2697],{"class":366},[360,8312,583],{"class":582},[360,8314,2268],{"class":662},[360,8316,666],{"class":366},[360,8318,8319],{"class":381},"with_capacity",[360,8321,671],{"class":366},[360,8323,6141],{"class":578},[360,8325,801],{"class":366},[360,8327,8328,8331,8334,8337,8339,8342,8344],{"class":362,"line":3500},[360,8329,8330],{"class":574},"    for",[360,8332,8333],{"class":578}," _",[360,8335,8336],{"class":574}," in",[360,8338,1457],{"class":414},[360,8340,8341],{"class":366},"..",[360,8343,6141],{"class":578},[360,8345,896],{"class":366},[360,8347,8348,8351,8353,8356,8358,8360,8362,8364],{"class":362,"line":3505},[360,8349,8350],{"class":578},"        vect",[360,8352,31],{"class":366},[360,8354,8355],{"class":381},"push",[360,8357,671],{"class":366},[360,8359,8223],{"class":578},[360,8361,31],{"class":366},[360,8363,8246],{"class":574},[360,8365,841],{"class":366},[360,8367,8368],{"class":362,"line":3530},[360,8369,2927],{"class":366},[360,8371,8372],{"class":362,"line":3545},[360,8373,8374],{"class":578},"    vect\n",[360,8376,8377],{"class":362,"line":3558},[360,8378,847],{"class":366},[360,8380,8381],{"class":362,"line":3573},[360,8382,372],{"emptyLinePlaceholder":320},[360,8384,8385,8387,8390,8392,8394,8396,8398,8400,8402,8404],{"class":362,"line":3578},[360,8386,2166],{"class":574},[360,8388,8389],{"class":381}," generate_random_sha256",[360,8391,671],{"class":366},[360,8393,8223],{"class":578},[360,8395,2734],{"class":366},[360,8397,2290],{"class":574},[360,8399,8230],{"class":662},[360,8401,3052],{"class":366},[360,8403,7805],{"class":662},[360,8405,896],{"class":366},[360,8407,8408,8410,8412,8415,8417,8419,8421,8424,8426,8428,8430,8432],{"class":362,"line":3583},[360,8409,2177],{"class":574},[360,8411,2235],{"class":574},[360,8413,8414],{"class":578}," sha256",[360,8416,401],{"class":582},[360,8418,8084],{"class":662},[360,8420,5879],{"class":366},[360,8422,8423],{"class":578},"data",[360,8425,4418],{"class":366},[360,8427,1344],{"class":414},[360,8429,4423],{"class":366},[360,8431,6772],{"class":414},[360,8433,8434],{"class":366},"] };\n",[360,8436,8437,8439,8441,8443,8445,8447,8449],{"class":362,"line":6893},[360,8438,8330],{"class":574},[360,8440,6178],{"class":578},[360,8442,8336],{"class":574},[360,8444,1457],{"class":414},[360,8446,8341],{"class":366},[360,8448,6772],{"class":414},[360,8450,896],{"class":366},[360,8452,8453,8456,8459,8461,8463,8465,8468,8470,8472],{"class":362,"line":6899},[360,8454,8455],{"class":578},"        sha256",[360,8457,8458],{"class":366},".data[",[360,8460,6187],{"class":578},[360,8462,2390],{"class":366},[360,8464,583],{"class":582},[360,8466,8467],{"class":578}," rng",[360,8469,31],{"class":366},[360,8471,8246],{"class":381},[360,8473,2204],{"class":366},[360,8475,8476],{"class":362,"line":6905},[360,8477,2927],{"class":366},[360,8479,8480],{"class":362,"line":6920},[360,8481,8482],{"class":578},"    sha256\n",[360,8484,8485],{"class":362,"line":6942},[360,8486,847],{"class":366},[360,8488,8489],{"class":362,"line":6974},[360,8490,372],{"emptyLinePlaceholder":320},[360,8492,8493,8495,8497],{"class":362,"line":6992},[360,8494,2166],{"class":574},[360,8496,2169],{"class":381},[360,8498,2172],{"class":366},[360,8500,8501,8503,8506,8508,8511,8513,8515],{"class":362,"line":6997},[360,8502,2177],{"class":574},[360,8504,8505],{"class":578}," formatter",[360,8507,401],{"class":582},[360,8509,8510],{"class":381}," make_format",[360,8512,671],{"class":366},[360,8514,7823],{"class":414},[360,8516,801],{"class":366},[360,8518,8519,8521,8523,8525,8527,8529,8531,8534],{"class":362,"line":7002},[360,8520,2177],{"class":574},[360,8522,2235],{"class":574},[360,8524,8467],{"class":578},[360,8526,401],{"class":582},[360,8528,7842],{"class":662},[360,8530,666],{"class":366},[360,8532,8533],{"class":381},"thread_rng",[360,8535,2204],{"class":366},[360,8537,8538],{"class":362,"line":7008},[360,8539,8540],{"class":644},"    \u002F\u002F Get the memory consumption of the current process\n",[360,8542,8543,8545,8548,8550,8553,8555,8558,8560,8562],{"class":362,"line":7041},[360,8544,2177],{"class":574},[360,8546,8547],{"class":578}," memory",[360,8549,401],{"class":582},[360,8551,8552],{"class":662}," pid",[360,8554,666],{"class":366},[360,8556,8557],{"class":381},"statm_self",[360,8559,3487],{"class":366},[360,8561,2201],{"class":381},[360,8563,2204],{"class":366},[360,8565,8566],{"class":362,"line":7047},[360,8567,8568],{"class":644},"    \u002F\u002F Get the current time in ms\n",[360,8570,8571,8573,8576,8578,8580,8582,8585,8587,8590,8592,8594],{"class":362,"line":7058},[360,8572,2177],{"class":574},[360,8574,8575],{"class":578}," now",[360,8577,401],{"class":582},[360,8579,2145],{"class":662},[360,8581,666],{"class":366},[360,8583,8584],{"class":662},"time",[360,8586,666],{"class":366},[360,8588,8589],{"class":662},"SystemTime",[360,8591,666],{"class":366},[360,8593,6884],{"class":381},[360,8595,5008],{"class":366},[360,8597,8598,8601,8604,8606,8608,8610,8612,8614,8617],{"class":362,"line":7064},[360,8599,8600],{"class":366},"        .",[360,8602,8603],{"class":381},"duration_since",[360,8605,671],{"class":366},[360,8607,5096],{"class":662},[360,8609,666],{"class":366},[360,8611,8584],{"class":662},[360,8613,666],{"class":366},[360,8615,8616],{"class":414},"UNIX_EPOCH",[360,8618,2922],{"class":366},[360,8620,8621,8623,8625],{"class":362,"line":7086},[360,8622,8600],{"class":366},[360,8624,2201],{"class":381},[360,8626,5008],{"class":366},[360,8628,8629,8631,8634],{"class":362,"line":7091},[360,8630,8600],{"class":366},[360,8632,8633],{"class":381},"as_millis",[360,8635,2204],{"class":366},[360,8637,8638],{"class":362,"line":7126},[360,8639,372],{"emptyLinePlaceholder":320},[360,8641,8642],{"class":362,"line":7165},[360,8643,8644],{"class":644},"    \u002F\u002F Create a vector with 1_300_000 elements of type TestObject\n",[360,8646,8647,8649,8652,8654,8656],{"class":362,"line":7170},[360,8648,2177],{"class":574},[360,8650,8651],{"class":578}," nb_object",[360,8653,401],{"class":582},[360,8655,6915],{"class":414},[360,8657,735],{"class":366},[360,8659,8660,8662,8664,8667,8669,8671,8673,8676,8678,8680,8682,8684,8686,8688,8691],{"class":362,"line":7176},[360,8661,2177],{"class":574},[360,8663,2235],{"class":574},[360,8665,8666],{"class":578}," test_objects",[360,8668,2691],{"class":366},[360,8670,2995],{"class":662},[360,8672,1358],{"class":366},[360,8674,8675],{"class":662},"TestObject",[360,8677,2697],{"class":366},[360,8679,583],{"class":582},[360,8681,2268],{"class":662},[360,8683,666],{"class":366},[360,8685,8319],{"class":381},[360,8687,671],{"class":366},[360,8689,8690],{"class":578},"nb_object",[360,8692,801],{"class":366},[360,8694,8695,8697,8699,8701,8703,8705,8707],{"class":362,"line":7182},[360,8696,8330],{"class":574},[360,8698,8333],{"class":578},[360,8700,8336],{"class":574},[360,8702,1457],{"class":414},[360,8704,8341],{"class":366},[360,8706,8690],{"class":578},[360,8708,896],{"class":366},[360,8710,8711,8714,8716,8718,8720,8722],{"class":362,"line":7200},[360,8712,8713],{"class":578},"        test_objects",[360,8715,31],{"class":366},[360,8717,8355],{"class":381},[360,8719,671],{"class":366},[360,8721,8675],{"class":662},[360,8723,896],{"class":366},[360,8725,8726,8729,8731,8734,8736,8738,8740,8742,8744],{"class":362,"line":7205},[360,8727,8728],{"class":578},"            path",[360,8730,2691],{"class":366},[360,8732,8733],{"class":381},"generate_random_vect",[360,8735,2287],{"class":366},[360,8737,2290],{"class":574},[360,8739,8467],{"class":578},[360,8741,2311],{"class":366},[360,8743,6349],{"class":414},[360,8745,5405],{"class":366},[360,8747,8748,8751,8753,8755],{"class":362,"line":7211},[360,8749,8750],{"class":578},"            stats",[360,8752,2691],{"class":366},[360,8754,8171],{"class":662},[360,8756,896],{"class":366},[360,8758,8759,8762,8764,8767,8769,8771,8773],{"class":362,"line":7219},[360,8760,8761],{"class":578},"                owner_id",[360,8763,2691],{"class":366},[360,8765,8766],{"class":381},"generate_random_number",[360,8768,2287],{"class":366},[360,8770,2290],{"class":574},[360,8772,8467],{"class":578},[360,8774,5405],{"class":366},[360,8776,8777,8780,8782,8784,8786,8788,8790],{"class":362,"line":7237},[360,8778,8779],{"class":578},"                group_id",[360,8781,2691],{"class":366},[360,8783,8766],{"class":381},[360,8785,2287],{"class":366},[360,8787,2290],{"class":574},[360,8789,8467],{"class":578},[360,8791,5405],{"class":366},[360,8793,8794,8797,8799,8801,8803,8805,8807],{"class":362,"line":7252},[360,8795,8796],{"class":578},"                size",[360,8798,2691],{"class":366},[360,8800,8766],{"class":381},[360,8802,2287],{"class":366},[360,8804,2290],{"class":574},[360,8806,8467],{"class":578},[360,8808,5405],{"class":366},[360,8810,8811,8814,8816,8818,8820,8822,8824],{"class":362,"line":7257},[360,8812,8813],{"class":578},"                compressed_size",[360,8815,2691],{"class":366},[360,8817,8766],{"class":381},[360,8819,2287],{"class":366},[360,8821,2290],{"class":574},[360,8823,8467],{"class":578},[360,8825,5405],{"class":366},[360,8827,8828,8831,8833,8835,8837,8839,8841],{"class":362,"line":7280},[360,8829,8830],{"class":578},"                last_read",[360,8832,2691],{"class":366},[360,8834,8766],{"class":381},[360,8836,2287],{"class":366},[360,8838,2290],{"class":574},[360,8840,8467],{"class":578},[360,8842,5405],{"class":366},[360,8844,8845,8848,8850,8852,8854,8856,8858],{"class":362,"line":7285},[360,8846,8847],{"class":578},"                last_modified",[360,8849,2691],{"class":366},[360,8851,8766],{"class":381},[360,8853,2287],{"class":366},[360,8855,2290],{"class":574},[360,8857,8467],{"class":578},[360,8859,5405],{"class":366},[360,8861,8862,8865,8867,8869,8871,8873,8875],{"class":362,"line":7291},[360,8863,8864],{"class":578},"                created",[360,8866,2691],{"class":366},[360,8868,8766],{"class":381},[360,8870,2287],{"class":366},[360,8872,2290],{"class":574},[360,8874,8467],{"class":578},[360,8876,5405],{"class":366},[360,8878,8879,8882,8884,8886,8888,8890,8892],{"class":362,"line":7314},[360,8880,8881],{"class":578},"                mode",[360,8883,2691],{"class":366},[360,8885,8766],{"class":381},[360,8887,2287],{"class":366},[360,8889,2290],{"class":574},[360,8891,8467],{"class":578},[360,8893,5405],{"class":366},[360,8895,8896,8899,8901,8903,8905,8907,8909],{"class":362,"line":7345},[360,8897,8898],{"class":578},"                dev",[360,8900,2691],{"class":366},[360,8902,8766],{"class":381},[360,8904,2287],{"class":366},[360,8906,2290],{"class":574},[360,8908,8467],{"class":578},[360,8910,5405],{"class":366},[360,8912,8913,8916,8918,8920,8922,8924,8926],{"class":362,"line":7351},[360,8914,8915],{"class":578},"                rdev",[360,8917,2691],{"class":366},[360,8919,8766],{"class":381},[360,8921,2287],{"class":366},[360,8923,2290],{"class":574},[360,8925,8467],{"class":578},[360,8927,5405],{"class":366},[360,8929,8930,8933,8935,8937,8939,8941,8943],{"class":362,"line":7374},[360,8931,8932],{"class":578},"                ino",[360,8934,2691],{"class":366},[360,8936,8766],{"class":381},[360,8938,2287],{"class":366},[360,8940,2290],{"class":574},[360,8942,8467],{"class":578},[360,8944,5405],{"class":366},[360,8946,8947,8950,8952,8954,8956,8958,8960],{"class":362,"line":7407},[360,8948,8949],{"class":578},"                nlink",[360,8951,2691],{"class":366},[360,8953,8766],{"class":381},[360,8955,2287],{"class":366},[360,8957,2290],{"class":574},[360,8959,8467],{"class":578},[360,8961,5405],{"class":366},[360,8963,8964],{"class":362,"line":7418},[360,8965,8966],{"class":366},"            },\n",[360,8968,8969,8972,8974,8977],{"class":362,"line":7426},[360,8970,8971],{"class":578},"            chunks",[360,8973,2691],{"class":366},[360,8975,8976],{"class":381},"vec!",[360,8978,8979],{"class":366},"[\n",[360,8981,8982,8985,8987,8989,8991],{"class":362,"line":7451},[360,8983,8984],{"class":381},"                generate_random_sha256",[360,8986,2287],{"class":366},[360,8988,2290],{"class":574},[360,8990,8467],{"class":578},[360,8992,5405],{"class":366},[360,8994,8995,8997,8999,9001,9003],{"class":362,"line":7457},[360,8996,8984],{"class":381},[360,8998,2287],{"class":366},[360,9000,2290],{"class":574},[360,9002,8467],{"class":578},[360,9004,5405],{"class":366},[360,9006,9007,9009,9011,9013,9015],{"class":362,"line":7462},[360,9008,8984],{"class":381},[360,9010,2287],{"class":366},[360,9012,2290],{"class":574},[360,9014,8467],{"class":578},[360,9016,5405],{"class":366},[360,9018,9019],{"class":362,"line":7467},[360,9020,9021],{"class":366},"            ],\n",[360,9023,9024,9027,9029,9032,9034,9036,9038],{"class":362,"line":7485},[360,9025,9026],{"class":578},"            sha256",[360,9028,2691],{"class":366},[360,9030,9031],{"class":381},"generate_random_sha256",[360,9033,2287],{"class":366},[360,9035,2290],{"class":574},[360,9037,8467],{"class":578},[360,9039,5405],{"class":366},[360,9041,9042],{"class":362,"line":7507},[360,9043,9044],{"class":366},"        });\n",[360,9046,9047],{"class":362,"line":7512},[360,9048,2927],{"class":366},[360,9050,9052],{"class":362,"line":9051},97,[360,9053,372],{"emptyLinePlaceholder":320},[360,9055,9057,9059,9062,9064,9066,9068,9070,9072,9074,9076,9078],{"class":362,"line":9056},98,[360,9058,2177],{"class":574},[360,9060,9061],{"class":578}," now_after_creation",[360,9063,401],{"class":582},[360,9065,2145],{"class":662},[360,9067,666],{"class":366},[360,9069,8584],{"class":662},[360,9071,666],{"class":366},[360,9073,8589],{"class":662},[360,9075,666],{"class":366},[360,9077,6884],{"class":381},[360,9079,5008],{"class":366},[360,9081,9083,9085,9087,9089,9091,9093,9095,9097,9099],{"class":362,"line":9082},99,[360,9084,8600],{"class":366},[360,9086,8603],{"class":381},[360,9088,671],{"class":366},[360,9090,5096],{"class":662},[360,9092,666],{"class":366},[360,9094,8584],{"class":662},[360,9096,666],{"class":366},[360,9098,8616],{"class":414},[360,9100,2922],{"class":366},[360,9102,9104,9106,9108],{"class":362,"line":9103},100,[360,9105,8600],{"class":366},[360,9107,2201],{"class":381},[360,9109,5008],{"class":366},[360,9111,9113,9115,9117],{"class":362,"line":9112},101,[360,9114,8600],{"class":366},[360,9116,8633],{"class":381},[360,9118,2204],{"class":366},[360,9120,9122],{"class":362,"line":9121},102,[360,9123,9124],{"class":644},"    \u002F\u002F Calculate the creation time\n",[360,9126,9128,9130,9132,9135,9137,9140,9143,9145],{"class":362,"line":9127},103,[360,9129,2303],{"class":381},[360,9131,671],{"class":366},[360,9133,9134],{"class":397},"\"Creation time: {} ms\"",[360,9136,2311],{"class":366},[360,9138,9139],{"class":578},"now_after_creation",[360,9141,9142],{"class":366}," - ",[360,9144,6884],{"class":578},[360,9146,801],{"class":366},[360,9148,9150],{"class":362,"line":9149},104,[360,9151,372],{"emptyLinePlaceholder":320},[360,9153,9155],{"class":362,"line":9154},105,[360,9156,8540],{"class":644},[360,9158,9160,9162,9165,9167,9169,9171,9173,9175,9177],{"class":362,"line":9159},106,[360,9161,2177],{"class":574},[360,9163,9164],{"class":578}," memory_after_creation",[360,9166,401],{"class":582},[360,9168,8552],{"class":662},[360,9170,666],{"class":366},[360,9172,8557],{"class":381},[360,9174,3487],{"class":366},[360,9176,2201],{"class":381},[360,9178,2204],{"class":366},[360,9180,9182],{"class":362,"line":9181},107,[360,9183,9184],{"class":644},"    \u002F\u002F Show memory consumption\n",[360,9186,9188,9190],{"class":362,"line":9187},108,[360,9189,2303],{"class":381},[360,9191,1395],{"class":366},[360,9193,9195,9198],{"class":362,"line":9194},109,[360,9196,9197],{"class":397},"        \"Memory consumption after creation: {}\"",[360,9199,2968],{"class":366},[360,9201,9203,9206,9208,9211,9214,9217,9220,9223],{"class":362,"line":9202},110,[360,9204,9205],{"class":381},"        formatter",[360,9207,7148],{"class":366},[360,9209,9210],{"class":578},"memory_after_creation",[360,9212,9213],{"class":366},".size - ",[360,9215,9216],{"class":578},"memory",[360,9218,9219],{"class":366},".size) * ",[360,9221,9222],{"class":414},"4096",[360,9224,2922],{"class":366},[360,9226,9228],{"class":362,"line":9227},111,[360,9229,9230],{"class":366},"    );\n",[360,9232,9234],{"class":362,"line":9233},112,[360,9235,9236],{"class":644},"    \u002F\u002F Show average memory consumption per object\n",[360,9238,9240,9242],{"class":362,"line":9239},113,[360,9241,2303],{"class":381},[360,9243,1395],{"class":366},[360,9245,9247,9250],{"class":362,"line":9246},114,[360,9248,9249],{"class":397},"        \"Average memory consumption per object: {}\"",[360,9251,2968],{"class":366},[360,9253,9255,9257,9260,9262,9264,9266,9268,9270,9273,9275],{"class":362,"line":9254},115,[360,9256,9205],{"class":381},[360,9258,9259],{"class":366},"(((",[360,9261,9210],{"class":578},[360,9263,9213],{"class":366},[360,9265,9216],{"class":578},[360,9267,9219],{"class":366},[360,9269,9222],{"class":414},[360,9271,9272],{"class":366},") \u002F ",[360,9274,8690],{"class":578},[360,9276,2922],{"class":366},[360,9278,9280],{"class":362,"line":9279},116,[360,9281,9230],{"class":366},[360,9283,9285],{"class":362,"line":9284},117,[360,9286,372],{"emptyLinePlaceholder":320},[360,9288,9290],{"class":362,"line":9289},118,[360,9291,9292],{"class":644},"    \u002F\u002F Remove the file test.bin if it exists\n",[360,9294,9296,9298,9300,9302,9304,9306,9309,9311,9314],{"class":362,"line":9295},119,[360,9297,4844],{"class":574},[360,9299,2145],{"class":662},[360,9301,666],{"class":366},[360,9303,2150],{"class":662},[360,9305,666],{"class":366},[360,9307,9308],{"class":381},"remove_file",[360,9310,671],{"class":366},[360,9312,9313],{"class":397},"\"test.bin\"",[360,9315,681],{"class":366},[360,9317,9319,9321,9323,9326],{"class":362,"line":9318},120,[360,9320,2915],{"class":662},[360,9322,671],{"class":366},[360,9324,9325],{"class":578},"_",[360,9327,9328],{"class":366},") => {}\n",[360,9330,9332,9335,9337,9339],{"class":362,"line":9331},121,[360,9333,9334],{"class":662},"        Err",[360,9336,671],{"class":366},[360,9338,9325],{"class":578},[360,9340,9328],{"class":366},[360,9342,9344],{"class":362,"line":9343},122,[360,9345,2927],{"class":366},[360,9347,9349],{"class":362,"line":9348},123,[360,9350,372],{"emptyLinePlaceholder":320},[360,9352,9354],{"class":362,"line":9353},124,[360,9355,9356],{"class":644},"    \u002F\u002F Serialize all the objects in a file\n",[360,9358,9360,9362,9364,9366,9368,9370,9372,9374,9376,9378,9381,9383,9385,9387,9389],{"class":362,"line":9359},125,[360,9361,2177],{"class":574},[360,9363,5642],{"class":578},[360,9365,401],{"class":582},[360,9367,2145],{"class":662},[360,9369,666],{"class":366},[360,9371,2150],{"class":662},[360,9373,666],{"class":366},[360,9375,2155],{"class":662},[360,9377,666],{"class":366},[360,9379,9380],{"class":381},"create",[360,9382,671],{"class":366},[360,9384,9313],{"class":397},[360,9386,2198],{"class":366},[360,9388,2201],{"class":381},[360,9390,2204],{"class":366},[360,9392,9394,9396,9398,9401,9403,9406,9408,9410,9412,9415],{"class":362,"line":9393},126,[360,9395,2177],{"class":574},[360,9397,2235],{"class":574},[360,9399,9400],{"class":578}," buffile",[360,9402,401],{"class":582},[360,9404,9405],{"class":662}," BufWriter",[360,9407,666],{"class":366},[360,9409,2221],{"class":381},[360,9411,671],{"class":366},[360,9413,9414],{"class":578},"file",[360,9416,801],{"class":366},[360,9418,9420,9422,9425,9427,9429,9431,9434],{"class":362,"line":9419},127,[360,9421,8330],{"class":574},[360,9423,9424],{"class":578}," test_object",[360,9426,8336],{"class":574},[360,9428,8666],{"class":578},[360,9430,31],{"class":366},[360,9432,9433],{"class":381},"iter",[360,9435,2172],{"class":366},[360,9437,9439,9442,9444,9447,9449,9451,9453,9455,9458,9460,9462],{"class":362,"line":9438},128,[360,9440,9441],{"class":662},"        bincode",[360,9443,666],{"class":366},[360,9445,9446],{"class":381},"serialize_into",[360,9448,2287],{"class":366},[360,9450,2290],{"class":574},[360,9452,9400],{"class":578},[360,9454,2311],{"class":366},[360,9456,9457],{"class":578},"test_object",[360,9459,2198],{"class":366},[360,9461,2201],{"class":381},[360,9463,2204],{"class":366},[360,9465,9467],{"class":362,"line":9466},129,[360,9468,2927],{"class":366},[360,9470,9472],{"class":362,"line":9471},130,[360,9473,372],{"emptyLinePlaceholder":320},[360,9475,9477],{"class":362,"line":9476},131,[360,9478,9479],{"class":644},"    \u002F\u002F Show time to write\n",[360,9481,9483,9485,9488,9490,9492,9494,9496,9498,9500,9502,9504],{"class":362,"line":9482},132,[360,9484,2177],{"class":574},[360,9486,9487],{"class":578}," now_after_serialization",[360,9489,401],{"class":582},[360,9491,2145],{"class":662},[360,9493,666],{"class":366},[360,9495,8584],{"class":662},[360,9497,666],{"class":366},[360,9499,8589],{"class":662},[360,9501,666],{"class":366},[360,9503,6884],{"class":381},[360,9505,5008],{"class":366},[360,9507,9509,9511,9513,9515,9517,9519,9521,9523,9525],{"class":362,"line":9508},133,[360,9510,8600],{"class":366},[360,9512,8603],{"class":381},[360,9514,671],{"class":366},[360,9516,5096],{"class":662},[360,9518,666],{"class":366},[360,9520,8584],{"class":662},[360,9522,666],{"class":366},[360,9524,8616],{"class":414},[360,9526,2922],{"class":366},[360,9528,9530,9532,9534],{"class":362,"line":9529},134,[360,9531,8600],{"class":366},[360,9533,2201],{"class":381},[360,9535,5008],{"class":366},[360,9537,9539,9541,9543],{"class":362,"line":9538},135,[360,9540,8600],{"class":366},[360,9542,8633],{"class":381},[360,9544,2204],{"class":366},[360,9546,9548],{"class":362,"line":9547},136,[360,9549,372],{"emptyLinePlaceholder":320},[360,9551,9553,9555],{"class":362,"line":9552},137,[360,9554,2303],{"class":381},[360,9556,1395],{"class":366},[360,9558,9560,9563],{"class":362,"line":9559},138,[360,9561,9562],{"class":397},"        \"Write to file time: {} ms\"",[360,9564,2968],{"class":366},[360,9566,9568,9571,9573],{"class":362,"line":9567},139,[360,9569,9570],{"class":578},"        now_after_serialization",[360,9572,9142],{"class":366},[360,9574,9575],{"class":578},"now_after_creation\n",[360,9577,9579],{"class":362,"line":9578},140,[360,9580,9230],{"class":366},[360,9582,9584],{"class":362,"line":9583},141,[360,9585,372],{"emptyLinePlaceholder":320},[360,9587,9589],{"class":362,"line":9588},142,[360,9590,9591],{"class":644},"    \u002F\u002F Get the file size and the average object size in file\n",[360,9593,9595,9597,9600,9602,9604,9606,9608,9610,9613,9615,9617,9619,9621],{"class":362,"line":9594},143,[360,9596,2177],{"class":574},[360,9598,9599],{"class":578}," metadata",[360,9601,401],{"class":582},[360,9603,2145],{"class":662},[360,9605,666],{"class":366},[360,9607,2150],{"class":662},[360,9609,666],{"class":366},[360,9611,9612],{"class":381},"metadata",[360,9614,671],{"class":366},[360,9616,9313],{"class":397},[360,9618,2198],{"class":366},[360,9620,2201],{"class":381},[360,9622,2204],{"class":366},[360,9624,9626,9628],{"class":362,"line":9625},144,[360,9627,2303],{"class":381},[360,9629,1395],{"class":366},[360,9631,9633,9636],{"class":362,"line":9632},145,[360,9634,9635],{"class":397},"        \"Size of file on disk: {}\"",[360,9637,2968],{"class":366},[360,9639,9641,9644,9646,9648,9650,9652,9654,9656],{"class":362,"line":9640},146,[360,9642,9643],{"class":381},"        format_size",[360,9645,671],{"class":366},[360,9647,9612],{"class":578},[360,9649,31],{"class":366},[360,9651,2802],{"class":381},[360,9653,6378],{"class":366},[360,9655,7823],{"class":414},[360,9657,2922],{"class":366},[360,9659,9661],{"class":362,"line":9660},147,[360,9662,9230],{"class":366},[360,9664,9666,9668],{"class":362,"line":9665},148,[360,9667,2303],{"class":381},[360,9669,1395],{"class":366},[360,9671,9673,9676],{"class":362,"line":9672},149,[360,9674,9675],{"class":397},"        \"Size of object in the file: {}\"",[360,9677,2968],{"class":366},[360,9679,9681,9683,9685,9687,9689,9691,9694,9696,9699,9701,9703,9705],{"class":362,"line":9680},150,[360,9682,9643],{"class":381},[360,9684,671],{"class":366},[360,9686,9612],{"class":578},[360,9688,31],{"class":366},[360,9690,2802],{"class":381},[360,9692,9693],{"class":366},"() \u002F ",[360,9695,8690],{"class":578},[360,9697,9698],{"class":574}," as",[360,9700,4508],{"class":662},[360,9702,2311],{"class":366},[360,9704,7823],{"class":414},[360,9706,2922],{"class":366},[360,9708,9710],{"class":362,"line":9709},151,[360,9711,9230],{"class":366},[360,9713,9715],{"class":362,"line":9714},152,[360,9716,847],{"class":366},[12,9718,9719],{},"Ce qui donne le résultat suivant :",[1545,9721,9722,9730],{},[1548,9723,9724],{},[1551,9725,9726,9728],{},[1554,9727],{},[1554,9729],{},[1567,9731,9732,9738,9745,9752,9759,9766,9773],{},[1551,9733,9734,9736],{},[1572,9735,7544],{},[1572,9737,7547],{},[1551,9739,9740,9742],{},[1572,9741,7552],{},[1572,9743,9744],{},"2 secondes",[1551,9746,9747,9749],{},[1572,9748,7560],{},[1572,9750,9751],{},"519,92 Mo",[1551,9753,9754,9756],{},[1572,9755,7568],{},[1572,9757,9758],{},"399 octets",[1551,9760,9761,9763],{},[1572,9762,7576],{},[1572,9764,9765],{},"1 seconde",[1551,9767,9768,9770],{},[1572,9769,7584],{},[1572,9771,9772],{},"441,99 Mb",[1551,9774,9775,9777],{},[1572,9776,7592],{},[1572,9778,9779],{},"339 octets",[12,9781,9782],{},"En comparant les résultats obtenus avec Node.js et Rust, on peut conclure que Rust est, sans contestation possible,\nbeaucoup plus performant que Node.js en termes de temps d'exécution et de consommation de mémoire pour la création de\n1,3 million d'objets. En effet, Rust a créé tous les objets en seulement 2 secondes et consommé 519,92 Mo de mémoire,\ntandis que Node.js a pris 15 secondes et consommé 2,8 Go de mémoire.",[12,9784,9785],{},"La consommation moyenne de mémoire par objet est du coup nettement plus faible avec Rust (399 octets) qu'avec\nNode.js (2,2 Ko).",[12,9787,9788],{},"En somme, cette première partie montre clairement que Rust est une alternative intéressante pour les applications\nnécessitant une manipulation intensive de données, en particulier lorsque la performance et la consommation de mémoire\nsont des critères importants.",[33,9790,9792],{"id":9791},"optimisation-de-notre-application","Optimisation de notre application",[12,9794,9795],{},"Pour optimiser notre application en TypeScript, nous allons développer un module natif en Node.js avec Rust. Pour cela,\nnous allons utiliser NAPI.RS.",[12,9797,9798],{},"N-API est une interface de programmation d'applications (API) qui permet aux modules natifs d'être facilement utilisés\ndans Node.js. Cela permet aux développeurs de créer des modules en C++ et de les utiliser dans des projets Node.js\nsans avoir à se soucier de la compatibilité entre les versions de Node.js.",[12,9800,9801],{},"N-API est une API stable et évolutive qui est maintenue par l'équipe Node.js. N-API fournit une interface de\nprogrammation d'applications indépendante du moteur JavaScript utilisé par Node.js. Cela signifie que les modules\ncompilés avec N-API fonctionnent de manière cohérente, quel que soit le moteur JavaScript utilisé par Node.js.",[12,9803,9804],{},"napi.rs est une bibliothèque Rust qui fournit une API pour écrire des modules Node.js en Rust. Elle simplifie la création\nde modules Node.js en fournissant des abstractions de niveau supérieur pour les fonctionnalités N-API. Avec napi.rs, les\ndéveloppeurs Rust peuvent facilement écrire des modules Node.js sans avoir à se soucier des détails techniques de N-API.",[12,9806,9807,9808,31],{},"Nous allons débuter le développement de la partie Rust de notre application. Je ne vais pas détailler la création d'un\nmodule Rust avec NAPI.RS. La documentation est assez bien faite pour cette partie : ",[47,9809,9810],{"href":9810,"rel":9811},"https:\u002F\u002Fnapi.rs\u002Fdocs\u002Fintroduction\u002Fsimple-package",[51],[12,9813,9814],{},"Le module que nous allons écrire doit conserver les objets qu'il crée en mémoire. En effet, si les objets créés côté Rust\nétaient ensuite transférés dans la partie Node.js, la consommation de mémoire serait la même que si nous avions créé\nles objets directement en Node.js.",[12,9816,9817],{},"L'exemple ci-dessous ne fait pas grand-chose, mais c'est un point à prendre en considération lorsque je vais développer\nle module pour mon application. Les objets transférés à la partie JavaScript ne doivent que transiter.",[12,9819,9820],{},"Voici la partie Rust :",[352,9822,9824],{"className":2114,"code":9823,"language":2116,"meta":291,"style":291},"#![deny(clippy::all)]\nuse humansize::{format_size, DECIMAL};\nuse procinfo::pid;\nuse rand::{rngs::ThreadRng, Rng};\n\n#[macro_use]\nextern crate napi_derive;\n\nstruct Stats {\n  owner_id: u64,\n  group_id: u64,\n  size: u64,\n  compressed_size: u64,\n  last_read: u64,\n  last_modified: u64,\n  created: u64,\n  mode: u64,\n  dev: u64,\n  rdev: u64,\n  ino: u64,\n  nlink: u64,\n}\n\nstruct Sha256 {\n  data: [u8; 32],\n}\n\nstruct TestObject {\n  path: Vec\u003Cu8>,\n  stats: Stats,\n\n  chunks: Vec\u003CSha256>,\n  sha256: Sha256,\n}\n\nfn generate_random_number(rng: &mut ThreadRng) -> u64 {\n  rng.gen()\n}\n\nfn generate_random_vect(rng: &mut ThreadRng, size: usize) -> Vec\u003Cu8> {\n  let mut vect: Vec\u003Cu8> = Vec::with_capacity(size);\n  for _ in 0..size {\n    vect.push(rng.gen());\n  }\n  vect\n}\n\nfn generate_random_sha256(rng: &mut ThreadRng) -> Sha256 {\n  let mut sha256 = Sha256 { data: [0; 32] };\n  for i in 0..32 {\n    sha256.data[i] = rng.gen();\n  }\n  sha256\n}\n\npub struct TestObjectWrapper {\n  test_objects: Vec\u003CTestObject>,\n}\n\n#[napi(js_name = \"TestObjectWrapper\")]\npub struct JsTestObjectWrapper {\n  test_object_wrapper: TestObjectWrapper,\n}\n\n#[napi]\nimpl JsTestObjectWrapper {\n  #[napi(constructor)]\n  pub fn new() -> Self {\n    Self {\n      test_object_wrapper: TestObjectWrapper {\n        test_objects: Vec::new(),\n      },\n    }\n  }\n\n  #[napi]\n  pub fn fill(&mut self, nb_object: i32) {\n    let mut rng = rand::thread_rng();\n    \u002F\u002F Get the memory consumption of the current process\n    let memory = pid::statm_self().unwrap();\n    \u002F\u002F Get the current time in ms\n    let now = std::time::SystemTime::now()\n      .duration_since(std::time::UNIX_EPOCH)\n      .unwrap()\n      .as_millis();\n\n    self.test_object_wrapper.test_objects = Vec::with_capacity(nb_object.try_into().unwrap());\n\n    for _ in 0..nb_object {\n      self.test_object_wrapper.test_objects.push(TestObject {\n        path: generate_random_vect(&mut rng, 100),\n        stats: Stats {\n          owner_id: generate_random_number(&mut rng),\n          group_id: generate_random_number(&mut rng),\n          size: generate_random_number(&mut rng),\n          compressed_size: generate_random_number(&mut rng),\n          last_read: generate_random_number(&mut rng),\n          last_modified: generate_random_number(&mut rng),\n          created: generate_random_number(&mut rng),\n          mode: generate_random_number(&mut rng),\n          dev: generate_random_number(&mut rng),\n          rdev: generate_random_number(&mut rng),\n          ino: generate_random_number(&mut rng),\n          nlink: generate_random_number(&mut rng),\n        },\n        chunks: vec![\n          generate_random_sha256(&mut rng),\n          generate_random_sha256(&mut rng),\n          generate_random_sha256(&mut rng),\n        ],\n        sha256: generate_random_sha256(&mut rng),\n      });\n    }\n\n    let now_after_creation = std::time::SystemTime::now()\n      .duration_since(std::time::UNIX_EPOCH)\n      .unwrap()\n      .as_millis();\n    \u002F\u002F Calculate the creation time\n    println!(\"Creation time: {} ms\", now_after_creation - now);\n\n    \u002F\u002F Get the memory consumption of the current process\n    let memory_after_creation = pid::statm_self().unwrap();\n    \u002F\u002F Show memory consumption\n    println!(\n      \"Memory consumption after creation: {}\",\n      format_size((memory_after_creation.size - memory.size) * 4096, DECIMAL)\n    );\n    \u002F\u002F Show average memory consumption per object\n    println!(\n      \"Average memory consumption per object: {}\",\n      format_size(\n        ((memory_after_creation.size - memory.size) * 4096) \u002F nb_object as usize,\n        DECIMAL\n      )\n    );\n  }\n\n  #[napi(js_name = \"toString\")]\n  pub fn to_string(&self) -> String {\n    format!(\n      \"TestObjectWrapper {{ test_objects: {} }}\",\n      self.test_object_wrapper.test_objects.len()\n    )\n  }\n}\n",[344,9825,9826,9831,9844,9852,9872,9876,9881,9892,9896,9904,9915,9926,9937,9948,9959,9970,9981,9992,10003,10014,10025,10036,10040,10044,10052,10067,10071,10075,10083,10097,10107,10111,10125,10135,10139,10143,10165,10176,10180,10184,10218,10251,10267,10286,10290,10295,10299,10303,10325,10351,10367,10387,10391,10396,10400,10404,10415,10430,10434,10438,10450,10461,10473,10477,10481,10486,10494,10499,10515,10522,10533,10547,10552,10556,10560,10564,10569,10595,10613,10617,10637,10641,10665,10686,10694,10702,10706,10737,10741,10757,10773,10794,10805,10822,10839,10856,10873,10890,10907,10924,10941,10958,10975,10992,11009,11014,11025,11038,11050,11062,11067,11083,11088,11092,11096,11120,11140,11148,11156,11160,11178,11182,11186,11206,11210,11216,11223,11246,11250,11254,11260,11267,11273,11299,11304,11309,11313,11317,11321,11333,11353,11360,11367,11377,11382,11386],{"__ignoreMap":291},[360,9827,9828],{"class":362,"line":363},[360,9829,9830],{"class":366},"#![deny(clippy::all)]\n",[360,9832,9833,9835,9837,9840,9842],{"class":362,"line":292},[360,9834,2123],{"class":574},[360,9836,7817],{"class":662},[360,9838,9839],{"class":366},"::{format_size, ",[360,9841,7823],{"class":662},[360,9843,1036],{"class":366},[360,9845,9846,9848,9850],{"class":362,"line":375},[360,9847,2123],{"class":574},[360,9849,7832],{"class":662},[360,9851,7835],{"class":366},[360,9853,9854,9856,9858,9860,9862,9864,9866,9868,9870],{"class":362,"line":433},[360,9855,2123],{"class":574},[360,9857,7842],{"class":662},[360,9859,7845],{"class":366},[360,9861,7848],{"class":662},[360,9863,666],{"class":366},[360,9865,7853],{"class":662},[360,9867,2311],{"class":366},[360,9869,7858],{"class":662},[360,9871,1036],{"class":366},[360,9873,9874],{"class":362,"line":478},[360,9875,372],{"emptyLinePlaceholder":320},[360,9877,9878],{"class":362,"line":483},[360,9879,9880],{"class":366},"#[macro_use]\n",[360,9882,9883,9886,9889],{"class":362,"line":489},[360,9884,9885],{"class":574},"extern",[360,9887,9888],{"class":574}," crate",[360,9890,9891],{"class":366}," napi_derive;\n",[360,9893,9894],{"class":362,"line":494},[360,9895,372],{"emptyLinePlaceholder":320},[360,9897,9898,9900,9902],{"class":362,"line":712},[360,9899,890],{"class":574},[360,9901,7926],{"class":662},[360,9903,896],{"class":366},[360,9905,9906,9909,9911,9913],{"class":362,"line":331},[360,9907,9908],{"class":578},"  owner_id",[360,9910,2691],{"class":366},[360,9912,4364],{"class":662},[360,9914,2968],{"class":366},[360,9916,9917,9920,9922,9924],{"class":362,"line":762},[360,9918,9919],{"class":578},"  group_id",[360,9921,2691],{"class":366},[360,9923,4364],{"class":662},[360,9925,2968],{"class":366},[360,9927,9928,9931,9933,9935],{"class":362,"line":781},[360,9929,9930],{"class":578},"  size",[360,9932,2691],{"class":366},[360,9934,4364],{"class":662},[360,9936,2968],{"class":366},[360,9938,9939,9942,9944,9946],{"class":362,"line":804},[360,9940,9941],{"class":578},"  compressed_size",[360,9943,2691],{"class":366},[360,9945,4364],{"class":662},[360,9947,2968],{"class":366},[360,9949,9950,9953,9955,9957],{"class":362,"line":817},[360,9951,9952],{"class":578},"  last_read",[360,9954,2691],{"class":366},[360,9956,4364],{"class":662},[360,9958,2968],{"class":366},[360,9960,9961,9964,9966,9968],{"class":362,"line":823},[360,9962,9963],{"class":578},"  last_modified",[360,9965,2691],{"class":366},[360,9967,4364],{"class":662},[360,9969,2968],{"class":366},[360,9971,9972,9975,9977,9979],{"class":362,"line":844},[360,9973,9974],{"class":578},"  created",[360,9976,2691],{"class":366},[360,9978,4364],{"class":662},[360,9980,2968],{"class":366},[360,9982,9983,9986,9988,9990],{"class":362,"line":1441},[360,9984,9985],{"class":578},"  mode",[360,9987,2691],{"class":366},[360,9989,4364],{"class":662},[360,9991,2968],{"class":366},[360,9993,9994,9997,9999,10001],{"class":362,"line":1462},[360,9995,9996],{"class":578},"  dev",[360,9998,2691],{"class":366},[360,10000,4364],{"class":662},[360,10002,2968],{"class":366},[360,10004,10005,10008,10010,10012],{"class":362,"line":1485},[360,10006,10007],{"class":578},"  rdev",[360,10009,2691],{"class":366},[360,10011,4364],{"class":662},[360,10013,2968],{"class":366},[360,10015,10016,10019,10021,10023],{"class":362,"line":1497},[360,10017,10018],{"class":578},"  ino",[360,10020,2691],{"class":366},[360,10022,4364],{"class":662},[360,10024,2968],{"class":366},[360,10026,10027,10030,10032,10034],{"class":362,"line":3161},[360,10028,10029],{"class":578},"  nlink",[360,10031,2691],{"class":366},[360,10033,4364],{"class":662},[360,10035,2968],{"class":366},[360,10037,10038],{"class":362,"line":3167},[360,10039,847],{"class":366},[360,10041,10042],{"class":362,"line":3194},[360,10043,372],{"emptyLinePlaceholder":320},[360,10045,10046,10048,10050],{"class":362,"line":3224},[360,10047,890],{"class":574},[360,10049,8084],{"class":662},[360,10051,896],{"class":366},[360,10053,10054,10057,10059,10061,10063,10065],{"class":362,"line":3239},[360,10055,10056],{"class":578},"  data",[360,10058,4418],{"class":366},[360,10060,2742],{"class":662},[360,10062,4423],{"class":366},[360,10064,6772],{"class":414},[360,10066,5436],{"class":366},[360,10068,10069],{"class":362,"line":3256},[360,10070,847],{"class":366},[360,10072,10073],{"class":362,"line":3276},[360,10074,372],{"emptyLinePlaceholder":320},[360,10076,10077,10079,10081],{"class":362,"line":3281},[360,10078,890],{"class":574},[360,10080,8132],{"class":662},[360,10082,896],{"class":366},[360,10084,10085,10087,10089,10091,10093,10095],{"class":362,"line":3305},[360,10086,6339],{"class":578},[360,10088,2691],{"class":366},[360,10090,2995],{"class":662},[360,10092,1358],{"class":366},[360,10094,2742],{"class":662},[360,10096,8161],{"class":366},[360,10098,10099,10101,10103,10105],{"class":362,"line":3320},[360,10100,6356],{"class":578},[360,10102,2691],{"class":366},[360,10104,8171],{"class":662},[360,10106,2968],{"class":366},[360,10108,10109],{"class":362,"line":3325},[360,10110,372],{"emptyLinePlaceholder":320},[360,10112,10113,10115,10117,10119,10121,10123],{"class":362,"line":3361},[360,10114,6763],{"class":578},[360,10116,2691],{"class":366},[360,10118,2995],{"class":662},[360,10120,1358],{"class":366},[360,10122,7805],{"class":662},[360,10124,8161],{"class":366},[360,10126,10127,10129,10131,10133],{"class":362,"line":3380},[360,10128,6797],{"class":578},[360,10130,2691],{"class":366},[360,10132,7805],{"class":662},[360,10134,2968],{"class":366},[360,10136,10137],{"class":362,"line":3405},[360,10138,847],{"class":366},[360,10140,10141],{"class":362,"line":3411},[360,10142,372],{"emptyLinePlaceholder":320},[360,10144,10145,10147,10149,10151,10153,10155,10157,10159,10161,10163],{"class":362,"line":3426},[360,10146,2166],{"class":574},[360,10148,8218],{"class":381},[360,10150,671],{"class":366},[360,10152,8223],{"class":578},[360,10154,2734],{"class":366},[360,10156,2290],{"class":574},[360,10158,8230],{"class":662},[360,10160,3052],{"class":366},[360,10162,4364],{"class":662},[360,10164,896],{"class":366},[360,10166,10167,10170,10172,10174],{"class":362,"line":3432},[360,10168,10169],{"class":578},"  rng",[360,10171,31],{"class":366},[360,10173,8246],{"class":381},[360,10175,5008],{"class":366},[360,10177,10178],{"class":362,"line":3438},[360,10179,847],{"class":366},[360,10181,10182],{"class":362,"line":3443},[360,10183,372],{"emptyLinePlaceholder":320},[360,10185,10186,10188,10190,10192,10194,10196,10198,10200,10202,10204,10206,10208,10210,10212,10214,10216],{"class":362,"line":3462},[360,10187,2166],{"class":574},[360,10189,8263],{"class":381},[360,10191,671],{"class":366},[360,10193,8223],{"class":578},[360,10195,2734],{"class":366},[360,10197,2290],{"class":574},[360,10199,8230],{"class":662},[360,10201,2311],{"class":366},[360,10203,6141],{"class":578},[360,10205,2691],{"class":366},[360,10207,2758],{"class":662},[360,10209,3052],{"class":366},[360,10211,2995],{"class":662},[360,10213,1358],{"class":366},[360,10215,2742],{"class":662},[360,10217,2711],{"class":366},[360,10219,10220,10223,10225,10227,10229,10231,10233,10235,10237,10239,10241,10243,10245,10247,10249],{"class":362,"line":3467},[360,10221,10222],{"class":574},"  let",[360,10224,2235],{"class":574},[360,10226,8300],{"class":578},[360,10228,2691],{"class":366},[360,10230,2995],{"class":662},[360,10232,1358],{"class":366},[360,10234,2742],{"class":662},[360,10236,2697],{"class":366},[360,10238,583],{"class":582},[360,10240,2268],{"class":662},[360,10242,666],{"class":366},[360,10244,8319],{"class":381},[360,10246,671],{"class":366},[360,10248,6141],{"class":578},[360,10250,801],{"class":366},[360,10252,10253,10255,10257,10259,10261,10263,10265],{"class":362,"line":3472},[360,10254,6170],{"class":574},[360,10256,8333],{"class":578},[360,10258,8336],{"class":574},[360,10260,1457],{"class":414},[360,10262,8341],{"class":366},[360,10264,6141],{"class":578},[360,10266,896],{"class":366},[360,10268,10269,10272,10274,10276,10278,10280,10282,10284],{"class":362,"line":3495},[360,10270,10271],{"class":578},"    vect",[360,10273,31],{"class":366},[360,10275,8355],{"class":381},[360,10277,671],{"class":366},[360,10279,8223],{"class":578},[360,10281,31],{"class":366},[360,10283,8246],{"class":574},[360,10285,841],{"class":366},[360,10287,10288],{"class":362,"line":3500},[360,10289,820],{"class":366},[360,10291,10292],{"class":362,"line":3505},[360,10293,10294],{"class":578},"  vect\n",[360,10296,10297],{"class":362,"line":3530},[360,10298,847],{"class":366},[360,10300,10301],{"class":362,"line":3545},[360,10302,372],{"emptyLinePlaceholder":320},[360,10304,10305,10307,10309,10311,10313,10315,10317,10319,10321,10323],{"class":362,"line":3558},[360,10306,2166],{"class":574},[360,10308,8389],{"class":381},[360,10310,671],{"class":366},[360,10312,8223],{"class":578},[360,10314,2734],{"class":366},[360,10316,2290],{"class":574},[360,10318,8230],{"class":662},[360,10320,3052],{"class":366},[360,10322,7805],{"class":662},[360,10324,896],{"class":366},[360,10326,10327,10329,10331,10333,10335,10337,10339,10341,10343,10345,10347,10349],{"class":362,"line":3573},[360,10328,10222],{"class":574},[360,10330,2235],{"class":574},[360,10332,8414],{"class":578},[360,10334,401],{"class":582},[360,10336,8084],{"class":662},[360,10338,5879],{"class":366},[360,10340,8423],{"class":578},[360,10342,4418],{"class":366},[360,10344,1344],{"class":414},[360,10346,4423],{"class":366},[360,10348,6772],{"class":414},[360,10350,8434],{"class":366},[360,10352,10353,10355,10357,10359,10361,10363,10365],{"class":362,"line":3578},[360,10354,6170],{"class":574},[360,10356,6178],{"class":578},[360,10358,8336],{"class":574},[360,10360,1457],{"class":414},[360,10362,8341],{"class":366},[360,10364,6772],{"class":414},[360,10366,896],{"class":366},[360,10368,10369,10371,10373,10375,10377,10379,10381,10383,10385],{"class":362,"line":3583},[360,10370,8197],{"class":578},[360,10372,8458],{"class":366},[360,10374,6187],{"class":578},[360,10376,2390],{"class":366},[360,10378,583],{"class":582},[360,10380,8467],{"class":578},[360,10382,31],{"class":366},[360,10384,8246],{"class":381},[360,10386,2204],{"class":366},[360,10388,10389],{"class":362,"line":6893},[360,10390,820],{"class":366},[360,10392,10393],{"class":362,"line":6899},[360,10394,10395],{"class":578},"  sha256\n",[360,10397,10398],{"class":362,"line":6905},[360,10399,847],{"class":366},[360,10401,10402],{"class":362,"line":6920},[360,10403,372],{"emptyLinePlaceholder":320},[360,10405,10406,10408,10410,10413],{"class":362,"line":6942},[360,10407,3637],{"class":574},[360,10409,3640],{"class":574},[360,10411,10412],{"class":662}," TestObjectWrapper",[360,10414,896],{"class":366},[360,10416,10417,10420,10422,10424,10426,10428],{"class":362,"line":6974},[360,10418,10419],{"class":578},"  test_objects",[360,10421,2691],{"class":366},[360,10423,2995],{"class":662},[360,10425,1358],{"class":366},[360,10427,8675],{"class":662},[360,10429,8161],{"class":366},[360,10431,10432],{"class":362,"line":6992},[360,10433,847],{"class":366},[360,10435,10436],{"class":362,"line":6997},[360,10437,372],{"emptyLinePlaceholder":320},[360,10439,10440,10443,10445,10448],{"class":362,"line":7002},[360,10441,10442],{"class":366},"#[napi(js_name ",[360,10444,583],{"class":582},[360,10446,10447],{"class":397}," \"TestObjectWrapper\"",[360,10449,7919],{"class":366},[360,10451,10452,10454,10456,10459],{"class":362,"line":7008},[360,10453,3637],{"class":574},[360,10455,3640],{"class":574},[360,10457,10458],{"class":662}," JsTestObjectWrapper",[360,10460,896],{"class":366},[360,10462,10463,10466,10468,10471],{"class":362,"line":7041},[360,10464,10465],{"class":578},"  test_object_wrapper",[360,10467,2691],{"class":366},[360,10469,10470],{"class":662},"TestObjectWrapper",[360,10472,2968],{"class":366},[360,10474,10475],{"class":362,"line":7047},[360,10476,847],{"class":366},[360,10478,10479],{"class":362,"line":7058},[360,10480,372],{"emptyLinePlaceholder":320},[360,10482,10483],{"class":362,"line":7064},[360,10484,10485],{"class":366},"#[napi]\n",[360,10487,10488,10490,10492],{"class":362,"line":7086},[360,10489,2683],{"class":574},[360,10491,10458],{"class":662},[360,10493,896],{"class":366},[360,10495,10496],{"class":362,"line":7091},[360,10497,10498],{"class":366},"  #[napi(constructor)]\n",[360,10500,10501,10504,10506,10508,10511,10513],{"class":362,"line":7126},[360,10502,10503],{"class":574},"  pub",[360,10505,4805],{"class":574},[360,10507,3040],{"class":381},[360,10509,10510],{"class":366},"() -> ",[360,10512,3055],{"class":662},[360,10514,896],{"class":366},[360,10516,10517,10520],{"class":362,"line":7165},[360,10518,10519],{"class":662},"    Self",[360,10521,896],{"class":366},[360,10523,10524,10527,10529,10531],{"class":362,"line":7170},[360,10525,10526],{"class":578},"      test_object_wrapper",[360,10528,2691],{"class":366},[360,10530,10470],{"class":662},[360,10532,896],{"class":366},[360,10534,10535,10537,10539,10541,10543,10545],{"class":362,"line":7176},[360,10536,8713],{"class":578},[360,10538,2691],{"class":366},[360,10540,2995],{"class":662},[360,10542,666],{"class":366},[360,10544,2221],{"class":381},[360,10546,6478],{"class":366},[360,10548,10549],{"class":362,"line":7182},[360,10550,10551],{"class":366},"      },\n",[360,10553,10554],{"class":362,"line":7200},[360,10555,2927],{"class":366},[360,10557,10558],{"class":362,"line":7205},[360,10559,820],{"class":366},[360,10561,10562],{"class":362,"line":7211},[360,10563,372],{"emptyLinePlaceholder":320},[360,10565,10566],{"class":362,"line":7219},[360,10567,10568],{"class":366},"  #[napi]\n",[360,10570,10571,10573,10575,10578,10580,10582,10584,10586,10588,10590,10593],{"class":362,"line":7237},[360,10572,10503],{"class":574},[360,10574,4805],{"class":574},[360,10576,10577],{"class":381}," fill",[360,10579,2287],{"class":366},[360,10581,2290],{"class":574},[360,10583,2726],{"class":662},[360,10585,2311],{"class":366},[360,10587,8690],{"class":578},[360,10589,2691],{"class":366},[360,10591,10592],{"class":662},"i32",[360,10594,681],{"class":366},[360,10596,10597,10599,10601,10603,10605,10607,10609,10611],{"class":362,"line":7252},[360,10598,2177],{"class":574},[360,10600,2235],{"class":574},[360,10602,8467],{"class":578},[360,10604,401],{"class":582},[360,10606,7842],{"class":662},[360,10608,666],{"class":366},[360,10610,8533],{"class":381},[360,10612,2204],{"class":366},[360,10614,10615],{"class":362,"line":7257},[360,10616,8540],{"class":644},[360,10618,10619,10621,10623,10625,10627,10629,10631,10633,10635],{"class":362,"line":7280},[360,10620,2177],{"class":574},[360,10622,8547],{"class":578},[360,10624,401],{"class":582},[360,10626,8552],{"class":662},[360,10628,666],{"class":366},[360,10630,8557],{"class":381},[360,10632,3487],{"class":366},[360,10634,2201],{"class":381},[360,10636,2204],{"class":366},[360,10638,10639],{"class":362,"line":7285},[360,10640,8568],{"class":644},[360,10642,10643,10645,10647,10649,10651,10653,10655,10657,10659,10661,10663],{"class":362,"line":7291},[360,10644,2177],{"class":574},[360,10646,8575],{"class":578},[360,10648,401],{"class":582},[360,10650,2145],{"class":662},[360,10652,666],{"class":366},[360,10654,8584],{"class":662},[360,10656,666],{"class":366},[360,10658,8589],{"class":662},[360,10660,666],{"class":366},[360,10662,6884],{"class":381},[360,10664,5008],{"class":366},[360,10666,10667,10670,10672,10674,10676,10678,10680,10682,10684],{"class":362,"line":7314},[360,10668,10669],{"class":366},"      .",[360,10671,8603],{"class":381},[360,10673,671],{"class":366},[360,10675,5096],{"class":662},[360,10677,666],{"class":366},[360,10679,8584],{"class":662},[360,10681,666],{"class":366},[360,10683,8616],{"class":414},[360,10685,2922],{"class":366},[360,10687,10688,10690,10692],{"class":362,"line":7345},[360,10689,10669],{"class":366},[360,10691,2201],{"class":381},[360,10693,5008],{"class":366},[360,10695,10696,10698,10700],{"class":362,"line":7351},[360,10697,10669],{"class":366},[360,10699,8633],{"class":381},[360,10701,2204],{"class":366},[360,10703,10704],{"class":362,"line":7374},[360,10705,372],{"emptyLinePlaceholder":320},[360,10707,10708,10711,10714,10716,10718,10720,10722,10724,10726,10728,10731,10733,10735],{"class":362,"line":7407},[360,10709,10710],{"class":662},"    self",[360,10712,10713],{"class":366},".test_object_wrapper.test_objects ",[360,10715,583],{"class":582},[360,10717,2268],{"class":662},[360,10719,666],{"class":366},[360,10721,8319],{"class":381},[360,10723,671],{"class":366},[360,10725,8690],{"class":578},[360,10727,31],{"class":366},[360,10729,10730],{"class":381},"try_into",[360,10732,3487],{"class":366},[360,10734,2201],{"class":381},[360,10736,841],{"class":366},[360,10738,10739],{"class":362,"line":7418},[360,10740,372],{"emptyLinePlaceholder":320},[360,10742,10743,10745,10747,10749,10751,10753,10755],{"class":362,"line":7426},[360,10744,8330],{"class":574},[360,10746,8333],{"class":578},[360,10748,8336],{"class":574},[360,10750,1457],{"class":414},[360,10752,8341],{"class":366},[360,10754,8690],{"class":578},[360,10756,896],{"class":366},[360,10758,10759,10762,10765,10767,10769,10771],{"class":362,"line":7451},[360,10760,10761],{"class":662},"      self",[360,10763,10764],{"class":366},".test_object_wrapper.test_objects.",[360,10766,8355],{"class":381},[360,10768,671],{"class":366},[360,10770,8675],{"class":662},[360,10772,896],{"class":366},[360,10774,10775,10778,10780,10782,10784,10786,10788,10790,10792],{"class":362,"line":7457},[360,10776,10777],{"class":578},"        path",[360,10779,2691],{"class":366},[360,10781,8733],{"class":381},[360,10783,2287],{"class":366},[360,10785,2290],{"class":574},[360,10787,8467],{"class":578},[360,10789,2311],{"class":366},[360,10791,6349],{"class":414},[360,10793,5405],{"class":366},[360,10795,10796,10799,10801,10803],{"class":362,"line":7462},[360,10797,10798],{"class":578},"        stats",[360,10800,2691],{"class":366},[360,10802,8171],{"class":662},[360,10804,896],{"class":366},[360,10806,10807,10810,10812,10814,10816,10818,10820],{"class":362,"line":7467},[360,10808,10809],{"class":578},"          owner_id",[360,10811,2691],{"class":366},[360,10813,8766],{"class":381},[360,10815,2287],{"class":366},[360,10817,2290],{"class":574},[360,10819,8467],{"class":578},[360,10821,5405],{"class":366},[360,10823,10824,10827,10829,10831,10833,10835,10837],{"class":362,"line":7485},[360,10825,10826],{"class":578},"          group_id",[360,10828,2691],{"class":366},[360,10830,8766],{"class":381},[360,10832,2287],{"class":366},[360,10834,2290],{"class":574},[360,10836,8467],{"class":578},[360,10838,5405],{"class":366},[360,10840,10841,10844,10846,10848,10850,10852,10854],{"class":362,"line":7507},[360,10842,10843],{"class":578},"          size",[360,10845,2691],{"class":366},[360,10847,8766],{"class":381},[360,10849,2287],{"class":366},[360,10851,2290],{"class":574},[360,10853,8467],{"class":578},[360,10855,5405],{"class":366},[360,10857,10858,10861,10863,10865,10867,10869,10871],{"class":362,"line":7512},[360,10859,10860],{"class":578},"          compressed_size",[360,10862,2691],{"class":366},[360,10864,8766],{"class":381},[360,10866,2287],{"class":366},[360,10868,2290],{"class":574},[360,10870,8467],{"class":578},[360,10872,5405],{"class":366},[360,10874,10875,10878,10880,10882,10884,10886,10888],{"class":362,"line":9051},[360,10876,10877],{"class":578},"          last_read",[360,10879,2691],{"class":366},[360,10881,8766],{"class":381},[360,10883,2287],{"class":366},[360,10885,2290],{"class":574},[360,10887,8467],{"class":578},[360,10889,5405],{"class":366},[360,10891,10892,10895,10897,10899,10901,10903,10905],{"class":362,"line":9056},[360,10893,10894],{"class":578},"          last_modified",[360,10896,2691],{"class":366},[360,10898,8766],{"class":381},[360,10900,2287],{"class":366},[360,10902,2290],{"class":574},[360,10904,8467],{"class":578},[360,10906,5405],{"class":366},[360,10908,10909,10912,10914,10916,10918,10920,10922],{"class":362,"line":9082},[360,10910,10911],{"class":578},"          created",[360,10913,2691],{"class":366},[360,10915,8766],{"class":381},[360,10917,2287],{"class":366},[360,10919,2290],{"class":574},[360,10921,8467],{"class":578},[360,10923,5405],{"class":366},[360,10925,10926,10929,10931,10933,10935,10937,10939],{"class":362,"line":9103},[360,10927,10928],{"class":578},"          mode",[360,10930,2691],{"class":366},[360,10932,8766],{"class":381},[360,10934,2287],{"class":366},[360,10936,2290],{"class":574},[360,10938,8467],{"class":578},[360,10940,5405],{"class":366},[360,10942,10943,10946,10948,10950,10952,10954,10956],{"class":362,"line":9112},[360,10944,10945],{"class":578},"          dev",[360,10947,2691],{"class":366},[360,10949,8766],{"class":381},[360,10951,2287],{"class":366},[360,10953,2290],{"class":574},[360,10955,8467],{"class":578},[360,10957,5405],{"class":366},[360,10959,10960,10963,10965,10967,10969,10971,10973],{"class":362,"line":9121},[360,10961,10962],{"class":578},"          rdev",[360,10964,2691],{"class":366},[360,10966,8766],{"class":381},[360,10968,2287],{"class":366},[360,10970,2290],{"class":574},[360,10972,8467],{"class":578},[360,10974,5405],{"class":366},[360,10976,10977,10980,10982,10984,10986,10988,10990],{"class":362,"line":9127},[360,10978,10979],{"class":578},"          ino",[360,10981,2691],{"class":366},[360,10983,8766],{"class":381},[360,10985,2287],{"class":366},[360,10987,2290],{"class":574},[360,10989,8467],{"class":578},[360,10991,5405],{"class":366},[360,10993,10994,10997,10999,11001,11003,11005,11007],{"class":362,"line":9149},[360,10995,10996],{"class":578},"          nlink",[360,10998,2691],{"class":366},[360,11000,8766],{"class":381},[360,11002,2287],{"class":366},[360,11004,2290],{"class":574},[360,11006,8467],{"class":578},[360,11008,5405],{"class":366},[360,11010,11011],{"class":362,"line":9154},[360,11012,11013],{"class":366},"        },\n",[360,11015,11016,11019,11021,11023],{"class":362,"line":9159},[360,11017,11018],{"class":578},"        chunks",[360,11020,2691],{"class":366},[360,11022,8976],{"class":381},[360,11024,8979],{"class":366},[360,11026,11027,11030,11032,11034,11036],{"class":362,"line":9181},[360,11028,11029],{"class":381},"          generate_random_sha256",[360,11031,2287],{"class":366},[360,11033,2290],{"class":574},[360,11035,8467],{"class":578},[360,11037,5405],{"class":366},[360,11039,11040,11042,11044,11046,11048],{"class":362,"line":9187},[360,11041,11029],{"class":381},[360,11043,2287],{"class":366},[360,11045,2290],{"class":574},[360,11047,8467],{"class":578},[360,11049,5405],{"class":366},[360,11051,11052,11054,11056,11058,11060],{"class":362,"line":9194},[360,11053,11029],{"class":381},[360,11055,2287],{"class":366},[360,11057,2290],{"class":574},[360,11059,8467],{"class":578},[360,11061,5405],{"class":366},[360,11063,11064],{"class":362,"line":9202},[360,11065,11066],{"class":366},"        ],\n",[360,11068,11069,11071,11073,11075,11077,11079,11081],{"class":362,"line":9227},[360,11070,8455],{"class":578},[360,11072,2691],{"class":366},[360,11074,9031],{"class":381},[360,11076,2287],{"class":366},[360,11078,2290],{"class":574},[360,11080,8467],{"class":578},[360,11082,5405],{"class":366},[360,11084,11085],{"class":362,"line":9233},[360,11086,11087],{"class":366},"      });\n",[360,11089,11090],{"class":362,"line":9239},[360,11091,2927],{"class":366},[360,11093,11094],{"class":362,"line":9246},[360,11095,372],{"emptyLinePlaceholder":320},[360,11097,11098,11100,11102,11104,11106,11108,11110,11112,11114,11116,11118],{"class":362,"line":9254},[360,11099,2177],{"class":574},[360,11101,9061],{"class":578},[360,11103,401],{"class":582},[360,11105,2145],{"class":662},[360,11107,666],{"class":366},[360,11109,8584],{"class":662},[360,11111,666],{"class":366},[360,11113,8589],{"class":662},[360,11115,666],{"class":366},[360,11117,6884],{"class":381},[360,11119,5008],{"class":366},[360,11121,11122,11124,11126,11128,11130,11132,11134,11136,11138],{"class":362,"line":9279},[360,11123,10669],{"class":366},[360,11125,8603],{"class":381},[360,11127,671],{"class":366},[360,11129,5096],{"class":662},[360,11131,666],{"class":366},[360,11133,8584],{"class":662},[360,11135,666],{"class":366},[360,11137,8616],{"class":414},[360,11139,2922],{"class":366},[360,11141,11142,11144,11146],{"class":362,"line":9284},[360,11143,10669],{"class":366},[360,11145,2201],{"class":381},[360,11147,5008],{"class":366},[360,11149,11150,11152,11154],{"class":362,"line":9289},[360,11151,10669],{"class":366},[360,11153,8633],{"class":381},[360,11155,2204],{"class":366},[360,11157,11158],{"class":362,"line":9295},[360,11159,9124],{"class":644},[360,11161,11162,11164,11166,11168,11170,11172,11174,11176],{"class":362,"line":9318},[360,11163,2303],{"class":381},[360,11165,671],{"class":366},[360,11167,9134],{"class":397},[360,11169,2311],{"class":366},[360,11171,9139],{"class":578},[360,11173,9142],{"class":366},[360,11175,6884],{"class":578},[360,11177,801],{"class":366},[360,11179,11180],{"class":362,"line":9331},[360,11181,372],{"emptyLinePlaceholder":320},[360,11183,11184],{"class":362,"line":9343},[360,11185,8540],{"class":644},[360,11187,11188,11190,11192,11194,11196,11198,11200,11202,11204],{"class":362,"line":9348},[360,11189,2177],{"class":574},[360,11191,9164],{"class":578},[360,11193,401],{"class":582},[360,11195,8552],{"class":662},[360,11197,666],{"class":366},[360,11199,8557],{"class":381},[360,11201,3487],{"class":366},[360,11203,2201],{"class":381},[360,11205,2204],{"class":366},[360,11207,11208],{"class":362,"line":9353},[360,11209,9184],{"class":644},[360,11211,11212,11214],{"class":362,"line":9359},[360,11213,2303],{"class":381},[360,11215,1395],{"class":366},[360,11217,11218,11221],{"class":362,"line":9393},[360,11219,11220],{"class":397},"      \"Memory consumption after creation: {}\"",[360,11222,2968],{"class":366},[360,11224,11225,11228,11230,11232,11234,11236,11238,11240,11242,11244],{"class":362,"line":9419},[360,11226,11227],{"class":381},"      format_size",[360,11229,7148],{"class":366},[360,11231,9210],{"class":578},[360,11233,9213],{"class":366},[360,11235,9216],{"class":578},[360,11237,9219],{"class":366},[360,11239,9222],{"class":414},[360,11241,2311],{"class":366},[360,11243,7823],{"class":414},[360,11245,2922],{"class":366},[360,11247,11248],{"class":362,"line":9438},[360,11249,9230],{"class":366},[360,11251,11252],{"class":362,"line":9466},[360,11253,9236],{"class":644},[360,11255,11256,11258],{"class":362,"line":9471},[360,11257,2303],{"class":381},[360,11259,1395],{"class":366},[360,11261,11262,11265],{"class":362,"line":9476},[360,11263,11264],{"class":397},"      \"Average memory consumption per object: {}\"",[360,11266,2968],{"class":366},[360,11268,11269,11271],{"class":362,"line":9482},[360,11270,11227],{"class":381},[360,11272,1395],{"class":366},[360,11274,11275,11278,11280,11282,11284,11286,11288,11290,11292,11294,11297],{"class":362,"line":9508},[360,11276,11277],{"class":366},"        ((",[360,11279,9210],{"class":578},[360,11281,9213],{"class":366},[360,11283,9216],{"class":578},[360,11285,9219],{"class":366},[360,11287,9222],{"class":414},[360,11289,9272],{"class":366},[360,11291,8690],{"class":578},[360,11293,9698],{"class":574},[360,11295,11296],{"class":662}," usize",[360,11298,2968],{"class":366},[360,11300,11301],{"class":362,"line":9529},[360,11302,11303],{"class":414},"        DECIMAL\n",[360,11305,11306],{"class":362,"line":9538},[360,11307,11308],{"class":366},"      )\n",[360,11310,11311],{"class":362,"line":9547},[360,11312,9230],{"class":366},[360,11314,11315],{"class":362,"line":9552},[360,11316,820],{"class":366},[360,11318,11319],{"class":362,"line":9559},[360,11320,372],{"emptyLinePlaceholder":320},[360,11322,11323,11326,11328,11331],{"class":362,"line":9567},[360,11324,11325],{"class":366},"  #[napi(js_name ",[360,11327,583],{"class":582},[360,11329,11330],{"class":397}," \"toString\"",[360,11332,7919],{"class":366},[360,11334,11335,11337,11339,11342,11344,11346,11348,11351],{"class":362,"line":9578},[360,11336,10503],{"class":574},[360,11338,4805],{"class":574},[360,11340,11341],{"class":381}," to_string",[360,11343,2287],{"class":366},[360,11345,3479],{"class":662},[360,11347,3052],{"class":366},[360,11349,11350],{"class":662},"String",[360,11352,896],{"class":366},[360,11354,11355,11358],{"class":362,"line":9583},[360,11356,11357],{"class":381},"    format!",[360,11359,1395],{"class":366},[360,11361,11362,11365],{"class":362,"line":9588},[360,11363,11364],{"class":397},"      \"TestObjectWrapper {{ test_objects: {} }}\"",[360,11366,2968],{"class":366},[360,11368,11369,11371,11373,11375],{"class":362,"line":9594},[360,11370,10761],{"class":662},[360,11372,10764],{"class":366},[360,11374,2802],{"class":381},[360,11376,5008],{"class":366},[360,11378,11379],{"class":362,"line":9625},[360,11380,11381],{"class":366},"    )\n",[360,11383,11384],{"class":362,"line":9632},[360,11385,820],{"class":366},[360,11387,11388],{"class":362,"line":9640},[360,11389,847],{"class":366},[12,11391,11392],{},"Pour la parte Node.JS :",[352,11394,11396],{"className":6044,"code":11395,"language":6046,"meta":291,"style":291},"const test = require(\".\u002Findex.js\");\nconst filesize = require(\"filesize.js\");\nconst fs = require(\"fs\");\nconst { serialize, deserialize } = require(\"v8\");\n\u002F\u002F Start by consuming memory with big object\n\n\u002F\u002F Run GC\nglobal.gc();\n\u002F\u002F Get memory consumption before\nconst memoryBefore = process.memoryUsage().heapUsed;\n\nconst time = Date.now();\n\n\u002F\u002F Create objects\nconst nbObjects = 1_300_000;\nconst testArray = new test.TestObjectWrapper();\ntestArray.fill(nbObjects);\n\n\u002F\u002F Bench creation\nconsole.log(\"Creation time: \", Date.now() - time);\n\n\u002F\u002F Run GC\n\u002F\u002F Get memory consumption after\nconst memoryAfter = process.memoryUsage().heapUsed;\n\n\u002F\u002F Print memory consumption\nconsole.log(\n  \"Memory consumption in JS: \",\n  filesize.default(memoryAfter - memoryBefore)\n);\n\nconsole.log(testArray.toString());\n",[344,11397,11398,11416,11432,11448,11472,11477,11481,11486,11496,11501,11521,11525,11541,11545,11550,11562,11580,11596,11600,11605,11633,11637,11641,11646,11666,11670,11675,11685,11692,11711,11715,11719],{"__ignoreMap":291},[360,11399,11400,11402,11405,11407,11409,11411,11414],{"class":362,"line":363},[360,11401,6053],{"class":574},[360,11403,11404],{"class":662}," test",[360,11406,401],{"class":582},[360,11408,6061],{"class":381},[360,11410,671],{"class":366},[360,11412,11413],{"class":397},"\".\u002Findex.js\"",[360,11415,801],{"class":366},[360,11417,11418,11420,11422,11424,11426,11428,11430],{"class":362,"line":292},[360,11419,6053],{"class":574},[360,11421,6056],{"class":662},[360,11423,401],{"class":582},[360,11425,6061],{"class":381},[360,11427,671],{"class":366},[360,11429,6066],{"class":397},[360,11431,801],{"class":366},[360,11433,11434,11436,11438,11440,11442,11444,11446],{"class":362,"line":375},[360,11435,6053],{"class":574},[360,11437,6075],{"class":662},[360,11439,401],{"class":582},[360,11441,6061],{"class":381},[360,11443,671],{"class":366},[360,11445,6084],{"class":397},[360,11447,801],{"class":366},[360,11449,11450,11452,11454,11456,11458,11460,11462,11464,11466,11468,11470],{"class":362,"line":433},[360,11451,6053],{"class":574},[360,11453,5879],{"class":366},[360,11455,6100],{"class":662},[360,11457,2311],{"class":366},[360,11459,6105],{"class":662},[360,11461,6108],{"class":366},[360,11463,583],{"class":582},[360,11465,6061],{"class":381},[360,11467,671],{"class":366},[360,11469,6117],{"class":397},[360,11471,801],{"class":366},[360,11473,11474],{"class":362,"line":478},[360,11475,11476],{"class":644},"\u002F\u002F Start by consuming memory with big object\n",[360,11478,11479],{"class":362,"line":483},[360,11480,372],{"emptyLinePlaceholder":320},[360,11482,11483],{"class":362,"line":489},[360,11484,11485],{"class":644},"\u002F\u002F Run GC\n",[360,11487,11488,11490,11492,11494],{"class":362,"line":494},[360,11489,6826],{"class":662},[360,11491,31],{"class":366},[360,11493,6831],{"class":381},[360,11495,2204],{"class":366},[360,11497,11498],{"class":362,"line":712},[360,11499,11500],{"class":644},"\u002F\u002F Get memory consumption before\n",[360,11502,11503,11505,11507,11509,11511,11513,11515,11517,11519],{"class":362,"line":331},[360,11504,6053],{"class":574},[360,11506,6845],{"class":662},[360,11508,401],{"class":582},[360,11510,6850],{"class":662},[360,11512,31],{"class":366},[360,11514,6855],{"class":381},[360,11516,3487],{"class":366},[360,11518,6860],{"class":578},[360,11520,735],{"class":366},[360,11522,11523],{"class":362,"line":762},[360,11524,372],{"emptyLinePlaceholder":320},[360,11526,11527,11529,11531,11533,11535,11537,11539],{"class":362,"line":781},[360,11528,6053],{"class":574},[360,11530,6874],{"class":662},[360,11532,401],{"class":582},[360,11534,6879],{"class":662},[360,11536,31],{"class":366},[360,11538,6884],{"class":381},[360,11540,2204],{"class":366},[360,11542,11543],{"class":362,"line":804},[360,11544,372],{"emptyLinePlaceholder":320},[360,11546,11547],{"class":362,"line":817},[360,11548,11549],{"class":644},"\u002F\u002F Create objects\n",[360,11551,11552,11554,11556,11558,11560],{"class":362,"line":823},[360,11553,6053],{"class":574},[360,11555,6910],{"class":662},[360,11557,401],{"class":582},[360,11559,6915],{"class":414},[360,11561,735],{"class":366},[360,11563,11564,11566,11568,11570,11572,11574,11576,11578],{"class":362,"line":844},[360,11565,6053],{"class":574},[360,11567,6925],{"class":662},[360,11569,401],{"class":582},[360,11571,3040],{"class":574},[360,11573,11404],{"class":662},[360,11575,31],{"class":366},[360,11577,10470],{"class":381},[360,11579,2204],{"class":366},[360,11581,11582,11585,11587,11590,11592,11594],{"class":362,"line":1441},[360,11583,11584],{"class":662},"testArray",[360,11586,31],{"class":366},[360,11588,11589],{"class":381},"fill",[360,11591,671],{"class":366},[360,11593,6937],{"class":578},[360,11595,801],{"class":366},[360,11597,11598],{"class":362,"line":1462},[360,11599,372],{"emptyLinePlaceholder":320},[360,11601,11602],{"class":362,"line":1485},[360,11603,11604],{"class":644},"\u002F\u002F Bench creation\n",[360,11606,11607,11609,11611,11613,11615,11617,11619,11621,11623,11625,11627,11629,11631],{"class":362,"line":1497},[360,11608,7011],{"class":662},[360,11610,31],{"class":366},[360,11612,7016],{"class":381},[360,11614,671],{"class":366},[360,11616,7021],{"class":397},[360,11618,2311],{"class":366},[360,11620,7026],{"class":662},[360,11622,31],{"class":366},[360,11624,6884],{"class":381},[360,11626,2805],{"class":366},[360,11628,1491],{"class":582},[360,11630,6874],{"class":578},[360,11632,801],{"class":366},[360,11634,11635],{"class":362,"line":3161},[360,11636,372],{"emptyLinePlaceholder":320},[360,11638,11639],{"class":362,"line":3167},[360,11640,11485],{"class":644},[360,11642,11643],{"class":362,"line":3194},[360,11644,11645],{"class":644},"\u002F\u002F Get memory consumption after\n",[360,11647,11648,11650,11652,11654,11656,11658,11660,11662,11664],{"class":362,"line":3224},[360,11649,6053],{"class":574},[360,11651,7069],{"class":662},[360,11653,401],{"class":582},[360,11655,6850],{"class":662},[360,11657,31],{"class":366},[360,11659,6855],{"class":381},[360,11661,3487],{"class":366},[360,11663,6860],{"class":578},[360,11665,735],{"class":366},[360,11667,11668],{"class":362,"line":3239},[360,11669,372],{"emptyLinePlaceholder":320},[360,11671,11672],{"class":362,"line":3256},[360,11673,11674],{"class":644},"\u002F\u002F Print memory consumption\n",[360,11676,11677,11679,11681,11683],{"class":362,"line":3276},[360,11678,7011],{"class":662},[360,11680,31],{"class":366},[360,11682,7016],{"class":381},[360,11684,1395],{"class":366},[360,11686,11687,11690],{"class":362,"line":3281},[360,11688,11689],{"class":397},"  \"Memory consumption in JS: \"",[360,11691,2968],{"class":366},[360,11693,11694,11697,11699,11701,11703,11705,11707,11709],{"class":362,"line":3305},[360,11695,11696],{"class":662},"  filesize",[360,11698,31],{"class":366},[360,11700,7112],{"class":381},[360,11702,671],{"class":366},[360,11704,7117],{"class":578},[360,11706,518],{"class":582},[360,11708,6845],{"class":578},[360,11710,2922],{"class":366},[360,11712,11713],{"class":362,"line":3320},[360,11714,801],{"class":366},[360,11716,11717],{"class":362,"line":3325},[360,11718,372],{"emptyLinePlaceholder":320},[360,11720,11721,11723,11725,11727,11729,11731,11733,11736],{"class":362,"line":3361},[360,11722,7011],{"class":662},[360,11724,31],{"class":366},[360,11726,7016],{"class":381},[360,11728,671],{"class":366},[360,11730,11584],{"class":662},[360,11732,31],{"class":366},[360,11734,11735],{"class":381},"toString",[360,11737,841],{"class":366},[12,11739,11740],{},"Voici le résultat:",[1545,11742,11743,11751],{},[1548,11744,11745],{},[1551,11746,11747,11749],{},[1554,11748],{},[1554,11750],{},[1567,11752,11753,11759,11765,11772],{},[1551,11754,11755,11757],{},[1572,11756,7544],{},[1572,11758,7547],{},[1551,11760,11761,11763],{},[1572,11762,7552],{},[1572,11764,9765],{},[1551,11766,11767,11769],{},[1572,11768,7560],{},[1572,11770,11771],{},"520,31 Mo",[1551,11773,11774,11776],{},[1572,11775,7568],{},[1572,11777,11778],{},"400 octets",[12,11780,11781],{},"Parfait, le module écrit en Rust va nous permettre de réduire la consommation mémoire de notre application et améliorer\nses performances.",[33,11783,11785,11787],{"id":11784},"conclusion-wasm",[129,11786,251],{}," - Wasm",[12,11789,11790],{},"Une alternative possible à l'écriture d'un module natif en Rust est l'utilisation de WebAssembly. WebAssembly est un\nlangage de bas niveau qui permet d'écrire des modules qui seront exécutés dans un environnement sécurisé. Il est\npossible d'écrire des modules en Rust qui seront compilés en WebAssembly.",[12,11792,11793,11794,31],{},"Pour compiler notre module en WebAssembly, nous allons utiliser le compilateur ",[47,11795,11798],{"href":11796,"rel":11797},"https:\u002F\u002Frustwasm.github.io\u002Fwasm-pack\u002F",[51],"wasm-pack",[12,11800,11801],{},"La partie Rust du module n'est pas très différente de la version native. La seule différence est que nous devons\nutiliser le crate wasm-bindgen pour pouvoir utiliser notre module dans Node.JS.",[12,11803,11804,11805,11809],{},"Là encore, la documentation est très bien faite (",[47,11806,11807],{"href":11807,"rel":11808},"https:\u002F\u002Frustwasm.github.io\u002Fdocs\u002Fbook\u002F",[51],"). Je ne vais pas détailler ici\nla création de ce module.",[352,11811,11813],{"className":2114,"code":11812,"language":2116,"meta":291,"style":291},"mod utils;\n\nuse rand::{rngs::ThreadRng, Rng};\n\nuse wasm_bindgen::prelude::*;\n\n\u002F\u002F When the `wee_alloc` feature is enabled, use `wee_alloc` as the global\n\u002F\u002F allocator.\n#[cfg(feature = \"wee_alloc\")]\n#[global_allocator]\nstatic ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;\n\n#[wasm_bindgen]\nstruct Stats {\n    owner_id: u64,\n    group_id: u64,\n    size: u64,\n    compressed_size: u64,\n    last_read: u64,\n    last_modified: u64,\n    created: u64,\n    mode: u64,\n    dev: u64,\n    rdev: u64,\n    ino: u64,\n    nlink: u64,\n}\n\n#[wasm_bindgen]\nstruct Sha256 {\n    data: [u8; 32],\n}\n\n#[wasm_bindgen]\nstruct TestObject {\n    path: Vec\u003Cu8>,\n    stats: Stats,\n\n    chunks: Vec\u003CSha256>,\n    sha256: Sha256,\n}\n\nfn generate_random_number(rng: &mut ThreadRng) -> u64 {\n    rng.gen()\n}\n\nfn generate_random_vect(rng: &mut ThreadRng, size: usize) -> Vec\u003Cu8> {\n    let mut vect: Vec\u003Cu8> = Vec::with_capacity(size);\n    for _ in 0..size {\n        vect.push(rng.gen());\n    }\n    vect\n}\n\nfn generate_random_sha256(rng: &mut ThreadRng) -> Sha256 {\n    let mut sha256 = Sha256 { data: [0; 32] };\n    for i in 0..32 {\n        sha256.data[i] = rng.gen();\n    }\n    sha256\n}\n\n#[wasm_bindgen]\npub struct TestObjectWrapper {\n    test_objects: Vec\u003CTestObject>,\n}\n\n#[wasm_bindgen]\nimpl TestObjectWrapper {\n    #[wasm_bindgen(constructor)]\n    pub fn new() -> Self {\n        Self {\n            test_objects: Vec::new(),\n        }\n    }\n\n    #[wasm_bindgen]\n    pub fn fill(&mut self, nb_object: i32) {\n        let mut rng = rand::thread_rng();\n        \u002F\u002F Get the current time in ms\n        self.test_objects = Vec::with_capacity(nb_object as usize);\n\n        for _ in 0..nb_object {\n            self.test_objects.push(TestObject {\n                path: generate_random_vect(&mut rng, 100),\n                stats: Stats {\n                    owner_id: generate_random_number(&mut rng),\n                    group_id: generate_random_number(&mut rng),\n                    size: generate_random_number(&mut rng),\n                    compressed_size: generate_random_number(&mut rng),\n                    last_read: generate_random_number(&mut rng),\n                    last_modified: generate_random_number(&mut rng),\n                    created: generate_random_number(&mut rng),\n                    mode: generate_random_number(&mut rng),\n                    dev: generate_random_number(&mut rng),\n                    rdev: generate_random_number(&mut rng),\n                    ino: generate_random_number(&mut rng),\n                    nlink: generate_random_number(&mut rng),\n                },\n                chunks: vec![\n                    generate_random_sha256(&mut rng),\n                    generate_random_sha256(&mut rng),\n                    generate_random_sha256(&mut rng),\n                ],\n                sha256: generate_random_sha256(&mut rng),\n            });\n        }\n    }\n\n    #[wasm_bindgen(js_name = toString)]\n    pub fn to_string(&self) -> String {\n        format!(\n            \"TestObjectWrapper {{ test_objects: {} }}\",\n            self.test_objects.len()\n        )\n    }\n}\n",[344,11814,11815,11823,11827,11847,11851,11866,11870,11875,11880,11892,11897,11930,11934,11939,11947,11957,11967,11977,11987,11997,12007,12017,12027,12037,12047,12057,12067,12071,12075,12079,12087,12101,12105,12109,12113,12121,12135,12145,12149,12163,12173,12177,12181,12203,12213,12217,12221,12255,12287,12303,12321,12325,12329,12333,12337,12359,12385,12401,12421,12425,12429,12433,12437,12441,12451,12466,12470,12474,12478,12486,12491,12506,12512,12527,12531,12535,12539,12544,12568,12586,12591,12616,12620,12637,12652,12673,12684,12701,12718,12735,12752,12769,12786,12803,12820,12837,12854,12871,12888,12893,12904,12917,12929,12941,12946,12963,12968,12972,12976,12980,12990,13008,13015,13022,13032,13037,13041],{"__ignoreMap":291},[360,11816,11817,11820],{"class":362,"line":363},[360,11818,11819],{"class":574},"mod",[360,11821,11822],{"class":366}," utils;\n",[360,11824,11825],{"class":362,"line":292},[360,11826,372],{"emptyLinePlaceholder":320},[360,11828,11829,11831,11833,11835,11837,11839,11841,11843,11845],{"class":362,"line":375},[360,11830,2123],{"class":574},[360,11832,7842],{"class":662},[360,11834,7845],{"class":366},[360,11836,7848],{"class":662},[360,11838,666],{"class":366},[360,11840,7853],{"class":662},[360,11842,2311],{"class":366},[360,11844,7858],{"class":662},[360,11846,1036],{"class":366},[360,11848,11849],{"class":362,"line":433},[360,11850,372],{"emptyLinePlaceholder":320},[360,11852,11853,11855,11858,11860,11863],{"class":362,"line":478},[360,11854,2123],{"class":574},[360,11856,11857],{"class":662}," wasm_bindgen",[360,11859,666],{"class":366},[360,11861,11862],{"class":662},"prelude",[360,11864,11865],{"class":366},"::*;\n",[360,11867,11868],{"class":362,"line":483},[360,11869,372],{"emptyLinePlaceholder":320},[360,11871,11872],{"class":362,"line":489},[360,11873,11874],{"class":644},"\u002F\u002F When the `wee_alloc` feature is enabled, use `wee_alloc` as the global\n",[360,11876,11877],{"class":362,"line":494},[360,11878,11879],{"class":644},"\u002F\u002F allocator.\n",[360,11881,11882,11885,11887,11890],{"class":362,"line":712},[360,11883,11884],{"class":366},"#[cfg(feature ",[360,11886,583],{"class":582},[360,11888,11889],{"class":397}," \"wee_alloc\"",[360,11891,7919],{"class":366},[360,11893,11894],{"class":362,"line":331},[360,11895,11896],{"class":366},"#[global_allocator]\n",[360,11898,11899,11901,11904,11906,11909,11911,11914,11916,11919,11921,11923,11925,11928],{"class":362,"line":762},[360,11900,5931],{"class":574},[360,11902,11903],{"class":414}," ALLOC",[360,11905,2691],{"class":366},[360,11907,11908],{"class":662},"wee_alloc",[360,11910,666],{"class":366},[360,11912,11913],{"class":662},"WeeAlloc",[360,11915,401],{"class":582},[360,11917,11918],{"class":662}," wee_alloc",[360,11920,666],{"class":366},[360,11922,11913],{"class":662},[360,11924,666],{"class":366},[360,11926,11927],{"class":414},"INIT",[360,11929,735],{"class":366},[360,11931,11932],{"class":362,"line":781},[360,11933,372],{"emptyLinePlaceholder":320},[360,11935,11936],{"class":362,"line":804},[360,11937,11938],{"class":366},"#[wasm_bindgen]\n",[360,11940,11941,11943,11945],{"class":362,"line":817},[360,11942,890],{"class":574},[360,11944,7926],{"class":662},[360,11946,896],{"class":366},[360,11948,11949,11951,11953,11955],{"class":362,"line":823},[360,11950,7933],{"class":578},[360,11952,2691],{"class":366},[360,11954,4364],{"class":662},[360,11956,2968],{"class":366},[360,11958,11959,11961,11963,11965],{"class":362,"line":844},[360,11960,7944],{"class":578},[360,11962,2691],{"class":366},[360,11964,4364],{"class":662},[360,11966,2968],{"class":366},[360,11968,11969,11971,11973,11975],{"class":362,"line":1441},[360,11970,6433],{"class":578},[360,11972,2691],{"class":366},[360,11974,4364],{"class":662},[360,11976,2968],{"class":366},[360,11978,11979,11981,11983,11985],{"class":362,"line":1462},[360,11980,7965],{"class":578},[360,11982,2691],{"class":366},[360,11984,4364],{"class":662},[360,11986,2968],{"class":366},[360,11988,11989,11991,11993,11995],{"class":362,"line":1485},[360,11990,7976],{"class":578},[360,11992,2691],{"class":366},[360,11994,4364],{"class":662},[360,11996,2968],{"class":366},[360,11998,11999,12001,12003,12005],{"class":362,"line":1497},[360,12000,7987],{"class":578},[360,12002,2691],{"class":366},[360,12004,4364],{"class":662},[360,12006,2968],{"class":366},[360,12008,12009,12011,12013,12015],{"class":362,"line":3161},[360,12010,6572],{"class":578},[360,12012,2691],{"class":366},[360,12014,4364],{"class":662},[360,12016,2968],{"class":366},[360,12018,12019,12021,12023,12025],{"class":362,"line":3167},[360,12020,6603],{"class":578},[360,12022,2691],{"class":366},[360,12024,4364],{"class":662},[360,12026,2968],{"class":366},[360,12028,12029,12031,12033,12035],{"class":362,"line":3194},[360,12030,6634],{"class":578},[360,12032,2691],{"class":366},[360,12034,4364],{"class":662},[360,12036,2968],{"class":366},[360,12038,12039,12041,12043,12045],{"class":362,"line":3224},[360,12040,6665],{"class":578},[360,12042,2691],{"class":366},[360,12044,4364],{"class":662},[360,12046,2968],{"class":366},[360,12048,12049,12051,12053,12055],{"class":362,"line":3239},[360,12050,6696],{"class":578},[360,12052,2691],{"class":366},[360,12054,4364],{"class":662},[360,12056,2968],{"class":366},[360,12058,12059,12061,12063,12065],{"class":362,"line":3256},[360,12060,6727],{"class":578},[360,12062,2691],{"class":366},[360,12064,4364],{"class":662},[360,12066,2968],{"class":366},[360,12068,12069],{"class":362,"line":3276},[360,12070,847],{"class":366},[360,12072,12073],{"class":362,"line":3281},[360,12074,372],{"emptyLinePlaceholder":320},[360,12076,12077],{"class":362,"line":3305},[360,12078,11938],{"class":366},[360,12080,12081,12083,12085],{"class":362,"line":3320},[360,12082,890],{"class":574},[360,12084,8084],{"class":662},[360,12086,896],{"class":366},[360,12088,12089,12091,12093,12095,12097,12099],{"class":362,"line":3325},[360,12090,8091],{"class":578},[360,12092,4418],{"class":366},[360,12094,2742],{"class":662},[360,12096,4423],{"class":366},[360,12098,6772],{"class":414},[360,12100,5436],{"class":366},[360,12102,12103],{"class":362,"line":3361},[360,12104,847],{"class":366},[360,12106,12107],{"class":362,"line":3380},[360,12108,372],{"emptyLinePlaceholder":320},[360,12110,12111],{"class":362,"line":3405},[360,12112,11938],{"class":366},[360,12114,12115,12117,12119],{"class":362,"line":3411},[360,12116,890],{"class":574},[360,12118,8132],{"class":662},[360,12120,896],{"class":366},[360,12122,12123,12125,12127,12129,12131,12133],{"class":362,"line":3426},[360,12124,5822],{"class":578},[360,12126,2691],{"class":366},[360,12128,2995],{"class":662},[360,12130,1358],{"class":366},[360,12132,2742],{"class":662},[360,12134,8161],{"class":366},[360,12136,12137,12139,12141,12143],{"class":362,"line":3432},[360,12138,8166],{"class":578},[360,12140,2691],{"class":366},[360,12142,8171],{"class":662},[360,12144,2968],{"class":366},[360,12146,12147],{"class":362,"line":3438},[360,12148,372],{"emptyLinePlaceholder":320},[360,12150,12151,12153,12155,12157,12159,12161],{"class":362,"line":3443},[360,12152,8182],{"class":578},[360,12154,2691],{"class":366},[360,12156,2995],{"class":662},[360,12158,1358],{"class":366},[360,12160,7805],{"class":662},[360,12162,8161],{"class":366},[360,12164,12165,12167,12169,12171],{"class":362,"line":3462},[360,12166,8197],{"class":578},[360,12168,2691],{"class":366},[360,12170,7805],{"class":662},[360,12172,2968],{"class":366},[360,12174,12175],{"class":362,"line":3467},[360,12176,847],{"class":366},[360,12178,12179],{"class":362,"line":3472},[360,12180,372],{"emptyLinePlaceholder":320},[360,12182,12183,12185,12187,12189,12191,12193,12195,12197,12199,12201],{"class":362,"line":3495},[360,12184,2166],{"class":574},[360,12186,8218],{"class":381},[360,12188,671],{"class":366},[360,12190,8223],{"class":578},[360,12192,2734],{"class":366},[360,12194,2290],{"class":574},[360,12196,8230],{"class":662},[360,12198,3052],{"class":366},[360,12200,4364],{"class":662},[360,12202,896],{"class":366},[360,12204,12205,12207,12209,12211],{"class":362,"line":3500},[360,12206,8241],{"class":578},[360,12208,31],{"class":366},[360,12210,8246],{"class":381},[360,12212,5008],{"class":366},[360,12214,12215],{"class":362,"line":3505},[360,12216,847],{"class":366},[360,12218,12219],{"class":362,"line":3530},[360,12220,372],{"emptyLinePlaceholder":320},[360,12222,12223,12225,12227,12229,12231,12233,12235,12237,12239,12241,12243,12245,12247,12249,12251,12253],{"class":362,"line":3545},[360,12224,2166],{"class":574},[360,12226,8263],{"class":381},[360,12228,671],{"class":366},[360,12230,8223],{"class":578},[360,12232,2734],{"class":366},[360,12234,2290],{"class":574},[360,12236,8230],{"class":662},[360,12238,2311],{"class":366},[360,12240,6141],{"class":578},[360,12242,2691],{"class":366},[360,12244,2758],{"class":662},[360,12246,3052],{"class":366},[360,12248,2995],{"class":662},[360,12250,1358],{"class":366},[360,12252,2742],{"class":662},[360,12254,2711],{"class":366},[360,12256,12257,12259,12261,12263,12265,12267,12269,12271,12273,12275,12277,12279,12281,12283,12285],{"class":362,"line":3558},[360,12258,2177],{"class":574},[360,12260,2235],{"class":574},[360,12262,8300],{"class":578},[360,12264,2691],{"class":366},[360,12266,2995],{"class":662},[360,12268,1358],{"class":366},[360,12270,2742],{"class":662},[360,12272,2697],{"class":366},[360,12274,583],{"class":582},[360,12276,2268],{"class":662},[360,12278,666],{"class":366},[360,12280,8319],{"class":381},[360,12282,671],{"class":366},[360,12284,6141],{"class":578},[360,12286,801],{"class":366},[360,12288,12289,12291,12293,12295,12297,12299,12301],{"class":362,"line":3573},[360,12290,8330],{"class":574},[360,12292,8333],{"class":578},[360,12294,8336],{"class":574},[360,12296,1457],{"class":414},[360,12298,8341],{"class":366},[360,12300,6141],{"class":578},[360,12302,896],{"class":366},[360,12304,12305,12307,12309,12311,12313,12315,12317,12319],{"class":362,"line":3578},[360,12306,8350],{"class":578},[360,12308,31],{"class":366},[360,12310,8355],{"class":381},[360,12312,671],{"class":366},[360,12314,8223],{"class":578},[360,12316,31],{"class":366},[360,12318,8246],{"class":574},[360,12320,841],{"class":366},[360,12322,12323],{"class":362,"line":3583},[360,12324,2927],{"class":366},[360,12326,12327],{"class":362,"line":6893},[360,12328,8374],{"class":578},[360,12330,12331],{"class":362,"line":6899},[360,12332,847],{"class":366},[360,12334,12335],{"class":362,"line":6905},[360,12336,372],{"emptyLinePlaceholder":320},[360,12338,12339,12341,12343,12345,12347,12349,12351,12353,12355,12357],{"class":362,"line":6920},[360,12340,2166],{"class":574},[360,12342,8389],{"class":381},[360,12344,671],{"class":366},[360,12346,8223],{"class":578},[360,12348,2734],{"class":366},[360,12350,2290],{"class":574},[360,12352,8230],{"class":662},[360,12354,3052],{"class":366},[360,12356,7805],{"class":662},[360,12358,896],{"class":366},[360,12360,12361,12363,12365,12367,12369,12371,12373,12375,12377,12379,12381,12383],{"class":362,"line":6942},[360,12362,2177],{"class":574},[360,12364,2235],{"class":574},[360,12366,8414],{"class":578},[360,12368,401],{"class":582},[360,12370,8084],{"class":662},[360,12372,5879],{"class":366},[360,12374,8423],{"class":578},[360,12376,4418],{"class":366},[360,12378,1344],{"class":414},[360,12380,4423],{"class":366},[360,12382,6772],{"class":414},[360,12384,8434],{"class":366},[360,12386,12387,12389,12391,12393,12395,12397,12399],{"class":362,"line":6974},[360,12388,8330],{"class":574},[360,12390,6178],{"class":578},[360,12392,8336],{"class":574},[360,12394,1457],{"class":414},[360,12396,8341],{"class":366},[360,12398,6772],{"class":414},[360,12400,896],{"class":366},[360,12402,12403,12405,12407,12409,12411,12413,12415,12417,12419],{"class":362,"line":6992},[360,12404,8455],{"class":578},[360,12406,8458],{"class":366},[360,12408,6187],{"class":578},[360,12410,2390],{"class":366},[360,12412,583],{"class":582},[360,12414,8467],{"class":578},[360,12416,31],{"class":366},[360,12418,8246],{"class":381},[360,12420,2204],{"class":366},[360,12422,12423],{"class":362,"line":6997},[360,12424,2927],{"class":366},[360,12426,12427],{"class":362,"line":7002},[360,12428,8482],{"class":578},[360,12430,12431],{"class":362,"line":7008},[360,12432,847],{"class":366},[360,12434,12435],{"class":362,"line":7041},[360,12436,372],{"emptyLinePlaceholder":320},[360,12438,12439],{"class":362,"line":7047},[360,12440,11938],{"class":366},[360,12442,12443,12445,12447,12449],{"class":362,"line":7058},[360,12444,3637],{"class":574},[360,12446,3640],{"class":574},[360,12448,10412],{"class":662},[360,12450,896],{"class":366},[360,12452,12453,12456,12458,12460,12462,12464],{"class":362,"line":7064},[360,12454,12455],{"class":578},"    test_objects",[360,12457,2691],{"class":366},[360,12459,2995],{"class":662},[360,12461,1358],{"class":366},[360,12463,8675],{"class":662},[360,12465,8161],{"class":366},[360,12467,12468],{"class":362,"line":7086},[360,12469,847],{"class":366},[360,12471,12472],{"class":362,"line":7091},[360,12473,372],{"emptyLinePlaceholder":320},[360,12475,12476],{"class":362,"line":7126},[360,12477,11938],{"class":366},[360,12479,12480,12482,12484],{"class":362,"line":7165},[360,12481,2683],{"class":574},[360,12483,10412],{"class":662},[360,12485,896],{"class":366},[360,12487,12488],{"class":362,"line":7170},[360,12489,12490],{"class":366},"    #[wasm_bindgen(constructor)]\n",[360,12492,12493,12496,12498,12500,12502,12504],{"class":362,"line":7176},[360,12494,12495],{"class":574},"    pub",[360,12497,4805],{"class":574},[360,12499,3040],{"class":381},[360,12501,10510],{"class":366},[360,12503,3055],{"class":662},[360,12505,896],{"class":366},[360,12507,12508,12510],{"class":362,"line":7182},[360,12509,3062],{"class":662},[360,12511,896],{"class":366},[360,12513,12514,12517,12519,12521,12523,12525],{"class":362,"line":7200},[360,12515,12516],{"class":578},"            test_objects",[360,12518,2691],{"class":366},[360,12520,2995],{"class":662},[360,12522,666],{"class":366},[360,12524,2221],{"class":381},[360,12526,6478],{"class":366},[360,12528,12529],{"class":362,"line":7205},[360,12530,2840],{"class":366},[360,12532,12533],{"class":362,"line":7211},[360,12534,2927],{"class":366},[360,12536,12537],{"class":362,"line":7219},[360,12538,372],{"emptyLinePlaceholder":320},[360,12540,12541],{"class":362,"line":7237},[360,12542,12543],{"class":366},"    #[wasm_bindgen]\n",[360,12545,12546,12548,12550,12552,12554,12556,12558,12560,12562,12564,12566],{"class":362,"line":7252},[360,12547,12495],{"class":574},[360,12549,4805],{"class":574},[360,12551,10577],{"class":381},[360,12553,2287],{"class":366},[360,12555,2290],{"class":574},[360,12557,2726],{"class":662},[360,12559,2311],{"class":366},[360,12561,8690],{"class":578},[360,12563,2691],{"class":366},[360,12565,10592],{"class":662},[360,12567,681],{"class":366},[360,12569,12570,12572,12574,12576,12578,12580,12582,12584],{"class":362,"line":7257},[360,12571,2845],{"class":574},[360,12573,2235],{"class":574},[360,12575,8467],{"class":578},[360,12577,401],{"class":582},[360,12579,7842],{"class":662},[360,12581,666],{"class":366},[360,12583,8533],{"class":381},[360,12585,2204],{"class":366},[360,12587,12588],{"class":362,"line":7280},[360,12589,12590],{"class":644},"        \u002F\u002F Get the current time in ms\n",[360,12592,12593,12595,12598,12600,12602,12604,12606,12608,12610,12612,12614],{"class":362,"line":7285},[360,12594,2899],{"class":662},[360,12596,12597],{"class":366},".test_objects ",[360,12599,583],{"class":582},[360,12601,2268],{"class":662},[360,12603,666],{"class":366},[360,12605,8319],{"class":381},[360,12607,671],{"class":366},[360,12609,8690],{"class":578},[360,12611,9698],{"class":574},[360,12613,11296],{"class":662},[360,12615,801],{"class":366},[360,12617,12618],{"class":362,"line":7291},[360,12619,372],{"emptyLinePlaceholder":320},[360,12621,12622,12625,12627,12629,12631,12633,12635],{"class":362,"line":7314},[360,12623,12624],{"class":574},"        for",[360,12626,8333],{"class":578},[360,12628,8336],{"class":574},[360,12630,1457],{"class":414},[360,12632,8341],{"class":366},[360,12634,8690],{"class":578},[360,12636,896],{"class":366},[360,12638,12639,12641,12644,12646,12648,12650],{"class":362,"line":7345},[360,12640,3446],{"class":662},[360,12642,12643],{"class":366},".test_objects.",[360,12645,8355],{"class":381},[360,12647,671],{"class":366},[360,12649,8675],{"class":662},[360,12651,896],{"class":366},[360,12653,12654,12657,12659,12661,12663,12665,12667,12669,12671],{"class":362,"line":7351},[360,12655,12656],{"class":578},"                path",[360,12658,2691],{"class":366},[360,12660,8733],{"class":381},[360,12662,2287],{"class":366},[360,12664,2290],{"class":574},[360,12666,8467],{"class":578},[360,12668,2311],{"class":366},[360,12670,6349],{"class":414},[360,12672,5405],{"class":366},[360,12674,12675,12678,12680,12682],{"class":362,"line":7374},[360,12676,12677],{"class":578},"                stats",[360,12679,2691],{"class":366},[360,12681,8171],{"class":662},[360,12683,896],{"class":366},[360,12685,12686,12689,12691,12693,12695,12697,12699],{"class":362,"line":7407},[360,12687,12688],{"class":578},"                    owner_id",[360,12690,2691],{"class":366},[360,12692,8766],{"class":381},[360,12694,2287],{"class":366},[360,12696,2290],{"class":574},[360,12698,8467],{"class":578},[360,12700,5405],{"class":366},[360,12702,12703,12706,12708,12710,12712,12714,12716],{"class":362,"line":7418},[360,12704,12705],{"class":578},"                    group_id",[360,12707,2691],{"class":366},[360,12709,8766],{"class":381},[360,12711,2287],{"class":366},[360,12713,2290],{"class":574},[360,12715,8467],{"class":578},[360,12717,5405],{"class":366},[360,12719,12720,12723,12725,12727,12729,12731,12733],{"class":362,"line":7426},[360,12721,12722],{"class":578},"                    size",[360,12724,2691],{"class":366},[360,12726,8766],{"class":381},[360,12728,2287],{"class":366},[360,12730,2290],{"class":574},[360,12732,8467],{"class":578},[360,12734,5405],{"class":366},[360,12736,12737,12740,12742,12744,12746,12748,12750],{"class":362,"line":7451},[360,12738,12739],{"class":578},"                    compressed_size",[360,12741,2691],{"class":366},[360,12743,8766],{"class":381},[360,12745,2287],{"class":366},[360,12747,2290],{"class":574},[360,12749,8467],{"class":578},[360,12751,5405],{"class":366},[360,12753,12754,12757,12759,12761,12763,12765,12767],{"class":362,"line":7457},[360,12755,12756],{"class":578},"                    last_read",[360,12758,2691],{"class":366},[360,12760,8766],{"class":381},[360,12762,2287],{"class":366},[360,12764,2290],{"class":574},[360,12766,8467],{"class":578},[360,12768,5405],{"class":366},[360,12770,12771,12774,12776,12778,12780,12782,12784],{"class":362,"line":7462},[360,12772,12773],{"class":578},"                    last_modified",[360,12775,2691],{"class":366},[360,12777,8766],{"class":381},[360,12779,2287],{"class":366},[360,12781,2290],{"class":574},[360,12783,8467],{"class":578},[360,12785,5405],{"class":366},[360,12787,12788,12791,12793,12795,12797,12799,12801],{"class":362,"line":7467},[360,12789,12790],{"class":578},"                    created",[360,12792,2691],{"class":366},[360,12794,8766],{"class":381},[360,12796,2287],{"class":366},[360,12798,2290],{"class":574},[360,12800,8467],{"class":578},[360,12802,5405],{"class":366},[360,12804,12805,12808,12810,12812,12814,12816,12818],{"class":362,"line":7485},[360,12806,12807],{"class":578},"                    mode",[360,12809,2691],{"class":366},[360,12811,8766],{"class":381},[360,12813,2287],{"class":366},[360,12815,2290],{"class":574},[360,12817,8467],{"class":578},[360,12819,5405],{"class":366},[360,12821,12822,12825,12827,12829,12831,12833,12835],{"class":362,"line":7507},[360,12823,12824],{"class":578},"                    dev",[360,12826,2691],{"class":366},[360,12828,8766],{"class":381},[360,12830,2287],{"class":366},[360,12832,2290],{"class":574},[360,12834,8467],{"class":578},[360,12836,5405],{"class":366},[360,12838,12839,12842,12844,12846,12848,12850,12852],{"class":362,"line":7512},[360,12840,12841],{"class":578},"                    rdev",[360,12843,2691],{"class":366},[360,12845,8766],{"class":381},[360,12847,2287],{"class":366},[360,12849,2290],{"class":574},[360,12851,8467],{"class":578},[360,12853,5405],{"class":366},[360,12855,12856,12859,12861,12863,12865,12867,12869],{"class":362,"line":9051},[360,12857,12858],{"class":578},"                    ino",[360,12860,2691],{"class":366},[360,12862,8766],{"class":381},[360,12864,2287],{"class":366},[360,12866,2290],{"class":574},[360,12868,8467],{"class":578},[360,12870,5405],{"class":366},[360,12872,12873,12876,12878,12880,12882,12884,12886],{"class":362,"line":9056},[360,12874,12875],{"class":578},"                    nlink",[360,12877,2691],{"class":366},[360,12879,8766],{"class":381},[360,12881,2287],{"class":366},[360,12883,2290],{"class":574},[360,12885,8467],{"class":578},[360,12887,5405],{"class":366},[360,12889,12890],{"class":362,"line":9082},[360,12891,12892],{"class":366},"                },\n",[360,12894,12895,12898,12900,12902],{"class":362,"line":9103},[360,12896,12897],{"class":578},"                chunks",[360,12899,2691],{"class":366},[360,12901,8976],{"class":381},[360,12903,8979],{"class":366},[360,12905,12906,12909,12911,12913,12915],{"class":362,"line":9112},[360,12907,12908],{"class":381},"                    generate_random_sha256",[360,12910,2287],{"class":366},[360,12912,2290],{"class":574},[360,12914,8467],{"class":578},[360,12916,5405],{"class":366},[360,12918,12919,12921,12923,12925,12927],{"class":362,"line":9121},[360,12920,12908],{"class":381},[360,12922,2287],{"class":366},[360,12924,2290],{"class":574},[360,12926,8467],{"class":578},[360,12928,5405],{"class":366},[360,12930,12931,12933,12935,12937,12939],{"class":362,"line":9127},[360,12932,12908],{"class":381},[360,12934,2287],{"class":366},[360,12936,2290],{"class":574},[360,12938,8467],{"class":578},[360,12940,5405],{"class":366},[360,12942,12943],{"class":362,"line":9149},[360,12944,12945],{"class":366},"                ],\n",[360,12947,12948,12951,12953,12955,12957,12959,12961],{"class":362,"line":9154},[360,12949,12950],{"class":578},"                sha256",[360,12952,2691],{"class":366},[360,12954,9031],{"class":381},[360,12956,2287],{"class":366},[360,12958,2290],{"class":574},[360,12960,8467],{"class":578},[360,12962,5405],{"class":366},[360,12964,12965],{"class":362,"line":9159},[360,12966,12967],{"class":366},"            });\n",[360,12969,12970],{"class":362,"line":9181},[360,12971,2840],{"class":366},[360,12973,12974],{"class":362,"line":9187},[360,12975,2927],{"class":366},[360,12977,12978],{"class":362,"line":9194},[360,12979,372],{"emptyLinePlaceholder":320},[360,12981,12982,12985,12987],{"class":362,"line":9202},[360,12983,12984],{"class":366},"    #[wasm_bindgen(js_name ",[360,12986,583],{"class":582},[360,12988,12989],{"class":366}," toString)]\n",[360,12991,12992,12994,12996,12998,13000,13002,13004,13006],{"class":362,"line":9227},[360,12993,12495],{"class":574},[360,12995,4805],{"class":574},[360,12997,11341],{"class":381},[360,12999,2287],{"class":366},[360,13001,3479],{"class":662},[360,13003,3052],{"class":366},[360,13005,11350],{"class":662},[360,13007,896],{"class":366},[360,13009,13010,13013],{"class":362,"line":9233},[360,13011,13012],{"class":381},"        format!",[360,13014,1395],{"class":366},[360,13016,13017,13020],{"class":362,"line":9239},[360,13018,13019],{"class":397},"            \"TestObjectWrapper {{ test_objects: {} }}\"",[360,13021,2968],{"class":366},[360,13023,13024,13026,13028,13030],{"class":362,"line":9246},[360,13025,3446],{"class":662},[360,13027,12643],{"class":366},[360,13029,2802],{"class":381},[360,13031,5008],{"class":366},[360,13033,13034],{"class":362,"line":9254},[360,13035,13036],{"class":366},"        )\n",[360,13038,13039],{"class":362,"line":9279},[360,13040,2927],{"class":366},[360,13042,13043],{"class":362,"line":9284},[360,13044,847],{"class":366},[12,13046,13047,13048,31],{},"Pour utiliser notre module dans Node.JS, nous devons importer le module ",[344,13049,13050],{},"wasm-bindgen",[352,13052,13054],{"className":6044,"code":13053,"language":6046,"meta":291,"style":291},"const { webcrypto } = require('node:crypto')\nglobal.crypto = webcrypto\n\nconst wasm = require('..\u002Fpkg\u002Ftest_rust_was.js');\nconst filesize = require(\"filesize.js\");\n\nglobal.gc();\nconst memoryBefore = process.memoryUsage().rss;\n\nconst time = Date.now();\n\nconst nbObjects = 1300000;\nconst testArray = new wasm.TestObjectWrapper();\ntestArray.fill(nbObjects);\n\nconsole.log(\"Creation time: \", Date.now() - time);\n\nglobal.gc();\nconst memoryAfter = process.memoryUsage().rss;\n\nconsole.log(\"Memory consumption in JS: \", filesize.default(memoryAfter - memoryBefore));\nconsole.log(\"Memory consumption calculated by head: \", filesize.default(432));\nconsole.log(\"Memory consumption by objects: \", filesize.default((memoryAfter - memoryBefore) \u002F nbObjects));\n  \nconsole.log(testArray.toString());\n",[344,13055,13056,13078,13092,13096,13114,13130,13134,13144,13165,13169,13185,13189,13202,13220,13234,13238,13266,13270,13280,13300,13304,13335,13363,13399,13404],{"__ignoreMap":291},[360,13057,13058,13060,13062,13065,13067,13069,13071,13073,13076],{"class":362,"line":363},[360,13059,6053],{"class":574},[360,13061,5879],{"class":366},[360,13063,13064],{"class":662},"webcrypto",[360,13066,6108],{"class":366},[360,13068,583],{"class":582},[360,13070,6061],{"class":381},[360,13072,671],{"class":366},[360,13074,13075],{"class":397},"'node:crypto'",[360,13077,2922],{"class":366},[360,13079,13080,13082,13084,13087,13089],{"class":362,"line":292},[360,13081,6826],{"class":662},[360,13083,31],{"class":366},[360,13085,13086],{"class":578},"crypto",[360,13088,401],{"class":582},[360,13090,13091],{"class":578}," webcrypto\n",[360,13093,13094],{"class":362,"line":375},[360,13095,372],{"emptyLinePlaceholder":320},[360,13097,13098,13100,13103,13105,13107,13109,13112],{"class":362,"line":433},[360,13099,6053],{"class":574},[360,13101,13102],{"class":662}," wasm",[360,13104,401],{"class":582},[360,13106,6061],{"class":381},[360,13108,671],{"class":366},[360,13110,13111],{"class":397},"'..\u002Fpkg\u002Ftest_rust_was.js'",[360,13113,801],{"class":366},[360,13115,13116,13118,13120,13122,13124,13126,13128],{"class":362,"line":478},[360,13117,6053],{"class":574},[360,13119,6056],{"class":662},[360,13121,401],{"class":582},[360,13123,6061],{"class":381},[360,13125,671],{"class":366},[360,13127,6066],{"class":397},[360,13129,801],{"class":366},[360,13131,13132],{"class":362,"line":483},[360,13133,372],{"emptyLinePlaceholder":320},[360,13135,13136,13138,13140,13142],{"class":362,"line":489},[360,13137,6826],{"class":662},[360,13139,31],{"class":366},[360,13141,6831],{"class":381},[360,13143,2204],{"class":366},[360,13145,13146,13148,13150,13152,13154,13156,13158,13160,13163],{"class":362,"line":494},[360,13147,6053],{"class":574},[360,13149,6845],{"class":662},[360,13151,401],{"class":582},[360,13153,6850],{"class":662},[360,13155,31],{"class":366},[360,13157,6855],{"class":381},[360,13159,3487],{"class":366},[360,13161,13162],{"class":578},"rss",[360,13164,735],{"class":366},[360,13166,13167],{"class":362,"line":712},[360,13168,372],{"emptyLinePlaceholder":320},[360,13170,13171,13173,13175,13177,13179,13181,13183],{"class":362,"line":331},[360,13172,6053],{"class":574},[360,13174,6874],{"class":662},[360,13176,401],{"class":582},[360,13178,6879],{"class":662},[360,13180,31],{"class":366},[360,13182,6884],{"class":381},[360,13184,2204],{"class":366},[360,13186,13187],{"class":362,"line":762},[360,13188,372],{"emptyLinePlaceholder":320},[360,13190,13191,13193,13195,13197,13200],{"class":362,"line":781},[360,13192,6053],{"class":574},[360,13194,6910],{"class":662},[360,13196,401],{"class":582},[360,13198,13199],{"class":414}," 1300000",[360,13201,735],{"class":366},[360,13203,13204,13206,13208,13210,13212,13214,13216,13218],{"class":362,"line":804},[360,13205,6053],{"class":574},[360,13207,6925],{"class":662},[360,13209,401],{"class":582},[360,13211,3040],{"class":574},[360,13213,13102],{"class":662},[360,13215,31],{"class":366},[360,13217,10470],{"class":381},[360,13219,2204],{"class":366},[360,13221,13222,13224,13226,13228,13230,13232],{"class":362,"line":817},[360,13223,11584],{"class":662},[360,13225,31],{"class":366},[360,13227,11589],{"class":381},[360,13229,671],{"class":366},[360,13231,6937],{"class":578},[360,13233,801],{"class":366},[360,13235,13236],{"class":362,"line":823},[360,13237,372],{"emptyLinePlaceholder":320},[360,13239,13240,13242,13244,13246,13248,13250,13252,13254,13256,13258,13260,13262,13264],{"class":362,"line":844},[360,13241,7011],{"class":662},[360,13243,31],{"class":366},[360,13245,7016],{"class":381},[360,13247,671],{"class":366},[360,13249,7021],{"class":397},[360,13251,2311],{"class":366},[360,13253,7026],{"class":662},[360,13255,31],{"class":366},[360,13257,6884],{"class":381},[360,13259,2805],{"class":366},[360,13261,1491],{"class":582},[360,13263,6874],{"class":578},[360,13265,801],{"class":366},[360,13267,13268],{"class":362,"line":1441},[360,13269,372],{"emptyLinePlaceholder":320},[360,13271,13272,13274,13276,13278],{"class":362,"line":1462},[360,13273,6826],{"class":662},[360,13275,31],{"class":366},[360,13277,6831],{"class":381},[360,13279,2204],{"class":366},[360,13281,13282,13284,13286,13288,13290,13292,13294,13296,13298],{"class":362,"line":1485},[360,13283,6053],{"class":574},[360,13285,7069],{"class":662},[360,13287,401],{"class":582},[360,13289,6850],{"class":662},[360,13291,31],{"class":366},[360,13293,6855],{"class":381},[360,13295,3487],{"class":366},[360,13297,13162],{"class":578},[360,13299,735],{"class":366},[360,13301,13302],{"class":362,"line":1497},[360,13303,372],{"emptyLinePlaceholder":320},[360,13305,13306,13308,13310,13312,13314,13317,13319,13321,13323,13325,13327,13329,13331,13333],{"class":362,"line":3161},[360,13307,7011],{"class":662},[360,13309,31],{"class":366},[360,13311,7016],{"class":381},[360,13313,671],{"class":366},[360,13315,13316],{"class":397},"\"Memory consumption in JS: \"",[360,13318,2311],{"class":366},[360,13320,7107],{"class":662},[360,13322,31],{"class":366},[360,13324,7112],{"class":381},[360,13326,671],{"class":366},[360,13328,7117],{"class":578},[360,13330,518],{"class":582},[360,13332,6845],{"class":578},[360,13334,4081],{"class":366},[360,13336,13337,13339,13341,13343,13345,13348,13350,13352,13354,13356,13358,13361],{"class":362,"line":3167},[360,13338,7011],{"class":662},[360,13340,31],{"class":366},[360,13342,7016],{"class":381},[360,13344,671],{"class":366},[360,13346,13347],{"class":397},"\"Memory consumption calculated by head: \"",[360,13349,2311],{"class":366},[360,13351,7107],{"class":662},[360,13353,31],{"class":366},[360,13355,7112],{"class":381},[360,13357,671],{"class":366},[360,13359,13360],{"class":414},"432",[360,13362,4081],{"class":366},[360,13364,13365,13367,13369,13371,13373,13375,13377,13379,13381,13383,13385,13387,13389,13391,13393,13395,13397],{"class":362,"line":3194},[360,13366,7011],{"class":662},[360,13368,31],{"class":366},[360,13370,7016],{"class":381},[360,13372,671],{"class":366},[360,13374,7137],{"class":397},[360,13376,2311],{"class":366},[360,13378,7107],{"class":662},[360,13380,31],{"class":366},[360,13382,7112],{"class":381},[360,13384,7148],{"class":366},[360,13386,7117],{"class":578},[360,13388,518],{"class":582},[360,13390,6845],{"class":578},[360,13392,3972],{"class":366},[360,13394,768],{"class":582},[360,13396,6910],{"class":578},[360,13398,4081],{"class":366},[360,13400,13401],{"class":362,"line":3224},[360,13402,13403],{"class":366},"  \n",[360,13405,13406,13408,13410,13412,13414,13416,13418,13420],{"class":362,"line":3239},[360,13407,7011],{"class":662},[360,13409,31],{"class":366},[360,13411,7016],{"class":381},[360,13413,671],{"class":366},[360,13415,11584],{"class":662},[360,13417,31],{"class":366},[360,13419,11735],{"class":381},[360,13421,841],{"class":366},[12,13423,13424],{},"Nous n'oublions pas de compiler notre module en mode release et avec la target nodejs.",[12,13426,13427],{},"Le résultat est alors le suivant :",[1545,13429,13430,13438],{},[1548,13431,13432],{},[1551,13433,13434,13436],{},[1554,13435],{},[1554,13437],{},[1567,13439,13440,13446,13453,13460],{},[1551,13441,13442,13444],{},[1572,13443,7544],{},[1572,13445,7547],{},[1551,13447,13448,13450],{},[1572,13449,7552],{},[1572,13451,13452],{},"42 secondes",[1551,13454,13455,13457],{},[1572,13456,7560],{},[1572,13458,13459],{},"450,6 Mo",[1551,13461,13462,13464],{},[1572,13463,7568],{},[1572,13465,13466],{},"363.5 octets",[12,13468,13469],{},"Wasm permet d'améliorer la consommation mémoire. Sur mon exemple, le temps de création n'est pas très impressionnant\nmais est, je crois, lié à la génération des nombres aléatoires.",[12,13471,13472],{},"L'utilisation de WASM pourrait être une bonne alternative.",[12,13474,13475],{},"Quand utiliser WASM et quand faire un module node ? L'avantage de faire du Wasm, c'est que le module peut tourner\négalement côté navigateur. L'autre avantage est que le module n'a pas besoin d'être recompilé en cas de changement de\nplateforme (Linux, Windows, ... ; x86, ARM, ...).",[12,13477,13478],{},"D'un autre côté, un module node natif a l'avantage d'être plus simple (moins de bindings) et sera sûrement plus rapide\nà l'exécution.",[33,13480,251],{"id":250},[12,13482,13483],{},"Pour améliorer les performances de notre application, nous allons donc écrire un module natif en Rust avec N-API.",[12,13485,13486,13487,31],{},"Vous pouvez retrouver le code source de cet article sur mon dépôt ",[47,13488,13491],{"href":13489,"rel":13490},"https:\u002F\u002Fgogs.shadoware.org\u002FShadowareOrg\u002Fblog_compare_js_rust_wasm",[51],"Gitea",[1613,13493,13494],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":291,"searchDepth":292,"depth":292,"links":13496},[13497,13498,13499,13500,13501,13502,13504],{"id":6027,"depth":292,"text":6028},{"id":6037,"depth":292,"text":6038},{"id":7604,"depth":292,"text":7605},{"id":7791,"depth":292,"text":7792},{"id":9791,"depth":292,"text":9792},{"id":11784,"depth":292,"text":13503},"Conclusion - Wasm",{"id":250,"depth":292,"text":251},"2023-05-10",{"type":9,"value":13507},[13508,13510,13512],[33,13509,6028],{"id":6027},[12,13511,6031],{},[12,13513,6034],{},{"planet":320},"\u002Fpost\u002Fwoodstock_rust",{"title":6022,"description":291},"woodstock_rust","posts\u002FWoodstock\u002F2023-05-10_woodstock_rust",[6016,6017,6018,1765,1766],"RXnKX2dJmrksM5sZOeN70MXCyeSAMu1H3Jj5D3fie28",{"id":13522,"title":13523,"author":7,"body":13524,"category":300,"categorySlug":301,"date":15634,"description":291,"excerpt":15635,"extension":317,"location":318,"meta":15654,"navigation":320,"path":15655,"published":320,"seo":15656,"slug":15657,"stem":15658,"tags":15659,"timeToRead":3194,"__hash__":15660},"posts\u002Fposts\u002FWoodstock\u002F2021-04-18_woodstock_protocol_language_sauvegarde.md","Woodstock Backup - Protocol et Language de sauvegarde",{"type":9,"value":13525,"toc":15620},[13526,13533,13544,13552,13555,13558,13561,13564,13567,13570,13574,13577,13591,13594,13602,13605,13608,13624,13628,13631,13645,13652,13655,13658,13676,13679,13690,13697,13700,13703,13707,13713,13716,13741,13744,13747,13750,13753,13756,13760,13763,13768,13771,13782,13785,13789,13792,13795,13814,13817,13825,13828,13834,13859,13862,13866,13869,13889,13892,13895,13898,13901,13905,13908,13911,13914,13917,13921,13940,13966,13972,13986,13999,14015,14025,14243,14250,15245,15253,15262,15265,15276,15282,15286,15298,15307,15310,15327,15330,15333,15413,15416,15419,15422,15480,15492,15495,15525,15528,15531,15536,15540,15563,15567,15570,15573,15576,15579,15597,15600,15603,15606,15617],[12,13527,13528],{},[69,13529],{"alt":13523,"src":13530,"className":13531,"width":13532},"\u002FWoodstock\u002Fsplash_proto.png",[73],"400px,",[123,13534,13535,13538,13541],{},[12,13536,13537],{},"Note de 2023 : Ce billet a été écrit en avril 2021, il y a deux ans, mais n'a jamais été publié. Le temps passe vite.",[12,13539,13540],{},"Depuis lors, j'ai travaillé sur d'autres projets, mais aussi sur ce logiciel de sauvegarde. En progressant dans le\ndéveloppement du projet, j'ai pu optimiser les performances et me faire une opinion sur le choix que j'ai finalement\nfait, que je partagerai à la fin de l'article.",[12,13542,13543],{},"Je mettrai à jour mes conclusions en fonction de mes avancées sur le sujet.",[12,13545,13546,13547,13551],{},"Dans notre ",[47,13548,13550],{"href":13549},"\u002Fpost\u002Fwoodstock_brtfs","précédent article",", nous avons vu comment dédupliquer les fichiers dans un pool sans\nutiliser btrfs, un système de fichier permettant la déduplication. Pour pouvoir copier les fichiers dans notre pool,\nle logiciel doit savoir comment écrire les fichiers de manière appropriée.",[12,13553,13554],{},"Si nous voulons continuer à utiliser rsync, nous pourrions envisager de créer un système de fichiers FUSE (Filesystem in\nUser Space) pour faire le pont entre rsync et notre pool de stockage. Cela nous permettrait de continuer à utiliser\nrsync pour les sauvegardes et les restaurations. Cependant, cela nécessiterait la mise en œuvre d'un système de fichiers\ncomplet, y compris la lecture, l'écriture, la déduplication, etc., pour un usage très spécifique de rsync. En fin de\ncompte, le système de fichiers ne serait utilisé que pour la sauvegarde (ajout de nouveaux éléments) et la restauration\n(lecture d'une sauvegarde). Il n'y aurait pas d'écriture aléatoire dans le système de fichiers, ni dans un fichier même.",[12,13556,13557],{},"Après avoir rapidement examiné cette possibilité, je l'ai écartée car elle me semble être une solution trop lourde pour\nmes besoins.",[12,13559,13560],{},"Par conséquent, nous devrons nous passer de rsync. Je n'ai pas trouvé de bibliothèque permettant d'implémenter\nfacilement une synchronisation sur le protocole rsync. Nous devrons donc écrire notre propre protocole de\nsynchronisation de fichiers.",[12,13562,13563],{},"Lorsque nous développerons ce protocole, nous devrons nous assurer de la sécurité. En effet, rsync est capable de\nsynchroniser des fichiers via un tunnel ssh. Notre protocole devra empêcher les attaquants d'écouter ce qui est\nsynchronisé et d'accéder aux fichiers sans autorisation.",[12,13565,13566],{},"Dans la suite de cet article, nous étudierons comment écrire notre protocole de synchronisation et nous comparerons les\nperformances de sauvegarde entre le langage JavaScript (actuellement utilisé par le serveur de sauvegarde) et le\nlangage C++.",[12,13568,13569],{},"Comme toujours, n'hésitez pas à me faire part de vos commentaires et de vos avis (système de commentaires en bas de la\npage).",[33,13571,13573],{"id":13572},"création-de-la-communication-périphériqueserveur","Création de la communication périphérique\u002Fserveur",[12,13575,13576],{},"Nous allons aborder la question de la communication entre le client et le serveur. Afin d'éviter toute confusion entre\nle client et le serveur dans le sens réseau et le client et le serveur dans le sens applicatif, nous allons désigner :",[140,13578,13579,13585],{},[143,13580,13581,13584],{},[344,13582,13583],{},"Périphérique"," pour le client à sauvegarder",[143,13586,13587,13590],{},[344,13588,13589],{},"Serveur de sauvegarde"," pour le serveur de sauvegarde.",[12,13592,13593],{},"En ce qui concerne le protocole de communication, je pense utiliser une HTTP2 plutôt que d'ouvrir un socket TCP et\ntravailler directement dessus. L'utilisation d'un protocole de haut niveau me permettra de m'appuyer sur des\nbibliothèques existantes et déjà largement utilisées. De plus, je n'aurai pas à gérer :",[140,13595,13596,13599],{},[143,13597,13598],{},"la compression",[143,13600,13601],{},"la prise en charge de TLS",[12,13603,13604],{},"En raison de la nature d'HTTP2, l'initiateur de la connexion est important : il faut déterminer qui est le serveur HTTP\net qui est le client HTTP.",[12,13606,13607],{},"Dans la suite de cet article, nous allons essayer de répondre aux deux questions suivantes :",[140,13609,13610,13613],{},[143,13611,13612],{},"Comment effectuer la communication entre le serveur de sauvegarde et le périphérique à sauvegarder ?",[143,13614,13615,13616],{},"Qui doit initier la connexion ?\n",[140,13617,13618,13621],{},[143,13619,13620],{},"Est-ce que le serveur de sauvegarde doit contacter le périphérique ?",[143,13622,13623],{},"Ou est-ce que le périphérique doit contacter le serveur de sauvegarde ?",[1901,13625,13627],{"id":13626},"le-serveur-de-sauvegarde-initie-la-connection","Le serveur de sauvegarde initie la connection",[12,13629,13630],{},"Nous allons parler de deux éléments clés pour la sauvegarde: le manifeste et les chunks.",[140,13632,13633,13639],{},[143,13634,13635,13638],{},[344,13636,13637],{},"Manifeste",": la liste des fichiers à sauvegarder avec le nom du fichier, les attributs, les acl, ... un hash du\nfichier et un hash des différents morceaux qui le constituent.",[143,13640,13641,13644],{},[344,13642,13643],{},"Chunk",": un morceau de fichier (un fichier peut être découpé en plusieurs morceaux de taille donnée).",[13646,13647,13648],"center",{},[69,13649],{"alt":13650,"src":13651},"Le serveur initie la connection","https:\u002F\u002Fwww.plantuml.com\u002Fplantuml\u002Fpng\u002FZP1DJWCn38NtEOKvm5oWYweIOe740i49hEILM2JErFcvqvnZBeO6LAcqAcBZZTydVtw7sjXQpyazj8WCojnWmiwzmmQCfZszhel97BTvwjZHiqeJJbAvIL4AeCHKkGzyi0NyXRwmUcHekwNODndSSCMuLCfCS-b6FlAfWuxYey2g-nsaQThJp-KTFUaeGW6LCgiSKLibxbItTRTBmpFnMFBCnbAB4W_upIx0L62urBp_szkw-3wlYvrhgUHZryz_Ydvd7JGu5t2lZ0Cqz9o-0000",[12,13653,13654],{},"Lorsqu'une sauvegarde doit démarrer, le serveur contacte le périphérique et initie la sauvegarde. Le périphérique\nenvoie ensuite les différents fichiers au serveur qui peut alors demander au périphérique les morceaux de fichiers\nqui lui manquent.",[12,13656,13657],{},"Voici des exemples de logiciels de sauvegarde où le périphérique initie la connexion:",[140,13659,13660,13668],{},[143,13661,13662,13667],{},[47,13663,13666],{"href":13664,"rel":13665},"https:\u002F\u002Fbackuppc.github.io\u002Fbackuppc\u002F",[51],"BackupPC"," - basé sur un rsync modifié pour gérer la partie pool",[143,13669,13670,13675],{},[47,13671,13674],{"href":13672,"rel":13673},"https:\u002F\u002Fwww.urbackup.org\u002F",[51],"UrBackup"," - basé sur son propre client de sauvegarde à installer sur le périphérique",[12,13677,13678],{},"Lorsque le serveur initie la connexion sur le périphérique:",[140,13680,13681,13684,13687],{},[143,13682,13683],{},"Le serveur décide quand faire la sauvegarde (en fonction de quand la dernière sauvegarde a été construite, des heures\nde travail, ...).",[143,13685,13686],{},"Le serveur a besoin de pouvoir accéder aux machines, mais les périphériques n'ont pas besoin d'avoir un accès direct\nau serveur de sauvegarde. Cela permet de ne pas compromettre le serveur de sauvegarde en cas de compromission d'un\npériphérique.",[143,13688,13689],{},"Le serveur doit détecter la présence du périphérique (si ce dernier n'est pas toujours sur le réseau) et donc faire\nun ping régulier, par exemple.",[12,13691,13692,13693,13696],{},"Il faudra prévoir un ",[344,13694,13695],{},"scheduler"," pour vérifier la présence des machines sur le réseau. Le serveur doit rester éveillé\n(et donc être actif) et ne peut pas juste attendre l'arrivée d'un périphérique.",[12,13698,13699],{},"Il doit y avoir un serveur (le serveur ne peut pas être juste un espace de stockage, comme un S3). Le serveur décide à\npartir du nouveau manifeste du client quels sont les fichiers qui ont changé et demande au client de lui envoyer ceux\nqui lui manquent.",[12,13701,13702],{},"Le serveur décide d'organiser son pool de sauvegarde comme il le souhaite, ainsi que le nombre de sauvegardes en\nparallèle. Il peut bloquer les sauvegardes si le pool est plein.",[1901,13704,13706],{"id":13705},"le-périphérique-initie-la-connection","Le périphérique initie la connection",[13646,13708,13709],{},[69,13710],{"alt":13711,"src":13712},"Le périphérique initie la connexion","https:\u002F\u002Fwww.plantuml.com\u002Fplantuml\u002Fpng\u002FZP3DJGD138NlKuKfW0PoG94G1sv8q80ryvArD3yRZxrAIMmTsnWQ52c00ENYW-tt_3tlkx6QbnpkR4815JQeS0WlsweoJwEU77J_GA_G1RgZvoecdAM3CbDdNt1aJGY1eyd2XijgoAtDD3TNYXCFbuF4IQ3z5_VldHqzjjfDFPgqIicfS9K3klq3zhQjULlZn7f4GRKXIz0gqAlyfjDbPcNfhH8lY2Fcfy_shlWQ-6-KfxeqeOHEfMa4-vdIDVwWEJbNwxTPNDWxiLCVOzU0ca98-FdoFMhoaZy0",[12,13714,13715],{},"Voici quelques exemples de logiciels de sauvegarde qui peuvent être déclenchés depuis le périphérique:",[140,13717,13718,13726,13733],{},[143,13719,13720,13725],{},[47,13721,13724],{"href":13722,"rel":13723},"https:\u002F\u002Fborgbackup.readthedocs.io\u002Fen\u002Fstable\u002Findex.html",[51],"Borg"," (avec un lieu de stockage)",[143,13727,13728,13725],{},[47,13729,13732],{"href":13730,"rel":13731},"https:\u002F\u002Frestic.net\u002F",[51],"Restic",[143,13734,13735,13740],{},[47,13736,13739],{"href":13737,"rel":13738},"https:\u002F\u002Fburp.grke.org\u002F",[51],"Burp"," (avec un serveur qui centralise les sauvegardes)",[12,13742,13743],{},"Le périphérique sait quand il est allumé et connecté au réseau. S'il y a une erreur de sauvegarde (par exemple, si le\nserveur de stockage n'est pas disponible), il peut réessayer plus tard. Il n'est donc pas nécessaire de planifier des\nsauvegardes sur le serveur, mais il est nécessaire d'avoir un plan de sauvegarde pour chaque périphérique.",[12,13745,13746],{},"Le périphérique doit être capable de se connecter au serveur, donc il est important d'ouvrir le flux de données du\npériphérique vers le serveur (par exemple, si le périphérique est un ordinateur hors réseau interne). Cela peut être\nrésolu en créant un VPN.",[12,13748,13749],{},"Lorsque la sauvegarde est initialisée, le serveur peut renvoyer des informations au périphérique pour indiquer qu'il\nrefuse la sauvegarde (pool plein, ...). Le périphérique devra alors réessayer plus tard.",[12,13751,13752],{},"Si un périphérique est compromis, toutes les sauvegardes de ce périphérique sont en danger (il existe des solutions\npour bloquer les sauvegardes en lecture\u002Fécriture). Si le pool de sauvegarde  est mutualisé entre plusieurs machines,\ncela peut compromettre l'ensemble du pool.",[12,13754,13755],{},"Le serveur reçoit un manifeste et une liste de chunks. Si nous souhaitons mutualiser le pool de sauvegarde, nous ne\npouvons pas laisser le client accéder à l'intégralité du pool. Nous devons donc disposer d'un serveur qui gère les\nchunks et vérifie que les fichiers reçus correspondent bien aux sauvegardes effectuées. Il est important de s'assurer\nque les clients n'envoient pas de chunks qui ne sont pas relatifs à une sauvegarde ou qui ont un sha incorrect pour\néviter que les fichiers soient mal rangés. Il faut aussi bloquer la modification des anciennes sauvegardes, et aussi\nconditionner la lecture de ces derniers.",[1901,13757,13759],{"id":13758},"choix","Choix",[12,13761,13762],{},"Personnellement, j'ai une préférence pour l'initialisation de la sauvegarde par le serveur. Dans mon projet actuel,\nj'ai déjà prévu le code pour gérer la file d'attente, lancer rsync, ainsi que le planificateur. Il serait facile de\nremplacer ce code par celui de mon nouveau serveur.",[123,13764,13765],{},[12,13766,13767],{},"Note de 2023: En avançant dans la réécriture, les dépendances ont été mises à jour et une grande partie du code a\nété modifié. Par conséquent, remplacer l'appel à rsync par un appel au nouveau système de sauvegarde n'a pas été\naussi simple que prévu.",[12,13769,13770],{},"Il y a plusieurs raisons pour lesquelles je penche vers le contrôle du déclenchement par le serveur :",[140,13772,13773,13776,13779],{},[143,13774,13775],{},"Le serveur sera le propriétaire du pool et des sauvegardes.",[143,13777,13778],{},"Le serveur décide du cycle de vie des sauvegardes (nombre de sauvegarde, durée de vie, ...)",[143,13780,13781],{},"Le serveur peut fusionner les sauvegardes de plusieurs périphériques dans le pool, donc il doit contrôler tout ce qui\ny entre.",[12,13783,13784],{},"Je tiens à souligner que la version finale sera terminée, tous les choix ici présent peuvent avoir été remis en\nquestion. En informatique, faire et défaire, c'est avancer.",[33,13786,13788],{"id":13787},"cinematique-dappel","Cinematique d'appel",[12,13790,13791],{},"Dans cet article, nous allons examiner la cinématique d'appel entre les requêtes et comment elle peut être utilisée\npour améliorer la sauvegarde de contenu en fonction de nos besoins.",[12,13793,13794],{},"Pour sauvegarder le contenu d'un périphérique, celui-ci doit suivre les étapes suivantes :",[140,13796,13797,13811],{},[143,13798,13799,13800],{},"Parcourir l'ensemble de ses fichiers et pour chaque fichier :\n",[140,13801,13802,13805,13808],{},[143,13803,13804],{},"Récupérer les attributs du fichier, tels que le nom, la date de création, de modification, les droits, etc.",[143,13806,13807],{},"Calculer un hash pour déterminer si le fichier est modifié et quelle partie du fichier a été modifiée.",[143,13809,13810],{},"Envoyer cette liste de fichiers (manifest) au serveur de sauvegarde.",[143,13812,13813],{},"Envoyer le contenu nouveau ou modifié des fichiers, chunk par chunk, vers le serveur.",[12,13815,13816],{},"Le processus de sauvegarde peut être optimisé de la manière suivante :",[140,13818,13819,13822],{},[143,13820,13821],{},"Le périphérique peut recevoir la dernière sauvegarde qu'il a effectuée et la comparer avec ce qu'il a de son côté\npour n'envoyer que le différentiel.",[143,13823,13824],{},"Il n'est pas nécessaire de calculer le hash du fichier entier s'il n'a jamais été sauvegardé. Ce hash peut être\ncalculé lors de la récupération des données, ce qui évite de lire deux fois le fichier.",[12,13826,13827],{},"Voici la séquence utilisée pour la sauvegade:",[13646,13829,13830],{},[69,13831],{"alt":13832,"src":13833},"Sequence de sauvegarde","https:\u002F\u002Fwww.plantuml.com\u002Fplantuml\u002Fpng\u002FVT5DJiCm40NWlK_nsC6YGVnBNLH5Y1qB12SOsLCo4DkfxScPo3boCTIW_b6HJPJ5wEczpyjSA1NrZJahDNk6fy99o9XtJXqdp1Pu7VeaRRtvhfNdkAhmgANcK6Gbbeh4C75zNU4vT57W53Q6ma7X60t1SGeoV2T69ktuWv9ZdEUIcFp5L86R2Y-I2wFXZ9NOMZXbq6VKClJvqaSdAzdyPMtR97xeio5RfAF2VyACQM9iqKPDi3MjzI3H79zYDblWjzGSjxjLdE4fo8fpoI15tbnesW_Xu8nn_6-1_Svj-5s5f-XRIYGv1b37TkV5HrmdxKyu41LRa0dI-mflGs-r7VeqlkWupDOQllwtc_1vEFGPO_OW4nQZrPA3Kz_y0000",[13835,13836,13837,13840,13847,13853],"ol",{},[143,13838,13839],{},"Le serveur doit commencer par s'authentifier auprès du client pour garantir que la communication se fait en toute\nsécurité. L'authentification peut se faire via un échange de clés publique\u002Fprivée, avec la connaissance d'un mot de\npasse commun associé au device. L'objectif est que le client puisse s'assurer qu'il communique avec le bon serveur.",[143,13841,13842,13843,13846],{},"Si une sauvegarde a déjà eu lieu par le passé, le serveur peut envoyer au client le contenu de la dernière\nsauvegarde. Cette liste comprend les fichiers avec leurs attributs et leur hash. Cette étape permet au client de\nsavoir quels fichiers ont été ajoutés, supprimés ou modifiés depuis la dernière sauvegarde.",[13844,13845],"br",{},"Par rapport à rsync, le serveur n'a pas besoin de recalculer cette liste.",[143,13848,13849,13850,13852],{},"Le client parcourt les différents dossiers demandés et génère une nouvelle liste. Il peut se contenter de n'envoyer\nque les fichiers qui ont changé depuis la dernière fois.",[13844,13851],{},"Le serveur stocke cela pour préparer la nouvelle sauvegarde. Il est possible d'utiliser un système de journal pour\nécrire les modifications retournées par le client. Ces modifications ne sont persistées dans le fichier final qu'une\nfois la sauvegarde terminée.",[143,13854,13855,13856,13858],{},"Le serveur utilise la liste reçue pour demander au client de lui renvoyer les fichiers modifiés. Si le client a\ncalculé le hash des chunks (morceaux de fichier), le serveur peut ne demander que les morceaux qui ont été modifiés\net pas l'intégralité du fichier.",[13844,13857],{},"Il est important de trouver une taille idéale pour les chunks. Si la taille est trop petite, cela risque de\nmultiplier la quantité de fichiers dans le pool sans aucun bénéfice. Si elle est trop grande, cela peut bloquer le\ntransfert intégral du fichier sur le serveur.",[12,13860,13861],{},"À l'avenir, il pourrait être envisageable d'avoir différents types de chunks pour déterminer ce qui doit être\nrenvoyé dans les transferts réseaux et ceux pour le stockage du pool. Cependant, cela complexifie le stockage.",[33,13863,13865],{"id":13864},"choix-du-protocol","Choix du protocol",[12,13867,13868],{},"Pour envoyer des informations en flux continu du périphérique au serveur et vice versa (un stream pour le manifeste,\nun autre pour les fichiers, un autre pour les logs), le choix de protocole est crucial. Voici quelques options que nous\nallons considérer pour notre shortlist :",[140,13870,13871,13877,13883],{},[143,13872,13873,13876],{},[344,13874,13875],{},"REST",": Protocole simple et facilement utilisable pour transférer des fichiers via upload ou download. Pour le\nstreaming, nous pouvons également envisager l'utilisation de Websocket.",[143,13878,13879,13882],{},[344,13880,13881],{},"gRPC",": Protocole permettant d'utiliser HTTP\u002F2 pour faire des requêtes avec du streaming bidirectionnel.",[143,13884,13885,13888],{},[344,13886,13887],{},"Protocole maison à base de socket",": Maîtrise complète du flux (comme rsync par exemple).",[12,13890,13891],{},"Comme vu précédement, les protocoles basés sur HTTP, comme REST et gRPC, offrent des avantages tels que l'utilisation\nd'un protocole de haut niveau permettant de bénéficier de TLS, de la compression, de la mutualisation de la connexion,\netc.",[12,13893,13894],{},"Le protocole maison, même s'il permettrait de bonnes performances, nécessite une plus grande complexité de\ndéveloppement, mais aussi un plus grand risque de bugs ou de failles de sécurité. Il est donc écarté de notre list\npour le moment, mais nous pourrions l'envisager dans une future refonte si les performances sont vraiment mauvaises.",[12,13896,13897],{},"Pour déterminer le protocole le plus performant pour nos besoins, nous allons comparer les protocoles REST s\u002F HTTP\u002F2 et\ngRPC.",[12,13899,13900],{},"Il est important de noter qu'il est crucial de choisir le langage ou le protocole le plus adapté à notre besoin et ne\npas partir sur des \"a priori\". Souvent, on choisit un langage ou un protocole parce qu'on le connaît bien ou parce\nqu'on l'estime meilleur dans certaines situations. Mais chaque besoin étant différent, l'utilisation dans un contexte\nne signifie pas qu'un langage ou un protocole est le meilleur dans tous les contextes.",[33,13902,13904],{"id":13903},"quel-langage-choisir","Quel langage choisir",[12,13906,13907],{},"Le client de sauvegarde doit être compatible avec Windows, Linux et MacOS.",[12,13909,13910],{},"Ma première approche pour développer un logiciel performant consiste à utiliser le language C++ pour le périphérique\net la partie synchronisation et gestion du pool pour serveur, tout en gardant Node.JS pour l'orchestration.",[12,13912,13913],{},"Comme une partie du serveur est développée en Node.JS, je vais également tester les performances dans ce langage. Si\nj'obtiens des performances similaires, le développement en Node.JS pourrait être plus simple (un seul language pour\ntout et moins de complexité à gérer pour le multithreading).",[12,13915,13916],{},"Si je décide de développer en C++, j'utiliserai Qt pour l'interface graphique, car je le connais bien.",[33,13918,13920],{"id":13919},"lécriture","L'écriture",[12,13922,13923,13925,13926,13929,13930,13933,13934,13936,13937,13939],{},[344,13924,13881],{}," est un framework moderne pour la création de services distants. Il est basé sur ",[344,13927,13928],{},"HTTP\u002F2",", qui offre des\naméliorations de performances significatives par rapport à ",[344,13931,13932],{},"HTTP\u002F1.1",". Pour le protocole ",[344,13935,13875],{},", il existe des\nlibrairies permettant de créer des serveurs et clients ",[344,13938,13928],{}," en C++, mais à mon grand désarroi c'est plus difficile\nque prévu.",[140,13941,13942,13950,13958],{},[143,13943,13944,13949],{},[47,13945,13948],{"href":13946,"rel":13947},"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fcpprestsdk",[51],"cpprestsdk",": Support HTTPS mais pas HTTP\u002F2 (en 2023, il n'évoluera plus),",[143,13951,13952,13957],{},[47,13953,13956],{"href":13954,"rel":13955},"https:\u002F\u002Fnghttp2.org\u002F",[51],"nghttp2",": Librairie très bas niveau (trop bas niveau),",[143,13959,13960,13965],{},[47,13961,13964],{"href":13962,"rel":13963},"https:\u002F\u002Fnghttp2.org\u002Fdocumentation\u002Flibnghttp2_asio.html",[51],"libnghttp2_asio",": Librairie plus haut niveau, possède une\ndépendance sur boost. J'ai également l'impression que cette librairie ne permet pas de faire tout ce qu'on veut en\nHTTP\u002F2 (par exemple le streaming d'un fichier n'est pas quelque chose de facile à écrire, contrairement à l'allocation\ncomplète en mémoire de la réponse à envoyer).",[12,13967,13968,13969,13971],{},"Pour le protocole ",[344,13970,13881],{},", nous avons:",[140,13973,13974],{},[143,13975,13976,2691,13981,13983,13984,31],{},[47,13977,13980],{"href":13978,"rel":13979},"https:\u002F\u002Fgrpc.io\u002Fdocs\u002Flanguages\u002Fcpp\u002Fquickstart\u002F",[51],"grpccpp",[344,13982,13881],{}," est de basé basé sur ",[344,13985,13928],{},[12,13987,13988,13989,13992,13993,13996,13997,31],{},"Coté ",[344,13990,13991],{},"Node.JS",", j'utilise ",[344,13994,13995],{},"Nest.JS"," pour la partie serveur, je vais donc m'appuyer sur les librairies suivante pour le\nprotocol ",[344,13998,13881],{},[140,14000,14001,14008],{},[143,14002,14003],{},[47,14004,14007],{"href":14005,"rel":14006},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fgrpc",[51],"grpc",[143,14009,14010],{},[47,14011,14014],{"href":14012,"rel":14013},"https:\u002F\u002Fdocs.nestjs.com\u002Fmicroservices\u002Fgrpc",[51],"@grpc\u002Fproto-loader",[12,14016,14017,14018,14020,14021,14024],{},"L'utilisation d'",[344,14019,13928],{}," avec Axios (utilisé par Nest.JS) peut se faire en utilisant ",[344,14022,14023],{},"http2-wrapper",":",[352,14026,14030],{"className":14027,"code":14028,"language":14029,"meta":291,"style":291},"language-ts shiki shiki-themes one-dark-pro","import * as http2 from \"http2-wrapper\";\nimport { AxiosRequestConfig } from \"axios\";\n\nconst data = ProtoGetChunkRequest.encode(request).finish();\nreturn this.httpService\n  .request\u003CReadable>({\n    method: \"post\",\n    url: `https:\u002F\u002F${this.hostToBackup}:3000\u002Fget-chunk`,\n    data,\n    transport: http2,\n    responseType: \"stream\",\n  } as AxiosRequestConfig)\n  .pipe(map((response) => response.data));\n","ts",[344,14031,14032,14052,14071,14075,14104,14116,14131,14143,14172,14178,14190,14202,14214],{"__ignoreMap":291},[360,14033,14034,14037,14039,14041,14044,14047,14050],{"class":362,"line":363},[360,14035,14036],{"class":574},"import",[360,14038,920],{"class":414},[360,14040,9698],{"class":574},[360,14042,14043],{"class":578}," http2",[360,14045,14046],{"class":574}," from",[360,14048,14049],{"class":397}," \"http2-wrapper\"",[360,14051,735],{"class":366},[360,14053,14054,14056,14058,14061,14063,14066,14069],{"class":362,"line":292},[360,14055,14036],{"class":574},[360,14057,5879],{"class":366},[360,14059,14060],{"class":578},"AxiosRequestConfig",[360,14062,6108],{"class":366},[360,14064,14065],{"class":574},"from",[360,14067,14068],{"class":397}," \"axios\"",[360,14070,735],{"class":366},[360,14072,14073],{"class":362,"line":375},[360,14074,372],{"emptyLinePlaceholder":320},[360,14076,14077,14079,14082,14084,14087,14089,14092,14094,14097,14099,14102],{"class":362,"line":433},[360,14078,6053],{"class":574},[360,14080,14081],{"class":662}," data",[360,14083,401],{"class":582},[360,14085,14086],{"class":662}," ProtoGetChunkRequest",[360,14088,31],{"class":366},[360,14090,14091],{"class":381},"encode",[360,14093,671],{"class":366},[360,14095,14096],{"class":578},"request",[360,14098,2198],{"class":366},[360,14100,14101],{"class":381},"finish",[360,14103,2204],{"class":366},[360,14105,14106,14108,14111,14113],{"class":362,"line":478},[360,14107,1454],{"class":574},[360,14109,14110],{"class":662}," this",[360,14112,31],{"class":366},[360,14114,14115],{"class":578},"httpService\n",[360,14117,14118,14121,14123,14125,14128],{"class":362,"line":483},[360,14119,14120],{"class":366},"  .",[360,14122,14096],{"class":381},[360,14124,1358],{"class":366},[360,14126,14127],{"class":662},"Readable",[360,14129,14130],{"class":366},">({\n",[360,14132,14133,14136,14138,14141],{"class":362,"line":489},[360,14134,14135],{"class":578},"    method",[360,14137,2691],{"class":366},[360,14139,14140],{"class":397},"\"post\"",[360,14142,2968],{"class":366},[360,14144,14145,14148,14150,14153,14156,14159,14161,14164,14167,14170],{"class":362,"line":494},[360,14146,14147],{"class":578},"    url",[360,14149,2691],{"class":366},[360,14151,14152],{"class":397},"`https:\u002F\u002F",[360,14154,14155],{"class":574},"${",[360,14157,14158],{"class":662},"this",[360,14160,31],{"class":366},[360,14162,14163],{"class":578},"hostToBackup",[360,14165,14166],{"class":574},"}",[360,14168,14169],{"class":397},":3000\u002Fget-chunk`",[360,14171,2968],{"class":366},[360,14173,14174,14176],{"class":362,"line":712},[360,14175,8091],{"class":578},[360,14177,2968],{"class":366},[360,14179,14180,14183,14185,14188],{"class":362,"line":331},[360,14181,14182],{"class":578},"    transport",[360,14184,2691],{"class":366},[360,14186,14187],{"class":578},"http2",[360,14189,2968],{"class":366},[360,14191,14192,14195,14197,14200],{"class":362,"line":762},[360,14193,14194],{"class":578},"    responseType",[360,14196,2691],{"class":366},[360,14198,14199],{"class":397},"\"stream\"",[360,14201,2968],{"class":366},[360,14203,14204,14207,14209,14212],{"class":362,"line":781},[360,14205,14206],{"class":366},"  } ",[360,14208,4505],{"class":574},[360,14210,14211],{"class":662}," AxiosRequestConfig",[360,14213,2922],{"class":366},[360,14215,14216,14218,14221,14223,14225,14227,14230,14232,14234,14237,14239,14241],{"class":362,"line":804},[360,14217,14120],{"class":366},[360,14219,14220],{"class":381},"pipe",[360,14222,671],{"class":366},[360,14224,4907],{"class":381},[360,14226,7148],{"class":366},[360,14228,14229],{"class":677},"response",[360,14231,3972],{"class":366},[360,14233,6331],{"class":574},[360,14235,14236],{"class":662}," response",[360,14238,31],{"class":366},[360,14240,8423],{"class":578},[360,14242,4081],{"class":366},[12,14244,14245,14246,14249],{},"Nous allons écrire un fichier de description ",[344,14247,14248],{},"protobuf"," (qui pourra être le même entre la version C++ et Node.JS). Le\nfichier va décrire chaque élément du fichier manifest, ainsi que les appels RPC entre le périphérique et le serveur.",[352,14251,14254],{"className":14252,"code":14253,"language":14248,"meta":291,"style":291},"language-protobuf shiki shiki-themes one-dark-pro","syntax = \"proto3\";\n\npackage woodstock;\n\nenum StatusCode {\n  Ok = 0;\n  Failed = 1;\n}\n\nmessage FileManifest {\n  message FileManifestStat {\n    int32 ownerId = 1;\n    int32 groupId = 2;\n    int64 size = 3;\n    int64 lastRead = 4;\n    int64 lastModified = 5;\n    int64 created = 6;\n    int32 mode = 7;\n  }\n\n  bytes path = 1;\n  FileManifestStat stats = 2;\n  repeated bytes chunks = 3;\n  bytes sha256 = 4;\n}\n\nmessage FileManifestJournalEntry {\n  enum EntryType {\n    ADD = 0;\n    MODIFY = 1;\n    REMOVE = 2;\n  }\n\n  oneof entry {\n    FileManifest manifest = 1;\n    bytes path = 2;\n  }\n  EntryType type = 3;\n}\n\nmessage BackupConfiguration {\n    message Share {\n        string name = 1;\n        repeated string includes = 2;\n        repeated string excludes = 3;\n        string pathPrefix = 4;\n    }\n\n    message Task {\n        string command = 1;\n        repeated Share shares = 2;\n        repeated string includes = 3;\n        repeated string excludes = 4;\n    }\n\n    message Operations {\n        repeated Task tasks = 1;\n        repeated Task finalizedTasks = 2;\n    }\n\n    Operations operations = 1;\n}\n\nmessage FileChunk {\n  bytes data = 1;\n}\n\nmessage PrepareBackupRequest {\n  BackupConfiguration configuration = 1;\n  uint32 lastBackupNumber = 2;\n  uint32 newBackupNumber = 3;\n}\n\nmessage PrepareBackupReply {\n  StatusCode code = 1;\n  bool needRefreshCache = 2;\n}\n\nmessage RefreshCacheReply {\n  StatusCode code = 1;\n}\n\nmessage LaunchBackupRequest {\n  uint32 backupNumber = 1;\n}\n\nmessage GetChunkRequest {\n  bytes filename = 1;\n  uint64 position = 2;\n  uint64 size = 3;\n  bytes sha256 = 4;\n}\n\nservice WoodstockpériphériqueService {\n  rpc PrepareBackup(PrepareBackupRequest) returns (PrepareBackupReply) {}\n\n  rpc RefreshCache(stream FileManifest) returns (RefreshCacheReply) {}\n\n  rpc LaunchBackup(LaunchBackupRequest) returns (stream FileManifestJournalEntry) {}\n\n  rpc GetChunk(GetChunkRequest) returns (stream FileChunk) {}\n}\n",[344,14255,14256,14268,14272,14282,14286,14296,14307,14318,14322,14326,14336,14346,14360,14373,14387,14400,14414,14428,14441,14445,14449,14462,14475,14492,14504,14508,14512,14521,14531,14542,14553,14564,14568,14572,14582,14596,14609,14613,14627,14631,14635,14644,14654,14668,14685,14700,14713,14717,14721,14730,14743,14757,14771,14785,14789,14793,14802,14817,14832,14836,14840,14854,14858,14862,14871,14883,14887,14891,14900,14914,14928,14941,14945,14949,14958,14972,14986,14990,14994,15003,15015,15019,15023,15032,15045,15049,15053,15062,15075,15089,15101,15113,15117,15121,15132,15157,15161,15185,15189,15213,15217,15241],{"__ignoreMap":291},[360,14257,14258,14261,14263,14266],{"class":362,"line":363},[360,14259,14260],{"class":574},"syntax",[360,14262,401],{"class":582},[360,14264,14265],{"class":397}," \"proto3\"",[360,14267,735],{"class":366},[360,14269,14270],{"class":362,"line":292},[360,14271,372],{"emptyLinePlaceholder":320},[360,14273,14274,14277,14280],{"class":362,"line":375},[360,14275,14276],{"class":574},"package",[360,14278,14279],{"class":397}," woodstock",[360,14281,735],{"class":366},[360,14283,14284],{"class":362,"line":433},[360,14285,372],{"emptyLinePlaceholder":320},[360,14287,14288,14291,14294],{"class":362,"line":478},[360,14289,14290],{"class":574},"enum",[360,14292,14293],{"class":662}," StatusCode",[360,14295,896],{"class":366},[360,14297,14298,14301,14303,14305],{"class":362,"line":483},[360,14299,14300],{"class":578},"  Ok",[360,14302,401],{"class":582},[360,14304,1457],{"class":414},[360,14306,735],{"class":366},[360,14308,14309,14312,14314,14316],{"class":362,"line":489},[360,14310,14311],{"class":578},"  Failed",[360,14313,401],{"class":582},[360,14315,1099],{"class":414},[360,14317,735],{"class":366},[360,14319,14320],{"class":362,"line":494},[360,14321,847],{"class":366},[360,14323,14324],{"class":362,"line":712},[360,14325,372],{"emptyLinePlaceholder":320},[360,14327,14328,14331,14334],{"class":362,"line":331},[360,14329,14330],{"class":574},"message",[360,14332,14333],{"class":662}," FileManifest",[360,14335,896],{"class":366},[360,14337,14338,14341,14344],{"class":362,"line":762},[360,14339,14340],{"class":574},"  message",[360,14342,14343],{"class":662}," FileManifestStat",[360,14345,896],{"class":366},[360,14347,14348,14351,14354,14356,14358],{"class":362,"line":781},[360,14349,14350],{"class":574},"    int32",[360,14352,14353],{"class":578}," ownerId",[360,14355,401],{"class":582},[360,14357,1099],{"class":414},[360,14359,735],{"class":366},[360,14361,14362,14364,14367,14369,14371],{"class":362,"line":804},[360,14363,14350],{"class":574},[360,14365,14366],{"class":578}," groupId",[360,14368,401],{"class":582},[360,14370,732],{"class":414},[360,14372,735],{"class":366},[360,14374,14375,14378,14380,14382,14385],{"class":362,"line":817},[360,14376,14377],{"class":574},"    int64",[360,14379,6192],{"class":578},[360,14381,401],{"class":582},[360,14383,14384],{"class":414}," 3",[360,14386,735],{"class":366},[360,14388,14389,14391,14394,14396,14398],{"class":362,"line":823},[360,14390,14377],{"class":574},[360,14392,14393],{"class":578}," lastRead",[360,14395,401],{"class":582},[360,14397,1143],{"class":414},[360,14399,735],{"class":366},[360,14401,14402,14404,14407,14409,14412],{"class":362,"line":844},[360,14403,14377],{"class":574},[360,14405,14406],{"class":578}," lastModified",[360,14408,401],{"class":582},[360,14410,14411],{"class":414}," 5",[360,14413,735],{"class":366},[360,14415,14416,14418,14421,14423,14426],{"class":362,"line":1441},[360,14417,14377],{"class":574},[360,14419,14420],{"class":578}," created",[360,14422,401],{"class":582},[360,14424,14425],{"class":414}," 6",[360,14427,735],{"class":366},[360,14429,14430,14432,14435,14437,14439],{"class":362,"line":1462},[360,14431,14350],{"class":574},[360,14433,14434],{"class":578}," mode",[360,14436,401],{"class":582},[360,14438,4671],{"class":414},[360,14440,735],{"class":366},[360,14442,14443],{"class":362,"line":1485},[360,14444,820],{"class":366},[360,14446,14447],{"class":362,"line":1497},[360,14448,372],{"emptyLinePlaceholder":320},[360,14450,14451,14454,14456,14458,14460],{"class":362,"line":3161},[360,14452,14453],{"class":574},"  bytes",[360,14455,4847],{"class":578},[360,14457,401],{"class":582},[360,14459,1099],{"class":414},[360,14461,735],{"class":366},[360,14463,14464,14467,14469,14471,14473],{"class":362,"line":3167},[360,14465,14466],{"class":574},"  FileManifestStat",[360,14468,7356],{"class":578},[360,14470,401],{"class":582},[360,14472,732],{"class":414},[360,14474,735],{"class":366},[360,14476,14477,14480,14483,14486,14488,14490],{"class":362,"line":3194},[360,14478,14479],{"class":574},"  repeated",[360,14481,14482],{"class":574}," bytes",[360,14484,14485],{"class":578}," chunks",[360,14487,401],{"class":582},[360,14489,14384],{"class":414},[360,14491,735],{"class":366},[360,14493,14494,14496,14498,14500,14502],{"class":362,"line":3224},[360,14495,14453],{"class":574},[360,14497,8414],{"class":578},[360,14499,401],{"class":582},[360,14501,1143],{"class":414},[360,14503,735],{"class":366},[360,14505,14506],{"class":362,"line":3239},[360,14507,847],{"class":366},[360,14509,14510],{"class":362,"line":3256},[360,14511,372],{"emptyLinePlaceholder":320},[360,14513,14514,14516,14519],{"class":362,"line":3276},[360,14515,14330],{"class":574},[360,14517,14518],{"class":662}," FileManifestJournalEntry",[360,14520,896],{"class":366},[360,14522,14523,14526,14529],{"class":362,"line":3281},[360,14524,14525],{"class":574},"  enum",[360,14527,14528],{"class":662}," EntryType",[360,14530,896],{"class":366},[360,14532,14533,14536,14538,14540],{"class":362,"line":3305},[360,14534,14535],{"class":578},"    ADD",[360,14537,401],{"class":582},[360,14539,1457],{"class":414},[360,14541,735],{"class":366},[360,14543,14544,14547,14549,14551],{"class":362,"line":3320},[360,14545,14546],{"class":578},"    MODIFY",[360,14548,401],{"class":582},[360,14550,1099],{"class":414},[360,14552,735],{"class":366},[360,14554,14555,14558,14560,14562],{"class":362,"line":3325},[360,14556,14557],{"class":578},"    REMOVE",[360,14559,401],{"class":582},[360,14561,732],{"class":414},[360,14563,735],{"class":366},[360,14565,14566],{"class":362,"line":3361},[360,14567,820],{"class":366},[360,14569,14570],{"class":362,"line":3380},[360,14571,372],{"emptyLinePlaceholder":320},[360,14573,14574,14577,14580],{"class":362,"line":3405},[360,14575,14576],{"class":574},"  oneof",[360,14578,14579],{"class":578}," entry",[360,14581,896],{"class":366},[360,14583,14584,14587,14590,14592,14594],{"class":362,"line":3411},[360,14585,14586],{"class":574},"    FileManifest",[360,14588,14589],{"class":578}," manifest",[360,14591,401],{"class":582},[360,14593,1099],{"class":414},[360,14595,735],{"class":366},[360,14597,14598,14601,14603,14605,14607],{"class":362,"line":3426},[360,14599,14600],{"class":574},"    bytes",[360,14602,4847],{"class":578},[360,14604,401],{"class":582},[360,14606,732],{"class":414},[360,14608,735],{"class":366},[360,14610,14611],{"class":362,"line":3432},[360,14612,820],{"class":366},[360,14614,14615,14618,14621,14623,14625],{"class":362,"line":3438},[360,14616,14617],{"class":574},"  EntryType",[360,14619,14620],{"class":578}," type",[360,14622,401],{"class":582},[360,14624,14384],{"class":414},[360,14626,735],{"class":366},[360,14628,14629],{"class":362,"line":3443},[360,14630,847],{"class":366},[360,14632,14633],{"class":362,"line":3462},[360,14634,372],{"emptyLinePlaceholder":320},[360,14636,14637,14639,14642],{"class":362,"line":3467},[360,14638,14330],{"class":574},[360,14640,14641],{"class":662}," BackupConfiguration",[360,14643,896],{"class":366},[360,14645,14646,14649,14652],{"class":362,"line":3472},[360,14647,14648],{"class":574},"    message",[360,14650,14651],{"class":662}," Share",[360,14653,896],{"class":366},[360,14655,14656,14659,14662,14664,14666],{"class":362,"line":3495},[360,14657,14658],{"class":574},"        string",[360,14660,14661],{"class":578}," name",[360,14663,401],{"class":582},[360,14665,1099],{"class":414},[360,14667,735],{"class":366},[360,14669,14670,14673,14676,14679,14681,14683],{"class":362,"line":3500},[360,14671,14672],{"class":574},"        repeated",[360,14674,14675],{"class":574}," string",[360,14677,14678],{"class":578}," includes",[360,14680,401],{"class":582},[360,14682,732],{"class":414},[360,14684,735],{"class":366},[360,14686,14687,14689,14691,14694,14696,14698],{"class":362,"line":3505},[360,14688,14672],{"class":574},[360,14690,14675],{"class":574},[360,14692,14693],{"class":578}," excludes",[360,14695,401],{"class":582},[360,14697,14384],{"class":414},[360,14699,735],{"class":366},[360,14701,14702,14704,14707,14709,14711],{"class":362,"line":3530},[360,14703,14658],{"class":574},[360,14705,14706],{"class":578}," pathPrefix",[360,14708,401],{"class":582},[360,14710,1143],{"class":414},[360,14712,735],{"class":366},[360,14714,14715],{"class":362,"line":3545},[360,14716,2927],{"class":366},[360,14718,14719],{"class":362,"line":3558},[360,14720,372],{"emptyLinePlaceholder":320},[360,14722,14723,14725,14728],{"class":362,"line":3573},[360,14724,14648],{"class":574},[360,14726,14727],{"class":662}," Task",[360,14729,896],{"class":366},[360,14731,14732,14734,14737,14739,14741],{"class":362,"line":3578},[360,14733,14658],{"class":574},[360,14735,14736],{"class":578}," command",[360,14738,401],{"class":582},[360,14740,1099],{"class":414},[360,14742,735],{"class":366},[360,14744,14745,14747,14749,14751,14753,14755],{"class":362,"line":3583},[360,14746,14672],{"class":574},[360,14748,14651],{"class":574},[360,14750,5340],{"class":578},[360,14752,401],{"class":582},[360,14754,732],{"class":414},[360,14756,735],{"class":366},[360,14758,14759,14761,14763,14765,14767,14769],{"class":362,"line":6893},[360,14760,14672],{"class":574},[360,14762,14675],{"class":574},[360,14764,14678],{"class":578},[360,14766,401],{"class":582},[360,14768,14384],{"class":414},[360,14770,735],{"class":366},[360,14772,14773,14775,14777,14779,14781,14783],{"class":362,"line":6899},[360,14774,14672],{"class":574},[360,14776,14675],{"class":574},[360,14778,14693],{"class":578},[360,14780,401],{"class":582},[360,14782,1143],{"class":414},[360,14784,735],{"class":366},[360,14786,14787],{"class":362,"line":6905},[360,14788,2927],{"class":366},[360,14790,14791],{"class":362,"line":6920},[360,14792,372],{"emptyLinePlaceholder":320},[360,14794,14795,14797,14800],{"class":362,"line":6942},[360,14796,14648],{"class":574},[360,14798,14799],{"class":662}," Operations",[360,14801,896],{"class":366},[360,14803,14804,14806,14808,14811,14813,14815],{"class":362,"line":6974},[360,14805,14672],{"class":574},[360,14807,14727],{"class":574},[360,14809,14810],{"class":578}," tasks",[360,14812,401],{"class":582},[360,14814,1099],{"class":414},[360,14816,735],{"class":366},[360,14818,14819,14821,14823,14826,14828,14830],{"class":362,"line":6992},[360,14820,14672],{"class":574},[360,14822,14727],{"class":574},[360,14824,14825],{"class":578}," finalizedTasks",[360,14827,401],{"class":582},[360,14829,732],{"class":414},[360,14831,735],{"class":366},[360,14833,14834],{"class":362,"line":6997},[360,14835,2927],{"class":366},[360,14837,14838],{"class":362,"line":7002},[360,14839,372],{"emptyLinePlaceholder":320},[360,14841,14842,14845,14848,14850,14852],{"class":362,"line":7008},[360,14843,14844],{"class":574},"    Operations",[360,14846,14847],{"class":578}," operations",[360,14849,401],{"class":582},[360,14851,1099],{"class":414},[360,14853,735],{"class":366},[360,14855,14856],{"class":362,"line":7041},[360,14857,847],{"class":366},[360,14859,14860],{"class":362,"line":7047},[360,14861,372],{"emptyLinePlaceholder":320},[360,14863,14864,14866,14869],{"class":362,"line":7058},[360,14865,14330],{"class":574},[360,14867,14868],{"class":662}," FileChunk",[360,14870,896],{"class":366},[360,14872,14873,14875,14877,14879,14881],{"class":362,"line":7064},[360,14874,14453],{"class":574},[360,14876,14081],{"class":578},[360,14878,401],{"class":582},[360,14880,1099],{"class":414},[360,14882,735],{"class":366},[360,14884,14885],{"class":362,"line":7086},[360,14886,847],{"class":366},[360,14888,14889],{"class":362,"line":7091},[360,14890,372],{"emptyLinePlaceholder":320},[360,14892,14893,14895,14898],{"class":362,"line":7126},[360,14894,14330],{"class":574},[360,14896,14897],{"class":662}," PrepareBackupRequest",[360,14899,896],{"class":366},[360,14901,14902,14905,14908,14910,14912],{"class":362,"line":7165},[360,14903,14904],{"class":574},"  BackupConfiguration",[360,14906,14907],{"class":578}," configuration",[360,14909,401],{"class":582},[360,14911,1099],{"class":414},[360,14913,735],{"class":366},[360,14915,14916,14919,14922,14924,14926],{"class":362,"line":7170},[360,14917,14918],{"class":574},"  uint32",[360,14920,14921],{"class":578}," lastBackupNumber",[360,14923,401],{"class":582},[360,14925,732],{"class":414},[360,14927,735],{"class":366},[360,14929,14930,14932,14935,14937,14939],{"class":362,"line":7176},[360,14931,14918],{"class":574},[360,14933,14934],{"class":578}," newBackupNumber",[360,14936,401],{"class":582},[360,14938,14384],{"class":414},[360,14940,735],{"class":366},[360,14942,14943],{"class":362,"line":7182},[360,14944,847],{"class":366},[360,14946,14947],{"class":362,"line":7200},[360,14948,372],{"emptyLinePlaceholder":320},[360,14950,14951,14953,14956],{"class":362,"line":7205},[360,14952,14330],{"class":574},[360,14954,14955],{"class":662}," PrepareBackupReply",[360,14957,896],{"class":366},[360,14959,14960,14963,14966,14968,14970],{"class":362,"line":7211},[360,14961,14962],{"class":574},"  StatusCode",[360,14964,14965],{"class":578}," code",[360,14967,401],{"class":582},[360,14969,1099],{"class":414},[360,14971,735],{"class":366},[360,14973,14974,14977,14980,14982,14984],{"class":362,"line":7219},[360,14975,14976],{"class":574},"  bool",[360,14978,14979],{"class":578}," needRefreshCache",[360,14981,401],{"class":582},[360,14983,732],{"class":414},[360,14985,735],{"class":366},[360,14987,14988],{"class":362,"line":7237},[360,14989,847],{"class":366},[360,14991,14992],{"class":362,"line":7252},[360,14993,372],{"emptyLinePlaceholder":320},[360,14995,14996,14998,15001],{"class":362,"line":7257},[360,14997,14330],{"class":574},[360,14999,15000],{"class":662}," RefreshCacheReply",[360,15002,896],{"class":366},[360,15004,15005,15007,15009,15011,15013],{"class":362,"line":7280},[360,15006,14962],{"class":574},[360,15008,14965],{"class":578},[360,15010,401],{"class":582},[360,15012,1099],{"class":414},[360,15014,735],{"class":366},[360,15016,15017],{"class":362,"line":7285},[360,15018,847],{"class":366},[360,15020,15021],{"class":362,"line":7291},[360,15022,372],{"emptyLinePlaceholder":320},[360,15024,15025,15027,15030],{"class":362,"line":7314},[360,15026,14330],{"class":574},[360,15028,15029],{"class":662}," LaunchBackupRequest",[360,15031,896],{"class":366},[360,15033,15034,15036,15039,15041,15043],{"class":362,"line":7345},[360,15035,14918],{"class":574},[360,15037,15038],{"class":578}," backupNumber",[360,15040,401],{"class":582},[360,15042,1099],{"class":414},[360,15044,735],{"class":366},[360,15046,15047],{"class":362,"line":7351},[360,15048,847],{"class":366},[360,15050,15051],{"class":362,"line":7374},[360,15052,372],{"emptyLinePlaceholder":320},[360,15054,15055,15057,15060],{"class":362,"line":7407},[360,15056,14330],{"class":574},[360,15058,15059],{"class":662}," GetChunkRequest",[360,15061,896],{"class":366},[360,15063,15064,15066,15069,15071,15073],{"class":362,"line":7418},[360,15065,14453],{"class":574},[360,15067,15068],{"class":578}," filename",[360,15070,401],{"class":582},[360,15072,1099],{"class":414},[360,15074,735],{"class":366},[360,15076,15077,15080,15083,15085,15087],{"class":362,"line":7426},[360,15078,15079],{"class":574},"  uint64",[360,15081,15082],{"class":578}," position",[360,15084,401],{"class":582},[360,15086,732],{"class":414},[360,15088,735],{"class":366},[360,15090,15091,15093,15095,15097,15099],{"class":362,"line":7451},[360,15092,15079],{"class":574},[360,15094,6192],{"class":578},[360,15096,401],{"class":582},[360,15098,14384],{"class":414},[360,15100,735],{"class":366},[360,15102,15103,15105,15107,15109,15111],{"class":362,"line":7457},[360,15104,14453],{"class":574},[360,15106,8414],{"class":578},[360,15108,401],{"class":582},[360,15110,1143],{"class":414},[360,15112,735],{"class":366},[360,15114,15115],{"class":362,"line":7462},[360,15116,847],{"class":366},[360,15118,15119],{"class":362,"line":7467},[360,15120,372],{"emptyLinePlaceholder":320},[360,15122,15123,15126,15129],{"class":362,"line":7485},[360,15124,15125],{"class":574},"service",[360,15127,15128],{"class":662}," Woodstockp",[360,15130,15131],{"class":366},"ériphériqueService {\n",[360,15133,15134,15137,15140,15142,15145,15147,15150,15152,15155],{"class":362,"line":7507},[360,15135,15136],{"class":574},"  rpc",[360,15138,15139],{"class":381}," PrepareBackup",[360,15141,671],{"class":366},[360,15143,15144],{"class":662},"PrepareBackupRequest",[360,15146,3972],{"class":366},[360,15148,15149],{"class":574},"returns",[360,15151,743],{"class":366},[360,15153,15154],{"class":662},"PrepareBackupReply",[360,15156,7249],{"class":366},[360,15158,15159],{"class":362,"line":7512},[360,15160,372],{"emptyLinePlaceholder":320},[360,15162,15163,15165,15168,15170,15172,15174,15176,15178,15180,15183],{"class":362,"line":9051},[360,15164,15136],{"class":574},[360,15166,15167],{"class":381}," RefreshCache",[360,15169,671],{"class":366},[360,15171,7294],{"class":574},[360,15173,14333],{"class":662},[360,15175,3972],{"class":366},[360,15177,15149],{"class":574},[360,15179,743],{"class":366},[360,15181,15182],{"class":662},"RefreshCacheReply",[360,15184,7249],{"class":366},[360,15186,15187],{"class":362,"line":9056},[360,15188,372],{"emptyLinePlaceholder":320},[360,15190,15191,15193,15196,15198,15201,15203,15205,15207,15209,15211],{"class":362,"line":9082},[360,15192,15136],{"class":574},[360,15194,15195],{"class":381}," LaunchBackup",[360,15197,671],{"class":366},[360,15199,15200],{"class":662},"LaunchBackupRequest",[360,15202,3972],{"class":366},[360,15204,15149],{"class":574},[360,15206,743],{"class":366},[360,15208,7294],{"class":574},[360,15210,14518],{"class":662},[360,15212,7249],{"class":366},[360,15214,15215],{"class":362,"line":9103},[360,15216,372],{"emptyLinePlaceholder":320},[360,15218,15219,15221,15224,15226,15229,15231,15233,15235,15237,15239],{"class":362,"line":9112},[360,15220,15136],{"class":574},[360,15222,15223],{"class":381}," GetChunk",[360,15225,671],{"class":366},[360,15227,15228],{"class":662},"GetChunkRequest",[360,15230,3972],{"class":366},[360,15232,15149],{"class":574},[360,15234,743],{"class":366},[360,15236,7294],{"class":574},[360,15238,14868],{"class":662},[360,15240,7249],{"class":366},[360,15242,15243],{"class":362,"line":9121},[360,15244,847],{"class":366},[12,15246,15247,15248,15252],{},"Vient ensuite l'écriture de la partie périphérique et de la partie serveur. Je me base sur le\n",[47,15249,15251],{"href":13978,"rel":15250},[51],"Quick Start"," pour la partie C++.",[12,15254,15255,15256,15261],{},"L'exemple se veut simple, et surtout utilise l'API synchrone. gRPC propose également une\n",[47,15257,15260],{"href":15258,"rel":15259},"https:\u002F\u002Fgrpc.io\u002Fdocs\u002Flanguages\u002Fcpp\u002Fasync\u002F",[51],"API asynchrone"," mais qui est plus complexe à mettre en place.",[12,15263,15264],{},"L'API asynchrone devrait permettre d'améliorer les performances dans le cadre d'application multi-threadé. Pour notre\ncas de test nous allons commencer par utiliser l'API synchrone.",[12,15266,15267,15268,15272,15273,31],{},"Dans le cas de l'API synchrone, le serveur reste multi-threadé (et peut donc aussi recevoir plusieurs requêtes en même\ntemps). Vous trouverez les sources de la partie périphérique et de la partie serveur dans le ",[47,15269,15271],{"href":15270},"\u002FWoodstock\u002Fwoodstock-backup-feature_storage-db.zip","ZIP suivant"," dans le dossier ",[344,15274,15275],{},"périphérique-sync",[12,15277,15278,15279,15281],{},"Le développement de la partie ",[344,15280,13928],{}," vient ensuite. La librairie n'est pas des plus faciles d'utilisation, je me\nconcentre sur le développement à des fins de tests de perfs et non de sécurité (ou de non bug).",[33,15283,15285],{"id":15284},"benchmark","Benchmark",[12,15287,15288,15289,15291,15292,15297],{},"Un bench d'envoi de fichier via ",[344,15290,13881],{}," a déjà été fait par d'autres personnes. L'article se trouve ici :\n",[47,15293,15296],{"href":15294,"rel":15295},"https:\u002F\u002Fops.tips\u002Fblog\u002Fsending-files-via-grpc\u002F",[51],"Sending files via gRPC",". Je vous laisse le lire.\nCet article a été fait en Go. Je suppose que le résultat devrait être très proche d'un résultat en C++.",[12,15299,15300,15301,15303,15304,15306],{},"Le résultat de cet article est que du pur ",[344,15302,13928],{}," en Go est tout de même plus performant que ",[344,15305,13881],{}," (probablement du\nà la sérialisation et à la déserialisation des messages qui prend un peu plus de temps).",[12,15308,15309],{},"Pour réaliser les tests, nous avons utilisé le scénario suivant :",[140,15311,15312,15315,15318,15321,15324],{},[143,15313,15314],{},"Sauvegarde d'environ 46 Go de données à partir d'un périphérique équipé d'un SSD ;",[143,15316,15317],{},"Le PC de destination est équipé d'un disque dur connecté en USB 3 ;",[143,15319,15320],{},"Les machines sont reliées par un tuyau de 1 Gb\u002Fs ;",[143,15322,15323],{},"Les chunks sont stockés au format du pool défini dans l'article\n[\u002Fpost\u002Fwoodstock_brtfs](Utilisation de Btrfs et son remplacement) ceci afin de representer au mieux notre cas\nd'utilisation.",[143,15325,15326],{},"Le hash est un SHA3_256, qui est plus performant qu'un SHA2_256.",[12,15328,15329],{},"Les tests ont été réalisés dans des conditions relativement réelles (calcul des hash, copie des fichiers dans un pool\nqui fait de la déduplication), ce qui prend en compte le transfert des fichiers mais aussi les calculs effectués autour.",[12,15331,15332],{},"Une fois le développement effectué, pour compiler la version compatible gRPC, il suffit de lancer la commande suivante :",[352,15334,15336],{"className":565,"code":15335,"language":567,"meta":291,"style":291},"cd périphérique-sync\nmkdir build\ncd build\ncmake -DWITH_PROTOCOL_HTTP2=OFF -DWITH_PROTOCOL_GRPC=ON -DCMAKE_BUILD_TYPE=Release ..\u002F\nmake -j16\n\n# Lancement du périphérique\n.\u002Fsrc\u002Fpériphérique_daemon\u002Fpériphérique\n\n# Lancement du serveur\n.\u002Fsrc\u002Fserver\u002Fserver\n",[344,15337,15338,15346,15354,15360,15377,15385,15389,15394,15399,15403,15408],{"__ignoreMap":291},[360,15339,15340,15343],{"class":362,"line":363},[360,15341,15342],{"class":582},"cd",[360,15344,15345],{"class":397}," périphérique-sync\n",[360,15347,15348,15351],{"class":362,"line":292},[360,15349,15350],{"class":381},"mkdir",[360,15352,15353],{"class":397}," build\n",[360,15355,15356,15358],{"class":362,"line":375},[360,15357,15342],{"class":582},[360,15359,15353],{"class":397},[360,15361,15362,15365,15368,15371,15374],{"class":362,"line":433},[360,15363,15364],{"class":381},"cmake",[360,15366,15367],{"class":414}," -DWITH_PROTOCOL_HTTP2=OFF",[360,15369,15370],{"class":414}," -DWITH_PROTOCOL_GRPC=ON",[360,15372,15373],{"class":414}," -DCMAKE_BUILD_TYPE=Release",[360,15375,15376],{"class":397}," ..\u002F\n",[360,15378,15379,15382],{"class":362,"line":478},[360,15380,15381],{"class":381},"make",[360,15383,15384],{"class":414}," -j16\n",[360,15386,15387],{"class":362,"line":483},[360,15388,372],{"emptyLinePlaceholder":320},[360,15390,15391],{"class":362,"line":489},[360,15392,15393],{"class":644},"# Lancement du périphérique\n",[360,15395,15396],{"class":362,"line":494},[360,15397,15398],{"class":381},".\u002Fsrc\u002Fpériphérique_daemon\u002Fpériphérique\n",[360,15400,15401],{"class":362,"line":712},[360,15402,372],{"emptyLinePlaceholder":320},[360,15404,15405],{"class":362,"line":331},[360,15406,15407],{"class":644},"# Lancement du serveur\n",[360,15409,15410],{"class":362,"line":762},[360,15411,15412],{"class":381},".\u002Fsrc\u002Fserver\u002Fserver\n",[12,15414,15415],{},"Pour la partie HTTP\u002F2, il faudra inverser les valeurs ON et OFF. Il est important de noter que la configuration du\nserveur est actuellement en dur et liée à la sauvegarde de l'ordinateur. Par conséquent, si vous souhaiter lancer\nle bench chez vous, cette configuration doit être modifiée pour adapter le serveur à votre propre configuration.",[12,15417,15418],{},"Une fois les tests effectués, j'ai réécris uniquement la partie serveur en NodeJS. La réécriture en Node.JS a été plus\nrapide que le développement en C++, car je savais exactement où nous allions et que le Javascript est plus simple à\nécrire (quand on utilise des frameworks comme RxJs, ...).",[12,15420,15421],{},"Voici le résultat du benchmark:",[1545,15423,15424,15439],{},[1548,15425,15426],{},[1551,15427,15428,15431,15435,15437],{},[1554,15429],{"align":15430},"left",[1554,15432,15434],{"align":15433},"right","rSync",[1554,15436,13881],{"align":15433},[1554,15438,13928],{"align":15433},[1567,15440,15441,15455,15468],{},[1551,15442,15443,15446,15449,15452],{},[1572,15444,15445],{"align":15430},"Server C++ \u002F Périphérique C++",[1572,15447,15448],{"align":15433},"47m",[1572,15450,15451],{"align":15433},"3h01",[1572,15453,15454],{"align":15433},"2h25",[1551,15456,15457,15460,15462,15465],{},[1572,15458,15459],{"align":15430},"Server Node.JS \u002F Périphérique C++ (concatMap)",[1572,15461],{"align":15433},[1572,15463,15464],{"align":15433},"4h57",[1572,15466,15467],{"align":15433},"1h50",[1551,15469,15470,15473,15475,15478],{},[1572,15471,15472],{"align":15430},"Server Node.JS \u002F Périphérique C++ (mergeMap)",[1572,15474],{"align":15433},[1572,15476,15477],{"align":15433},"60m",[1572,15479],{"align":15433},[12,15481,15482,15483,15485,15486,15488,15489,15491],{},"Je n'ai pas testé tous les cas de figure, j'ai principalement fait varier la partie serveur. Et je me suis concentré sur\n",[344,15484,13881],{}," car je voulais comprendre pourquoi ",[344,15487,13928],{}," était beaucoup plus rapide que ",[344,15490,13881],{}," en Node.JS.",[12,15493,15494],{},"Ce que le l'on peut remarquer:",[140,15496,15497,15511,15519,15522],{},[143,15498,15499,15500],{},"En C++ pure:\n",[140,15501,15502,15505,15508],{},[143,15503,15504],{},"rsync est le plus rapide",[143,15506,15507],{},"HTTP\u002F2 est légèrement plus rapide que gRPC",[143,15509,15510],{},"La lenteur est problablement due au fait qu'on soit monothreadé",[143,15512,15513,15514],{},"Sur une écriture monothreadé coté serveur:\n",[140,15515,15516],{},[143,15517,15518],{},"C++ est plus rapide que Node.JS pour gRPC mais pas pour HTTP\u002F2",[143,15520,15521],{},"La parallélisation avec NodeJS est beaucoup plus simple qu'en C++ : il est important de noter que l'amélioration\nvisible en NodeJS vient du fait qu'à partir du moment où l'on ne fait que des I\u002FO en asynchrone, le thread JavaScript\neffectue peu de traitement, ce qui permet d'avoir des traitements asynchrones multi-threadés.",[143,15523,15524],{},"Le transfert est nettement plus lent que rSync (même en HTTP\u002F2)",[12,15526,15527],{},"La grande question est donc : dans quel langage doit-on écrire le périphérique et le serveur au vu de ces résultats ?\nL'écriture en C++ sera plus performante avec l'utilisation de threads. Cependant, le code en C++ sera plus complexe\n(surtout avec le multi-threading) et plus long à écrire, avec des risques de fuites mémoires et de segmentation fault.",[12,15529,15530],{},"L'écriture en JavaScript sera moins performante, mais la parallélisation sera plus facile, et le risque de fuite sera\nmoins élevé. J'ai par contre peur que la consommation mémoire des objets JavaScript soit plus importante que celle des\nobjets en C++.",[123,15532,15533],{},[12,15534,15535],{},"Note de 2023: Le constat de la consommation mémoire des objets en Node.JS par rapport à C++ est vérifier. Je ferai un\narticle dédié sur le sujet.",[33,15537,15539],{"id":15538},"amélioration-possible-du-bench","Amélioration possible du bench",[140,15541,15542,15552,15560],{},[143,15543,15544,15545,15548,15549,15551],{},"Coté C++: J'ai testé ",[344,15546,15547],{},"RxCpp"," pour ajouter plus d'asynchronisme et traiter les objets en mode flux. Malheureusement,\ncontrairement à Node.JS, la librairie ",[344,15550,15547],{}," est mono-threadé. Du coup cela ne change rien. L'utilisation de RxCpp\nfait aussi des noeuds au cerveau à cause de l'utilisation des templates.",[143,15553,15554,15555,15559],{},"Coté C++: utiliser l'",[47,15556,15558],{"href":15258,"rel":15557},[51],"API Asynchrone"," de gRPC pourrait améliorer les choses.",[143,15561,15562],{},"Coté Node.JS: Il est possible d'améliorer les performances avec des bindings sur des librairies C++.",[33,15564,15566],{"id":15565},"pourquoi-nodejs-pourquoi-pas-nodejs","Pourquoi NodeJS \u002F Pourquoi pas NodeJS",[12,15568,15569],{},"On m'a toujours dit, et je considère que c'est une bonne pratique, d'avancer vite pour avoir une première version et\nensuite d'optimiser ce qui doit l'être (et uniquement ce qui doit l'être).",[12,15571,15572],{},"Clairement écrire en Javascript sera plus rapide que l'écriture en C++. Je pense donc commencer par un MVP en utilisant\nNodeJS. Et ensuite, si le besoin s'en fait sentir, je viendrai réécrire des parties en C++ soit via des bindings, soit\nvia des binaires dédiés.",[12,15574,15575],{},"Je vois déjà les anti NodeJS qui vont me dire que faire un logiciel de sauvegarde avec NodeJS c'est pas terrible. Que\nNodeJS est un language pourris :) ou que c'est un language pour faire des sites Internet, ou que cela utilise un\ninterpreteur.",[12,15577,15578],{},"Mais quand on pense que:",[140,15580,15581,15590],{},[143,15582,15583,15585,15586,15589],{},[344,15584,13666],{}," est fait en ",[344,15587,15588],{},"Perl"," (avec une partie faite en C depuis la version 4)",[143,15591,15592,15585,15594],{},[344,15593,13724],{},[344,15595,15596],{},"Python",[12,15598,15599],{},"Bref des logiciels de sauvegardes faits avec un language intreprété, il y en a.",[12,15601,15602],{},"Node.JS est basé sur le moteur V8 de Google dont les performances augmentent à chaque version. Donc la réponse pourrait\nsimplement être: pourquoi pas !\nLe plus important c'est de faire un logiciel fiable et qui fonctionne. Donc que l'on utiliser NodeJS, PHP ou autre pour\nfaire le développement, au final : OSEF.",[12,15604,15605],{},"Je terminerai donc sur cette note finale. Je vais finaliser quelques tests et me lancer dans le développement.",[123,15607,15608,15611,15614],{},[12,15609,15610],{},"Note de 2023 : Finalement, j'ai donc fait le développement en NodeJS. Les performances ont été grandement améliorées\ndepuis le bench. Par contre la consomation en mémoire des objets NodeJS éclate les scores les plus pessimistes\nque j'avais :).",[12,15612,15613],{},"Une fois la première version sortie, je réécrirai certaines parties dans des modules natifs pour améliorer les\nperformances. Voir le client complètement.",[12,15615,15616],{},"Par contre au lieu de choisir C++, je pense partir sur Rust que j'ai commencé à utiliser très récemment. Je ferai un\narticle sur le bench que j'ai pu faire sur la consommation mémoire de nodejs vs rust sur le sujet.",[1613,15618,15619],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}",{"title":291,"searchDepth":292,"depth":292,"links":15621},[15622,15627,15628,15629,15630,15631,15632,15633],{"id":13572,"depth":292,"text":13573,"children":15623},[15624,15625,15626],{"id":13626,"depth":375,"text":13627},{"id":13705,"depth":375,"text":13706},{"id":13758,"depth":375,"text":13759},{"id":13787,"depth":292,"text":13788},{"id":13864,"depth":292,"text":13865},{"id":13903,"depth":292,"text":13904},{"id":13919,"depth":292,"text":13920},{"id":15284,"depth":292,"text":15285},{"id":15538,"depth":292,"text":15539},{"id":15565,"depth":292,"text":15566},"2023-04-07",{"type":9,"value":15636},[15637,15642,15650],[12,15638,15639],{},[69,15640],{"alt":13523,"src":13530,"className":15641,"width":13532},[73],[123,15643,15644,15646,15648],{},[12,15645,13537],{},[12,15647,13540],{},[12,15649,13543],{},[12,15651,13546,15652,13551],{},[47,15653,13550],{"href":13549},{},"\u002Fpost\u002Fwoodstock_protocol_language_sauvegarde",{"title":13523,"description":291},"woodstock_protocol_language_sauvegarde","posts\u002FWoodstock\u002F2021-04-18_woodstock_protocol_language_sauvegarde",[6016,6017,6018,1765,1766],"Ysf2Tbm729RouGvBsMuyaZAuMY3uaQkdpCWyqg6fk7U",{"id":15662,"title":15663,"author":7,"body":15664,"category":300,"categorySlug":301,"date":21553,"description":15668,"excerpt":21554,"extension":317,"location":318,"meta":21579,"navigation":320,"path":21580,"published":320,"seo":21581,"slug":21582,"stem":21583,"tags":21584,"timeToRead":1485,"__hash__":21589},"posts\u002Fposts\u002FProgrammation\u002F2021-09-27_achat_velo.md","Du souhait d'achat d'un vélo ...",{"type":9,"value":15665,"toc":21537},[15666,15669,15676,15688,15691,15698,15701,15704,15708,15711,15722,15725,15732,15735,15743,15746,15757,15762,15769,15777,15785,15861,15864,16196,16199,16202,16209,16212,16239,16242,16245,16264,16270,16281,16284,16288,16295,16298,16305,16312,16315,16326,16329,16424,16427,16431,16434,16480,16483,16776,16779,16783,16786,16789,16798,16800,17429,17432,17438,17915,17918,17925,17929,17937,17945,18369,18372,18388,18391,18395,18398,18401,18404,18407,18410,18413,18416,18420,18423,18426,18429,18432,18435,18806,18809,19227,19230,19233,19251,20113,20116,20123,20127,20130,20141,20437,20440,20443,20970,20973,20977,20980,20983,20990,21047,21054,21061,21399,21402,21459,21463,21466,21469,21476,21480,21483,21486,21489,21492,21495,21498,21534],[12,15667,15668],{},"Que penseriez-vous si je vous racontais un peu mes vacances ? Attendez ... attendez ... ne partez pas ... l'histoire est intéressante,\net surtout nous allons parler informatique.",[12,15670,15671,15672,15675],{},"Début Août j'ai décidé de m'acheter un nouveau vélo (un VTC à assistance électrique). Le choix du vélo importe peu, mais du fait d'une pénurie\nde matière première et d'une forte demande en vélo depuis le début de la crise ",[129,15673,15674],{},"de mes"," sanitaire, tous les vélos sont en rupture de stock.",[12,15677,15678,15679],{},"J'ai fait le choix personnel de me rendre dans une enseigne connue dont le nom est aussi une discipline de l'athlétisme pour acheter ce VTC.",[15680,15681,15682],"sup",{},[47,15683,1944],{"href":15684,"ariaDescribedBy":15685,"dataFootnoteRef":291,"id":15687},"#user-content-fn-1",[15686],"footnote-label","user-content-fnref-1",[12,15689,15690],{},"Et là c'est le drame.",[12,15692,15693,15694,15697],{},"Si vous regardez les différents vélos de la marque (et en fonction de la taille du cadre qui vous correspond) vous tombez sur le message: ",[105,15695,15696],{},"En\nrupture de stock",". (Bon. À aujourd'hui, nous avons un peu plus de stock sur le site)",[12,15699,15700],{},"Arf. Moi qui quand j'ai décidé quelque chose, je deviens impatient ...",[12,15702,15703],{},"Alors il est vrai que j'aurais pu aller voir sur un autre site, aller dans une autre boutique pour choisir un autre modèle, mais ce n'est pas\nce que j'ai fait.",[33,15705,15707],{"id":15706},"lattente","L'attente",[12,15709,15710],{},"J'ai donc commencé par attendre, en allant régulièrement sur le site ou en rafraîchissant l'onglet d'un navigateur. C'est long, la page est\nrelativement lourde pour un site WEB: plus de 2.2M de fichier à transférer pour un total de 175 requêtes et ce malgrès la présence d'un adblock.",[12,15712,15713,15714,15717,15718,15721],{},"De plus je dois sélectionner manuellement la taille dans une select box pour voir : ",[105,15715,15716],{},"Rupture de stock sur cette taille",". Là je clique sur\nle bouton ",[105,15719,15720],{},"Vérifier le stock en magasin",", ... je rentre mon code postal, ... et je regarde sur l'ensemble des magasins de ma région...",[12,15723,15724],{},"Bref, je prépare mes valises, et je pars me mettre au vert. Je fais un peu de marche avec les enfants (C'est les vacances quoi). Et je ne\npeux donc pas m'amuser à rafraîchir en continu (même si je le fais depuis mon téléphone portable).",[12,15726,15727,15728,15731],{},"Bien sûr j'ai cliqué sur le bouton ",[105,15729,15730],{},"M'avertir lorsque le produit est à nouveau disponible"," mais je me demande si ce bouton fonctionne, je n'ai\nà aujourd'hui toujours pas recu de mail 😄.",[12,15733,15734],{},"Je décide donc de passer à l'étape suivante.",[33,15736,15738,15739,15742],{"id":15737},"la-1er-version","La 1",[15680,15740,15741],{},"er"," version",[12,15744,15745],{},"Je me pose donc et me demande comment je peux mettre mes compétences à contribution pour m'aider moi-même à m'acheter pour moi mon propre vélo. Je décide donc de mon propre chef de me développer une application sur mon compte AWS que je viens de me créer. Ce programme devra\nme permettre de faire plusieurs choses:",[13835,15747,15748,15751,15754],{},[143,15749,15750],{},"En un coup d'oeil visualiser le stock pour le vélo sur Internet et dans les différents magasins",[143,15752,15753],{},"M'avertir si le stock change",[143,15755,15756],{},"Et le plus important, ne pas me prendre la tête et développer l'application dans le moins de temps possible",[12,15758,15738,15759,15761],{},[15680,15760,15741],{}," version que je développe a pour but de visualiser le stock.",[12,15763,15764],{},[69,15765],{"alt":15766,"className":15767,"src":15768},"Selecteur JS",[73],"\u002FProgrammation\u002Fachat_velo\u002Ffirst_version.png",[12,15770,15771,15772,15776],{},"Le but de l'application est de récupérer l'état des stocks du site Internet. Si je peux le faire avec un navigateur internet sur le site,\nalors un programme peut le faire aussi. Je prends les outils dont j'ai l'habitude pour faire le travail: Node.JS et le framework\n",[47,15773,13995],{"href":15774,"rel":15775},"https:\u002F\u002Fnestjs.com\u002F",[51]," - framework que j'apprécie pour sa simplicité d'utilisation.",[12,15778,15779,15780,14024],{},"Pour parser la page, j'utilise ",[47,15781,15784],{"href":15782,"rel":15783},"https:\u002F\u002Fgithub.com\u002Fjsdom\u002Fjsdom",[51],"JSDom",[352,15786,15788],{"className":14027,"code":15787,"language":14029,"meta":291,"style":291},"const dom = await JSDOM.fromURL(VTC_540E_URL, options);\n\nconsole.log(dom.window.document.querySelector(\"#product-size-selection\"));\n",[344,15789,15790,15822,15826],{"__ignoreMap":291},[360,15791,15792,15794,15797,15799,15802,15805,15807,15810,15812,15815,15817,15820],{"class":362,"line":363},[360,15793,6053],{"class":574},[360,15795,15796],{"class":662}," dom",[360,15798,401],{"class":582},[360,15800,15801],{"class":574}," await",[360,15803,15804],{"class":662}," JSDOM",[360,15806,31],{"class":366},[360,15808,15809],{"class":381},"fromURL",[360,15811,671],{"class":366},[360,15813,15814],{"class":662},"VTC_540E_URL",[360,15816,2311],{"class":366},[360,15818,15819],{"class":578},"options",[360,15821,801],{"class":366},[360,15823,15824],{"class":362,"line":292},[360,15825,372],{"emptyLinePlaceholder":320},[360,15827,15828,15830,15832,15834,15836,15839,15841,15844,15846,15849,15851,15854,15856,15859],{"class":362,"line":375},[360,15829,7011],{"class":662},[360,15831,31],{"class":366},[360,15833,7016],{"class":381},[360,15835,671],{"class":366},[360,15837,15838],{"class":662},"dom",[360,15840,31],{"class":366},[360,15842,15843],{"class":662},"window",[360,15845,31],{"class":366},[360,15847,15848],{"class":662},"document",[360,15850,31],{"class":366},[360,15852,15853],{"class":381},"querySelector",[360,15855,671],{"class":366},[360,15857,15858],{"class":397},"\"#product-size-selection\"",[360,15860,4081],{"class":366},[12,15862,15863],{},"Première erreur quand je lance le programme:",[352,15865,15869],{"className":15866,"code":15867,"language":15868,"meta":291,"style":291},"language-sh shiki shiki-themes one-dark-pro","(node:15246) UnhandledPromiseRejectionWarning: Error: Parse Error: Header overflow\n    at TLSSocket.socketOnData (_http_client.js:476:22)\n    at TLSSocket.emit (events.js:311:20)\n    at addChunk (_stream_readable.js:294:12)\n    at readableAddChunk (_stream_readable.js:275:11)\n    at TLSSocket.Readable.push (_stream_readable.js:209:10)\n    at TLSWrap.onStreamRead (internal\u002Fstream_base_commons.js:186:23)\n(node:15246) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https:\u002F\u002Fnodejs.org\u002Fapi\u002Fcli.html#cli_unhandled_rejections_mode). (rejection id: 1)\n(node:15246) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.\n","sh",[344,15870,15871,15897,15908,15918,15928,15938,15948,15958,16125],{"__ignoreMap":291},[360,15872,15873,15875,15878,15880,15883,15886,15889,15891,15894],{"class":362,"line":363},[360,15874,671],{"class":366},[360,15876,15877],{"class":381},"node:15246",[360,15879,3972],{"class":366},[360,15881,15882],{"class":381},"UnhandledPromiseRejectionWarning:",[360,15884,15885],{"class":397}," Error:",[360,15887,15888],{"class":397}," Parse",[360,15890,15885],{"class":397},[360,15892,15893],{"class":397}," Header",[360,15895,15896],{"class":397}," overflow\n",[360,15898,15899,15902,15905],{"class":362,"line":292},[360,15900,15901],{"class":381},"    at",[360,15903,15904],{"class":397}," TLSSocket.socketOnData",[360,15906,15907],{"class":366}," (_http_client.js:476:22)\n",[360,15909,15910,15912,15915],{"class":362,"line":375},[360,15911,15901],{"class":381},[360,15913,15914],{"class":397}," TLSSocket.emit",[360,15916,15917],{"class":366}," (events.js:311:20)\n",[360,15919,15920,15922,15925],{"class":362,"line":433},[360,15921,15901],{"class":381},[360,15923,15924],{"class":397}," addChunk",[360,15926,15927],{"class":366}," (_stream_readable.js:294:12)\n",[360,15929,15930,15932,15935],{"class":362,"line":478},[360,15931,15901],{"class":381},[360,15933,15934],{"class":397}," readableAddChunk",[360,15936,15937],{"class":366}," (_stream_readable.js:275:11)\n",[360,15939,15940,15942,15945],{"class":362,"line":483},[360,15941,15901],{"class":381},[360,15943,15944],{"class":397}," TLSSocket.Readable.push",[360,15946,15947],{"class":366}," (_stream_readable.js:209:10)\n",[360,15949,15950,15952,15955],{"class":362,"line":489},[360,15951,15901],{"class":381},[360,15953,15954],{"class":397}," TLSWrap.onStreamRead",[360,15956,15957],{"class":366}," (internal\u002Fstream_base_commons.js:186:23)\n",[360,15959,15960,15962,15964,15966,15968,15971,15974,15977,15980,15983,15986,15989,15992,15995,15998,16000,16003,16006,16009,16012,16015,16018,16021,16024,16026,16029,16031,16033,16036,16039,16041,16044,16047,16050,16053,16055,16058,16061,16064,16067,16069,16072,16075,16077,16080,16083,16085,16088,16091,16094,16097,16099,16102,16104,16107,16110,16113,16115,16118,16121,16123],{"class":362,"line":494},[360,15961,671],{"class":366},[360,15963,15877],{"class":381},[360,15965,3972],{"class":366},[360,15967,15882],{"class":381},[360,15969,15970],{"class":397}," Unhandled",[360,15972,15973],{"class":397}," promise",[360,15975,15976],{"class":397}," rejection.",[360,15978,15979],{"class":397}," This",[360,15981,15982],{"class":397}," error",[360,15984,15985],{"class":397}," originated",[360,15987,15988],{"class":397}," either",[360,15990,15991],{"class":397}," by",[360,15993,15994],{"class":397}," throwing",[360,15996,15997],{"class":397}," inside",[360,15999,529],{"class":397},[360,16001,16002],{"class":397}," an",[360,16004,16005],{"class":397}," async",[360,16007,16008],{"class":397}," function",[360,16010,16011],{"class":397}," without",[360,16013,16014],{"class":397}," a",[360,16016,16017],{"class":397}," catch",[360,16019,16020],{"class":397}," block,",[360,16022,16023],{"class":397}," or",[360,16025,15991],{"class":397},[360,16027,16028],{"class":397}," rejecting",[360,16030,16014],{"class":397},[360,16032,15973],{"class":397},[360,16034,16035],{"class":397}," which",[360,16037,16038],{"class":397}," was",[360,16040,427],{"class":397},[360,16042,16043],{"class":397}," handled",[360,16045,16046],{"class":397}," with",[360,16048,16049],{"class":397}," .catch",[360,16051,16052],{"class":366},"()",[360,16054,31],{"class":397},[360,16056,16057],{"class":397}," To",[360,16059,16060],{"class":397}," terminate",[360,16062,16063],{"class":397}," the",[360,16065,16066],{"class":397}," node",[360,16068,6850],{"class":397},[360,16070,16071],{"class":397}," on",[360,16073,16074],{"class":397}," unhandled",[360,16076,15973],{"class":397},[360,16078,16079],{"class":397}," rejection,",[360,16081,16082],{"class":397}," use",[360,16084,16063],{"class":397},[360,16086,16087],{"class":397}," CLI",[360,16089,16090],{"class":397}," flag",[360,16092,16093],{"class":397}," `",[360,16095,16096],{"class":578},"--unhandled-rejections",[360,16098,583],{"class":582},[360,16100,16101],{"class":397},"strict`",[360,16103,743],{"class":366},[360,16105,16106],{"class":381},"see",[360,16108,16109],{"class":397}," https:\u002F\u002Fnodejs.org\u002Fapi\u002Fcli.html#cli_unhandled_rejections_mode",[360,16111,16112],{"class":366},")",[360,16114,31],{"class":582},[360,16116,16117],{"class":366}," (rejection ",[360,16119,16120],{"class":397},"id:",[360,16122,1099],{"class":414},[360,16124,2922],{"class":366},[360,16126,16127,16129,16131,16134,16137,16139,16141,16144,16147,16150,16153,16155,16158,16160,16162,16165,16167,16169,16171,16174,16176,16178,16181,16183,16185,16187,16190,16193],{"class":362,"line":712},[360,16128,671],{"class":366},[360,16130,15877],{"class":381},[360,16132,16133],{"class":366},") [DEP0018] ",[360,16135,16136],{"class":381},"DeprecationWarning:",[360,16138,15970],{"class":397},[360,16140,15973],{"class":397},[360,16142,16143],{"class":397}," rejections",[360,16145,16146],{"class":397}," are",[360,16148,16149],{"class":397}," deprecated.",[360,16151,16152],{"class":397}," In",[360,16154,16063],{"class":397},[360,16156,16157],{"class":397}," future,",[360,16159,15973],{"class":397},[360,16161,16143],{"class":397},[360,16163,16164],{"class":397}," that",[360,16166,16146],{"class":397},[360,16168,427],{"class":397},[360,16170,16043],{"class":397},[360,16172,16173],{"class":397}," will",[360,16175,16060],{"class":397},[360,16177,16063],{"class":397},[360,16179,16180],{"class":397}," Node.js",[360,16182,6850],{"class":397},[360,16184,16046],{"class":397},[360,16186,16014],{"class":397},[360,16188,16189],{"class":397}," non-zero",[360,16191,16192],{"class":397}," exit",[360,16194,16195],{"class":397}," code.\n",[12,16197,16198],{},"Pas de chance, les headers http de la grande enseigne contiennent tellement de blabla que nodejs limite et bloque. C'est l'effet CSP (Content-Security-Policy). Les CSP sont\nutilisés pour bloquer les requêtes faites par le navigateur sur une page si elle ne sont pas autorisées.",[12,16200,16201],{},"Par exemple, si un utisateur arrive à profiter d'une faille et arrive dans un avis client à mettre une iframe, une image, ... vers un site dont il possède le contrôle. La CSP\nva dire au navigateur que ce site n'est pas autorisé. Et le hack de l'utilisateur ne fonctionnera pas totalement.",[12,16203,16204,16205,16208],{},"Mais quand un site commence à avoir beaucoup de ",[105,16206,16207],{},"\"partenaire\""," (google, vimeo, cloudfront, facebook, gstatic.com, et tous les trucs bloqués par\nadblock ...), la liste prend de la place.",[12,16210,16211],{},"Je relance node avec l'option adéquate:",[352,16213,16215],{"className":15866,"code":16214,"language":15868,"meta":291,"style":291},"node --max-http-header-size=80000 app.js\n\nHTMLSelectElement {}\n",[344,16216,16217,16227,16231],{"__ignoreMap":291},[360,16218,16219,16221,16224],{"class":362,"line":363},[360,16220,551],{"class":381},[360,16222,16223],{"class":414}," --max-http-header-size=80000",[360,16225,16226],{"class":397}," app.js\n",[360,16228,16229],{"class":362,"line":292},[360,16230,372],{"emptyLinePlaceholder":320},[360,16232,16233,16236],{"class":362,"line":375},[360,16234,16235],{"class":381},"HTMLSelectElement",[360,16237,16238],{"class":397}," {}\n",[12,16240,16241],{},"Cela commence bien.",[12,16243,16244],{},"Maintenant nous allons devoir ouvrir le sélecteur de taille, choisir la taille L (qui me correspond) et cliquer dessus. Je pourrai alors récupérer l'info de stock.",[12,16246,16247,16248,16253,16260,16261,31],{},"Malheureusement beaucoup de choses sur le site sont en JavaScript, ",[47,16249,16252],{"href":16250,"rel":16251},"https:\u002F\u002Fgithub.com\u002Fjsdom\u002Fjsdom\u002Fissues\u002F2162",[51],"JSDom ne permet pas d'executer le JS de la page",[15680,16254,16255],{},[47,16256,795],{"href":16257,"ariaDescribedBy":16258,"dataFootnoteRef":291,"id":16259},"#user-content-fn-2",[15686],"user-content-fnref-2"," et donc je suis bloqué. Déjà, pour un truc que je voulais faire rapidement, mauvais choix de solution ;). Je commence à me dire que je vais devoir sortir la grosse\nartillerie : ",[105,16262,16263],{},"Puppeteer",[12,16265,16266],{},[69,16267],{"alt":15766,"className":16268,"src":16269},[73],"\u002FProgrammation\u002Fachat_velo\u002Fselecteur_js.png",[12,16271,16272,16276,16277,16280],{},[47,16273,16263],{"href":16274,"rel":16275},"https:\u002F\u002Fgithub.com\u002Fpuppeteer\u002Fpuppeteer",[51]," est une librairie javascript qui permet de contrôler le navigateur chrome en mode headless (sans fenêtre). Cela me\npermettrait donc de parser la page en ",[129,16278,16279],{},"simulant"," avec un navigateur chrome.",[12,16282,16283],{},"Mais attendez, s'il y a beaucoup de javascript, il y a peut-être des requêtes XHR ?",[33,16285,16287],{"id":16286},"xhr","XHR",[12,16289,16290,16291,16294],{},"XHR, c'est pour ",[344,16292,16293],{},"XMLHttpRequest",", ce sont des requêtes executées par le Javascript pour récupérer quelques informations.",[12,16296,16297],{},"Avec Chrome, on peut récupérer la liste des requêtes qui sont effectuées lors de l'affichage de la page mais également lors des différentes interactions.",[12,16299,16300],{},[69,16301],{"alt":16302,"className":16303,"src":16304},"Vue network de Chrome",[73],"\u002FProgrammation\u002Fachat_velo\u002Fchrome_network.png",[12,16306,16307,16308,16311],{},"On active alors le filtre ",[105,16309,16310],{},"Fetch\u002FXHR"," qu nous permet de voir les requêtes qui ne sont pas du CSS, ni du HTML, ni du JS, mais uniquement des requêtes qui sont lancées\npar le code Javascript.",[12,16313,16314],{},"Bien sûr il faut éliminer les requêtes vers d'autres sites (comme abtasty, ...). On peut alors retrouver la requête qui permet de retourner le stock du site Internet:",[352,16316,16320],{"className":16317,"code":16318,"language":16319,"meta":291,"style":291},"language-http shiki shiki-themes one-dark-pro","GET \u002Ffr\u002Fajax\u002Fnfs\u002Fstocks\u002Fonline?skuIds=4216661,4216663,4216662,4216664\n","http",[344,16321,16322],{"__ignoreMap":291},[360,16323,16324],{"class":362,"line":363},[360,16325,16318],{},[12,16327,16328],{},"Et avec la réponse:",[352,16330,16334],{"className":16331,"code":16332,"language":16333,"meta":291,"style":291},"language-json shiki shiki-themes one-dark-pro","{\n  \"4216661\": {\n    \"stockOnline\": 0\n  },\n  \"4216662\": {\n    \"stockOnline\": 0\n  },\n  \"4216663\": {\n    \"stockOnline\": 0\n  },\n  \"4216664\": {\n    \"stockOnline\": 18\n  }\n}\n","json",[344,16335,16336,16341,16348,16358,16362,16369,16377,16381,16388,16396,16400,16407,16416,16420],{"__ignoreMap":291},[360,16337,16338],{"class":362,"line":363},[360,16339,16340],{"class":366},"{\n",[360,16342,16343,16346],{"class":362,"line":292},[360,16344,16345],{"class":578},"  \"4216661\"",[360,16347,6359],{"class":366},[360,16349,16350,16353,16355],{"class":362,"line":375},[360,16351,16352],{"class":578},"    \"stockOnline\"",[360,16354,2691],{"class":366},[360,16356,16357],{"class":414},"0\n",[360,16359,16360],{"class":362,"line":433},[360,16361,6758],{"class":366},[360,16363,16364,16367],{"class":362,"line":478},[360,16365,16366],{"class":578},"  \"4216662\"",[360,16368,6359],{"class":366},[360,16370,16371,16373,16375],{"class":362,"line":483},[360,16372,16352],{"class":578},[360,16374,2691],{"class":366},[360,16376,16357],{"class":414},[360,16378,16379],{"class":362,"line":489},[360,16380,6758],{"class":366},[360,16382,16383,16386],{"class":362,"line":494},[360,16384,16385],{"class":578},"  \"4216663\"",[360,16387,6359],{"class":366},[360,16389,16390,16392,16394],{"class":362,"line":712},[360,16391,16352],{"class":578},[360,16393,2691],{"class":366},[360,16395,16357],{"class":414},[360,16397,16398],{"class":362,"line":331},[360,16399,6758],{"class":366},[360,16401,16402,16405],{"class":362,"line":762},[360,16403,16404],{"class":578},"  \"4216664\"",[360,16406,6359],{"class":366},[360,16408,16409,16411,16413],{"class":362,"line":781},[360,16410,16352],{"class":578},[360,16412,2691],{"class":366},[360,16414,16415],{"class":414},"18\n",[360,16417,16418],{"class":362,"line":804},[360,16419,820],{"class":366},[360,16421,16422],{"class":362,"line":817},[360,16423,847],{"class":366},[12,16425,16426],{},"La requête nous retourne les différents stocks pour les différentes tailles de cadre (S, M, L, XL). C'est la taille L qui m'intéresse, mais comment savoir quel\ncode produit correspond à quelle taille ?",[33,16428,16430],{"id":16429},"code-source-de-la-page","Code source de la page",[12,16432,16433],{},"On peut afficher le code source de la page (clic droit sur la page HTML : Afficher la source). Dans le source HTML on retrouve le bout de code suivant :",[352,16435,16439],{"className":16436,"code":16437,"language":16438,"meta":291,"style":291},"language-html shiki shiki-themes one-dark-pro","\u003Cscript id=\"__dkt\" type=\"application\u002Fjson\">\n  ...\n\u003C\u002Fscript>\n","html",[344,16440,16441,16466,16471],{"__ignoreMap":291},[360,16442,16443,16445,16448,16451,16453,16456,16458,16460,16463],{"class":362,"line":363},[360,16444,1358],{"class":366},[360,16446,16447],{"class":578},"script",[360,16449,16450],{"class":414}," id",[360,16452,583],{"class":366},[360,16454,16455],{"class":397},"\"__dkt\"",[360,16457,14620],{"class":414},[360,16459,583],{"class":366},[360,16461,16462],{"class":397},"\"application\u002Fjson\"",[360,16464,16465],{"class":366},">\n",[360,16467,16468],{"class":362,"line":292},[360,16469,16470],{"class":366},"  ...\n",[360,16472,16473,16476,16478],{"class":362,"line":375},[360,16474,16475],{"class":366},"\u003C\u002F",[360,16477,16447],{"class":578},[360,16479,16465],{"class":366},[12,16481,16482],{},"Le JSON contient le contexte qui sera utilisé par le code Javascript pour la génération de la page et le côté interactif. C'est l'équivalent d'un appel XHR intégré au démarrage\nde la page. On peut y retrouver ce que l'on cherche :",[352,16484,16486],{"className":16331,"code":16485,"language":16333,"meta":291,"style":291},"{\n  \"skus\": [\n    {\n      \"skuId\": \"4216661\",\n      \"size\": \"S\",\n      \"grossWeight\": \"20.9\",\n      \"price\": 2199,\n      \"isNotAvailable\": true,\n      \"availableInStores\": []\n    },\n    {\n      \"skuId\": \"4216663\",\n      \"size\": \"M\",\n      \"grossWeight\": \"21.0\",\n      \"price\": 2199,\n      \"isNotAvailable\": true,\n      \"availableInStores\": []\n    },\n    {\n      \"skuId\": \"4216662\",\n      \"size\": \"L\",\n      \"grossWeight\": \"21.1\",\n      \"price\": 2199,\n      \"isNotAvailable\": true,\n      \"availableInStores\": []\n    },\n    {\n      \"skuId\": \"4216664\",\n      \"size\": \"XL\",\n      \"grossWeight\": \"21.2\",\n      \"price\": 2199,\n      \"availableInStores\": []\n    }\n  ]\n}\n",[344,16487,16488,16492,16500,16505,16517,16529,16541,16553,16564,16572,16576,16580,16591,16602,16613,16623,16633,16639,16643,16647,16658,16669,16680,16690,16700,16706,16710,16714,16725,16736,16747,16757,16763,16767,16772],{"__ignoreMap":291},[360,16489,16490],{"class":362,"line":363},[360,16491,16340],{"class":366},[360,16493,16494,16497],{"class":362,"line":292},[360,16495,16496],{"class":578},"  \"skus\"",[360,16498,16499],{"class":366},": [\n",[360,16501,16502],{"class":362,"line":375},[360,16503,16504],{"class":366},"    {\n",[360,16506,16507,16510,16512,16515],{"class":362,"line":433},[360,16508,16509],{"class":578},"      \"skuId\"",[360,16511,2691],{"class":366},[360,16513,16514],{"class":397},"\"4216661\"",[360,16516,2968],{"class":366},[360,16518,16519,16522,16524,16527],{"class":362,"line":478},[360,16520,16521],{"class":578},"      \"size\"",[360,16523,2691],{"class":366},[360,16525,16526],{"class":397},"\"S\"",[360,16528,2968],{"class":366},[360,16530,16531,16534,16536,16539],{"class":362,"line":483},[360,16532,16533],{"class":578},"      \"grossWeight\"",[360,16535,2691],{"class":366},[360,16537,16538],{"class":397},"\"20.9\"",[360,16540,2968],{"class":366},[360,16542,16543,16546,16548,16551],{"class":362,"line":489},[360,16544,16545],{"class":578},"      \"price\"",[360,16547,2691],{"class":366},[360,16549,16550],{"class":414},"2199",[360,16552,2968],{"class":366},[360,16554,16555,16558,16560,16562],{"class":362,"line":494},[360,16556,16557],{"class":578},"      \"isNotAvailable\"",[360,16559,2691],{"class":366},[360,16561,3081],{"class":414},[360,16563,2968],{"class":366},[360,16565,16566,16569],{"class":362,"line":712},[360,16567,16568],{"class":578},"      \"availableInStores\"",[360,16570,16571],{"class":366},": []\n",[360,16573,16574],{"class":362,"line":331},[360,16575,6505],{"class":366},[360,16577,16578],{"class":362,"line":762},[360,16579,16504],{"class":366},[360,16581,16582,16584,16586,16589],{"class":362,"line":781},[360,16583,16509],{"class":578},[360,16585,2691],{"class":366},[360,16587,16588],{"class":397},"\"4216663\"",[360,16590,2968],{"class":366},[360,16592,16593,16595,16597,16600],{"class":362,"line":804},[360,16594,16521],{"class":578},[360,16596,2691],{"class":366},[360,16598,16599],{"class":397},"\"M\"",[360,16601,2968],{"class":366},[360,16603,16604,16606,16608,16611],{"class":362,"line":817},[360,16605,16533],{"class":578},[360,16607,2691],{"class":366},[360,16609,16610],{"class":397},"\"21.0\"",[360,16612,2968],{"class":366},[360,16614,16615,16617,16619,16621],{"class":362,"line":823},[360,16616,16545],{"class":578},[360,16618,2691],{"class":366},[360,16620,16550],{"class":414},[360,16622,2968],{"class":366},[360,16624,16625,16627,16629,16631],{"class":362,"line":844},[360,16626,16557],{"class":578},[360,16628,2691],{"class":366},[360,16630,3081],{"class":414},[360,16632,2968],{"class":366},[360,16634,16635,16637],{"class":362,"line":1441},[360,16636,16568],{"class":578},[360,16638,16571],{"class":366},[360,16640,16641],{"class":362,"line":1462},[360,16642,6505],{"class":366},[360,16644,16645],{"class":362,"line":1485},[360,16646,16504],{"class":366},[360,16648,16649,16651,16653,16656],{"class":362,"line":1497},[360,16650,16509],{"class":578},[360,16652,2691],{"class":366},[360,16654,16655],{"class":397},"\"4216662\"",[360,16657,2968],{"class":366},[360,16659,16660,16662,16664,16667],{"class":362,"line":3161},[360,16661,16521],{"class":578},[360,16663,2691],{"class":366},[360,16665,16666],{"class":397},"\"L\"",[360,16668,2968],{"class":366},[360,16670,16671,16673,16675,16678],{"class":362,"line":3167},[360,16672,16533],{"class":578},[360,16674,2691],{"class":366},[360,16676,16677],{"class":397},"\"21.1\"",[360,16679,2968],{"class":366},[360,16681,16682,16684,16686,16688],{"class":362,"line":3194},[360,16683,16545],{"class":578},[360,16685,2691],{"class":366},[360,16687,16550],{"class":414},[360,16689,2968],{"class":366},[360,16691,16692,16694,16696,16698],{"class":362,"line":3224},[360,16693,16557],{"class":578},[360,16695,2691],{"class":366},[360,16697,3081],{"class":414},[360,16699,2968],{"class":366},[360,16701,16702,16704],{"class":362,"line":3239},[360,16703,16568],{"class":578},[360,16705,16571],{"class":366},[360,16707,16708],{"class":362,"line":3256},[360,16709,6505],{"class":366},[360,16711,16712],{"class":362,"line":3276},[360,16713,16504],{"class":366},[360,16715,16716,16718,16720,16723],{"class":362,"line":3281},[360,16717,16509],{"class":578},[360,16719,2691],{"class":366},[360,16721,16722],{"class":397},"\"4216664\"",[360,16724,2968],{"class":366},[360,16726,16727,16729,16731,16734],{"class":362,"line":3305},[360,16728,16521],{"class":578},[360,16730,2691],{"class":366},[360,16732,16733],{"class":397},"\"XL\"",[360,16735,2968],{"class":366},[360,16737,16738,16740,16742,16745],{"class":362,"line":3320},[360,16739,16533],{"class":578},[360,16741,2691],{"class":366},[360,16743,16744],{"class":397},"\"21.2\"",[360,16746,2968],{"class":366},[360,16748,16749,16751,16753,16755],{"class":362,"line":3325},[360,16750,16545],{"class":578},[360,16752,2691],{"class":366},[360,16754,16550],{"class":414},[360,16756,2968],{"class":366},[360,16758,16759,16761],{"class":362,"line":3361},[360,16760,16568],{"class":578},[360,16762,16571],{"class":366},[360,16764,16765],{"class":362,"line":3380},[360,16766,2927],{"class":366},[360,16768,16769],{"class":362,"line":3405},[360,16770,16771],{"class":366},"  ]\n",[360,16773,16774],{"class":362,"line":3411},[360,16775,847],{"class":366},[12,16777,16778],{},"La taille qui m'intéresse est donc le SKU 4216662.",[33,16780,16782],{"id":16781},"stock-des-magasins","Stock des magasins",[12,16784,16785],{},"Vient ensuite la partie sur le stock des magasins. Je clique sur le bouton permettant de vérifier le stock des magasins, rentre mon code postal, et je me\nretrouve avec la liste des magasins.",[12,16787,16788],{},"Je regarde les requêtes et trouve celle qui m'intéresse avec l'ensemble des magasins du nord de la france:",[352,16790,16792],{"className":16317,"code":16791,"language":16319,"meta":291,"style":291},"GET \u002Ffr\u002Fajax\u002Frest\u002Fmodel\u002Fcom\u002Fdecathlon\u002Fcube\u002Fcommerce\u002Finventory\u002FInventoryActor\u002FgetStoreAvailability?storeIds=0070000200002%2C0070093300933%2C0070043700437%2C0070051800518%2C0070011800118%2C0070219902199%2C0070050400504%2C0070253902539%2C0070001500015%2C0070064800648&skuId=4216662&modelId=8614842&displayStoreDetails=false\n",[344,16793,16794],{"__ignoreMap":291},[360,16795,16796],{"class":362,"line":363},[360,16797,16791],{},[12,16799,16328],{},[352,16801,16803],{"className":16331,"code":16802,"language":16333,"meta":291,"style":291},"{\n  \"responseTO\": {\n    \"data\": [\n      {\n        \"aboveThreshold\": false,\n        \"address\": null,\n        \"availabilityInfo\": \"noStock\",\n        \"clickNcollect1h\": false,\n        \"favoriteStore\": false,\n        \"latitude\": 0,\n        \"longitude\": 0,\n        \"optionId\": null,\n        \"originId\": null,\n        \"phoneNumber\": null,\n        \"priceId\": null,\n        \"quantity\": 0,\n        \"securedStockLevel\": 0,\n        \"skuId\": \"4216662\",\n        \"storeId\": \"0070000200002\",\n        \"storeName\": \"Neuville en Ferrain - Roncq\",\n        \"storeSchedule\": null,\n        \"storeUrl\": null\n      },\n      {\n        \"aboveThreshold\": false,\n        \"address\": null,\n        \"availabilityInfo\": \"noStock\",\n        \"clickNcollect1h\": false,\n        \"favoriteStore\": false,\n        \"latitude\": 0,\n        \"longitude\": 0,\n        \"optionId\": null,\n        \"originId\": null,\n        \"phoneNumber\": null,\n        \"priceId\": null,\n        \"quantity\": 0,\n        \"securedStockLevel\": 1,\n        \"skuId\": \"4216662\",\n        \"storeId\": \"0070051800518\",\n        \"storeName\": \"Marcq-en-Baroeul DOMYOS\",\n        \"storeSchedule\": null,\n        \"storeUrl\": null\n      },\n      {\n        \"aboveThreshold\": false,\n        \"address\": null,\n        \"availabilityInfo\": \"noStock\",\n        \"clickNcollect1h\": false,\n        \"favoriteStore\": false,\n        \"latitude\": 0,\n        \"longitude\": 0,\n        \"optionId\": null,\n        \"originId\": null,\n        \"phoneNumber\": null,\n        \"priceId\": null,\n        \"quantity\": 0,\n        \"securedStockLevel\": 1,\n        \"skuId\": \"4216662\",\n        \"storeId\": \"0070219902199\",\n        \"storeName\": \"Villeneuve d'Ascq - DX\",\n        \"storeSchedule\": null,\n        \"storeUrl\": null\n      },\n      ...\n    ],\n  }\n}\n",[344,16804,16805,16809,16816,16823,16828,16840,16852,16864,16875,16886,16897,16908,16919,16930,16941,16952,16963,16974,16985,16997,17009,17020,17030,17034,17038,17048,17058,17068,17078,17088,17098,17108,17118,17128,17138,17148,17158,17168,17178,17189,17200,17210,17218,17222,17226,17236,17246,17256,17266,17276,17286,17296,17306,17316,17326,17336,17346,17356,17366,17377,17388,17398,17406,17410,17416,17421,17425],{"__ignoreMap":291},[360,16806,16807],{"class":362,"line":363},[360,16808,16340],{"class":366},[360,16810,16811,16814],{"class":362,"line":292},[360,16812,16813],{"class":578},"  \"responseTO\"",[360,16815,6359],{"class":366},[360,16817,16818,16821],{"class":362,"line":375},[360,16819,16820],{"class":578},"    \"data\"",[360,16822,16499],{"class":366},[360,16824,16825],{"class":362,"line":433},[360,16826,16827],{"class":366},"      {\n",[360,16829,16830,16833,16835,16838],{"class":362,"line":478},[360,16831,16832],{"class":578},"        \"aboveThreshold\"",[360,16834,2691],{"class":366},[360,16836,16837],{"class":414},"false",[360,16839,2968],{"class":366},[360,16841,16842,16845,16847,16850],{"class":362,"line":483},[360,16843,16844],{"class":578},"        \"address\"",[360,16846,2691],{"class":366},[360,16848,16849],{"class":414},"null",[360,16851,2968],{"class":366},[360,16853,16854,16857,16859,16862],{"class":362,"line":489},[360,16855,16856],{"class":578},"        \"availabilityInfo\"",[360,16858,2691],{"class":366},[360,16860,16861],{"class":397},"\"noStock\"",[360,16863,2968],{"class":366},[360,16865,16866,16869,16871,16873],{"class":362,"line":494},[360,16867,16868],{"class":578},"        \"clickNcollect1h\"",[360,16870,2691],{"class":366},[360,16872,16837],{"class":414},[360,16874,2968],{"class":366},[360,16876,16877,16880,16882,16884],{"class":362,"line":712},[360,16878,16879],{"class":578},"        \"favoriteStore\"",[360,16881,2691],{"class":366},[360,16883,16837],{"class":414},[360,16885,2968],{"class":366},[360,16887,16888,16891,16893,16895],{"class":362,"line":331},[360,16889,16890],{"class":578},"        \"latitude\"",[360,16892,2691],{"class":366},[360,16894,1344],{"class":414},[360,16896,2968],{"class":366},[360,16898,16899,16902,16904,16906],{"class":362,"line":762},[360,16900,16901],{"class":578},"        \"longitude\"",[360,16903,2691],{"class":366},[360,16905,1344],{"class":414},[360,16907,2968],{"class":366},[360,16909,16910,16913,16915,16917],{"class":362,"line":781},[360,16911,16912],{"class":578},"        \"optionId\"",[360,16914,2691],{"class":366},[360,16916,16849],{"class":414},[360,16918,2968],{"class":366},[360,16920,16921,16924,16926,16928],{"class":362,"line":804},[360,16922,16923],{"class":578},"        \"originId\"",[360,16925,2691],{"class":366},[360,16927,16849],{"class":414},[360,16929,2968],{"class":366},[360,16931,16932,16935,16937,16939],{"class":362,"line":817},[360,16933,16934],{"class":578},"        \"phoneNumber\"",[360,16936,2691],{"class":366},[360,16938,16849],{"class":414},[360,16940,2968],{"class":366},[360,16942,16943,16946,16948,16950],{"class":362,"line":823},[360,16944,16945],{"class":578},"        \"priceId\"",[360,16947,2691],{"class":366},[360,16949,16849],{"class":414},[360,16951,2968],{"class":366},[360,16953,16954,16957,16959,16961],{"class":362,"line":844},[360,16955,16956],{"class":578},"        \"quantity\"",[360,16958,2691],{"class":366},[360,16960,1344],{"class":414},[360,16962,2968],{"class":366},[360,16964,16965,16968,16970,16972],{"class":362,"line":1441},[360,16966,16967],{"class":578},"        \"securedStockLevel\"",[360,16969,2691],{"class":366},[360,16971,1344],{"class":414},[360,16973,2968],{"class":366},[360,16975,16976,16979,16981,16983],{"class":362,"line":1462},[360,16977,16978],{"class":578},"        \"skuId\"",[360,16980,2691],{"class":366},[360,16982,16655],{"class":397},[360,16984,2968],{"class":366},[360,16986,16987,16990,16992,16995],{"class":362,"line":1485},[360,16988,16989],{"class":578},"        \"storeId\"",[360,16991,2691],{"class":366},[360,16993,16994],{"class":397},"\"0070000200002\"",[360,16996,2968],{"class":366},[360,16998,16999,17002,17004,17007],{"class":362,"line":1497},[360,17000,17001],{"class":578},"        \"storeName\"",[360,17003,2691],{"class":366},[360,17005,17006],{"class":397},"\"Neuville en Ferrain - Roncq\"",[360,17008,2968],{"class":366},[360,17010,17011,17014,17016,17018],{"class":362,"line":3161},[360,17012,17013],{"class":578},"        \"storeSchedule\"",[360,17015,2691],{"class":366},[360,17017,16849],{"class":414},[360,17019,2968],{"class":366},[360,17021,17022,17025,17027],{"class":362,"line":3167},[360,17023,17024],{"class":578},"        \"storeUrl\"",[360,17026,2691],{"class":366},[360,17028,17029],{"class":414},"null\n",[360,17031,17032],{"class":362,"line":3194},[360,17033,10551],{"class":366},[360,17035,17036],{"class":362,"line":3224},[360,17037,16827],{"class":366},[360,17039,17040,17042,17044,17046],{"class":362,"line":3239},[360,17041,16832],{"class":578},[360,17043,2691],{"class":366},[360,17045,16837],{"class":414},[360,17047,2968],{"class":366},[360,17049,17050,17052,17054,17056],{"class":362,"line":3256},[360,17051,16844],{"class":578},[360,17053,2691],{"class":366},[360,17055,16849],{"class":414},[360,17057,2968],{"class":366},[360,17059,17060,17062,17064,17066],{"class":362,"line":3276},[360,17061,16856],{"class":578},[360,17063,2691],{"class":366},[360,17065,16861],{"class":397},[360,17067,2968],{"class":366},[360,17069,17070,17072,17074,17076],{"class":362,"line":3281},[360,17071,16868],{"class":578},[360,17073,2691],{"class":366},[360,17075,16837],{"class":414},[360,17077,2968],{"class":366},[360,17079,17080,17082,17084,17086],{"class":362,"line":3305},[360,17081,16879],{"class":578},[360,17083,2691],{"class":366},[360,17085,16837],{"class":414},[360,17087,2968],{"class":366},[360,17089,17090,17092,17094,17096],{"class":362,"line":3320},[360,17091,16890],{"class":578},[360,17093,2691],{"class":366},[360,17095,1344],{"class":414},[360,17097,2968],{"class":366},[360,17099,17100,17102,17104,17106],{"class":362,"line":3325},[360,17101,16901],{"class":578},[360,17103,2691],{"class":366},[360,17105,1344],{"class":414},[360,17107,2968],{"class":366},[360,17109,17110,17112,17114,17116],{"class":362,"line":3361},[360,17111,16912],{"class":578},[360,17113,2691],{"class":366},[360,17115,16849],{"class":414},[360,17117,2968],{"class":366},[360,17119,17120,17122,17124,17126],{"class":362,"line":3380},[360,17121,16923],{"class":578},[360,17123,2691],{"class":366},[360,17125,16849],{"class":414},[360,17127,2968],{"class":366},[360,17129,17130,17132,17134,17136],{"class":362,"line":3405},[360,17131,16934],{"class":578},[360,17133,2691],{"class":366},[360,17135,16849],{"class":414},[360,17137,2968],{"class":366},[360,17139,17140,17142,17144,17146],{"class":362,"line":3411},[360,17141,16945],{"class":578},[360,17143,2691],{"class":366},[360,17145,16849],{"class":414},[360,17147,2968],{"class":366},[360,17149,17150,17152,17154,17156],{"class":362,"line":3426},[360,17151,16956],{"class":578},[360,17153,2691],{"class":366},[360,17155,1344],{"class":414},[360,17157,2968],{"class":366},[360,17159,17160,17162,17164,17166],{"class":362,"line":3432},[360,17161,16967],{"class":578},[360,17163,2691],{"class":366},[360,17165,1944],{"class":414},[360,17167,2968],{"class":366},[360,17169,17170,17172,17174,17176],{"class":362,"line":3438},[360,17171,16978],{"class":578},[360,17173,2691],{"class":366},[360,17175,16655],{"class":397},[360,17177,2968],{"class":366},[360,17179,17180,17182,17184,17187],{"class":362,"line":3443},[360,17181,16989],{"class":578},[360,17183,2691],{"class":366},[360,17185,17186],{"class":397},"\"0070051800518\"",[360,17188,2968],{"class":366},[360,17190,17191,17193,17195,17198],{"class":362,"line":3462},[360,17192,17001],{"class":578},[360,17194,2691],{"class":366},[360,17196,17197],{"class":397},"\"Marcq-en-Baroeul DOMYOS\"",[360,17199,2968],{"class":366},[360,17201,17202,17204,17206,17208],{"class":362,"line":3467},[360,17203,17013],{"class":578},[360,17205,2691],{"class":366},[360,17207,16849],{"class":414},[360,17209,2968],{"class":366},[360,17211,17212,17214,17216],{"class":362,"line":3472},[360,17213,17024],{"class":578},[360,17215,2691],{"class":366},[360,17217,17029],{"class":414},[360,17219,17220],{"class":362,"line":3495},[360,17221,10551],{"class":366},[360,17223,17224],{"class":362,"line":3500},[360,17225,16827],{"class":366},[360,17227,17228,17230,17232,17234],{"class":362,"line":3505},[360,17229,16832],{"class":578},[360,17231,2691],{"class":366},[360,17233,16837],{"class":414},[360,17235,2968],{"class":366},[360,17237,17238,17240,17242,17244],{"class":362,"line":3530},[360,17239,16844],{"class":578},[360,17241,2691],{"class":366},[360,17243,16849],{"class":414},[360,17245,2968],{"class":366},[360,17247,17248,17250,17252,17254],{"class":362,"line":3545},[360,17249,16856],{"class":578},[360,17251,2691],{"class":366},[360,17253,16861],{"class":397},[360,17255,2968],{"class":366},[360,17257,17258,17260,17262,17264],{"class":362,"line":3558},[360,17259,16868],{"class":578},[360,17261,2691],{"class":366},[360,17263,16837],{"class":414},[360,17265,2968],{"class":366},[360,17267,17268,17270,17272,17274],{"class":362,"line":3573},[360,17269,16879],{"class":578},[360,17271,2691],{"class":366},[360,17273,16837],{"class":414},[360,17275,2968],{"class":366},[360,17277,17278,17280,17282,17284],{"class":362,"line":3578},[360,17279,16890],{"class":578},[360,17281,2691],{"class":366},[360,17283,1344],{"class":414},[360,17285,2968],{"class":366},[360,17287,17288,17290,17292,17294],{"class":362,"line":3583},[360,17289,16901],{"class":578},[360,17291,2691],{"class":366},[360,17293,1344],{"class":414},[360,17295,2968],{"class":366},[360,17297,17298,17300,17302,17304],{"class":362,"line":6893},[360,17299,16912],{"class":578},[360,17301,2691],{"class":366},[360,17303,16849],{"class":414},[360,17305,2968],{"class":366},[360,17307,17308,17310,17312,17314],{"class":362,"line":6899},[360,17309,16923],{"class":578},[360,17311,2691],{"class":366},[360,17313,16849],{"class":414},[360,17315,2968],{"class":366},[360,17317,17318,17320,17322,17324],{"class":362,"line":6905},[360,17319,16934],{"class":578},[360,17321,2691],{"class":366},[360,17323,16849],{"class":414},[360,17325,2968],{"class":366},[360,17327,17328,17330,17332,17334],{"class":362,"line":6920},[360,17329,16945],{"class":578},[360,17331,2691],{"class":366},[360,17333,16849],{"class":414},[360,17335,2968],{"class":366},[360,17337,17338,17340,17342,17344],{"class":362,"line":6942},[360,17339,16956],{"class":578},[360,17341,2691],{"class":366},[360,17343,1344],{"class":414},[360,17345,2968],{"class":366},[360,17347,17348,17350,17352,17354],{"class":362,"line":6974},[360,17349,16967],{"class":578},[360,17351,2691],{"class":366},[360,17353,1944],{"class":414},[360,17355,2968],{"class":366},[360,17357,17358,17360,17362,17364],{"class":362,"line":6992},[360,17359,16978],{"class":578},[360,17361,2691],{"class":366},[360,17363,16655],{"class":397},[360,17365,2968],{"class":366},[360,17367,17368,17370,17372,17375],{"class":362,"line":6997},[360,17369,16989],{"class":578},[360,17371,2691],{"class":366},[360,17373,17374],{"class":397},"\"0070219902199\"",[360,17376,2968],{"class":366},[360,17378,17379,17381,17383,17386],{"class":362,"line":7002},[360,17380,17001],{"class":578},[360,17382,2691],{"class":366},[360,17384,17385],{"class":397},"\"Villeneuve d'Ascq - DX\"",[360,17387,2968],{"class":366},[360,17389,17390,17392,17394,17396],{"class":362,"line":7008},[360,17391,17013],{"class":578},[360,17393,2691],{"class":366},[360,17395,16849],{"class":414},[360,17397,2968],{"class":366},[360,17399,17400,17402,17404],{"class":362,"line":7041},[360,17401,17024],{"class":578},[360,17403,2691],{"class":366},[360,17405,17029],{"class":414},[360,17407,17408],{"class":362,"line":7047},[360,17409,10551],{"class":366},[360,17411,17412],{"class":362,"line":7058},[360,17413,17415],{"class":17414},"sLaUg","      ...\n",[360,17417,17418],{"class":362,"line":7064},[360,17419,17420],{"class":366},"    ],\n",[360,17422,17423],{"class":362,"line":7086},[360,17424,820],{"class":366},[360,17426,17427],{"class":362,"line":7091},[360,17428,847],{"class":366},[12,17430,17431],{},"Parfait, j'ai l'ensemble des requêtes et le résultat permettant de recupérer les informations dont j'ai besoin. Il ne me reste plus qu'à coder. Je crée donc\nun premier service dont le but est pour un code donné de récupérer le stock internet et les stocks en magasin.",[12,17433,17434,17435,17437],{},"Il est probable que j'aurais pu mieux écrire mon code (et d'ailleurs mieux utiliser RxJS), mais je vous rappelle, ceci est un 1",[15680,17436,15741],{}," jet. Le but étant de déployer\ncela le plus rapidement possible.",[352,17439,17441],{"className":14027,"code":17440,"language":14029,"meta":291,"style":291},"@Injectable()\nexport class AppService {\n  constructor(private httpService: HttpService) {}\n\n  async getVtcElectectricL(code: string): Promise\u003CStockInformation[]> {\n    const availability = [];\n    const sku = await firstValueFrom(\n      this.httpService.get\u003CStocksOnline>(STOCKS_ONLINE([code])),\n    );\n    const onlineStocks = sku.data[code]?.stockOnline;\n\n    availability.push({\n      type: 'Internet',\n      stocks: onlineStocks,\n    });\n\n    const stores = await firstValueFrom(\n      this.httpService.get\u003CStocksStores>(STOCKS_STORE(code)),\n    );\n\n    availability.push(\n      ...stores.data.responseTO.data\n        .map((store) => ({\n          type: store.storeName,\n          stocks: store.quantity,\n        }))\n        .sort((a, b) => b.stocks - a.stocks),\n    );\n\n    return availability.map((store) => ({\n      ...store,\n      availability: store.stocks > 0 ? 'available' : 'not_available',\n    }));\n  }\n}\n",[344,17442,17443,17453,17465,17485,17489,17520,17533,17549,17583,17587,17614,17618,17630,17642,17654,17659,17663,17678,17707,17711,17715,17725,17747,17764,17780,17796,17801,17837,17841,17845,17865,17873,17902,17907,17911],{"__ignoreMap":291},[360,17444,17445,17448,17451],{"class":362,"line":363},[360,17446,17447],{"class":366},"@",[360,17449,17450],{"class":381},"Injectable",[360,17452,5008],{"class":366},[360,17454,17455,17457,17460,17463],{"class":362,"line":292},[360,17456,575],{"class":574},[360,17458,17459],{"class":574}," class",[360,17461,17462],{"class":662}," AppService",[360,17464,896],{"class":366},[360,17466,17467,17470,17472,17475,17478,17480,17483],{"class":362,"line":375},[360,17468,17469],{"class":574},"  constructor",[360,17471,671],{"class":366},[360,17473,17474],{"class":574},"private",[360,17476,17477],{"class":677}," httpService",[360,17479,2691],{"class":366},[360,17481,17482],{"class":662},"HttpService",[360,17484,7249],{"class":366},[360,17486,17487],{"class":362,"line":433},[360,17488,372],{"emptyLinePlaceholder":320},[360,17490,17491,17494,17497,17499,17501,17503,17506,17509,17512,17514,17517],{"class":362,"line":478},[360,17492,17493],{"class":574},"  async",[360,17495,17496],{"class":381}," getVtcElectectricL",[360,17498,671],{"class":366},[360,17500,344],{"class":677},[360,17502,2691],{"class":366},[360,17504,17505],{"class":662},"string",[360,17507,17508],{"class":366},"): ",[360,17510,17511],{"class":662},"Promise",[360,17513,1358],{"class":366},[360,17515,17516],{"class":662},"StockInformation",[360,17518,17519],{"class":366},"[]> {\n",[360,17521,17522,17525,17528,17530],{"class":362,"line":483},[360,17523,17524],{"class":574},"    const",[360,17526,17527],{"class":662}," availability",[360,17529,401],{"class":582},[360,17531,17532],{"class":366}," [];\n",[360,17534,17535,17537,17540,17542,17544,17547],{"class":362,"line":489},[360,17536,17524],{"class":574},[360,17538,17539],{"class":662}," sku",[360,17541,401],{"class":582},[360,17543,15801],{"class":574},[360,17545,17546],{"class":381}," firstValueFrom",[360,17548,1395],{"class":366},[360,17550,17551,17554,17556,17559,17561,17564,17566,17569,17572,17575,17578,17580],{"class":362,"line":494},[360,17552,17553],{"class":662},"      this",[360,17555,31],{"class":366},[360,17557,17558],{"class":662},"httpService",[360,17560,31],{"class":366},[360,17562,17563],{"class":381},"get",[360,17565,1358],{"class":366},[360,17567,17568],{"class":662},"StocksOnline",[360,17570,17571],{"class":366},">(",[360,17573,17574],{"class":381},"STOCKS_ONLINE",[360,17576,17577],{"class":366},"([",[360,17579,344],{"class":578},[360,17581,17582],{"class":366},"])),\n",[360,17584,17585],{"class":362,"line":712},[360,17586,9230],{"class":366},[360,17588,17589,17591,17594,17596,17598,17600,17602,17604,17606,17609,17612],{"class":362,"line":331},[360,17590,17524],{"class":574},[360,17592,17593],{"class":662}," onlineStocks",[360,17595,401],{"class":582},[360,17597,17539],{"class":662},[360,17599,31],{"class":366},[360,17601,8423],{"class":578},[360,17603,2385],{"class":366},[360,17605,344],{"class":578},[360,17607,17608],{"class":366},"]?.",[360,17610,17611],{"class":578},"stockOnline",[360,17613,735],{"class":366},[360,17615,17616],{"class":362,"line":762},[360,17617,372],{"emptyLinePlaceholder":320},[360,17619,17620,17623,17625,17627],{"class":362,"line":781},[360,17621,17622],{"class":662},"    availability",[360,17624,31],{"class":366},[360,17626,8355],{"class":381},[360,17628,17629],{"class":366},"({\n",[360,17631,17632,17635,17637,17640],{"class":362,"line":804},[360,17633,17634],{"class":578},"      type",[360,17636,2691],{"class":366},[360,17638,17639],{"class":397},"'Internet'",[360,17641,2968],{"class":366},[360,17643,17644,17647,17649,17652],{"class":362,"line":817},[360,17645,17646],{"class":578},"      stocks",[360,17648,2691],{"class":366},[360,17650,17651],{"class":578},"onlineStocks",[360,17653,2968],{"class":366},[360,17655,17656],{"class":362,"line":823},[360,17657,17658],{"class":366},"    });\n",[360,17660,17661],{"class":362,"line":844},[360,17662,372],{"emptyLinePlaceholder":320},[360,17664,17665,17667,17670,17672,17674,17676],{"class":362,"line":1441},[360,17666,17524],{"class":574},[360,17668,17669],{"class":662}," stores",[360,17671,401],{"class":582},[360,17673,15801],{"class":574},[360,17675,17546],{"class":381},[360,17677,1395],{"class":366},[360,17679,17680,17682,17684,17686,17688,17690,17692,17695,17697,17700,17702,17704],{"class":362,"line":1462},[360,17681,17553],{"class":662},[360,17683,31],{"class":366},[360,17685,17558],{"class":662},[360,17687,31],{"class":366},[360,17689,17563],{"class":381},[360,17691,1358],{"class":366},[360,17693,17694],{"class":662},"StocksStores",[360,17696,17571],{"class":366},[360,17698,17699],{"class":381},"STOCKS_STORE",[360,17701,671],{"class":366},[360,17703,344],{"class":578},[360,17705,17706],{"class":366},")),\n",[360,17708,17709],{"class":362,"line":1485},[360,17710,9230],{"class":366},[360,17712,17713],{"class":362,"line":1497},[360,17714,372],{"emptyLinePlaceholder":320},[360,17716,17717,17719,17721,17723],{"class":362,"line":3161},[360,17718,17622],{"class":662},[360,17720,31],{"class":366},[360,17722,8355],{"class":381},[360,17724,1395],{"class":366},[360,17726,17727,17730,17733,17735,17737,17739,17742,17744],{"class":362,"line":3167},[360,17728,17729],{"class":366},"      ...",[360,17731,17732],{"class":662},"stores",[360,17734,31],{"class":366},[360,17736,8423],{"class":662},[360,17738,31],{"class":366},[360,17740,17741],{"class":662},"responseTO",[360,17743,31],{"class":366},[360,17745,17746],{"class":578},"data\n",[360,17748,17749,17751,17753,17755,17758,17760,17762],{"class":362,"line":3194},[360,17750,8600],{"class":366},[360,17752,4907],{"class":381},[360,17754,7148],{"class":366},[360,17756,17757],{"class":677},"store",[360,17759,3972],{"class":366},[360,17761,6331],{"class":574},[360,17763,6334],{"class":366},[360,17765,17766,17769,17771,17773,17775,17778],{"class":362,"line":3224},[360,17767,17768],{"class":578},"          type",[360,17770,2691],{"class":366},[360,17772,17757],{"class":662},[360,17774,31],{"class":366},[360,17776,17777],{"class":578},"storeName",[360,17779,2968],{"class":366},[360,17781,17782,17785,17787,17789,17791,17794],{"class":362,"line":3239},[360,17783,17784],{"class":578},"          stocks",[360,17786,2691],{"class":366},[360,17788,17757],{"class":662},[360,17790,31],{"class":366},[360,17792,17793],{"class":578},"quantity",[360,17795,2968],{"class":366},[360,17797,17798],{"class":362,"line":3256},[360,17799,17800],{"class":366},"        }))\n",[360,17802,17803,17805,17808,17810,17812,17814,17816,17818,17820,17822,17824,17827,17829,17831,17833,17835],{"class":362,"line":3276},[360,17804,8600],{"class":366},[360,17806,17807],{"class":381},"sort",[360,17809,7148],{"class":366},[360,17811,47],{"class":677},[360,17813,2311],{"class":366},[360,17815,2252],{"class":677},[360,17817,3972],{"class":366},[360,17819,6331],{"class":574},[360,17821,2211],{"class":662},[360,17823,31],{"class":366},[360,17825,17826],{"class":578},"stocks",[360,17828,518],{"class":582},[360,17830,16014],{"class":662},[360,17832,31],{"class":366},[360,17834,17826],{"class":578},[360,17836,5405],{"class":366},[360,17838,17839],{"class":362,"line":3281},[360,17840,9230],{"class":366},[360,17842,17843],{"class":362,"line":3305},[360,17844,372],{"emptyLinePlaceholder":320},[360,17846,17847,17849,17851,17853,17855,17857,17859,17861,17863],{"class":362,"line":3320},[360,17848,1386],{"class":574},[360,17850,17527],{"class":662},[360,17852,31],{"class":366},[360,17854,4907],{"class":381},[360,17856,7148],{"class":366},[360,17858,17757],{"class":677},[360,17860,3972],{"class":366},[360,17862,6331],{"class":574},[360,17864,6334],{"class":366},[360,17866,17867,17869,17871],{"class":362,"line":3325},[360,17868,17729],{"class":366},[360,17870,17757],{"class":578},[360,17872,2968],{"class":366},[360,17874,17875,17878,17880,17882,17884,17886,17888,17890,17892,17895,17897,17900],{"class":362,"line":3361},[360,17876,17877],{"class":578},"      availability",[360,17879,2691],{"class":366},[360,17881,17757],{"class":662},[360,17883,31],{"class":366},[360,17885,17826],{"class":578},[360,17887,3538],{"class":582},[360,17889,1457],{"class":414},[360,17891,7612],{"class":574},[360,17893,17894],{"class":397}," 'available'",[360,17896,632],{"class":574},[360,17898,17899],{"class":397}," 'not_available'",[360,17901,2968],{"class":366},[360,17903,17904],{"class":362,"line":3380},[360,17905,17906],{"class":366},"    }));\n",[360,17908,17909],{"class":362,"line":3405},[360,17910,820],{"class":366},[360,17912,17913],{"class":362,"line":3411},[360,17914,847],{"class":366},[12,17916,17917],{},"Une petite page en Mustashe pour afficher en HTML le contenu de la page et c'est parti !",[12,17919,17920],{},[69,17921],{"alt":17922,"className":17923,"src":17924},"La page WEB",[73],"\u002FProgrammation\u002Fachat_velo\u002Fpage_web.png",[33,17926,17928],{"id":17927},"le-déploiement","Le déploiement",[12,17930,17931,17932,31],{},"Afin d'améliorer mes compétences professionnelles je décide de déployer cette application sur AWS, et afin que cette application me coûte le moins cher possible, je\nvais déployer cette application dans une Lambda à l'aide du framework ",[47,17933,17936],{"href":17934,"rel":17935},"https:\u002F\u002Fwww.serverless.com\u002F",[51],"Serverless",[12,17938,17939,17940,31],{},"Viens alors l'adaptation du l'application Nest.JS pour utiliser le framework Serverless. Je laisse la documentation de Nest.JS expliquer comment faire:\n",[47,17941,17944],{"href":17942,"rel":17943},"https:\u002F\u002Fdocs.nestjs.com\u002Ffaq\u002Fserverless",[51],"Nest.JS - Serverless",[352,17946,17950],{"className":17947,"code":17948,"language":17949,"meta":291,"style":291},"language-yaml shiki shiki-themes one-dark-pro","service: triathlon\nframeworkVersion: \"2\"\n\nplugins:\n  - serverless-plugin-log-retention\n  - serverless-offline\n  - serverless-domain-manager\n\ncustom:\n  region: eu-central-1\n  logRetentionInDays: 7\n  serverless-offline:\n    noPrependStageInUrl: true\n    allowCache: false\n  customDomain:\n    domainName: \"decat-${self:provider.stage}.aws.shadoware.org\"\n    basePath: \"\"\n    certificateName: \"aws.shadoware.org\"\n    createRoute53Record: true\n    endpointType: \"regional\"\n    securityPolicy: tls_1_2\n    apiType: rest\n    autoDomain: false\n\nprovider:\n  name: aws\n  region: ${self:custom.region}\n  runtime: nodejs12.x\n  lambdaHashingVersion: \"20201221\"\n  stage: ${opt:stage, 'dev'}\n  environment:\n    NODE_OPTIONS: \"--max-http-header-size=80000\"\n\npackage:\n  patterns:\n    - \"!.\u002F**\"\n    - dist\u002F**\n    - views\u002F**\n\nfunctions:\n  api:\n    handler: dist\u002Fmain.handler\n    environment:\n      region: ${self:custom.region}\n    events:\n      - http:\n          path: \u002F\n          method: ANY\n      - http:\n          path: \u002F{proxy+}\n          method: ANY\n","yaml",[344,17951,17952,17961,17971,17975,17983,17991,17998,18005,18009,18016,18026,18036,18043,18053,18063,18070,18080,18090,18100,18109,18119,18129,18139,18148,18152,18159,18169,18178,18188,18198,18208,18215,18225,18229,18235,18242,18250,18257,18264,18268,18275,18282,18292,18299,18308,18315,18324,18334,18344,18352,18361],{"__ignoreMap":291},[360,17953,17954,17956,17958],{"class":362,"line":363},[360,17955,15125],{"class":578},[360,17957,2691],{"class":366},[360,17959,17960],{"class":397},"triathlon\n",[360,17962,17963,17966,17968],{"class":362,"line":292},[360,17964,17965],{"class":578},"frameworkVersion",[360,17967,2691],{"class":366},[360,17969,17970],{"class":397},"\"2\"\n",[360,17972,17973],{"class":362,"line":375},[360,17974,372],{"emptyLinePlaceholder":320},[360,17976,17977,17980],{"class":362,"line":433},[360,17978,17979],{"class":578},"plugins",[360,17981,17982],{"class":366},":\n",[360,17984,17985,17988],{"class":362,"line":478},[360,17986,17987],{"class":366},"  - ",[360,17989,17990],{"class":397},"serverless-plugin-log-retention\n",[360,17992,17993,17995],{"class":362,"line":483},[360,17994,17987],{"class":366},[360,17996,17997],{"class":397},"serverless-offline\n",[360,17999,18000,18002],{"class":362,"line":489},[360,18001,17987],{"class":366},[360,18003,18004],{"class":397},"serverless-domain-manager\n",[360,18006,18007],{"class":362,"line":494},[360,18008,372],{"emptyLinePlaceholder":320},[360,18010,18011,18014],{"class":362,"line":712},[360,18012,18013],{"class":578},"custom",[360,18015,17982],{"class":366},[360,18017,18018,18021,18023],{"class":362,"line":331},[360,18019,18020],{"class":578},"  region",[360,18022,2691],{"class":366},[360,18024,18025],{"class":397},"eu-central-1\n",[360,18027,18028,18031,18033],{"class":362,"line":762},[360,18029,18030],{"class":578},"  logRetentionInDays",[360,18032,2691],{"class":366},[360,18034,18035],{"class":414},"7\n",[360,18037,18038,18041],{"class":362,"line":781},[360,18039,18040],{"class":578},"  serverless-offline",[360,18042,17982],{"class":366},[360,18044,18045,18048,18050],{"class":362,"line":804},[360,18046,18047],{"class":578},"    noPrependStageInUrl",[360,18049,2691],{"class":366},[360,18051,18052],{"class":414},"true\n",[360,18054,18055,18058,18060],{"class":362,"line":817},[360,18056,18057],{"class":578},"    allowCache",[360,18059,2691],{"class":366},[360,18061,18062],{"class":414},"false\n",[360,18064,18065,18068],{"class":362,"line":823},[360,18066,18067],{"class":578},"  customDomain",[360,18069,17982],{"class":366},[360,18071,18072,18075,18077],{"class":362,"line":844},[360,18073,18074],{"class":578},"    domainName",[360,18076,2691],{"class":366},[360,18078,18079],{"class":397},"\"decat-${self:provider.stage}.aws.shadoware.org\"\n",[360,18081,18082,18085,18087],{"class":362,"line":1441},[360,18083,18084],{"class":578},"    basePath",[360,18086,2691],{"class":366},[360,18088,18089],{"class":397},"\"\"\n",[360,18091,18092,18095,18097],{"class":362,"line":1462},[360,18093,18094],{"class":578},"    certificateName",[360,18096,2691],{"class":366},[360,18098,18099],{"class":397},"\"aws.shadoware.org\"\n",[360,18101,18102,18105,18107],{"class":362,"line":1485},[360,18103,18104],{"class":578},"    createRoute53Record",[360,18106,2691],{"class":366},[360,18108,18052],{"class":414},[360,18110,18111,18114,18116],{"class":362,"line":1497},[360,18112,18113],{"class":578},"    endpointType",[360,18115,2691],{"class":366},[360,18117,18118],{"class":397},"\"regional\"\n",[360,18120,18121,18124,18126],{"class":362,"line":3161},[360,18122,18123],{"class":578},"    securityPolicy",[360,18125,2691],{"class":366},[360,18127,18128],{"class":397},"tls_1_2\n",[360,18130,18131,18134,18136],{"class":362,"line":3167},[360,18132,18133],{"class":578},"    apiType",[360,18135,2691],{"class":366},[360,18137,18138],{"class":397},"rest\n",[360,18140,18141,18144,18146],{"class":362,"line":3194},[360,18142,18143],{"class":578},"    autoDomain",[360,18145,2691],{"class":366},[360,18147,18062],{"class":414},[360,18149,18150],{"class":362,"line":3224},[360,18151,372],{"emptyLinePlaceholder":320},[360,18153,18154,18157],{"class":362,"line":3239},[360,18155,18156],{"class":578},"provider",[360,18158,17982],{"class":366},[360,18160,18161,18164,18166],{"class":362,"line":3256},[360,18162,18163],{"class":578},"  name",[360,18165,2691],{"class":366},[360,18167,18168],{"class":397},"aws\n",[360,18170,18171,18173,18175],{"class":362,"line":3276},[360,18172,18020],{"class":578},[360,18174,2691],{"class":366},[360,18176,18177],{"class":397},"${self:custom.region}\n",[360,18179,18180,18183,18185],{"class":362,"line":3281},[360,18181,18182],{"class":578},"  runtime",[360,18184,2691],{"class":366},[360,18186,18187],{"class":397},"nodejs12.x\n",[360,18189,18190,18193,18195],{"class":362,"line":3305},[360,18191,18192],{"class":578},"  lambdaHashingVersion",[360,18194,2691],{"class":366},[360,18196,18197],{"class":397},"\"20201221\"\n",[360,18199,18200,18203,18205],{"class":362,"line":3320},[360,18201,18202],{"class":578},"  stage",[360,18204,2691],{"class":366},[360,18206,18207],{"class":397},"${opt:stage, 'dev'}\n",[360,18209,18210,18213],{"class":362,"line":3325},[360,18211,18212],{"class":578},"  environment",[360,18214,17982],{"class":366},[360,18216,18217,18220,18222],{"class":362,"line":3361},[360,18218,18219],{"class":578},"    NODE_OPTIONS",[360,18221,2691],{"class":366},[360,18223,18224],{"class":397},"\"--max-http-header-size=80000\"\n",[360,18226,18227],{"class":362,"line":3380},[360,18228,372],{"emptyLinePlaceholder":320},[360,18230,18231,18233],{"class":362,"line":3405},[360,18232,14276],{"class":578},[360,18234,17982],{"class":366},[360,18236,18237,18240],{"class":362,"line":3411},[360,18238,18239],{"class":578},"  patterns",[360,18241,17982],{"class":366},[360,18243,18244,18247],{"class":362,"line":3426},[360,18245,18246],{"class":366},"    - ",[360,18248,18249],{"class":397},"\"!.\u002F**\"\n",[360,18251,18252,18254],{"class":362,"line":3432},[360,18253,18246],{"class":366},[360,18255,18256],{"class":397},"dist\u002F**\n",[360,18258,18259,18261],{"class":362,"line":3438},[360,18260,18246],{"class":366},[360,18262,18263],{"class":397},"views\u002F**\n",[360,18265,18266],{"class":362,"line":3443},[360,18267,372],{"emptyLinePlaceholder":320},[360,18269,18270,18273],{"class":362,"line":3462},[360,18271,18272],{"class":578},"functions",[360,18274,17982],{"class":366},[360,18276,18277,18280],{"class":362,"line":3467},[360,18278,18279],{"class":578},"  api",[360,18281,17982],{"class":366},[360,18283,18284,18287,18289],{"class":362,"line":3472},[360,18285,18286],{"class":578},"    handler",[360,18288,2691],{"class":366},[360,18290,18291],{"class":397},"dist\u002Fmain.handler\n",[360,18293,18294,18297],{"class":362,"line":3495},[360,18295,18296],{"class":578},"    environment",[360,18298,17982],{"class":366},[360,18300,18301,18304,18306],{"class":362,"line":3500},[360,18302,18303],{"class":578},"      region",[360,18305,2691],{"class":366},[360,18307,18177],{"class":397},[360,18309,18310,18313],{"class":362,"line":3505},[360,18311,18312],{"class":578},"    events",[360,18314,17982],{"class":366},[360,18316,18317,18320,18322],{"class":362,"line":3530},[360,18318,18319],{"class":366},"      - ",[360,18321,16319],{"class":578},[360,18323,17982],{"class":366},[360,18325,18326,18329,18331],{"class":362,"line":3545},[360,18327,18328],{"class":578},"          path",[360,18330,2691],{"class":366},[360,18332,18333],{"class":397},"\u002F\n",[360,18335,18336,18339,18341],{"class":362,"line":3558},[360,18337,18338],{"class":578},"          method",[360,18340,2691],{"class":366},[360,18342,18343],{"class":397},"ANY\n",[360,18345,18346,18348,18350],{"class":362,"line":3573},[360,18347,18319],{"class":366},[360,18349,16319],{"class":578},[360,18351,17982],{"class":366},[360,18353,18354,18356,18358],{"class":362,"line":3578},[360,18355,18328],{"class":578},[360,18357,2691],{"class":366},[360,18359,18360],{"class":397},"\u002F{proxy+}\n",[360,18362,18363,18365,18367],{"class":362,"line":3583},[360,18364,18338],{"class":578},[360,18366,2691],{"class":366},[360,18368,18343],{"class":397},[12,18370,18371],{},"Il ne reste plus qu'à lancer le déploiement:",[352,18373,18375],{"className":15866,"code":18374,"language":15868,"meta":291,"style":291},"npx serverless deploy\n",[344,18376,18377],{"__ignoreMap":291},[360,18378,18379,18382,18385],{"class":362,"line":363},[360,18380,18381],{"class":381},"npx",[360,18383,18384],{"class":397}," serverless",[360,18386,18387],{"class":397}," deploy\n",[12,18389,18390],{},"Nous avons alors notre belle page de déployée.",[33,18392,18394],{"id":18393},"la-suite-de-laventure","La suite de l'aventure",[12,18396,18397],{},"Me voilà avec un petit programme qui me permet de facilement visualiser les stocks du vélo que je souhaite. J'en profite également pour ajouter le même\nproduit en taille XL (où il y a du stock) et un VTT.",[12,18399,18400],{},"Le problème c'est que je dois continuer à rafraîchir la page, même si c'est plus rapide.",[12,18402,18403],{},"Pour l'anecdocte, après une matinée de glandouille (c'est les vacances), je décide de rafraîchir la page vers midi. Je vois \"Stock: 1\". Heureux, je me précipite pour\nacheter le seul exemplaire. Mais lors de la commande je tombe sur le fameux message: \"Internal Server Error\" dans un bandeau rouge en haut de l'écran.",[12,18405,18406],{},"J'appelle le service client qui m'informe que cela provient du fait qu'il n'y a déjà plus de stock mais que le stock du site n'est mis à jours que tout les 24h.\nJe m'en doutais mais le message d'erreur laisse à désirer un peu.",[12,18408,18409],{},"Malgrès l'apparition soudaine d'un stock, je n'ai recu aucun mail pour me prévenir (relatif à la fonctionnalité \"M'avertir lorsque le produit est à nouveau disponible\"). Il\nme faut un moyen d'être averti dans les premiers dès qu'il y a du stock.",[12,18411,18412],{},"La situation s'est reproduite sans que je sois averti par mail.",[12,18414,18415],{},"Bref, il me faut une solution !",[33,18417,18419],{"id":18418},"la-notification","La notification",[12,18421,18422],{},"Je profite donc des services AWS pour développer une nouvelle fonctionnalité. Cette dernière est simple: je vais faire une requête à mon\nservice toutes les 30 minutes, pour vérifier le stock, et si ce dernier bouge, j'envoie un SMS.",[12,18424,18425],{},"Le coût actuel d'envoi d'un SMS vers la France sur AWS est de 0.06933$. Donc si je recois 1 SMS par heure en journée, je vais aller vers 1$ par jour.\nC'est à prévoir pour mon budget. Maintenant je veux recevoir le minimum de SMS. Je n'ai pas envie de recevoir de SMS quand le stock ne change pas. Il faut donc\nque je puisse comparer le stock entre l'état précédent et l'etat actuel.",[12,18427,18428],{},"Quand on utilise les lambda (fonction) d'AWS, il n'y a pas de serveur de démarré. Donc je ne peux pas stocker les valeurs précédentes temporairement en\nmémoire pour contrôler les changements (ce qui ne serait pas une bonne pratique, mais un truc rapide à faire pour un dev maison).",[12,18430,18431],{},"Je stocke donc le dernier accès au site dans une base de données de type Document de chez AWS: DynamoDB.",[12,18433,18434],{},"Le service d'envoi de SMS est simple (et prend un numéro de téléphone et un message):",[352,18436,18438],{"className":14027,"code":18437,"language":14029,"meta":291,"style":291},"  \u002F**\n   * Sends a SMS message to the specificed phone number.\n   * Returns the message ID from SNS\n   * @param   {String} phoneNumber\n   * @param   {String} message\n   * @returns {Promise|String}\n   *\u002F\n  async sendMessage(phoneNumber, message) {\n    await this.SNS.setSMSAttributes({\n      attributes: { DefaultSMSType: 'Promotional' },\n    }).promise();\n\n    const smsData = {\n      Message: message,\n      PhoneNumber: phoneNumber,\n      MessageAttributes: {\n        'AWS.SNS.SMS.SenderID': {\n          DataType: 'String',\n          StringValue: 'DecatStock',\n        },\n      },\n    };\n\n    this.logger.log(\n      `Send message to ${phoneNumber} (${message.length}):\\n${message}`,\n    );\n    const response = await this.SNS.publish(smsData).promise();\n\n    this.logger.log(`Response of SMS is ${JSON.stringify(response)}`);\n    return response.MessageId;\n  }\n",[344,18439,18440,18445,18450,18455,18471,18482,18492,18497,18515,18534,18551,18561,18565,18576,18587,18598,18605,18612,18624,18636,18640,18644,18649,18653,18669,18710,18714,18746,18750,18789,18802],{"__ignoreMap":291},[360,18441,18442],{"class":362,"line":363},[360,18443,18444],{"class":644},"  \u002F**\n",[360,18446,18447],{"class":362,"line":292},[360,18448,18449],{"class":644},"   * Sends a SMS message to the specificed phone number.\n",[360,18451,18452],{"class":362,"line":375},[360,18453,18454],{"class":644},"   * Returns the message ID from SNS\n",[360,18456,18457,18460,18464,18468],{"class":362,"line":433},[360,18458,18459],{"class":644},"   * ",[360,18461,18463],{"class":18462},"shdRp","@param",[360,18465,18467],{"class":18466},"sKU4T","   {String}",[360,18469,18470],{"class":677}," phoneNumber\n",[360,18472,18473,18475,18477,18479],{"class":362,"line":478},[360,18474,18459],{"class":644},[360,18476,18463],{"class":18462},[360,18478,18467],{"class":18466},[360,18480,18481],{"class":677}," message\n",[360,18483,18484,18486,18489],{"class":362,"line":483},[360,18485,18459],{"class":644},[360,18487,18488],{"class":18462},"@returns",[360,18490,18491],{"class":18466}," {Promise|String}\n",[360,18493,18494],{"class":362,"line":489},[360,18495,18496],{"class":644},"   *\u002F\n",[360,18498,18499,18501,18504,18506,18509,18511,18513],{"class":362,"line":494},[360,18500,17493],{"class":578},[360,18502,18503],{"class":381}," sendMessage",[360,18505,671],{"class":366},[360,18507,18508],{"class":578},"phoneNumber",[360,18510,2311],{"class":366},[360,18512,14330],{"class":578},[360,18514,681],{"class":366},[360,18516,18517,18520,18522,18524,18527,18529,18532],{"class":362,"line":712},[360,18518,18519],{"class":574},"    await",[360,18521,14110],{"class":662},[360,18523,31],{"class":366},[360,18525,18526],{"class":662},"SNS",[360,18528,31],{"class":366},[360,18530,18531],{"class":381},"setSMSAttributes",[360,18533,17629],{"class":366},[360,18535,18536,18539,18541,18544,18546,18549],{"class":362,"line":331},[360,18537,18538],{"class":578},"      attributes",[360,18540,6367],{"class":366},[360,18542,18543],{"class":578},"DefaultSMSType",[360,18545,2691],{"class":366},[360,18547,18548],{"class":397},"'Promotional'",[360,18550,6397],{"class":366},[360,18552,18553,18556,18559],{"class":362,"line":762},[360,18554,18555],{"class":366},"    }).",[360,18557,18558],{"class":381},"promise",[360,18560,2204],{"class":366},[360,18562,18563],{"class":362,"line":781},[360,18564,372],{"emptyLinePlaceholder":320},[360,18566,18567,18569,18572,18574],{"class":362,"line":804},[360,18568,17524],{"class":574},[360,18570,18571],{"class":662}," smsData",[360,18573,401],{"class":582},[360,18575,896],{"class":366},[360,18577,18578,18581,18583,18585],{"class":362,"line":817},[360,18579,18580],{"class":578},"      Message",[360,18582,2691],{"class":366},[360,18584,14330],{"class":578},[360,18586,2968],{"class":366},[360,18588,18589,18592,18594,18596],{"class":362,"line":823},[360,18590,18591],{"class":578},"      PhoneNumber",[360,18593,2691],{"class":366},[360,18595,18508],{"class":578},[360,18597,2968],{"class":366},[360,18599,18600,18603],{"class":362,"line":844},[360,18601,18602],{"class":578},"      MessageAttributes",[360,18604,6359],{"class":366},[360,18606,18607,18610],{"class":362,"line":1441},[360,18608,18609],{"class":397},"        'AWS.SNS.SMS.SenderID'",[360,18611,6359],{"class":366},[360,18613,18614,18617,18619,18622],{"class":362,"line":1462},[360,18615,18616],{"class":578},"          DataType",[360,18618,2691],{"class":366},[360,18620,18621],{"class":397},"'String'",[360,18623,2968],{"class":366},[360,18625,18626,18629,18631,18634],{"class":362,"line":1485},[360,18627,18628],{"class":578},"          StringValue",[360,18630,2691],{"class":366},[360,18632,18633],{"class":397},"'DecatStock'",[360,18635,2968],{"class":366},[360,18637,18638],{"class":362,"line":1497},[360,18639,11013],{"class":366},[360,18641,18642],{"class":362,"line":3161},[360,18643,10551],{"class":366},[360,18645,18646],{"class":362,"line":3167},[360,18647,18648],{"class":366},"    };\n",[360,18650,18651],{"class":362,"line":3194},[360,18652,372],{"emptyLinePlaceholder":320},[360,18654,18655,18658,18660,18663,18665,18667],{"class":362,"line":3224},[360,18656,18657],{"class":662},"    this",[360,18659,31],{"class":366},[360,18661,18662],{"class":662},"logger",[360,18664,31],{"class":366},[360,18666,7016],{"class":381},[360,18668,1395],{"class":366},[360,18670,18671,18674,18676,18678,18680,18682,18684,18686,18688,18691,18693,18696,18699,18701,18703,18705,18708],{"class":362,"line":3239},[360,18672,18673],{"class":397},"      `Send message to ",[360,18675,14155],{"class":574},[360,18677,18508],{"class":578},[360,18679,14166],{"class":574},[360,18681,743],{"class":397},[360,18683,14155],{"class":574},[360,18685,14330],{"class":662},[360,18687,31],{"class":366},[360,18689,18690],{"class":578},"length",[360,18692,14166],{"class":574},[360,18694,18695],{"class":397},"):",[360,18697,18698],{"class":582},"\\n",[360,18700,14155],{"class":574},[360,18702,14330],{"class":578},[360,18704,14166],{"class":574},[360,18706,18707],{"class":397},"`",[360,18709,2968],{"class":366},[360,18711,18712],{"class":362,"line":3256},[360,18713,9230],{"class":366},[360,18715,18716,18718,18720,18722,18724,18726,18728,18730,18732,18735,18737,18740,18742,18744],{"class":362,"line":3276},[360,18717,17524],{"class":574},[360,18719,14236],{"class":662},[360,18721,401],{"class":582},[360,18723,15801],{"class":574},[360,18725,14110],{"class":662},[360,18727,31],{"class":366},[360,18729,18526],{"class":662},[360,18731,31],{"class":366},[360,18733,18734],{"class":381},"publish",[360,18736,671],{"class":366},[360,18738,18739],{"class":578},"smsData",[360,18741,2198],{"class":366},[360,18743,18558],{"class":381},[360,18745,2204],{"class":366},[360,18747,18748],{"class":362,"line":3281},[360,18749,372],{"emptyLinePlaceholder":320},[360,18751,18752,18754,18756,18758,18760,18762,18764,18767,18769,18772,18774,18777,18779,18781,18783,18785,18787],{"class":362,"line":3305},[360,18753,18657],{"class":662},[360,18755,31],{"class":366},[360,18757,18662],{"class":662},[360,18759,31],{"class":366},[360,18761,7016],{"class":381},[360,18763,671],{"class":366},[360,18765,18766],{"class":397},"`Response of SMS is ",[360,18768,14155],{"class":574},[360,18770,18771],{"class":662},"JSON",[360,18773,31],{"class":366},[360,18775,18776],{"class":381},"stringify",[360,18778,671],{"class":366},[360,18780,14229],{"class":578},[360,18782,16112],{"class":366},[360,18784,14166],{"class":574},[360,18786,18707],{"class":397},[360,18788,801],{"class":366},[360,18790,18791,18793,18795,18797,18800],{"class":362,"line":3320},[360,18792,1386],{"class":574},[360,18794,14236],{"class":662},[360,18796,31],{"class":366},[360,18798,18799],{"class":578},"MessageId",[360,18801,735],{"class":366},[360,18803,18804],{"class":362,"line":3325},[360,18805,820],{"class":366},[12,18807,18808],{},"Le service permettant de lire et d'écrire dans la base DynamoDB est lui aussi très simple et ne possède que deux méthodes:",[352,18810,18812],{"className":14027,"code":18811,"language":14029,"meta":291,"style":291},"class {\n  async findOneById(sku: string): Promise\u003CDecathlonStatus> {\n    try {\n      const result = await dynamoDB\n        .get({\n          TableName: process.env.DECATHLON_TABLE_NAME,\n          Key: { id: sku },\n        })\n        .promise();\n      return result.Item as DecathlonStatus;\n    } catch (error) {\n      this.logger.warn(`Can't read the table ${sku}: ${error.message}`);\n      return null;\n    }\n  }\n\n  async update(\n    sku: string,\n    items: StockInformations\n  ): Promise\u003CDecathlonStatus> {\n    const status = new DecathlonStatus();\n    status.id = sku;\n    status.informations = items;\n\n    try {\n      await dynamoDB\n        .put({\n          TableName: process.env.DECATHLON_TABLE_NAME,\n          Item: status,\n        })\n        .promise();\n      return status;\n    } catch (error) {\n      throw new InternalServerErrorException(error);\n    }\n  }\n}\n",[344,18813,18814,18821,18848,18855,18869,18877,18899,18915,18920,18928,18947,18961,19001,19010,19014,19018,19022,19031,19042,19052,19065,19080,19095,19111,19115,19121,19128,19137,19155,19167,19171,19179,19187,19199,19215,19219,19223],{"__ignoreMap":291},[360,18815,18816,18819],{"class":362,"line":363},[360,18817,18818],{"class":574},"class",[360,18820,896],{"class":366},[360,18822,18823,18825,18828,18830,18833,18835,18837,18839,18841,18843,18846],{"class":362,"line":292},[360,18824,17493],{"class":574},[360,18826,18827],{"class":381}," findOneById",[360,18829,671],{"class":366},[360,18831,18832],{"class":677},"sku",[360,18834,2691],{"class":366},[360,18836,17505],{"class":662},[360,18838,17508],{"class":366},[360,18840,17511],{"class":662},[360,18842,1358],{"class":366},[360,18844,18845],{"class":662},"DecathlonStatus",[360,18847,2711],{"class":366},[360,18849,18850,18853],{"class":362,"line":375},[360,18851,18852],{"class":574},"    try",[360,18854,896],{"class":366},[360,18856,18857,18860,18862,18864,18866],{"class":362,"line":433},[360,18858,18859],{"class":574},"      const",[360,18861,4375],{"class":662},[360,18863,401],{"class":582},[360,18865,15801],{"class":574},[360,18867,18868],{"class":578}," dynamoDB\n",[360,18870,18871,18873,18875],{"class":362,"line":478},[360,18872,8600],{"class":366},[360,18874,17563],{"class":381},[360,18876,17629],{"class":366},[360,18878,18879,18882,18884,18887,18889,18892,18894,18897],{"class":362,"line":483},[360,18880,18881],{"class":578},"          TableName",[360,18883,2691],{"class":366},[360,18885,18886],{"class":662},"process",[360,18888,31],{"class":366},[360,18890,18891],{"class":662},"env",[360,18893,31],{"class":366},[360,18895,18896],{"class":578},"DECATHLON_TABLE_NAME",[360,18898,2968],{"class":366},[360,18900,18901,18904,18906,18909,18911,18913],{"class":362,"line":489},[360,18902,18903],{"class":578},"          Key",[360,18905,6367],{"class":366},[360,18907,18908],{"class":578},"id",[360,18910,2691],{"class":366},[360,18912,18832],{"class":578},[360,18914,6397],{"class":366},[360,18916,18917],{"class":362,"line":494},[360,18918,18919],{"class":366},"        })\n",[360,18921,18922,18924,18926],{"class":362,"line":712},[360,18923,8600],{"class":366},[360,18925,18558],{"class":381},[360,18927,2204],{"class":366},[360,18929,18930,18933,18935,18937,18940,18942,18945],{"class":362,"line":331},[360,18931,18932],{"class":574},"      return",[360,18934,4375],{"class":662},[360,18936,31],{"class":366},[360,18938,18939],{"class":578},"Item",[360,18941,9698],{"class":574},[360,18943,18944],{"class":662}," DecathlonStatus",[360,18946,735],{"class":366},[360,18948,18949,18952,18954,18956,18959],{"class":362,"line":762},[360,18950,18951],{"class":366},"    } ",[360,18953,7242],{"class":574},[360,18955,743],{"class":366},[360,18957,18958],{"class":578},"error",[360,18960,681],{"class":366},[360,18962,18963,18965,18967,18969,18971,18974,18976,18979,18981,18983,18985,18987,18989,18991,18993,18995,18997,18999],{"class":362,"line":781},[360,18964,17553],{"class":662},[360,18966,31],{"class":366},[360,18968,18662],{"class":662},[360,18970,31],{"class":366},[360,18972,18973],{"class":381},"warn",[360,18975,671],{"class":366},[360,18977,18978],{"class":397},"`Can't read the table ",[360,18980,14155],{"class":574},[360,18982,18832],{"class":578},[360,18984,14166],{"class":574},[360,18986,2691],{"class":397},[360,18988,14155],{"class":574},[360,18990,18958],{"class":662},[360,18992,31],{"class":366},[360,18994,14330],{"class":578},[360,18996,14166],{"class":574},[360,18998,18707],{"class":397},[360,19000,801],{"class":366},[360,19002,19003,19005,19008],{"class":362,"line":804},[360,19004,18932],{"class":574},[360,19006,19007],{"class":414}," null",[360,19009,735],{"class":366},[360,19011,19012],{"class":362,"line":817},[360,19013,2927],{"class":366},[360,19015,19016],{"class":362,"line":823},[360,19017,820],{"class":366},[360,19019,19020],{"class":362,"line":844},[360,19021,372],{"emptyLinePlaceholder":320},[360,19023,19024,19026,19029],{"class":362,"line":1441},[360,19025,17493],{"class":574},[360,19027,19028],{"class":381}," update",[360,19030,1395],{"class":366},[360,19032,19033,19036,19038,19040],{"class":362,"line":1462},[360,19034,19035],{"class":677},"    sku",[360,19037,2691],{"class":366},[360,19039,17505],{"class":662},[360,19041,2968],{"class":366},[360,19043,19044,19047,19049],{"class":362,"line":1485},[360,19045,19046],{"class":677},"    items",[360,19048,2691],{"class":366},[360,19050,19051],{"class":662},"StockInformations\n",[360,19053,19054,19057,19059,19061,19063],{"class":362,"line":1497},[360,19055,19056],{"class":366},"  ): ",[360,19058,17511],{"class":662},[360,19060,1358],{"class":366},[360,19062,18845],{"class":662},[360,19064,2711],{"class":366},[360,19066,19067,19069,19072,19074,19076,19078],{"class":362,"line":3161},[360,19068,17524],{"class":574},[360,19070,19071],{"class":662}," status",[360,19073,401],{"class":582},[360,19075,3040],{"class":574},[360,19077,18944],{"class":381},[360,19079,2204],{"class":366},[360,19081,19082,19085,19087,19089,19091,19093],{"class":362,"line":3167},[360,19083,19084],{"class":662},"    status",[360,19086,31],{"class":366},[360,19088,18908],{"class":578},[360,19090,401],{"class":582},[360,19092,17539],{"class":578},[360,19094,735],{"class":366},[360,19096,19097,19099,19101,19104,19106,19109],{"class":362,"line":3194},[360,19098,19084],{"class":662},[360,19100,31],{"class":366},[360,19102,19103],{"class":578},"informations",[360,19105,401],{"class":582},[360,19107,19108],{"class":578}," items",[360,19110,735],{"class":366},[360,19112,19113],{"class":362,"line":3224},[360,19114,372],{"emptyLinePlaceholder":320},[360,19116,19117,19119],{"class":362,"line":3239},[360,19118,18852],{"class":574},[360,19120,896],{"class":366},[360,19122,19123,19126],{"class":362,"line":3256},[360,19124,19125],{"class":574},"      await",[360,19127,18868],{"class":578},[360,19129,19130,19132,19135],{"class":362,"line":3276},[360,19131,8600],{"class":366},[360,19133,19134],{"class":381},"put",[360,19136,17629],{"class":366},[360,19138,19139,19141,19143,19145,19147,19149,19151,19153],{"class":362,"line":3281},[360,19140,18881],{"class":578},[360,19142,2691],{"class":366},[360,19144,18886],{"class":662},[360,19146,31],{"class":366},[360,19148,18891],{"class":662},[360,19150,31],{"class":366},[360,19152,18896],{"class":578},[360,19154,2968],{"class":366},[360,19156,19157,19160,19162,19165],{"class":362,"line":3305},[360,19158,19159],{"class":578},"          Item",[360,19161,2691],{"class":366},[360,19163,19164],{"class":578},"status",[360,19166,2968],{"class":366},[360,19168,19169],{"class":362,"line":3320},[360,19170,18919],{"class":366},[360,19172,19173,19175,19177],{"class":362,"line":3325},[360,19174,8600],{"class":366},[360,19176,18558],{"class":381},[360,19178,2204],{"class":366},[360,19180,19181,19183,19185],{"class":362,"line":3361},[360,19182,18932],{"class":574},[360,19184,19071],{"class":578},[360,19186,735],{"class":366},[360,19188,19189,19191,19193,19195,19197],{"class":362,"line":3380},[360,19190,18951],{"class":366},[360,19192,7242],{"class":574},[360,19194,743],{"class":366},[360,19196,18958],{"class":578},[360,19198,681],{"class":366},[360,19200,19201,19204,19206,19209,19211,19213],{"class":362,"line":3405},[360,19202,19203],{"class":574},"      throw",[360,19205,3040],{"class":574},[360,19207,19208],{"class":381}," InternalServerErrorException",[360,19210,671],{"class":366},[360,19212,18958],{"class":578},[360,19214,801],{"class":366},[360,19216,19217],{"class":362,"line":3411},[360,19218,2927],{"class":366},[360,19220,19221],{"class":362,"line":3426},[360,19222,820],{"class":366},[360,19224,19225],{"class":362,"line":3432},[360,19226,847],{"class":366},[12,19228,19229],{},"Le but est bien de lire le status et d'écrire le status pour un produit.",[12,19231,19232],{},"Le service qui sera appellé de façon régulière est relativement simple. Il va:",[13835,19234,19235,19241,19248],{},[143,19236,19237,19238,19240],{},"appeler le service d'API ",[344,19239,13875],{}," pour vérifier le stock en live,",[143,19242,19243,19244,19247],{},"appeler la service ",[344,19245,19246],{},"DynamoDB"," pour récupérer le dernier stock en base de données,",[143,19249,19250],{},"et faire la différences entre les deux, et s'il y en a une: envoyer un SMS.",[352,19252,19254],{"className":14027,"code":19253,"language":14029,"meta":291,"style":291},"export class AvailibilityCheckerService {\n  private logger = new Logger(AvailibilityCheckerService.name);\n\n  constructor(\n    private service: AppService,\n    private decathlonService: DecathlonsService,\n    private smsService: SMSService,\n  ) {}\n\n  async checkAvailibility() {\n    const message = (\n      await Promise.all(\n        PRODUCTS.map(\n          async (product) =>\n            await this.checkAvailabilityOfSku(product.code, product.name),\n        ),\n      )\n    )\n      .filter((message) => !!message)\n      .join('\\n\\n');\n\n    if (message.length) {\n      await this.smsService.sendMessage(process.env.PHONE_NUMBER, message);\n    }\n  }\n\n  async checkAvailabilityOfSku(code: string, name: string) {\n    const stocks = await this.service.getVtcElectectricL(code);\n    const oldStocks = await this.decathlonService.findOneById(code);\n    const diffStocks = this.diffStocks(oldStocks?.informations, stocks);\n    this.logger.debug(`The are ${diffStocks.length} stocks that change`);\n\n    let message;\n    if (diffStocks.length) {\n      message = diffStocks\n        .map((value) => `  ${value.type} - ${value.stocks}`)\n        .join('\\n');\n    }\n\n    await this.decathlonService.update(code, stocks);\n    return message && `${name}:\\n${message}`;\n  }\n\n  diffStocks(oldInfos: StockInformations, newInfos: StockInformations) {\n    oldInfos || (oldInfos = []);\n    newInfos || (newInfos = []);\n\n    const oldMap = oldInfos.reduce((acc, i) => {\n      acc[i.type] = i;\n      return acc;\n    }, {} as Record\u003Cstring, StockInformation>);\n\n    return newInfos.filter((info) => {\n      const oldStocks = oldMap[info.type]?.stocks || 0;\n      return oldStocks !== (info?.stocks || 0);\n    });\n  }\n}\n",[344,19255,19256,19267,19294,19298,19304,19319,19333,19347,19352,19356,19365,19377,19391,19402,19417,19447,19452,19456,19460,19482,19500,19504,19518,19553,19557,19561,19565,19590,19618,19647,19679,19712,19716,19724,19738,19748,19793,19809,19813,19817,19842,19872,19876,19880,19906,19922,19937,19941,19973,19994,20003,20024,20028,20050,20078,20101,20105,20109],{"__ignoreMap":291},[360,19257,19258,19260,19262,19265],{"class":362,"line":363},[360,19259,575],{"class":574},[360,19261,17459],{"class":574},[360,19263,19264],{"class":662}," AvailibilityCheckerService",[360,19266,896],{"class":366},[360,19268,19269,19272,19275,19277,19279,19282,19284,19287,19289,19292],{"class":362,"line":292},[360,19270,19271],{"class":574},"  private",[360,19273,19274],{"class":578}," logger",[360,19276,401],{"class":582},[360,19278,3040],{"class":574},[360,19280,19281],{"class":381}," Logger",[360,19283,671],{"class":366},[360,19285,19286],{"class":662},"AvailibilityCheckerService",[360,19288,31],{"class":366},[360,19290,19291],{"class":578},"name",[360,19293,801],{"class":366},[360,19295,19296],{"class":362,"line":375},[360,19297,372],{"emptyLinePlaceholder":320},[360,19299,19300,19302],{"class":362,"line":433},[360,19301,17469],{"class":574},[360,19303,1395],{"class":366},[360,19305,19306,19309,19312,19314,19317],{"class":362,"line":478},[360,19307,19308],{"class":574},"    private",[360,19310,19311],{"class":677}," service",[360,19313,2691],{"class":366},[360,19315,19316],{"class":662},"AppService",[360,19318,2968],{"class":366},[360,19320,19321,19323,19326,19328,19331],{"class":362,"line":483},[360,19322,19308],{"class":574},[360,19324,19325],{"class":677}," decathlonService",[360,19327,2691],{"class":366},[360,19329,19330],{"class":662},"DecathlonsService",[360,19332,2968],{"class":366},[360,19334,19335,19337,19340,19342,19345],{"class":362,"line":489},[360,19336,19308],{"class":574},[360,19338,19339],{"class":677}," smsService",[360,19341,2691],{"class":366},[360,19343,19344],{"class":662},"SMSService",[360,19346,2968],{"class":366},[360,19348,19349],{"class":362,"line":494},[360,19350,19351],{"class":366},"  ) {}\n",[360,19353,19354],{"class":362,"line":712},[360,19355,372],{"emptyLinePlaceholder":320},[360,19357,19358,19360,19363],{"class":362,"line":331},[360,19359,17493],{"class":574},[360,19361,19362],{"class":381}," checkAvailibility",[360,19364,2172],{"class":366},[360,19366,19367,19369,19372,19374],{"class":362,"line":762},[360,19368,17524],{"class":574},[360,19370,19371],{"class":381}," message",[360,19373,401],{"class":582},[360,19375,19376],{"class":366}," (\n",[360,19378,19379,19381,19384,19386,19389],{"class":362,"line":781},[360,19380,19125],{"class":574},[360,19382,19383],{"class":662}," Promise",[360,19385,31],{"class":366},[360,19387,19388],{"class":381},"all",[360,19390,1395],{"class":366},[360,19392,19393,19396,19398,19400],{"class":362,"line":804},[360,19394,19395],{"class":662},"        PRODUCTS",[360,19397,31],{"class":366},[360,19399,4907],{"class":381},[360,19401,1395],{"class":366},[360,19403,19404,19407,19409,19412,19414],{"class":362,"line":817},[360,19405,19406],{"class":574},"          async",[360,19408,743],{"class":366},[360,19410,19411],{"class":677},"product",[360,19413,3972],{"class":366},[360,19415,19416],{"class":574},"=>\n",[360,19418,19419,19422,19424,19426,19429,19431,19433,19435,19437,19439,19441,19443,19445],{"class":362,"line":823},[360,19420,19421],{"class":574},"            await",[360,19423,14110],{"class":662},[360,19425,31],{"class":366},[360,19427,19428],{"class":381},"checkAvailabilityOfSku",[360,19430,671],{"class":366},[360,19432,19411],{"class":662},[360,19434,31],{"class":366},[360,19436,344],{"class":578},[360,19438,2311],{"class":366},[360,19440,19411],{"class":662},[360,19442,31],{"class":366},[360,19444,19291],{"class":578},[360,19446,5405],{"class":366},[360,19448,19449],{"class":362,"line":844},[360,19450,19451],{"class":366},"        ),\n",[360,19453,19454],{"class":362,"line":1441},[360,19455,11308],{"class":366},[360,19457,19458],{"class":362,"line":1462},[360,19459,11381],{"class":366},[360,19461,19462,19464,19467,19469,19471,19473,19475,19478,19480],{"class":362,"line":1485},[360,19463,10669],{"class":366},[360,19465,19466],{"class":381},"filter",[360,19468,7148],{"class":366},[360,19470,14330],{"class":677},[360,19472,3972],{"class":366},[360,19474,6331],{"class":574},[360,19476,19477],{"class":582}," !!",[360,19479,14330],{"class":578},[360,19481,2922],{"class":366},[360,19483,19484,19486,19488,19490,19493,19496,19498],{"class":362,"line":1497},[360,19485,10669],{"class":366},[360,19487,5493],{"class":381},[360,19489,671],{"class":366},[360,19491,19492],{"class":397},"'",[360,19494,19495],{"class":582},"\\n\\n",[360,19497,19492],{"class":397},[360,19499,801],{"class":366},[360,19501,19502],{"class":362,"line":3161},[360,19503,372],{"emptyLinePlaceholder":320},[360,19505,19506,19508,19510,19512,19514,19516],{"class":362,"line":3167},[360,19507,5657],{"class":574},[360,19509,743],{"class":366},[360,19511,14330],{"class":662},[360,19513,31],{"class":366},[360,19515,18690],{"class":578},[360,19517,681],{"class":366},[360,19519,19520,19522,19524,19526,19529,19531,19534,19536,19538,19540,19542,19544,19547,19549,19551],{"class":362,"line":3194},[360,19521,19125],{"class":574},[360,19523,14110],{"class":662},[360,19525,31],{"class":366},[360,19527,19528],{"class":662},"smsService",[360,19530,31],{"class":366},[360,19532,19533],{"class":381},"sendMessage",[360,19535,671],{"class":366},[360,19537,18886],{"class":662},[360,19539,31],{"class":366},[360,19541,18891],{"class":662},[360,19543,31],{"class":366},[360,19545,19546],{"class":578},"PHONE_NUMBER",[360,19548,2311],{"class":366},[360,19550,14330],{"class":578},[360,19552,801],{"class":366},[360,19554,19555],{"class":362,"line":3224},[360,19556,2927],{"class":366},[360,19558,19559],{"class":362,"line":3239},[360,19560,820],{"class":366},[360,19562,19563],{"class":362,"line":3256},[360,19564,372],{"emptyLinePlaceholder":320},[360,19566,19567,19569,19572,19574,19576,19578,19580,19582,19584,19586,19588],{"class":362,"line":3276},[360,19568,17493],{"class":574},[360,19570,19571],{"class":381}," checkAvailabilityOfSku",[360,19573,671],{"class":366},[360,19575,344],{"class":677},[360,19577,2691],{"class":366},[360,19579,17505],{"class":662},[360,19581,2311],{"class":366},[360,19583,19291],{"class":677},[360,19585,2691],{"class":366},[360,19587,17505],{"class":662},[360,19589,681],{"class":366},[360,19591,19592,19594,19597,19599,19601,19603,19605,19607,19609,19612,19614,19616],{"class":362,"line":3281},[360,19593,17524],{"class":574},[360,19595,19596],{"class":662}," stocks",[360,19598,401],{"class":582},[360,19600,15801],{"class":574},[360,19602,14110],{"class":662},[360,19604,31],{"class":366},[360,19606,15125],{"class":662},[360,19608,31],{"class":366},[360,19610,19611],{"class":381},"getVtcElectectricL",[360,19613,671],{"class":366},[360,19615,344],{"class":578},[360,19617,801],{"class":366},[360,19619,19620,19622,19625,19627,19629,19631,19633,19636,19638,19641,19643,19645],{"class":362,"line":3305},[360,19621,17524],{"class":574},[360,19623,19624],{"class":662}," oldStocks",[360,19626,401],{"class":582},[360,19628,15801],{"class":574},[360,19630,14110],{"class":662},[360,19632,31],{"class":366},[360,19634,19635],{"class":662},"decathlonService",[360,19637,31],{"class":366},[360,19639,19640],{"class":381},"findOneById",[360,19642,671],{"class":366},[360,19644,344],{"class":578},[360,19646,801],{"class":366},[360,19648,19649,19651,19654,19656,19658,19660,19663,19665,19668,19671,19673,19675,19677],{"class":362,"line":3320},[360,19650,17524],{"class":574},[360,19652,19653],{"class":662}," diffStocks",[360,19655,401],{"class":582},[360,19657,14110],{"class":662},[360,19659,31],{"class":366},[360,19661,19662],{"class":381},"diffStocks",[360,19664,671],{"class":366},[360,19666,19667],{"class":662},"oldStocks",[360,19669,19670],{"class":366},"?.",[360,19672,19103],{"class":578},[360,19674,2311],{"class":366},[360,19676,17826],{"class":578},[360,19678,801],{"class":366},[360,19680,19681,19683,19685,19687,19689,19692,19694,19697,19699,19701,19703,19705,19707,19710],{"class":362,"line":3325},[360,19682,18657],{"class":662},[360,19684,31],{"class":366},[360,19686,18662],{"class":662},[360,19688,31],{"class":366},[360,19690,19691],{"class":381},"debug",[360,19693,671],{"class":366},[360,19695,19696],{"class":397},"`The are ",[360,19698,14155],{"class":574},[360,19700,19662],{"class":662},[360,19702,31],{"class":366},[360,19704,18690],{"class":578},[360,19706,14166],{"class":574},[360,19708,19709],{"class":397}," stocks that change`",[360,19711,801],{"class":366},[360,19713,19714],{"class":362,"line":3361},[360,19715,372],{"emptyLinePlaceholder":320},[360,19717,19718,19720,19722],{"class":362,"line":3380},[360,19719,2177],{"class":574},[360,19721,19371],{"class":578},[360,19723,735],{"class":366},[360,19725,19726,19728,19730,19732,19734,19736],{"class":362,"line":3405},[360,19727,5657],{"class":574},[360,19729,743],{"class":366},[360,19731,19662],{"class":662},[360,19733,31],{"class":366},[360,19735,18690],{"class":578},[360,19737,681],{"class":366},[360,19739,19740,19743,19745],{"class":362,"line":3411},[360,19741,19742],{"class":578},"      message",[360,19744,401],{"class":582},[360,19746,19747],{"class":578}," diffStocks\n",[360,19749,19750,19752,19754,19756,19759,19761,19763,19766,19768,19770,19772,19775,19777,19779,19781,19783,19785,19787,19789,19791],{"class":362,"line":3426},[360,19751,8600],{"class":366},[360,19753,4907],{"class":381},[360,19755,7148],{"class":366},[360,19757,19758],{"class":677},"value",[360,19760,3972],{"class":366},[360,19762,6331],{"class":574},[360,19764,19765],{"class":397}," `  ",[360,19767,14155],{"class":574},[360,19769,19758],{"class":662},[360,19771,31],{"class":366},[360,19773,19774],{"class":578},"type",[360,19776,14166],{"class":574},[360,19778,9142],{"class":397},[360,19780,14155],{"class":574},[360,19782,19758],{"class":662},[360,19784,31],{"class":366},[360,19786,17826],{"class":578},[360,19788,14166],{"class":574},[360,19790,18707],{"class":397},[360,19792,2922],{"class":366},[360,19794,19795,19797,19799,19801,19803,19805,19807],{"class":362,"line":3432},[360,19796,8600],{"class":366},[360,19798,5493],{"class":381},[360,19800,671],{"class":366},[360,19802,19492],{"class":397},[360,19804,18698],{"class":582},[360,19806,19492],{"class":397},[360,19808,801],{"class":366},[360,19810,19811],{"class":362,"line":3438},[360,19812,2927],{"class":366},[360,19814,19815],{"class":362,"line":3443},[360,19816,372],{"emptyLinePlaceholder":320},[360,19818,19819,19821,19823,19825,19827,19829,19832,19834,19836,19838,19840],{"class":362,"line":3462},[360,19820,18519],{"class":574},[360,19822,14110],{"class":662},[360,19824,31],{"class":366},[360,19826,19635],{"class":662},[360,19828,31],{"class":366},[360,19830,19831],{"class":381},"update",[360,19833,671],{"class":366},[360,19835,344],{"class":578},[360,19837,2311],{"class":366},[360,19839,17826],{"class":578},[360,19841,801],{"class":366},[360,19843,19844,19846,19848,19850,19852,19854,19856,19858,19860,19862,19864,19866,19868,19870],{"class":362,"line":3467},[360,19845,1386],{"class":574},[360,19847,19371],{"class":578},[360,19849,754],{"class":582},[360,19851,16093],{"class":397},[360,19853,14155],{"class":574},[360,19855,19291],{"class":578},[360,19857,14166],{"class":574},[360,19859,14024],{"class":397},[360,19861,18698],{"class":582},[360,19863,14155],{"class":574},[360,19865,14330],{"class":578},[360,19867,14166],{"class":574},[360,19869,18707],{"class":397},[360,19871,735],{"class":366},[360,19873,19874],{"class":362,"line":3472},[360,19875,820],{"class":366},[360,19877,19878],{"class":362,"line":3495},[360,19879,372],{"emptyLinePlaceholder":320},[360,19881,19882,19885,19887,19890,19892,19895,19897,19900,19902,19904],{"class":362,"line":3500},[360,19883,19884],{"class":381},"  diffStocks",[360,19886,671],{"class":366},[360,19888,19889],{"class":677},"oldInfos",[360,19891,2691],{"class":366},[360,19893,19894],{"class":662},"StockInformations",[360,19896,2311],{"class":366},[360,19898,19899],{"class":677},"newInfos",[360,19901,2691],{"class":366},[360,19903,19894],{"class":662},[360,19905,681],{"class":366},[360,19907,19908,19911,19913,19915,19917,19919],{"class":362,"line":3505},[360,19909,19910],{"class":578},"    oldInfos",[360,19912,2401],{"class":582},[360,19914,743],{"class":366},[360,19916,19889],{"class":578},[360,19918,401],{"class":582},[360,19920,19921],{"class":366}," []);\n",[360,19923,19924,19927,19929,19931,19933,19935],{"class":362,"line":3530},[360,19925,19926],{"class":578},"    newInfos",[360,19928,2401],{"class":582},[360,19930,743],{"class":366},[360,19932,19899],{"class":578},[360,19934,401],{"class":582},[360,19936,19921],{"class":366},[360,19938,19939],{"class":362,"line":3545},[360,19940,372],{"emptyLinePlaceholder":320},[360,19942,19943,19945,19948,19950,19953,19955,19958,19960,19963,19965,19967,19969,19971],{"class":362,"line":3558},[360,19944,17524],{"class":574},[360,19946,19947],{"class":662}," oldMap",[360,19949,401],{"class":582},[360,19951,19952],{"class":662}," oldInfos",[360,19954,31],{"class":366},[360,19956,19957],{"class":381},"reduce",[360,19959,7148],{"class":366},[360,19961,19962],{"class":677},"acc",[360,19964,2311],{"class":366},[360,19966,6187],{"class":677},[360,19968,3972],{"class":366},[360,19970,6331],{"class":574},[360,19972,896],{"class":366},[360,19974,19975,19978,19980,19982,19984,19986,19988,19990,19992],{"class":362,"line":3573},[360,19976,19977],{"class":578},"      acc",[360,19979,2385],{"class":366},[360,19981,6187],{"class":662},[360,19983,31],{"class":366},[360,19985,19774],{"class":578},[360,19987,2390],{"class":366},[360,19989,583],{"class":582},[360,19991,6178],{"class":578},[360,19993,735],{"class":366},[360,19995,19996,19998,20001],{"class":362,"line":3578},[360,19997,18932],{"class":574},[360,19999,20000],{"class":578}," acc",[360,20002,735],{"class":366},[360,20004,20005,20008,20010,20013,20015,20017,20019,20021],{"class":362,"line":3583},[360,20006,20007],{"class":366},"    }, {} ",[360,20009,4505],{"class":574},[360,20011,20012],{"class":662}," Record",[360,20014,1358],{"class":366},[360,20016,17505],{"class":662},[360,20018,2311],{"class":366},[360,20020,17516],{"class":662},[360,20022,20023],{"class":366},">);\n",[360,20025,20026],{"class":362,"line":6893},[360,20027,372],{"emptyLinePlaceholder":320},[360,20029,20030,20032,20035,20037,20039,20041,20044,20046,20048],{"class":362,"line":6899},[360,20031,1386],{"class":574},[360,20033,20034],{"class":662}," newInfos",[360,20036,31],{"class":366},[360,20038,19466],{"class":381},[360,20040,7148],{"class":366},[360,20042,20043],{"class":677},"info",[360,20045,3972],{"class":366},[360,20047,6331],{"class":574},[360,20049,896],{"class":366},[360,20051,20052,20054,20056,20058,20060,20062,20064,20066,20068,20070,20072,20074,20076],{"class":362,"line":6905},[360,20053,18859],{"class":574},[360,20055,19624],{"class":662},[360,20057,401],{"class":582},[360,20059,19947],{"class":578},[360,20061,2385],{"class":366},[360,20063,20043],{"class":662},[360,20065,31],{"class":366},[360,20067,19774],{"class":578},[360,20069,17608],{"class":366},[360,20071,17826],{"class":578},[360,20073,2401],{"class":582},[360,20075,1457],{"class":414},[360,20077,735],{"class":366},[360,20079,20080,20082,20084,20087,20089,20091,20093,20095,20097,20099],{"class":362,"line":6920},[360,20081,18932],{"class":574},[360,20083,19624],{"class":578},[360,20085,20086],{"class":582}," !==",[360,20088,743],{"class":366},[360,20090,20043],{"class":662},[360,20092,19670],{"class":366},[360,20094,17826],{"class":578},[360,20096,2401],{"class":582},[360,20098,1457],{"class":414},[360,20100,801],{"class":366},[360,20102,20103],{"class":362,"line":6942},[360,20104,17658],{"class":366},[360,20106,20107],{"class":362,"line":6974},[360,20108,820],{"class":366},[360,20110,20111],{"class":362,"line":6992},[360,20112,847],{"class":366},[12,20114,20115],{},"Cela me permet de recevoir un SMS de la forme :",[12,20117,20118],{},[69,20119],{"alt":20120,"className":20121,"src":20122},"Les SMS",[73],"\u002FProgrammation\u002Fachat_velo\u002FSMS.png",[33,20124,20126],{"id":20125},"déploiement-de-la-notification","Déploiement de la notification",[12,20128,20129],{},"Pour déployer la notification, il me faut deux endpoints (un pour la partie web, et l'autre pour la notification).",[12,20131,20132,20133,20136,20137,20140],{},"Je garde donc dans le dossier ",[344,20134,20135],{},"src"," le fichier ",[344,20138,20139],{},"main.ts"," pour la partie web et je créé un point d'entrée spécial pour la lambda de notification:",[352,20142,20144],{"className":14027,"code":20143,"language":14029,"meta":291,"style":291},"\nimport { HttpStatus } from '@nestjs\u002Fcommon';\nimport { NestFactory } from '@nestjs\u002Fcore';\nimport { Handler } from 'aws-lambda';\n\nimport { CheckAvailabilityModule } from '.\u002Fcheck-availability.module';\nimport { AvailibilityCheckerService } from '.\u002Favailability\u002Favailibility-checker.service';\n\nlet service: AvailibilityCheckerService;\n\nasync function bootstrap(): Promise\u003CAvailibilityCheckerService> {\n  const appContext = await NestFactory.createApplicationContext(\n    CheckAvailabilityModule,\n  );\n  return appContext.get(AvailibilityCheckerService);\n}\n\nexport const handler: Handler = async () => {\n  service = service ?? (await bootstrap());\n\n  await service.checkAvailibility();\n\n  return {\n    statusCode: HttpStatus.OK,\n  };\n};\n",[344,20145,20146,20150,20168,20186,20204,20208,20226,20243,20247,20259,20263,20284,20305,20312,20316,20332,20336,20340,20363,20384,20388,20402,20406,20412,20428,20433],{"__ignoreMap":291},[360,20147,20148],{"class":362,"line":363},[360,20149,372],{"emptyLinePlaceholder":320},[360,20151,20152,20154,20156,20159,20161,20163,20166],{"class":362,"line":292},[360,20153,14036],{"class":574},[360,20155,5879],{"class":366},[360,20157,20158],{"class":578},"HttpStatus",[360,20160,6108],{"class":366},[360,20162,14065],{"class":574},[360,20164,20165],{"class":397}," '@nestjs\u002Fcommon'",[360,20167,735],{"class":366},[360,20169,20170,20172,20174,20177,20179,20181,20184],{"class":362,"line":375},[360,20171,14036],{"class":574},[360,20173,5879],{"class":366},[360,20175,20176],{"class":578},"NestFactory",[360,20178,6108],{"class":366},[360,20180,14065],{"class":574},[360,20182,20183],{"class":397}," '@nestjs\u002Fcore'",[360,20185,735],{"class":366},[360,20187,20188,20190,20192,20195,20197,20199,20202],{"class":362,"line":433},[360,20189,14036],{"class":574},[360,20191,5879],{"class":366},[360,20193,20194],{"class":578},"Handler",[360,20196,6108],{"class":366},[360,20198,14065],{"class":574},[360,20200,20201],{"class":397}," 'aws-lambda'",[360,20203,735],{"class":366},[360,20205,20206],{"class":362,"line":478},[360,20207,372],{"emptyLinePlaceholder":320},[360,20209,20210,20212,20214,20217,20219,20221,20224],{"class":362,"line":483},[360,20211,14036],{"class":574},[360,20213,5879],{"class":366},[360,20215,20216],{"class":578},"CheckAvailabilityModule",[360,20218,6108],{"class":366},[360,20220,14065],{"class":574},[360,20222,20223],{"class":397}," '.\u002Fcheck-availability.module'",[360,20225,735],{"class":366},[360,20227,20228,20230,20232,20234,20236,20238,20241],{"class":362,"line":489},[360,20229,14036],{"class":574},[360,20231,5879],{"class":366},[360,20233,19286],{"class":578},[360,20235,6108],{"class":366},[360,20237,14065],{"class":574},[360,20239,20240],{"class":397}," '.\u002Favailability\u002Favailibility-checker.service'",[360,20242,735],{"class":366},[360,20244,20245],{"class":362,"line":494},[360,20246,372],{"emptyLinePlaceholder":320},[360,20248,20249,20251,20253,20255,20257],{"class":362,"line":712},[360,20250,6175],{"class":574},[360,20252,19311],{"class":578},[360,20254,2691],{"class":366},[360,20256,19286],{"class":662},[360,20258,735],{"class":366},[360,20260,20261],{"class":362,"line":331},[360,20262,372],{"emptyLinePlaceholder":320},[360,20264,20265,20268,20270,20273,20276,20278,20280,20282],{"class":362,"line":762},[360,20266,20267],{"class":574},"async",[360,20269,16008],{"class":574},[360,20271,20272],{"class":381}," bootstrap",[360,20274,20275],{"class":366},"(): ",[360,20277,17511],{"class":662},[360,20279,1358],{"class":366},[360,20281,19286],{"class":662},[360,20283,2711],{"class":366},[360,20285,20286,20288,20291,20293,20295,20298,20300,20303],{"class":362,"line":781},[360,20287,1244],{"class":574},[360,20289,20290],{"class":662}," appContext",[360,20292,401],{"class":582},[360,20294,15801],{"class":574},[360,20296,20297],{"class":662}," NestFactory",[360,20299,31],{"class":366},[360,20301,20302],{"class":381},"createApplicationContext",[360,20304,1395],{"class":366},[360,20306,20307,20310],{"class":362,"line":804},[360,20308,20309],{"class":578},"    CheckAvailabilityModule",[360,20311,2968],{"class":366},[360,20313,20314],{"class":362,"line":817},[360,20315,7454],{"class":366},[360,20317,20318,20320,20322,20324,20326,20328,20330],{"class":362,"line":823},[360,20319,826],{"class":574},[360,20321,20290],{"class":662},[360,20323,31],{"class":366},[360,20325,17563],{"class":381},[360,20327,671],{"class":366},[360,20329,19286],{"class":578},[360,20331,801],{"class":366},[360,20333,20334],{"class":362,"line":844},[360,20335,847],{"class":366},[360,20337,20338],{"class":362,"line":1441},[360,20339,372],{"emptyLinePlaceholder":320},[360,20341,20342,20344,20346,20349,20351,20353,20355,20357,20359,20361],{"class":362,"line":1462},[360,20343,575],{"class":574},[360,20345,1088],{"class":574},[360,20347,20348],{"class":381}," handler",[360,20350,2691],{"class":366},[360,20352,20194],{"class":662},[360,20354,401],{"class":582},[360,20356,16005],{"class":574},[360,20358,6328],{"class":366},[360,20360,6331],{"class":574},[360,20362,896],{"class":366},[360,20364,20365,20368,20370,20372,20375,20377,20380,20382],{"class":362,"line":1485},[360,20366,20367],{"class":578},"  service",[360,20369,401],{"class":582},[360,20371,19311],{"class":578},[360,20373,20374],{"class":582}," ??",[360,20376,743],{"class":366},[360,20378,20379],{"class":574},"await",[360,20381,20272],{"class":381},[360,20383,841],{"class":366},[360,20385,20386],{"class":362,"line":1497},[360,20387,372],{"emptyLinePlaceholder":320},[360,20389,20390,20393,20395,20397,20400],{"class":362,"line":3161},[360,20391,20392],{"class":574},"  await",[360,20394,19311],{"class":662},[360,20396,31],{"class":366},[360,20398,20399],{"class":381},"checkAvailibility",[360,20401,2204],{"class":366},[360,20403,20404],{"class":362,"line":3167},[360,20405,372],{"emptyLinePlaceholder":320},[360,20407,20408,20410],{"class":362,"line":3194},[360,20409,826],{"class":574},[360,20411,896],{"class":366},[360,20413,20414,20417,20419,20421,20423,20426],{"class":362,"line":3224},[360,20415,20416],{"class":578},"    statusCode",[360,20418,2691],{"class":366},[360,20420,20158],{"class":662},[360,20422,31],{"class":366},[360,20424,20425],{"class":578},"OK",[360,20427,2968],{"class":366},[360,20429,20430],{"class":362,"line":3239},[360,20431,20432],{"class":366},"  };\n",[360,20434,20435],{"class":362,"line":3256},[360,20436,1036],{"class":366},[12,20438,20439],{},"Contrairement à la partie WEB ce service ne démarre pas de serveur Web (ni la partie express).",[12,20441,20442],{},"Le paramétrage de la lambda se fait donc avec le fichier serverless.yml dont voici les principales modifications:",[352,20444,20446],{"className":17947,"code":20445,"language":17949,"meta":291,"style":291},"service: decathlon\nframeworkVersion: \"2\"\n\nplugins:\n  - serverless-dynamodb-local\n  - serverless-plugin-log-retention\n  - serverless-offline\n  - serverless-domain-manager\n\ncustom:\n  region: eu-central-1\n  logRetentionInDays: 7\n  serverless-offline:\n    noPrependStageInUrl: true\n    allowCache: false\n  decathlonTable:\n    name: ${self:provider.stage}-decathlon\n    arn: !GetAtt decathlonTable.Arn\n  dynamodb:\n    stages:\n      - ${self:provider.stage}\n    start:\n      migrate: true\n  endpoints:\n    dynamodbURL: \"http:\u002F\u002Flocalhost:8000\"\n  customDomain: ...\n\nprovider:\n  name: aws\n  region: ${self:custom.region}\n  runtime: nodejs12.x\n  lambdaHashingVersion: \"20201221\"\n  stage: ${opt:stage, 'dev'}\n  environment:\n    DYNAMODB_ENDPOINT: ${self:custom.endpoints.dynamodbURL}\n    DECATHLON_TABLE_NAME: ${self:custom.decathlonTable.name}\n    NODE_OPTIONS: \"--max-http-header-size=80000\"\n  iamRoleStatements: ${file(delivery\u002Froles.yml)}\n\npackage:\n  individually: true\n  patterns:\n    - \"!.\u002F**\"\n\nfunctions:\n  api:\n    handler: dist\u002Fmain.handler\n    environment:\n      region: ${self:custom.region}\n    events:\n      - http:\n          path: \u002F\n          method: ANY\n      - http:\n          path: \u002F{proxy+}\n          method: ANY\n    package:\n      patterns:\n        - dist\u002Fmain.js\n        - views\u002F**\n\n  check-availability:\n    handler: dist\u002Fcheck-availability.handler\n    events:\n      - schedule: rate(30 minutes)\n    package:\n      patterns:\n        - dist\u002Fcheck-availability.js\n\nresources:\n  Resources:\n    decathlonTable: ${file(delivery\u002FdecathlonTable.yml):decathlonTable}\n",[344,20447,20448,20457,20465,20469,20475,20482,20488,20494,20500,20504,20510,20518,20526,20532,20540,20548,20555,20565,20578,20585,20592,20599,20606,20615,20622,20632,20640,20644,20650,20658,20666,20674,20682,20690,20696,20706,20716,20724,20734,20738,20744,20753,20759,20765,20769,20775,20781,20789,20795,20803,20809,20817,20825,20833,20841,20849,20857,20864,20871,20879,20885,20889,20896,20905,20911,20923,20929,20935,20942,20946,20953,20960],{"__ignoreMap":291},[360,20449,20450,20452,20454],{"class":362,"line":363},[360,20451,15125],{"class":578},[360,20453,2691],{"class":366},[360,20455,20456],{"class":397},"decathlon\n",[360,20458,20459,20461,20463],{"class":362,"line":292},[360,20460,17965],{"class":578},[360,20462,2691],{"class":366},[360,20464,17970],{"class":397},[360,20466,20467],{"class":362,"line":375},[360,20468,372],{"emptyLinePlaceholder":320},[360,20470,20471,20473],{"class":362,"line":433},[360,20472,17979],{"class":578},[360,20474,17982],{"class":366},[360,20476,20477,20479],{"class":362,"line":478},[360,20478,17987],{"class":366},[360,20480,20481],{"class":397},"serverless-dynamodb-local\n",[360,20483,20484,20486],{"class":362,"line":483},[360,20485,17987],{"class":366},[360,20487,17990],{"class":397},[360,20489,20490,20492],{"class":362,"line":489},[360,20491,17987],{"class":366},[360,20493,17997],{"class":397},[360,20495,20496,20498],{"class":362,"line":494},[360,20497,17987],{"class":366},[360,20499,18004],{"class":397},[360,20501,20502],{"class":362,"line":712},[360,20503,372],{"emptyLinePlaceholder":320},[360,20505,20506,20508],{"class":362,"line":331},[360,20507,18013],{"class":578},[360,20509,17982],{"class":366},[360,20511,20512,20514,20516],{"class":362,"line":762},[360,20513,18020],{"class":578},[360,20515,2691],{"class":366},[360,20517,18025],{"class":397},[360,20519,20520,20522,20524],{"class":362,"line":781},[360,20521,18030],{"class":578},[360,20523,2691],{"class":366},[360,20525,18035],{"class":414},[360,20527,20528,20530],{"class":362,"line":804},[360,20529,18040],{"class":578},[360,20531,17982],{"class":366},[360,20533,20534,20536,20538],{"class":362,"line":817},[360,20535,18047],{"class":578},[360,20537,2691],{"class":366},[360,20539,18052],{"class":414},[360,20541,20542,20544,20546],{"class":362,"line":823},[360,20543,18057],{"class":578},[360,20545,2691],{"class":366},[360,20547,18062],{"class":414},[360,20549,20550,20553],{"class":362,"line":844},[360,20551,20552],{"class":578},"  decathlonTable",[360,20554,17982],{"class":366},[360,20556,20557,20560,20562],{"class":362,"line":1441},[360,20558,20559],{"class":578},"    name",[360,20561,2691],{"class":366},[360,20563,20564],{"class":397},"${self:provider.stage}-decathlon\n",[360,20566,20567,20570,20572,20575],{"class":362,"line":1462},[360,20568,20569],{"class":578},"    arn",[360,20571,2691],{"class":366},[360,20573,20574],{"class":574},"!GetAtt",[360,20576,20577],{"class":397}," decathlonTable.Arn\n",[360,20579,20580,20583],{"class":362,"line":1485},[360,20581,20582],{"class":578},"  dynamodb",[360,20584,17982],{"class":366},[360,20586,20587,20590],{"class":362,"line":1497},[360,20588,20589],{"class":578},"    stages",[360,20591,17982],{"class":366},[360,20593,20594,20596],{"class":362,"line":3161},[360,20595,18319],{"class":366},[360,20597,20598],{"class":397},"${self:provider.stage}\n",[360,20600,20601,20604],{"class":362,"line":3167},[360,20602,20603],{"class":578},"    start",[360,20605,17982],{"class":366},[360,20607,20608,20611,20613],{"class":362,"line":3194},[360,20609,20610],{"class":578},"      migrate",[360,20612,2691],{"class":366},[360,20614,18052],{"class":414},[360,20616,20617,20620],{"class":362,"line":3224},[360,20618,20619],{"class":578},"  endpoints",[360,20621,17982],{"class":366},[360,20623,20624,20627,20629],{"class":362,"line":3239},[360,20625,20626],{"class":578},"    dynamodbURL",[360,20628,2691],{"class":366},[360,20630,20631],{"class":397},"\"http:\u002F\u002Flocalhost:8000\"\n",[360,20633,20634,20636,20638],{"class":362,"line":3256},[360,20635,18067],{"class":578},[360,20637,2691],{"class":366},[360,20639,3164],{"class":414},[360,20641,20642],{"class":362,"line":3276},[360,20643,372],{"emptyLinePlaceholder":320},[360,20645,20646,20648],{"class":362,"line":3281},[360,20647,18156],{"class":578},[360,20649,17982],{"class":366},[360,20651,20652,20654,20656],{"class":362,"line":3305},[360,20653,18163],{"class":578},[360,20655,2691],{"class":366},[360,20657,18168],{"class":397},[360,20659,20660,20662,20664],{"class":362,"line":3320},[360,20661,18020],{"class":578},[360,20663,2691],{"class":366},[360,20665,18177],{"class":397},[360,20667,20668,20670,20672],{"class":362,"line":3325},[360,20669,18182],{"class":578},[360,20671,2691],{"class":366},[360,20673,18187],{"class":397},[360,20675,20676,20678,20680],{"class":362,"line":3361},[360,20677,18192],{"class":578},[360,20679,2691],{"class":366},[360,20681,18197],{"class":397},[360,20683,20684,20686,20688],{"class":362,"line":3380},[360,20685,18202],{"class":578},[360,20687,2691],{"class":366},[360,20689,18207],{"class":397},[360,20691,20692,20694],{"class":362,"line":3405},[360,20693,18212],{"class":578},[360,20695,17982],{"class":366},[360,20697,20698,20701,20703],{"class":362,"line":3411},[360,20699,20700],{"class":578},"    DYNAMODB_ENDPOINT",[360,20702,2691],{"class":366},[360,20704,20705],{"class":397},"${self:custom.endpoints.dynamodbURL}\n",[360,20707,20708,20711,20713],{"class":362,"line":3426},[360,20709,20710],{"class":578},"    DECATHLON_TABLE_NAME",[360,20712,2691],{"class":366},[360,20714,20715],{"class":397},"${self:custom.decathlonTable.name}\n",[360,20717,20718,20720,20722],{"class":362,"line":3432},[360,20719,18219],{"class":578},[360,20721,2691],{"class":366},[360,20723,18224],{"class":397},[360,20725,20726,20729,20731],{"class":362,"line":3438},[360,20727,20728],{"class":578},"  iamRoleStatements",[360,20730,2691],{"class":366},[360,20732,20733],{"class":397},"${file(delivery\u002Froles.yml)}\n",[360,20735,20736],{"class":362,"line":3443},[360,20737,372],{"emptyLinePlaceholder":320},[360,20739,20740,20742],{"class":362,"line":3462},[360,20741,14276],{"class":578},[360,20743,17982],{"class":366},[360,20745,20746,20749,20751],{"class":362,"line":3467},[360,20747,20748],{"class":578},"  individually",[360,20750,2691],{"class":366},[360,20752,18052],{"class":414},[360,20754,20755,20757],{"class":362,"line":3472},[360,20756,18239],{"class":578},[360,20758,17982],{"class":366},[360,20760,20761,20763],{"class":362,"line":3495},[360,20762,18246],{"class":366},[360,20764,18249],{"class":397},[360,20766,20767],{"class":362,"line":3500},[360,20768,372],{"emptyLinePlaceholder":320},[360,20770,20771,20773],{"class":362,"line":3505},[360,20772,18272],{"class":578},[360,20774,17982],{"class":366},[360,20776,20777,20779],{"class":362,"line":3530},[360,20778,18279],{"class":578},[360,20780,17982],{"class":366},[360,20782,20783,20785,20787],{"class":362,"line":3545},[360,20784,18286],{"class":578},[360,20786,2691],{"class":366},[360,20788,18291],{"class":397},[360,20790,20791,20793],{"class":362,"line":3558},[360,20792,18296],{"class":578},[360,20794,17982],{"class":366},[360,20796,20797,20799,20801],{"class":362,"line":3573},[360,20798,18303],{"class":578},[360,20800,2691],{"class":366},[360,20802,18177],{"class":397},[360,20804,20805,20807],{"class":362,"line":3578},[360,20806,18312],{"class":578},[360,20808,17982],{"class":366},[360,20810,20811,20813,20815],{"class":362,"line":3583},[360,20812,18319],{"class":366},[360,20814,16319],{"class":578},[360,20816,17982],{"class":366},[360,20818,20819,20821,20823],{"class":362,"line":6893},[360,20820,18328],{"class":578},[360,20822,2691],{"class":366},[360,20824,18333],{"class":397},[360,20826,20827,20829,20831],{"class":362,"line":6899},[360,20828,18338],{"class":578},[360,20830,2691],{"class":366},[360,20832,18343],{"class":397},[360,20834,20835,20837,20839],{"class":362,"line":6905},[360,20836,18319],{"class":366},[360,20838,16319],{"class":578},[360,20840,17982],{"class":366},[360,20842,20843,20845,20847],{"class":362,"line":6920},[360,20844,18328],{"class":578},[360,20846,2691],{"class":366},[360,20848,18360],{"class":397},[360,20850,20851,20853,20855],{"class":362,"line":6942},[360,20852,18338],{"class":578},[360,20854,2691],{"class":366},[360,20856,18343],{"class":397},[360,20858,20859,20862],{"class":362,"line":6974},[360,20860,20861],{"class":578},"    package",[360,20863,17982],{"class":366},[360,20865,20866,20869],{"class":362,"line":6992},[360,20867,20868],{"class":578},"      patterns",[360,20870,17982],{"class":366},[360,20872,20873,20876],{"class":362,"line":6997},[360,20874,20875],{"class":366},"        - ",[360,20877,20878],{"class":397},"dist\u002Fmain.js\n",[360,20880,20881,20883],{"class":362,"line":7002},[360,20882,20875],{"class":366},[360,20884,18263],{"class":397},[360,20886,20887],{"class":362,"line":7008},[360,20888,372],{"emptyLinePlaceholder":320},[360,20890,20891,20894],{"class":362,"line":7041},[360,20892,20893],{"class":578},"  check-availability",[360,20895,17982],{"class":366},[360,20897,20898,20900,20902],{"class":362,"line":7047},[360,20899,18286],{"class":578},[360,20901,2691],{"class":366},[360,20903,20904],{"class":397},"dist\u002Fcheck-availability.handler\n",[360,20906,20907,20909],{"class":362,"line":7058},[360,20908,18312],{"class":578},[360,20910,17982],{"class":366},[360,20912,20913,20915,20918,20920],{"class":362,"line":7064},[360,20914,18319],{"class":366},[360,20916,20917],{"class":578},"schedule",[360,20919,2691],{"class":366},[360,20921,20922],{"class":397},"rate(30 minutes)\n",[360,20924,20925,20927],{"class":362,"line":7086},[360,20926,20861],{"class":578},[360,20928,17982],{"class":366},[360,20930,20931,20933],{"class":362,"line":7091},[360,20932,20868],{"class":578},[360,20934,17982],{"class":366},[360,20936,20937,20939],{"class":362,"line":7126},[360,20938,20875],{"class":366},[360,20940,20941],{"class":397},"dist\u002Fcheck-availability.js\n",[360,20943,20944],{"class":362,"line":7165},[360,20945,372],{"emptyLinePlaceholder":320},[360,20947,20948,20951],{"class":362,"line":7170},[360,20949,20950],{"class":578},"resources",[360,20952,17982],{"class":366},[360,20954,20955,20958],{"class":362,"line":7176},[360,20956,20957],{"class":578},"  Resources",[360,20959,17982],{"class":366},[360,20961,20962,20965,20967],{"class":362,"line":7182},[360,20963,20964],{"class":578},"    decathlonTable",[360,20966,2691],{"class":366},[360,20968,20969],{"class":397},"${file(delivery\u002FdecathlonTable.yml):decathlonTable}\n",[12,20971,20972],{},"Il ne reste plus qu'à déployer et profiter de l'envoi de SMS.",[33,20974,20976],{"id":20975},"optimisation","Optimisation",[12,20978,20979],{},"Sur AWS, le coût d'une lambda est lié au nombre d'exécutions mais aussi au temps d'exécution. Il est important que le temps d'exécution soit le plus\nrapide possible.",[12,20981,20982],{},"Ici dans notre cas le temps le temps de traitement sera lié au temps de réponse de la requête HTTP extérieur à notre site. Afin de parfaire notre petite\napplication de bonne pratique, nous allons utiliser webpack (côté serveur) afin d'optimiser le temps de démarrage de notre application.",[12,20984,20985,20986,20989],{},"Grâce au framework Nest.JS, cela est très facile à faire, dans le fichier ",[344,20987,20988],{},"nest-cli.json",", nous allons demander à Nest.JS de générer un bundle webpack:",[352,20991,20993],{"className":16331,"code":20992,"language":16333,"meta":291,"style":291},"{\n  \"collection\": \"@nestjs\u002Fschematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"webpack\": true\n  }\n}\n",[344,20994,20995,20999,21011,21023,21030,21039,21043],{"__ignoreMap":291},[360,20996,20997],{"class":362,"line":363},[360,20998,16340],{"class":366},[360,21000,21001,21004,21006,21009],{"class":362,"line":292},[360,21002,21003],{"class":578},"  \"collection\"",[360,21005,2691],{"class":366},[360,21007,21008],{"class":397},"\"@nestjs\u002Fschematics\"",[360,21010,2968],{"class":366},[360,21012,21013,21016,21018,21021],{"class":362,"line":375},[360,21014,21015],{"class":578},"  \"sourceRoot\"",[360,21017,2691],{"class":366},[360,21019,21020],{"class":397},"\"src\"",[360,21022,2968],{"class":366},[360,21024,21025,21028],{"class":362,"line":433},[360,21026,21027],{"class":578},"  \"compilerOptions\"",[360,21029,6359],{"class":366},[360,21031,21032,21035,21037],{"class":362,"line":478},[360,21033,21034],{"class":578},"    \"webpack\"",[360,21036,2691],{"class":366},[360,21038,18052],{"class":414},[360,21040,21041],{"class":362,"line":483},[360,21042,820],{"class":366},[360,21044,21045],{"class":362,"line":489},[360,21046,847],{"class":366},[12,21048,21049,21050,2198],{},"Par défaut, webpack ne crée un bundle qu'avec le source de notre application (et donc sans les modules node). Ce qui nous intéresse c'est de faire un bundle\ncomprenant notre application ainsi que les modules node (on peut voir un bench sur la ",[47,21051,21053],{"href":17942,"rel":21052},[51],"FAQ Nest.JS",[12,21055,21056,21057,21060],{},"Pour cela nous allons créer un fichier ",[344,21058,21059],{},"webpack.config.js"," qui sera pris automatiquement (inspiré de la documentation mais modifié pour posséder plusieurs points\nd'entrées, on exclut aussi le framework AWS qui est déjà inclus dans AWS):",[352,21062,21064],{"className":14027,"code":21063,"language":14029,"meta":291,"style":291},"module.exports = (options, webpack) => {\n  const lazyImports = [\n    \"@nestjs\u002Fmicroservices\u002Fmicroservices-module\",\n    \"@nestjs\u002Fwebsockets\u002Fsocket-module\",\n  ];\n\n  return {\n    ...options,\n    entry: {\n      main: options.entry,\n      \"check-availability\": options.entry.replace(\"main\", \"check-availability\"),\n    },\n    externals: [\"aws-sdk\"],\n    output: {\n      filename: \"[name].js\",\n      libraryTarget: \"commonjs2\",\n    },\n    plugins: [\n      ...options.plugins,\n      new webpack.IgnorePlugin({\n        checkResource(resource) {\n          if (lazyImports.includes(resource)) {\n            try {\n              require.resolve(resource);\n            } catch (err) {\n              return true;\n            }\n          }\n          return false;\n        },\n      }),\n    ],\n  };\n};\n",[344,21065,21066,21093,21105,21112,21119,21124,21128,21134,21143,21150,21166,21196,21200,21212,21219,21231,21243,21247,21254,21266,21281,21293,21315,21322,21338,21351,21360,21364,21369,21378,21382,21387,21391,21395],{"__ignoreMap":291},[360,21067,21068,21071,21073,21076,21078,21080,21082,21084,21087,21089,21091],{"class":362,"line":363},[360,21069,21070],{"class":662},"module",[360,21072,31],{"class":366},[360,21074,21075],{"class":662},"exports",[360,21077,401],{"class":582},[360,21079,743],{"class":366},[360,21081,15819],{"class":677},[360,21083,2311],{"class":366},[360,21085,21086],{"class":677},"webpack",[360,21088,3972],{"class":366},[360,21090,6331],{"class":574},[360,21092,896],{"class":366},[360,21094,21095,21097,21100,21102],{"class":362,"line":292},[360,21096,1244],{"class":574},[360,21098,21099],{"class":662}," lazyImports",[360,21101,401],{"class":582},[360,21103,21104],{"class":366}," [\n",[360,21106,21107,21110],{"class":362,"line":375},[360,21108,21109],{"class":397},"    \"@nestjs\u002Fmicroservices\u002Fmicroservices-module\"",[360,21111,2968],{"class":366},[360,21113,21114,21117],{"class":362,"line":433},[360,21115,21116],{"class":397},"    \"@nestjs\u002Fwebsockets\u002Fsocket-module\"",[360,21118,2968],{"class":366},[360,21120,21121],{"class":362,"line":478},[360,21122,21123],{"class":366},"  ];\n",[360,21125,21126],{"class":362,"line":483},[360,21127,372],{"emptyLinePlaceholder":320},[360,21129,21130,21132],{"class":362,"line":489},[360,21131,826],{"class":574},[360,21133,896],{"class":366},[360,21135,21136,21139,21141],{"class":362,"line":494},[360,21137,21138],{"class":366},"    ...",[360,21140,15819],{"class":578},[360,21142,2968],{"class":366},[360,21144,21145,21148],{"class":362,"line":712},[360,21146,21147],{"class":578},"    entry",[360,21149,6359],{"class":366},[360,21151,21152,21155,21157,21159,21161,21164],{"class":362,"line":331},[360,21153,21154],{"class":578},"      main",[360,21156,2691],{"class":366},[360,21158,15819],{"class":662},[360,21160,31],{"class":366},[360,21162,21163],{"class":578},"entry",[360,21165,2968],{"class":366},[360,21167,21168,21171,21173,21175,21177,21179,21181,21184,21186,21189,21191,21194],{"class":362,"line":762},[360,21169,21170],{"class":397},"      \"check-availability\"",[360,21172,2691],{"class":366},[360,21174,15819],{"class":662},[360,21176,31],{"class":366},[360,21178,21163],{"class":662},[360,21180,31],{"class":366},[360,21182,21183],{"class":381},"replace",[360,21185,671],{"class":366},[360,21187,21188],{"class":397},"\"main\"",[360,21190,2311],{"class":366},[360,21192,21193],{"class":397},"\"check-availability\"",[360,21195,5405],{"class":366},[360,21197,21198],{"class":362,"line":781},[360,21199,6505],{"class":366},[360,21201,21202,21205,21207,21210],{"class":362,"line":804},[360,21203,21204],{"class":578},"    externals",[360,21206,4418],{"class":366},[360,21208,21209],{"class":397},"\"aws-sdk\"",[360,21211,5436],{"class":366},[360,21213,21214,21217],{"class":362,"line":817},[360,21215,21216],{"class":578},"    output",[360,21218,6359],{"class":366},[360,21220,21221,21224,21226,21229],{"class":362,"line":823},[360,21222,21223],{"class":578},"      filename",[360,21225,2691],{"class":366},[360,21227,21228],{"class":397},"\"[name].js\"",[360,21230,2968],{"class":366},[360,21232,21233,21236,21238,21241],{"class":362,"line":844},[360,21234,21235],{"class":578},"      libraryTarget",[360,21237,2691],{"class":366},[360,21239,21240],{"class":397},"\"commonjs2\"",[360,21242,2968],{"class":366},[360,21244,21245],{"class":362,"line":1441},[360,21246,6505],{"class":366},[360,21248,21249,21252],{"class":362,"line":1462},[360,21250,21251],{"class":578},"    plugins",[360,21253,16499],{"class":366},[360,21255,21256,21258,21260,21262,21264],{"class":362,"line":1485},[360,21257,17729],{"class":366},[360,21259,15819],{"class":662},[360,21261,31],{"class":366},[360,21263,17979],{"class":578},[360,21265,2968],{"class":366},[360,21267,21268,21271,21274,21276,21279],{"class":362,"line":1497},[360,21269,21270],{"class":574},"      new",[360,21272,21273],{"class":662}," webpack",[360,21275,31],{"class":366},[360,21277,21278],{"class":381},"IgnorePlugin",[360,21280,17629],{"class":366},[360,21282,21283,21286,21288,21291],{"class":362,"line":3161},[360,21284,21285],{"class":381},"        checkResource",[360,21287,671],{"class":366},[360,21289,21290],{"class":677},"resource",[360,21292,681],{"class":366},[360,21294,21295,21298,21300,21303,21305,21308,21310,21312],{"class":362,"line":3167},[360,21296,21297],{"class":574},"          if",[360,21299,743],{"class":366},[360,21301,21302],{"class":662},"lazyImports",[360,21304,31],{"class":366},[360,21306,21307],{"class":381},"includes",[360,21309,671],{"class":366},[360,21311,21290],{"class":578},[360,21313,21314],{"class":366},")) {\n",[360,21316,21317,21320],{"class":362,"line":3194},[360,21318,21319],{"class":574},"            try",[360,21321,896],{"class":366},[360,21323,21324,21327,21329,21332,21334,21336],{"class":362,"line":3224},[360,21325,21326],{"class":662},"              require",[360,21328,31],{"class":366},[360,21330,21331],{"class":381},"resolve",[360,21333,671],{"class":366},[360,21335,21290],{"class":578},[360,21337,801],{"class":366},[360,21339,21340,21343,21345,21347,21349],{"class":362,"line":3239},[360,21341,21342],{"class":366},"            } ",[360,21344,7242],{"class":574},[360,21346,743],{"class":366},[360,21348,5057],{"class":578},[360,21350,681],{"class":366},[360,21352,21353,21356,21358],{"class":362,"line":3256},[360,21354,21355],{"class":574},"              return",[360,21357,3134],{"class":414},[360,21359,735],{"class":366},[360,21361,21362],{"class":362,"line":3276},[360,21363,3435],{"class":366},[360,21365,21366],{"class":362,"line":3281},[360,21367,21368],{"class":366},"          }\n",[360,21370,21371,21374,21376],{"class":362,"line":3305},[360,21372,21373],{"class":574},"          return",[360,21375,3315],{"class":414},[360,21377,735],{"class":366},[360,21379,21380],{"class":362,"line":3320},[360,21381,11013],{"class":366},[360,21383,21384],{"class":362,"line":3325},[360,21385,21386],{"class":366},"      }),\n",[360,21388,21389],{"class":362,"line":3361},[360,21390,17420],{"class":366},[360,21392,21393],{"class":362,"line":3380},[360,21394,20432],{"class":366},[360,21396,21397],{"class":362,"line":3405},[360,21398,1036],{"class":366},[12,21400,21401],{},"A l'heure actuelle (mais principalement à cause du temps d'exécution de la requête), la requête prend environ 1s:",[352,21403,21406],{"className":21404,"code":21405,"language":7016,"meta":291,"style":291},"language-log shiki shiki-themes one-dark-pro","REPORT RequestId: eaa2b5a3-a754-4b1f-adcc-22ca3c6045aa Duration: 984.41 ms Billed Duration: 985 ms Memory Size: 1024 MB Max Memory Used: 109 MB Init Duration: 540.30 ms\n",[344,21407,21408],{"__ignoreMap":291},[360,21409,21410,21413,21416,21419,21422,21424,21427,21430,21433,21436,21439,21442,21445,21448,21451,21453,21456],{"class":362,"line":363},[360,21411,21412],{"class":366},"REPORT RequestId: ",[360,21414,21415],{"class":414},"eaa2b5a3-a754-4b1f-adcc-22ca3c6045aa",[360,21417,21418],{"class":366}," Duration: ",[360,21420,21421],{"class":414},"984",[360,21423,31],{"class":366},[360,21425,21426],{"class":414},"41",[360,21428,21429],{"class":366}," ms Billed Duration: ",[360,21431,21432],{"class":414},"985",[360,21434,21435],{"class":366}," ms Memory Size: ",[360,21437,21438],{"class":414},"1024",[360,21440,21441],{"class":366}," MB Max Memory Used: ",[360,21443,21444],{"class":414},"109",[360,21446,21447],{"class":366}," MB Init Duration: ",[360,21449,21450],{"class":414},"540",[360,21452,31],{"class":366},[360,21454,21455],{"class":414},"30",[360,21457,21458],{"class":366}," ms\n",[33,21460,21462],{"id":21461},"le-coût-du-projet","Le coût du projet",[12,21464,21465],{},"Grâce au Free-Tiers d'AWS, ce qui me coûte réellement de l'argent dans ce projet est SNS (qui sert à l'envoi de SMS). L'autre coût est relatif à Route 53 car j'ai déployé le site\ndans un sous-domaine.",[12,21467,21468],{},"Au 29 Août 2021, je vais avoir dépensé 7,34$ pour me faire plaisir (j'aurais pu le déployer sur mes propres serveurs dédiés) et pour pouvoir m'acheter un vélo sans\nattendre que le site m'envoie un mail ou qu'il y ait suffisamment de stock pendant suffisamment longtemps pour que je puisse voir le vélo, ou l'acheter en magasin.",[12,21470,21471],{},[69,21472],{"alt":21473,"className":21474,"src":21475},"Coût du projet",[73],"\u002FProgrammation\u002Fachat_velo\u002Fcout.png",[33,21477,21479],{"id":21478},"bilan","Bilan",[12,21481,21482],{},"On est fin septembre, j'ai reçu mon vélo et j'ai pu rouler plusieurs semaines avec (Je l'ai recu début septembre).",[12,21484,21485],{},"Cela a commencé par une notification à 11h59 indiquant que 4 exemplaires avaient été ajoutés au site. J'ai pu le commander dans la foulée. A 14h, tous les exemplaires avaient été vendus.\nJe devais partir manger quand j'ai reçu la notification.",[12,21487,21488],{},"Si je n'avais pas développé ce petit programme, je n'aurais jamais su que des vélos étaient en stock, car je n'ai jamais reçu le fameux mail. De plus en travaillant\n(car je suis revenu de vacances depuis) je ne peux pas rafraîchir la page en continu (1 fois le matin, 1 fois le soir).",[12,21490,21491],{},"Bref, est-ce que le mail que doit nous envoyer le site est de la poudre aux yeux ? Se sert-il d'une file d'attente (et dans ce cas je m'excuse auprès de celui que\nj'ai doublé) ? Ou n'est-il envoyé que quand il y a plus de 10 exemplaires qui arrivent sur le site ?",[12,21493,21494],{},"Depuis j'ai désactivé le programme. Avant j'avais pu voir le stock bouger rapidement sur les VTT en XL et sur le VTC en XL et en S. Ce que je peux dire c'est qu'une\ntrentaine de vélo ajoutés sur le VTT le soir à 21h partent comme des petits pains. Il n'en restait plus le lendemin à 12h...",[12,21496,21497],{},"Au delà de l'achat du vélo, j'ai été content de pouvoir mettre un site en production rapidement et quasi-gratuitement (si on ne compte pas les SMS). Je me demande ce\nque m'aurais coûté le même site au delà de la période des 1 an (après la fin du free-tiers).",[21499,21500,21503,21508],"section",{"className":21501,"dataFootnotes":291},[21502],"footnotes",[33,21504,21507],{"className":21505,"id":15686},[21506],"sr-only","Footnotes",[13835,21509,21510,21521],{},[143,21511,21513,21514],{"id":21512},"user-content-fn-1","Certains me conseillent des petits magasins de vélo, d'autres des VTCAE à plus de 5 000 €. Bref, nous ne sommes pas là pour parler de mon choix d'enseigne. Mais si vous voulez tout savoir, c'est une question pratique. Il est à coté de chez moi. ",[47,21515,21520],{"href":21516,"ariaLabel":21517,"className":21518,"dataFootnoteBackref":291},"#user-content-fnref-1","Back to reference 1",[21519],"data-footnote-backref","↩",[143,21522,21524,21529],{"id":21523},"user-content-fn-2",[123,21525,21526],{},[12,21527,21528],{},"Hello friend jsdom only handles static html, to make the click event you will need a headless browser for scraping the web. There are several one of them is the Puppeter that uses the chorme in the background.",[47,21530,21520],{"href":21531,"ariaLabel":21532,"className":21533,"dataFootnoteBackref":291},"#user-content-fnref-2","Back to reference 2",[21519],[1613,21535,21536],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sLaUg, html code.shiki .sLaUg{--shiki-default:#FFFFFF}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .shdRp, html code.shiki .shdRp{--shiki-default:#C678DD;--shiki-default-font-style:italic}html pre.shiki code .sKU4T, html code.shiki .sKU4T{--shiki-default:#E5C07B;--shiki-default-font-style:italic}",{"title":291,"searchDepth":292,"depth":292,"links":21538},[21539,21540,21542,21543,21544,21545,21546,21547,21548,21549,21550,21551,21552],{"id":15706,"depth":292,"text":15707},{"id":15737,"depth":292,"text":21541},"La 1er version",{"id":16286,"depth":292,"text":16287},{"id":16429,"depth":292,"text":16430},{"id":16781,"depth":292,"text":16782},{"id":17927,"depth":292,"text":17928},{"id":18393,"depth":292,"text":18394},{"id":18418,"depth":292,"text":18419},{"id":20125,"depth":292,"text":20126},{"id":20975,"depth":292,"text":20976},{"id":21461,"depth":292,"text":21462},{"id":21478,"depth":292,"text":21479},{"id":15686,"depth":292,"text":21507},"2021-09-27",{"type":9,"value":21555},[21556,21558,21562,21569,21571,21575,21577],[12,21557,15668],{},[12,21559,15671,21560,15675],{},[129,21561,15674],{},[12,21563,15678,21564],{},[15680,21565,21566],{},[47,21567,1944],{"href":15684,"ariaDescribedBy":21568,"dataFootnoteRef":291,"id":15687},[15686],[12,21570,15690],{},[12,21572,15693,21573,15697],{},[105,21574,15696],{},[12,21576,15700],{},[12,21578,15703],{},{"planet":320},"\u002Fpost\u002Fachat_velo",{"title":15663,"description":15668},"achat_velo","posts\u002FProgrammation\u002F2021-09-27_achat_velo",[1765,1766,21585,21586,21587,21588],"aws","web","velo","sms","p5JgMwprkltEBjhdZdpkmC59vL1CqDYiHhoE51Qhs0U",{"id":21591,"title":21592,"author":7,"body":21593,"category":300,"categorySlug":301,"date":24634,"description":21597,"excerpt":24635,"extension":317,"location":318,"meta":24657,"navigation":320,"path":24658,"published":320,"seo":24659,"slug":24660,"stem":24661,"tags":24662,"timeToRead":3167,"__hash__":24665},"posts\u002Fposts\u002FProgrammation\u002F2020-11-29_creation-api-3.md","Comment créer une bonne API Web - Partie 3",{"type":9,"value":21594,"toc":24613},[21595,21598,21601,21621,21624,21628,21631,21639,21642,21648,21651,21654,21657,21788,21795,21801,21804,21970,21973,21976,21984,21988,21991,21994,21997,22000,22003,22011,22014,22018,22021,22024,22134,22137,22140,22147,22150,22158,22162,22169,22177,22181,22184,22447,22450,22467,22476,22479,22511,22514,22531,22534,22537,22613,22616,22627,22639,22683,22686,22835,22838,22842,22845,22848,22851,22854,22857,22861,22926,22929,22932,22938,22942,22945,23020,23033,23038,23041,23170,23177,23181,23184,23192,23205,23214,23217,23221,23224,23227,23230,23241,23247,23274,23390,23398,23402,23405,23408,23414,23425,23593,23602,23606,23615,23618,23683,23686,23695,23753,23756,23853,23859,23863,23868,23871,23882,23885,23893,23897,23900,23918,23922,23928,23931,24027,24030,24033,24036,24075,24078,24258,24264,24267,24275,24278,24287,24290,24298,24302,24309,24312,24315,24318,24361,24364,24372,24546,24553,24555,24558,24561,24565,24610],[12,21596,21597],{},"Bonjour,",[12,21599,21600],{},"Cet article fait partie d'un ensemble:",[140,21602,21603,21609,21615],{},[143,21604,21605],{},[47,21606,21608],{"href":21607},"\u002Fpost\u002Fcreation-api-1\u002F","Généralités sur l'écriture d'une bonne API",[143,21610,21611],{},[47,21612,21614],{"href":21613},"\u002Fpost\u002Fcreation-api-2\u002F","Qu'est ce qu'une API REST",[143,21616,21617],{},[47,21618,21620],{"href":21619},"\u002Fpost\u002Fcreation-api-3\u002F","Qu'est ce qu'une API GraphQL",[12,21622,21623],{},"Il y a quelques années de cela, j'ai souhaité résoudre un problème que j'ai depuis longtemps avec les API REST: comment bien\nnormaliser les tris, les projections, et les filtres. En effectuant mes recherches je suis tombé sur deux frameworks qui permettent\nde résoudre le problème des projections.",[33,21625,21627],{"id":21626},"quest-quune-api-falcor","Qu'est qu'une API Falcor",[12,21629,21630],{},"Je ne vais parler que succinctement de Falcor. C'est un framework que je n'ai pas utilisé mais j'ai tout de même été très intéressé\npar ce dernier et je vais écrire quelques lignes sur ce Framework.",[12,21632,21633,21634,31],{},"Pour plus d'informations, vous pourrez vous référer à la ",[47,21635,21638],{"href":21636,"rel":21637},"https:\u002F\u002Fnetflix.github.io\u002Ffalcor\u002Fstarter\u002Fwhat-is-falcor.html",[51],"documentation",[12,21640,21641],{},"Pour reprendre les explications de la documentation, Falcor est un middleware de votre application qui permet d'interroger des ressources\nau format JSON sur le serveur, comme votre application le ferait sur des données en mémoire.",[12,21643,21644],{},[69,21645],{"alt":21646,"src":21647},"Falcor","https:\u002F\u002Fnetflix.github.io\u002Ffalcor\u002Fdocumentation\u002Fnetwork-diagram.png",[12,21649,21650],{},"La requête envoyée alors au serveur ne contient que les champs demandés par le client, ce qui permet au serveur de sélectionner les champs\net de ne retourner que ces champs. De plus le serveur peut n'exposer qu'un seul modèle contenant toutes les ressources (que ce soit pour\nretourner des listes ou des items particuliers).",[12,21652,21653],{},"En une seule requête, le client peut alors demander l'ensemble des données dont il a besoin, et l'afficher.",[12,21655,21656],{},"Nous n'avons plus alors le dilemne \"faut-il créér une sous-resource, ou l'intégrer dans la ressource actuelle ?\". Du point de vue du client:\nplus besoin d'effectuer plusieurs requêtes complexes pour récupérer plusieurs ressources, un seul appel suffit.",[352,21658,21660],{"className":6044,"code":21659,"language":6046,"meta":291,"style":291},"\u002Fmodel.json?paths=[\"user.name\", \"user.surname\", \"user.address\"]\n\nGET \u002Fmodel.json?paths=[\"user.name\", \"user.surname\", \"user.address\"]\n{\n  user: {\n    name: \"Frank\",\n    surname: \"Underwood\",\n    address: \"1600 Pennsylvania Avenue, Washington, DC\"\n  }\n}\n",[344,21661,21662,21699,21703,21736,21740,21747,21758,21770,21780,21784],{"__ignoreMap":291},[360,21663,21664,21666,21669,21671,21673,21676,21679,21681,21683,21686,21688,21691,21693,21696],{"class":362,"line":363},[360,21665,768],{"class":582},[360,21667,21668],{"class":662},"model",[360,21670,31],{"class":366},[360,21672,16333],{"class":578},[360,21674,21675],{"class":574},"?",[360,21677,21678],{"class":578},"paths",[360,21680,583],{"class":582},[360,21682,2385],{"class":366},[360,21684,21685],{"class":397},"\"user.name\"",[360,21687,2311],{"class":366},[360,21689,21690],{"class":397},"\"user.surname\"",[360,21692,2311],{"class":366},[360,21694,21695],{"class":397},"\"user.address\"",[360,21697,21698],{"class":366},"]\n",[360,21700,21701],{"class":362,"line":292},[360,21702,372],{"emptyLinePlaceholder":320},[360,21704,21705,21708,21710,21712,21714,21716,21718,21720,21722,21724,21726,21728,21730,21732,21734],{"class":362,"line":375},[360,21706,21707],{"class":662},"GET",[360,21709,7444],{"class":582},[360,21711,21668],{"class":662},[360,21713,31],{"class":366},[360,21715,16333],{"class":578},[360,21717,21675],{"class":574},[360,21719,21678],{"class":578},[360,21721,583],{"class":582},[360,21723,2385],{"class":366},[360,21725,21685],{"class":397},[360,21727,2311],{"class":366},[360,21729,21690],{"class":397},[360,21731,2311],{"class":366},[360,21733,21695],{"class":397},[360,21735,21698],{"class":366},[360,21737,21738],{"class":362,"line":433},[360,21739,16340],{"class":366},[360,21741,21742,21745],{"class":362,"line":478},[360,21743,21744],{"class":578},"  user",[360,21746,6359],{"class":366},[360,21748,21749,21751,21753,21756],{"class":362,"line":483},[360,21750,20559],{"class":578},[360,21752,2691],{"class":366},[360,21754,21755],{"class":397},"\"Frank\"",[360,21757,2968],{"class":366},[360,21759,21760,21763,21765,21768],{"class":362,"line":489},[360,21761,21762],{"class":578},"    surname",[360,21764,2691],{"class":366},[360,21766,21767],{"class":397},"\"Underwood\"",[360,21769,2968],{"class":366},[360,21771,21772,21775,21777],{"class":362,"line":494},[360,21773,21774],{"class":578},"    address",[360,21776,2691],{"class":366},[360,21778,21779],{"class":397},"\"1600 Pennsylvania Avenue, Washington, DC\"\n",[360,21781,21782],{"class":362,"line":712},[360,21783,820],{"class":366},[360,21785,21786],{"class":362,"line":331},[360,21787,847],{"class":366},[12,21789,21790,21791,21794],{},"Le ",[344,21792,21793],{},"Router"," falcor côté serveur, s'occupe alors de dispatcher les différentes parties demandées par le client à différents backends, qui peuvent\nalors répondre indépendament les uns des autres.\nFalcor va s'occuper alors d'aggréger le résultat.",[12,21796,21797,31],{},[69,21798],{"alt":21799,"src":21800},"Diagramme de service","https:\u002F\u002Fnetflix.github.io\u002Ffalcor\u002Fimages\u002Fservices-diagram.png",[12,21802,21803],{},"Pour récupérer des données depuis le front:",[352,21805,21807],{"className":6044,"code":21806,"language":6046,"meta":291,"style":291},"\u002F\u002F ask for name and age of user with id = 5\nmodel.get(\"users[5]['name','age']\");\u002F\u002F which will eventually return something like\n{\n  \"users\": {\n    \"5\": {\n      \"name\": \"John Doe\",\n      \"age\": 33\n    }\n  }\n}\u002F\u002F you can also ask for ranges\nmodel.get(\"users[5..7].name);\u002F\u002F which eventually returns the following\n{\n  \"users\": {\n    \"5\": { \"name\": \"John Doe\" },\n    \"6\": { \"name\": \"Jane Doe\" },\n    \"7\": { \"name\": \"Mary Poppins\" }\n  }\n}\n",[344,21808,21809,21814,21833,21837,21844,21851,21863,21873,21877,21881,21888,21904,21908,21914,21929,21945,21962,21966],{"__ignoreMap":291},[360,21810,21811],{"class":362,"line":363},[360,21812,21813],{"class":644},"\u002F\u002F ask for name and age of user with id = 5\n",[360,21815,21816,21818,21820,21822,21824,21827,21830],{"class":362,"line":292},[360,21817,21668],{"class":662},[360,21819,31],{"class":366},[360,21821,17563],{"class":381},[360,21823,671],{"class":366},[360,21825,21826],{"class":397},"\"users[5]['name','age']\"",[360,21828,21829],{"class":366},");",[360,21831,21832],{"class":644},"\u002F\u002F which will eventually return something like\n",[360,21834,21835],{"class":362,"line":375},[360,21836,16340],{"class":366},[360,21838,21839,21842],{"class":362,"line":433},[360,21840,21841],{"class":397},"  \"users\"",[360,21843,6359],{"class":366},[360,21845,21846,21849],{"class":362,"line":478},[360,21847,21848],{"class":397},"    \"5\"",[360,21850,6359],{"class":366},[360,21852,21853,21856,21858,21861],{"class":362,"line":483},[360,21854,21855],{"class":397},"      \"name\"",[360,21857,2691],{"class":366},[360,21859,21860],{"class":397},"\"John Doe\"",[360,21862,2968],{"class":366},[360,21864,21865,21868,21870],{"class":362,"line":489},[360,21866,21867],{"class":397},"      \"age\"",[360,21869,2691],{"class":366},[360,21871,21872],{"class":414},"33\n",[360,21874,21875],{"class":362,"line":494},[360,21876,2927],{"class":366},[360,21878,21879],{"class":362,"line":712},[360,21880,820],{"class":366},[360,21882,21883,21885],{"class":362,"line":331},[360,21884,14166],{"class":366},[360,21886,21887],{"class":644},"\u002F\u002F you can also ask for ranges\n",[360,21889,21890,21892,21894,21896,21898,21901],{"class":362,"line":762},[360,21891,21668],{"class":662},[360,21893,31],{"class":366},[360,21895,17563],{"class":381},[360,21897,671],{"class":366},[360,21899,21900],{"class":397},"\"users[5..7].name);\u002F\u002F which eventually returns the followin",[360,21902,21903],{"class":17414},"g\n",[360,21905,21906],{"class":362,"line":781},[360,21907,16340],{"class":366},[360,21909,21910,21912],{"class":362,"line":804},[360,21911,21841],{"class":397},[360,21913,6359],{"class":366},[360,21915,21916,21918,21920,21923,21925,21927],{"class":362,"line":817},[360,21917,21848],{"class":397},[360,21919,6367],{"class":366},[360,21921,21922],{"class":397},"\"name\"",[360,21924,2691],{"class":366},[360,21926,21860],{"class":397},[360,21928,6397],{"class":366},[360,21930,21931,21934,21936,21938,21940,21943],{"class":362,"line":823},[360,21932,21933],{"class":397},"    \"6\"",[360,21935,6367],{"class":366},[360,21937,21922],{"class":397},[360,21939,2691],{"class":366},[360,21941,21942],{"class":397},"\"Jane Doe\"",[360,21944,6397],{"class":366},[360,21946,21947,21950,21952,21954,21956,21959],{"class":362,"line":844},[360,21948,21949],{"class":397},"    \"7\"",[360,21951,6367],{"class":366},[360,21953,21922],{"class":397},[360,21955,2691],{"class":366},[360,21957,21958],{"class":397},"\"Mary Poppins\"",[360,21960,21961],{"class":366}," }\n",[360,21963,21964],{"class":362,"line":1441},[360,21965,820],{"class":366},[360,21967,21968],{"class":362,"line":1462},[360,21969,847],{"class":366},[12,21971,21972],{},"L'avantage de ce framework, est qu'il permet de simplifier l'écriture des projections et de la partie lecture d'une API.",[12,21974,21975],{},"Ce pourquoi je n'ai pas choisi ce framework vient en deux choses:",[140,21977,21978,21981],{},[143,21979,21980],{},"Il est disponible principalement pour Javascript (NodeJS + Front) ; Il existe une version Java même qui n'a pas été mise à jour\ndepuis 2018 et donc je ne retrouve pas les sources.",[143,21982,21983],{},"J'ai trouvé mieux en GraphQL.",[33,21985,21987],{"id":21986},"quest-quune-api-graphql","Qu'est qu'une API GraphQL",[12,21989,21990],{},"Venant du constat que Falcor répondait à mon besoin de pouvoir normaliser la projection mais avec quelques limites, j'ai continué mes\nrecherches et je suis tombé sur GraphQL.",[12,21992,21993],{},"GraphQL répond à la même problèmatique: pouvoir laisser au client choisir la projection qu'il souhaite des données. Comme Falcor,\nGraphQL permet de ramener plusieurs ressources en une requête. Et comme Falcor, GraphQL permet d'aggréger le résultat côté serveur\nde façon asynchrone.",[12,21995,21996],{},"L'avantage de GraphQL sur Falcor est que GraphQL est une norme écrite par Facebook alors que Falcor est une librairie Javascript.\nDe la norme GraphQL, découle une implémentation officielle en Javascript mais aussi dans plein d'autres languages.",[12,21998,21999],{},"Par contre GraphQL n'est qu'un language de requête. Il ne décrit pas comment doit être transportée la requête sur le réseau, ni\ncomment doit être transférée la réponse. Seul le contenu est normalisé. Les frameworks sont tout de même compatibles entre eux.",[12,22001,22002],{},"Par contre cela permet d'utiliser GraphQL pour autre chose que des requêtes réseaux. On pourrait envisager de faire un service qui\nne répond qu'à des requêtes GraphQL. Ce service est alors rattaché au contrôleur pour une exposition mais aussi directement\nappelable en interne par d'autres services. Cela pourrait permettre de faire une couche d'abstraction interne.",[12,22004,22005,22006,31],{},"Il existe plusieurs frameworks ajoutant la couche de transport à GraphQL. Dans la suite je parlerai d'une des implémentations qui se\nnomme ",[47,22007,22010],{"href":22008,"rel":22009},"https:\u002F\u002Fwww.apollographql.com\u002F",[51],"Apollo",[12,22012,22013],{},"Maintenant passons au vif du sujet.",[1901,22015,22017],{"id":22016},"query-introduction"," Query - Introduction",[12,22019,22020],{},"Le système de requête de graphql permet au client de décrire ce qu'il souhaite récupérer. C'est au client de décider des éléments\nqu'il souhaite et de construire sa requête.",[12,22022,22023],{},"Voici un exemple de requête de requête:",[352,22025,22029],{"className":22026,"code":22027,"language":22028,"meta":291,"style":291},"language-graphql shiki shiki-themes one-dark-pro","query Dashboard {\n  queueStats {\n    waiting\n    active\n    failed\n    lastExecution\n    nextWakeup\n  }\n  diskUsageStats {\n    currentRepartition {\n      host\n      total\n    }\n    currentSpace {\n      size\n      used\n    }\n  }\n}\n","graphql",[344,22030,22031,22041,22048,22053,22058,22063,22068,22073,22077,22084,22091,22096,22101,22105,22112,22117,22122,22126,22130],{"__ignoreMap":291},[360,22032,22033,22036,22039],{"class":362,"line":363},[360,22034,22035],{"class":574},"query",[360,22037,22038],{"class":381}," Dashboard",[360,22040,896],{"class":366},[360,22042,22043,22046],{"class":362,"line":292},[360,22044,22045],{"class":578},"  queueStats",[360,22047,896],{"class":366},[360,22049,22050],{"class":362,"line":375},[360,22051,22052],{"class":578},"    waiting\n",[360,22054,22055],{"class":362,"line":433},[360,22056,22057],{"class":578},"    active\n",[360,22059,22060],{"class":362,"line":478},[360,22061,22062],{"class":578},"    failed\n",[360,22064,22065],{"class":362,"line":483},[360,22066,22067],{"class":578},"    lastExecution\n",[360,22069,22070],{"class":362,"line":489},[360,22071,22072],{"class":578},"    nextWakeup\n",[360,22074,22075],{"class":362,"line":494},[360,22076,820],{"class":366},[360,22078,22079,22082],{"class":362,"line":712},[360,22080,22081],{"class":578},"  diskUsageStats",[360,22083,896],{"class":366},[360,22085,22086,22089],{"class":362,"line":331},[360,22087,22088],{"class":578},"    currentRepartition",[360,22090,896],{"class":366},[360,22092,22093],{"class":362,"line":762},[360,22094,22095],{"class":578},"      host\n",[360,22097,22098],{"class":362,"line":781},[360,22099,22100],{"class":578},"      total\n",[360,22102,22103],{"class":362,"line":804},[360,22104,2927],{"class":366},[360,22106,22107,22110],{"class":362,"line":817},[360,22108,22109],{"class":578},"    currentSpace",[360,22111,896],{"class":366},[360,22113,22114],{"class":362,"line":823},[360,22115,22116],{"class":578},"      size\n",[360,22118,22119],{"class":362,"line":844},[360,22120,22121],{"class":578},"      used\n",[360,22123,22124],{"class":362,"line":1441},[360,22125,2927],{"class":366},[360,22127,22128],{"class":362,"line":1462},[360,22129,820],{"class":366},[360,22131,22132],{"class":362,"line":1485},[360,22133,847],{"class":366},[12,22135,22136],{},"Derrière chaqu'un des membres ci-dessus, on peut retrouver un resolver. Un resolver c'est l'équivalent du contrôleur pour une API REST.\nC'est le resolver qui va récupérer les informations demandées par le client (arguments, projection, ...) et les transférer au service.",[12,22138,22139],{},"Il nous faudra alors faire un lien entre le schéma et ces resolvers. Pour le client, peu importe qu'il faille, pour une requête, exécuter\nen tâche de fond 1 resolver ou 10 resolver. Le client n'a pas besoin de le savoir.",[12,22141,22142,22143,22146],{},"Imaginons que dans l'exemple ci-dessous le champs ",[344,22144,22145],{},"nextWakeup"," nécessite un calcul complexe. Il suffit de créer un resolver qui\neffectue ce calcul.\nSi jamais le client n'a pas besoin de l'afficher et du coup, ne le demande pas, alors ce calcul complexe ne sera pas fait et c'est du temps\nde traitement gagné sur le serveur.",[12,22148,22149],{},"En REST, un champ qui nécessite un calcul complexe et soit",[140,22151,22152,22155],{},[143,22153,22154],{},"inclus dans la resource et donc toujours effectué quelque soit le besoin du client",[143,22156,22157],{},"séparé dans une ressource séparée, au risque de complexifier l'API et de demander au client de faire plusieurs requêtes si nécessaire (surtout si\non a plus d'un champ calculé).",[1901,22159,22161],{"id":22160},"nommer-ces-requêtes","Nommer ces requêtes",[12,22163,22164,22165,22168],{},"Dans l'exemple ci-dessus, on peut remarquer que la requête possède un nom. C'est une bonne pratique de toujours nommer l'opération\n(ici ",[344,22166,22167],{},"Dashboard","). Nommer les opérations permet de :",[140,22170,22171,22174],{},[143,22172,22173],{},"mettre plusieurs opérations nommées dans une seule requête.",[143,22175,22176],{},"mais aussi de mieux tracer et débugger les requêtes côté serveur dans les logs.",[1901,22178,22180],{"id":22179},"query-coté-serveur","Query - Coté serveur",[12,22182,22183],{},"Côté serveur nous allons commencer par décrire le schéma que pourra alors utiliser le client pour effectuer ces requêtes. Par exemple :",[352,22185,22187],{"className":22026,"code":22186,"language":22028,"meta":291,"style":291},"scalar Date\n\n\"\"\"\nDefine the state of the queue\n\"\"\"\ntype QueueStats {\n  \"\"\"\n  Number of task waiting in queue\n  \"\"\"\n  waiting: Int!\n  \"\"\"\n  Number of task active in queue\n  \"\"\"\n  active: Int!\n  \"\"\"\n  Number of task that have failed\n  \"\"\"\n  failed: Int!\n  \"\"\"\n  Date of the last execution\n  \"\"\"\n  lastExecution: Date!\n  \"\"\"\n  Date of the next wakeup\n  \"\"\"\n  nextWakeup: Date!\n}\n\ntype DiskCurrentRepartition {\n  host: Int!\n  total: Int!\n}\n\ntype DiskCurrentSpace {\n  size: Int!\n  used: Int!\n}\n\ntype DiskUsageStats {\n  currentRepartition: [DiskCurrentRepartition!]!\n  currentSpace: DiskCurrentSpace!\n}\n\ntype Query {\n  queueStats: QueueStats!\n  diskUsageState: DiskUsageStats!\n}\n",[344,22188,22189,22197,22201,22206,22211,22215,22222,22227,22232,22236,22244,22248,22253,22257,22264,22268,22273,22277,22284,22288,22293,22297,22305,22309,22314,22318,22325,22329,22333,22340,22347,22354,22358,22362,22369,22375,22382,22386,22390,22397,22405,22413,22417,22421,22428,22435,22443],{"__ignoreMap":291},[360,22190,22191,22194],{"class":362,"line":363},[360,22192,22193],{"class":574},"scalar",[360,22195,22196],{"class":366}," Date\n",[360,22198,22199],{"class":362,"line":292},[360,22200,372],{"emptyLinePlaceholder":320},[360,22202,22203],{"class":362,"line":375},[360,22204,22205],{"class":644},"\"\"\"\n",[360,22207,22208],{"class":362,"line":433},[360,22209,22210],{"class":644},"Define the state of the queue\n",[360,22212,22213],{"class":362,"line":478},[360,22214,22205],{"class":644},[360,22216,22217,22219],{"class":362,"line":483},[360,22218,19774],{"class":574},[360,22220,22221],{"class":366}," QueueStats {\n",[360,22223,22224],{"class":362,"line":489},[360,22225,22226],{"class":644},"  \"\"\"\n",[360,22228,22229],{"class":362,"line":494},[360,22230,22231],{"class":644},"  Number of task waiting in queue\n",[360,22233,22234],{"class":362,"line":712},[360,22235,22226],{"class":644},[360,22237,22238,22241],{"class":362,"line":331},[360,22239,22240],{"class":578},"  waiting",[360,22242,22243],{"class":366},": Int!\n",[360,22245,22246],{"class":362,"line":762},[360,22247,22226],{"class":644},[360,22249,22250],{"class":362,"line":781},[360,22251,22252],{"class":644},"  Number of task active in queue\n",[360,22254,22255],{"class":362,"line":804},[360,22256,22226],{"class":644},[360,22258,22259,22262],{"class":362,"line":817},[360,22260,22261],{"class":578},"  active",[360,22263,22243],{"class":366},[360,22265,22266],{"class":362,"line":823},[360,22267,22226],{"class":644},[360,22269,22270],{"class":362,"line":844},[360,22271,22272],{"class":644},"  Number of task that have failed\n",[360,22274,22275],{"class":362,"line":1441},[360,22276,22226],{"class":644},[360,22278,22279,22282],{"class":362,"line":1462},[360,22280,22281],{"class":578},"  failed",[360,22283,22243],{"class":366},[360,22285,22286],{"class":362,"line":1485},[360,22287,22226],{"class":644},[360,22289,22290],{"class":362,"line":1497},[360,22291,22292],{"class":644},"  Date of the last execution\n",[360,22294,22295],{"class":362,"line":3161},[360,22296,22226],{"class":644},[360,22298,22299,22302],{"class":362,"line":3167},[360,22300,22301],{"class":578},"  lastExecution",[360,22303,22304],{"class":366},": Date!\n",[360,22306,22307],{"class":362,"line":3194},[360,22308,22226],{"class":644},[360,22310,22311],{"class":362,"line":3224},[360,22312,22313],{"class":644},"  Date of the next wakeup\n",[360,22315,22316],{"class":362,"line":3239},[360,22317,22226],{"class":644},[360,22319,22320,22323],{"class":362,"line":3256},[360,22321,22322],{"class":578},"  nextWakeup",[360,22324,22304],{"class":366},[360,22326,22327],{"class":362,"line":3276},[360,22328,847],{"class":366},[360,22330,22331],{"class":362,"line":3281},[360,22332,372],{"emptyLinePlaceholder":320},[360,22334,22335,22337],{"class":362,"line":3305},[360,22336,19774],{"class":574},[360,22338,22339],{"class":366}," DiskCurrentRepartition {\n",[360,22341,22342,22345],{"class":362,"line":3320},[360,22343,22344],{"class":578},"  host",[360,22346,22243],{"class":366},[360,22348,22349,22352],{"class":362,"line":3325},[360,22350,22351],{"class":578},"  total",[360,22353,22243],{"class":366},[360,22355,22356],{"class":362,"line":3361},[360,22357,847],{"class":366},[360,22359,22360],{"class":362,"line":3380},[360,22361,372],{"emptyLinePlaceholder":320},[360,22363,22364,22366],{"class":362,"line":3405},[360,22365,19774],{"class":574},[360,22367,22368],{"class":366}," DiskCurrentSpace {\n",[360,22370,22371,22373],{"class":362,"line":3411},[360,22372,9930],{"class":578},[360,22374,22243],{"class":366},[360,22376,22377,22380],{"class":362,"line":3426},[360,22378,22379],{"class":578},"  used",[360,22381,22243],{"class":366},[360,22383,22384],{"class":362,"line":3432},[360,22385,847],{"class":366},[360,22387,22388],{"class":362,"line":3438},[360,22389,372],{"emptyLinePlaceholder":320},[360,22391,22392,22394],{"class":362,"line":3443},[360,22393,19774],{"class":574},[360,22395,22396],{"class":366}," DiskUsageStats {\n",[360,22398,22399,22402],{"class":362,"line":3462},[360,22400,22401],{"class":578},"  currentRepartition",[360,22403,22404],{"class":366},": [DiskCurrentRepartition!]!\n",[360,22406,22407,22410],{"class":362,"line":3467},[360,22408,22409],{"class":578},"  currentSpace",[360,22411,22412],{"class":366},": DiskCurrentSpace!\n",[360,22414,22415],{"class":362,"line":3472},[360,22416,847],{"class":366},[360,22418,22419],{"class":362,"line":3495},[360,22420,372],{"emptyLinePlaceholder":320},[360,22422,22423,22425],{"class":362,"line":3500},[360,22424,19774],{"class":574},[360,22426,22427],{"class":366}," Query {\n",[360,22429,22430,22432],{"class":362,"line":3505},[360,22431,22045],{"class":578},[360,22433,22434],{"class":366},": QueueStats!\n",[360,22436,22437,22440],{"class":362,"line":3530},[360,22438,22439],{"class":578},"  diskUsageState",[360,22441,22442],{"class":366},": DiskUsageStats!\n",[360,22444,22445],{"class":362,"line":3545},[360,22446,847],{"class":366},[12,22448,22449],{},"On peut remarquer plusieurs choses:",[140,22451,22452,22455,22458,22461,22464],{},[143,22453,22454],{},"Tous les champs ont un type (String, Int, Float, Array, Date)",[143,22456,22457],{},"Il est possible de créer de nouveaux types simples, scalaires: par exemple champ de type Date.",[143,22459,22460],{},"Il est possible de créer de nouveaux types complexes, ce qui en fait nos structures.",[143,22462,22463],{},"Le point d'exclamation permet d'indiquer que le champ retourné ne sera jamais null (et donc le client peut compter dessus s'il le souhaite).",[143,22465,22466],{},"Il est possible de mettre de la documentation au niveau de chaque champ mais aussi au niveau des types.",[12,22468,22469,22470,22475],{},"Ce schéma (qui peut aussi être généré à l'aide d'annotations en Typescript, ",[47,22471,22474],{"href":22472,"rel":22473},"https:\u002F\u002Fdocs.nestjs.com\u002Fgraphql\u002Fresolvers#code-first-resolver",[51],"par exemple",")\nsert également de documentation (un peu comme swagger).",[12,22477,22478],{},"Il est alors possible d'utiliser des outils comme",[140,22480,22481,22489,22496,22504],{},[143,22482,22483,22488],{},[47,22484,22487],{"href":22485,"rel":22486},"https:\u002F\u002F2fd.github.io\u002Fgraphdoc\u002F",[51],"Graph Doc",",",[143,22490,22491,22488],{},[47,22492,22495],{"href":22493,"rel":22494},"https:\u002F\u002Fdocql.io\u002F",[51],"DocQL",[143,22497,22498,22503],{},[47,22499,22502],{"href":22500,"rel":22501},"https:\u002F\u002Fgithub.com\u002FAPIs-guru\u002Fgraphql-voyager",[51],"GraphQL Voyager",", et",[143,22505,22506],{},[47,22507,22510],{"href":22508,"rel":22509},"https:\u002F\u002Fgithub.com\u002Fwayfair\u002Fdociql",[51],"Doc iQL",[12,22512,22513],{},"pour générer de la documentation mais aussi des outils comme",[140,22515,22516,22523],{},[143,22517,22518],{},[47,22519,22522],{"href":22520,"rel":22521},"https:\u002F\u002Fgithub.com\u002Fgraphql\u002Fgraphql-playground",[51],"GraphQL Playground",[143,22524,22525,22530],{},[47,22526,22529],{"href":22527,"rel":22528},"https:\u002F\u002Fgithub.com\u002Fgraphql\u002Fgraphiql",[51],"GraphiQL"," qui sont des IDE permettant de faire des requêtes (avec documentation et auto-completion).",[12,22532,22533],{},"Une fois le schéma écrit, il peut être communiqué aux équipes front (si les équipes sont séparées). Pendant que l'on développe alors le front, côté\nserveur on peut alors implémenter le schéma.",[12,22535,22536],{},"Pour implémenter le schéma ci-dessus, nous allons écrire un resolver (en Javascript pour l'exemple).",[352,22538,22540],{"className":6044,"code":22539,"language":6046,"meta":291,"style":291},"const resolvers = {\n  Query: {\n    queueStats() {\n      return getQueueStats();\n    },\n    async diskUsageState() {\n      return await getDiskUsageState();\n    },\n  },\n};\n",[344,22541,22542,22553,22560,22567,22576,22580,22590,22601,22605,22609],{"__ignoreMap":291},[360,22543,22544,22546,22549,22551],{"class":362,"line":363},[360,22545,6053],{"class":574},[360,22547,22548],{"class":662}," resolvers",[360,22550,401],{"class":582},[360,22552,896],{"class":366},[360,22554,22555,22558],{"class":362,"line":292},[360,22556,22557],{"class":578},"  Query",[360,22559,6359],{"class":366},[360,22561,22562,22565],{"class":362,"line":375},[360,22563,22564],{"class":381},"    queueStats",[360,22566,2172],{"class":366},[360,22568,22569,22571,22574],{"class":362,"line":433},[360,22570,18932],{"class":574},[360,22572,22573],{"class":381}," getQueueStats",[360,22575,2204],{"class":366},[360,22577,22578],{"class":362,"line":478},[360,22579,6505],{"class":366},[360,22581,22582,22585,22588],{"class":362,"line":483},[360,22583,22584],{"class":574},"    async",[360,22586,22587],{"class":381}," diskUsageState",[360,22589,2172],{"class":366},[360,22591,22592,22594,22596,22599],{"class":362,"line":489},[360,22593,18932],{"class":574},[360,22595,15801],{"class":574},[360,22597,22598],{"class":381}," getDiskUsageState",[360,22600,2204],{"class":366},[360,22602,22603],{"class":362,"line":494},[360,22604,6505],{"class":366},[360,22606,22607],{"class":362,"line":712},[360,22608,6758],{"class":366},[360,22610,22611],{"class":362,"line":331},[360,22612,1036],{"class":366},[12,22614,22615],{},"Un resolver peut pour un champ:",[140,22617,22618,22621,22624],{},[143,22619,22620],{},"retourner une valeur",[143,22622,22623],{},"retourner une fonction qui retourne la valeur",[143,22625,22626],{},"retourner une fonction qui retourne une promesse avec la valeur",[12,22628,22629,22630,22633,22634,854,22636,632],{},"Ainsi imaginons que la méthode ",[344,22631,22632],{},"getQueueStats()"," retourne l'objet suivant, dans lequel il manque ",[344,22635,22145],{},[344,22637,22638],{},"lastExecution",[352,22640,22642],{"className":16331,"code":22641,"language":16333,"meta":291,"style":291},"{\n  \"waiting\": 0,\n  \"active\": 2,\n  \"failed\": 0\n}\n",[344,22643,22644,22648,22659,22670,22679],{"__ignoreMap":291},[360,22645,22646],{"class":362,"line":363},[360,22647,16340],{"class":366},[360,22649,22650,22653,22655,22657],{"class":362,"line":292},[360,22651,22652],{"class":578},"  \"waiting\"",[360,22654,2691],{"class":366},[360,22656,1344],{"class":414},[360,22658,2968],{"class":366},[360,22660,22661,22664,22666,22668],{"class":362,"line":375},[360,22662,22663],{"class":578},"  \"active\"",[360,22665,2691],{"class":366},[360,22667,795],{"class":414},[360,22669,2968],{"class":366},[360,22671,22672,22675,22677],{"class":362,"line":433},[360,22673,22674],{"class":578},"  \"failed\"",[360,22676,2691],{"class":366},[360,22678,16357],{"class":414},[360,22680,22681],{"class":362,"line":478},[360,22682,847],{"class":366},[12,22684,22685],{},"Il est possible d'écrire un resolver :",[352,22687,22689],{"className":6044,"code":22688,"language":6046,"meta":291,"style":291},"const resolvers = {\n  Query: {\n    queueStats() {\n      return getQueueStats();\n    },\n    async diskUsageState() {\n      return await getDiskUsageState();\n    },\n  },\n  QueueStats: {\n    lastExecution(parent \u002F*: QueueStats *\u002F) {\n      const { active } = parent; \u002F\u002F Ici pour l'exemple on peut récuperer un attribut de parent.\n      return getLastExecution();\n    },\n    nextWakeup() {\n      return getNextWakup();\n    },\n  },\n};\n",[344,22690,22691,22701,22707,22713,22721,22725,22733,22743,22747,22751,22758,22773,22794,22803,22807,22814,22823,22827,22831],{"__ignoreMap":291},[360,22692,22693,22695,22697,22699],{"class":362,"line":363},[360,22694,6053],{"class":574},[360,22696,22548],{"class":662},[360,22698,401],{"class":582},[360,22700,896],{"class":366},[360,22702,22703,22705],{"class":362,"line":292},[360,22704,22557],{"class":578},[360,22706,6359],{"class":366},[360,22708,22709,22711],{"class":362,"line":375},[360,22710,22564],{"class":381},[360,22712,2172],{"class":366},[360,22714,22715,22717,22719],{"class":362,"line":433},[360,22716,18932],{"class":574},[360,22718,22573],{"class":381},[360,22720,2204],{"class":366},[360,22722,22723],{"class":362,"line":478},[360,22724,6505],{"class":366},[360,22726,22727,22729,22731],{"class":362,"line":483},[360,22728,22584],{"class":574},[360,22730,22587],{"class":381},[360,22732,2172],{"class":366},[360,22734,22735,22737,22739,22741],{"class":362,"line":489},[360,22736,18932],{"class":574},[360,22738,15801],{"class":574},[360,22740,22598],{"class":381},[360,22742,2204],{"class":366},[360,22744,22745],{"class":362,"line":494},[360,22746,6505],{"class":366},[360,22748,22749],{"class":362,"line":712},[360,22750,6758],{"class":366},[360,22752,22753,22756],{"class":362,"line":331},[360,22754,22755],{"class":578},"  QueueStats",[360,22757,6359],{"class":366},[360,22759,22760,22763,22765,22768,22771],{"class":362,"line":762},[360,22761,22762],{"class":381},"    lastExecution",[360,22764,671],{"class":366},[360,22766,22767],{"class":677},"parent",[360,22769,22770],{"class":644}," \u002F*: QueueStats *\u002F",[360,22772,681],{"class":366},[360,22774,22775,22777,22779,22782,22784,22786,22789,22791],{"class":362,"line":781},[360,22776,18859],{"class":574},[360,22778,5879],{"class":366},[360,22780,22781],{"class":662},"active",[360,22783,6108],{"class":366},[360,22785,583],{"class":582},[360,22787,22788],{"class":578}," parent",[360,22790,4423],{"class":366},[360,22792,22793],{"class":644},"\u002F\u002F Ici pour l'exemple on peut récuperer un attribut de parent.\n",[360,22795,22796,22798,22801],{"class":362,"line":804},[360,22797,18932],{"class":574},[360,22799,22800],{"class":381}," getLastExecution",[360,22802,2204],{"class":366},[360,22804,22805],{"class":362,"line":817},[360,22806,6505],{"class":366},[360,22808,22809,22812],{"class":362,"line":823},[360,22810,22811],{"class":381},"    nextWakeup",[360,22813,2172],{"class":366},[360,22815,22816,22818,22821],{"class":362,"line":844},[360,22817,18932],{"class":574},[360,22819,22820],{"class":381}," getNextWakup",[360,22822,2204],{"class":366},[360,22824,22825],{"class":362,"line":1441},[360,22826,6505],{"class":366},[360,22828,22829],{"class":362,"line":1462},[360,22830,6758],{"class":366},[360,22832,22833],{"class":362,"line":1485},[360,22834,1036],{"class":366},[12,22836,22837],{},"Il est alors possible de créer son schéma en pensant à comment le client va intéroger ce dernier, et lors de l'implémentation ajouter des structures\ncomplexes qui sont issues du calcul synchrone ou asynchrone des données.",[1901,22839,22841],{"id":22840},"query-nullable","Query - Nullable",[12,22843,22844],{},"On a vu précédement qu'on pouvait utiliser le point d'exclamation pour indiquer qu'un champ ne sera jamais NULL. Cela peut avoir des avantages pour le client\nmais cela a aussi de grandes implications côté serveur.",[12,22846,22847],{},"Par défaut pour GraphQL, tous les champs sont nullable par défaut. En effet, si un resolver n'arrive pas à récupérer la donnée (erreur côté serveur, back HS, problème\nde base de données, problème réseau, droits d'accès différents selon les champs ...), le serveur pourra retourner NULL à la place de la valeur (et une erreur en\nparallèle du json). Cela permet au client une vue partielle même si certains services ne sont pas disponibles.",[12,22849,22850],{},"Si le champ ne peut pas être null, alors le json ne pourra pas du tout être envoyé et c'est la requête complète qui est en ereur.",[12,22852,22853],{},"C'est pour cela qu'en GraphQL chaque champ peut, par défaut, obtenir la valeur null.",[12,22855,22856],{},"Lors de la conception d'un schéma GraphQL, il faut utiliser la possibilité de rendre le champ non nullable avec réflexion et uniquement pour les champs dont on\nsouhaite garantir la non nullité.",[1901,22858,22860],{"id":22859},"query-ajout-darguments","Query - Ajout d'arguments",[352,22862,22864],{"className":22026,"code":22863,"language":22028,"meta":291,"style":291},"query HeroNameAndFriends($episode: Episode) {\n  hero(episode: $episode) {\n    name\n    friends {\n      name\n    }\n  }\n}\n",[344,22865,22866,22881,22897,22902,22909,22914,22918,22922],{"__ignoreMap":291},[360,22867,22868,22870,22873,22875,22878],{"class":362,"line":363},[360,22869,22035],{"class":574},[360,22871,22872],{"class":381}," HeroNameAndFriends",[360,22874,671],{"class":366},[360,22876,22877],{"class":677},"$episode",[360,22879,22880],{"class":366},": Episode) {\n",[360,22882,22883,22886,22888,22891,22893,22895],{"class":362,"line":292},[360,22884,22885],{"class":578},"  hero",[360,22887,671],{"class":366},[360,22889,22890],{"class":677},"episode",[360,22892,2691],{"class":366},[360,22894,22877],{"class":578},[360,22896,681],{"class":366},[360,22898,22899],{"class":362,"line":375},[360,22900,22901],{"class":578},"    name\n",[360,22903,22904,22907],{"class":362,"line":433},[360,22905,22906],{"class":578},"    friends",[360,22908,896],{"class":366},[360,22910,22911],{"class":362,"line":478},[360,22912,22913],{"class":578},"      name\n",[360,22915,22916],{"class":362,"line":483},[360,22917,2927],{"class":366},[360,22919,22920],{"class":362,"line":489},[360,22921,820],{"class":366},[360,22923,22924],{"class":362,"line":494},[360,22925,847],{"class":366},[12,22927,22928],{},"Il est possible en GraphQL de définir certain champs comme ayant des paramètres. Ils seront alors passés au resolver. Il est également possible d'avoir\ndes paramètres à différents niveaux du schéma (pas seulement au niveau le plus haut).",[12,22930,22931],{},"Le passage de paramètres permet d'écrire son opération une fois et ensuite de l'appeler avec des paramètres. C'est important de définir les saisie utilisateurs\ncomme des paramètres pour éviter les injections GraphQL (comme en SQL, ou autre).",[12,22933,22934,22937],{},[28,22935,22936],{},"Règle n°1",": Ne jamais faire confiance à l'utilisateur.",[1901,22939,22941],{"id":22940},"query-création-dalias","Query - Création d'alias",[12,22943,22944],{},"Si on souhaite récupérer plusieurs valeurs d'un attribut en fonction de ses paramètres, il est possible de le demander plusieurs fois et de lui associer\nun alias.",[352,22946,22948],{"className":22026,"code":22947,"language":22028,"meta":291,"style":291},"query aliasQuery {\n  empireHero: hero(episode: EMPIRE) {\n    name\n  }\n  jediHero: hero(episode: JEDI) {\n    name\n  }\n}\n",[344,22949,22950,22959,22980,22984,22988,23008,23012,23016],{"__ignoreMap":291},[360,22951,22952,22954,22957],{"class":362,"line":363},[360,22953,22035],{"class":574},[360,22955,22956],{"class":381}," aliasQuery",[360,22958,896],{"class":366},[360,22960,22961,22964,22966,22969,22971,22973,22975,22978],{"class":362,"line":292},[360,22962,22963],{"class":397},"  empireHero",[360,22965,2691],{"class":366},[360,22967,22968],{"class":578},"hero",[360,22970,671],{"class":366},[360,22972,22890],{"class":677},[360,22974,14024],{"class":366},[360,22976,22977],{"class":414}," EMPIRE",[360,22979,681],{"class":366},[360,22981,22982],{"class":362,"line":375},[360,22983,22901],{"class":578},[360,22985,22986],{"class":362,"line":433},[360,22987,820],{"class":366},[360,22989,22990,22993,22995,22997,22999,23001,23003,23006],{"class":362,"line":478},[360,22991,22992],{"class":397},"  jediHero",[360,22994,2691],{"class":366},[360,22996,22968],{"class":578},[360,22998,671],{"class":366},[360,23000,22890],{"class":677},[360,23002,14024],{"class":366},[360,23004,23005],{"class":414}," JEDI",[360,23007,681],{"class":366},[360,23009,23010],{"class":362,"line":483},[360,23011,22901],{"class":578},[360,23013,23014],{"class":362,"line":489},[360,23015,820],{"class":366},[360,23017,23018],{"class":362,"line":494},[360,23019,847],{"class":366},[12,23021,23022,23023,854,23026,23029,23030,23032],{},"Dans le JSON résultant, on retrouve alors les deux attributs ",[344,23024,23025],{},"empireHero",[344,23027,23028],{},"jediHero"," qui sont tous les deux issus du membre ",[344,23031,22968],{}," avec un paramètre\ndifférent. Cela peut aussi être utilisé pour simplement renommer un champ.",[23034,23035,23037],"h4",{"id":23036},"query-fragment","Query - Fragment",[12,23039,23040],{},"Les fragments permettent de factoriser et de créer des morceaux de requêtes réutilisables.",[352,23042,23044],{"className":22026,"code":23043,"language":22028,"meta":291,"style":291},"# Dans le fichier FragmentJob.graphql\n\nfragment FragmentJob on Job {\n  id\n  state\n  failedReason\n  data {\n    host\n  }\n}\n\n# Dans le fichier QueueTasks.graphql\n\n#import \".\u002FFragmentJob.graphql\"\n\nquery QueueTasks($state: [String!]) {\n  queue(state: $state) {\n    ...FragmentJob\n  }\n}\n",[344,23045,23046,23051,23055,23068,23073,23078,23083,23089,23094,23098,23102,23106,23111,23115,23120,23124,23139,23155,23162,23166],{"__ignoreMap":291},[360,23047,23048],{"class":362,"line":363},[360,23049,23050],{"class":644},"# Dans le fichier FragmentJob.graphql\n",[360,23052,23053],{"class":362,"line":292},[360,23054,372],{"emptyLinePlaceholder":320},[360,23056,23057,23060,23063,23065],{"class":362,"line":375},[360,23058,23059],{"class":574},"fragment",[360,23061,23062],{"class":366}," FragmentJob ",[360,23064,7299],{"class":574},[360,23066,23067],{"class":366}," Job {\n",[360,23069,23070],{"class":362,"line":433},[360,23071,23072],{"class":578},"  id\n",[360,23074,23075],{"class":362,"line":478},[360,23076,23077],{"class":578},"  state\n",[360,23079,23080],{"class":362,"line":483},[360,23081,23082],{"class":578},"  failedReason\n",[360,23084,23085,23087],{"class":362,"line":489},[360,23086,10056],{"class":578},[360,23088,896],{"class":366},[360,23090,23091],{"class":362,"line":494},[360,23092,23093],{"class":578},"    host\n",[360,23095,23096],{"class":362,"line":712},[360,23097,820],{"class":366},[360,23099,23100],{"class":362,"line":331},[360,23101,847],{"class":366},[360,23103,23104],{"class":362,"line":762},[360,23105,372],{"emptyLinePlaceholder":320},[360,23107,23108],{"class":362,"line":781},[360,23109,23110],{"class":644},"# Dans le fichier QueueTasks.graphql\n",[360,23112,23113],{"class":362,"line":804},[360,23114,372],{"emptyLinePlaceholder":320},[360,23116,23117],{"class":362,"line":817},[360,23118,23119],{"class":644},"#import \".\u002FFragmentJob.graphql\"\n",[360,23121,23122],{"class":362,"line":823},[360,23123,372],{"emptyLinePlaceholder":320},[360,23125,23126,23128,23131,23133,23136],{"class":362,"line":844},[360,23127,22035],{"class":574},[360,23129,23130],{"class":381}," QueueTasks",[360,23132,671],{"class":366},[360,23134,23135],{"class":677},"$state",[360,23137,23138],{"class":366},": [String!]) {\n",[360,23140,23141,23144,23146,23149,23151,23153],{"class":362,"line":1441},[360,23142,23143],{"class":578},"  queue",[360,23145,671],{"class":366},[360,23147,23148],{"class":677},"state",[360,23150,2691],{"class":366},[360,23152,23135],{"class":578},[360,23154,681],{"class":366},[360,23156,23157,23159],{"class":362,"line":1462},[360,23158,21138],{"class":366},[360,23160,23161],{"class":578},"FragmentJob\n",[360,23163,23164],{"class":362,"line":1485},[360,23165,820],{"class":366},[360,23167,23168],{"class":362,"line":1497},[360,23169,847],{"class":366},[12,23171,23172,23173,23176],{},"Le Fragment ",[344,23174,23175],{},"FragmentJob"," peut alors être réutilisé dans différentes requêtes, voir même plusieurs fois dans la même requête.",[1901,23178,23180],{"id":23179},"query-gestion-de-version","Query - Gestion de version",[12,23182,23183],{},"J'en parlais dans les articles précédents, il existe plusieurs manières de versionner une API. GraphQL n'y échappe pas. On peut:",[140,23185,23186,23189],{},[143,23187,23188],{},"ajouter un numéro de version dans le path de l'url, dans le nom de l'hôte, dans un header http.",[143,23190,23191],{},"ou décider de gérer une seule API rétro-compatible où on décommissionne au fur et à mesure les champs.",[12,23193,23194,23195,23200,23201,23204],{},"Les créateurs de GraphQL partagent ",[47,23196,23199],{"href":23197,"rel":23198},"https:\u002F\u002Fgraphql.org\u002Flearn\u002Fbest-practices\u002F#versioning",[51],"leur opinions",". Comme c'est le client qui décide\ndes champs qu'il souhaite rappatrier, toute évolution du schéma ajoutant de nouveaux attributs ne pose aucun problème et ne surchargera pas\nplus le client.\nLes suppressions doivent passer par une phase d'obsolescence ou les attributs sont marqués avec l'annotation ",[344,23202,23203],{},"@deprecated"," et leur décommissionnement\nautomatique.",[12,23206,23207,23208,23213],{},"Afin de pouvoir facilement décommissionner des attributs, le mieux est de savoir quels attributs sont utilisés ou non. La librairie Apollo permet de\nse connecter au ",[47,23209,23212],{"href":23210,"rel":23211},"https:\u002F\u002Fstudio.apollographql.com\u002F",[51],"studio d'appolo"," et de visualiser l'utilisation des attributs. Savoir qu'un attribut n'est pas\nutilisé permet de le décommissionner ou de le modifier. Bien sûr et malheureusement cette partie n'est pas open source. Je n'ai pas encore trouvé de\ndashboard OpenSource permettant d'analyser l'utilisation d'un champ.",[12,23215,23216],{},"Ce qui est important c'est d'avoir une politique de versionning.",[1901,23218,23220],{"id":23219},"query-pagination","Query - Pagination",[12,23222,23223],{},"GraphQL n'a pas défini de règle concernant la pagination car il y a plein de manières de la gérer. Pour des listes contenant peu d'éléments, il n'y a\npar exemple pas lieu de gérer la pagination.",[12,23225,23226],{},"Quand on envisage la pagination, on peut en faire une par page avec un nombre d'éléments à passer (skip), ou une basée sur l'id du premier élément\nà afficher.",[12,23228,23229],{},"Il existe également des patterns que l'on peut utiliser pour ne pas réinventer une nouvelle facon de faire.",[12,23231,23232,23233,23236,23237,23240],{},"Par exemple l'un de ses patterns s'appele ",[344,23234,23235],{},"Connections"," et des librairies comme ",[344,23238,23239],{},"Relay"," savent comment gérer automatiquement ce pattern.",[12,23242,23243,23244,23246],{},"Dans le pattern ",[344,23245,23235],{},", nous retrouvons les notions:",[140,23248,23249,23260],{},[143,23250,23251,23252],{},"En entrée",[140,23253,23254,23257],{},[143,23255,23256],{},"nombre d'éléments à récupérer",[143,23258,23259],{},"le curseur à partir duquel retourner les données",[143,23261,23262,23263],{},"En sortie",[140,23264,23265,23268,23271],{},[143,23266,23267],{},"Le nombre d'éléments total",[143,23269,23270],{},"Les informations sur la page comme le prochain curseur et si on a une page suivante",[143,23272,23273],{},"Les différents éléments de la page (avec le curseur associé)",[352,23275,23277],{"className":22026,"code":23276,"language":22028,"meta":291,"style":291},"{\n  hero {\n    name\n    friendsConnection(first: 2, after: \"Y3Vyc29yMQ==\") {\n      totalCount\n      edges {\n        node {\n          name\n        }\n        cursor\n      }\n      pageInfo {\n        endCursor\n        hasNextPage\n      }\n    }\n  }\n}\n",[344,23278,23279,23283,23289,23293,23319,23324,23331,23338,23343,23347,23352,23357,23364,23369,23374,23378,23382,23386],{"__ignoreMap":291},[360,23280,23281],{"class":362,"line":363},[360,23282,16340],{"class":366},[360,23284,23285,23287],{"class":362,"line":292},[360,23286,22885],{"class":578},[360,23288,896],{"class":366},[360,23290,23291],{"class":362,"line":375},[360,23292,22901],{"class":578},[360,23294,23295,23298,23300,23303,23305,23307,23309,23312,23314,23317],{"class":362,"line":433},[360,23296,23297],{"class":578},"    friendsConnection",[360,23299,671],{"class":366},[360,23301,23302],{"class":677},"first",[360,23304,2691],{"class":366},[360,23306,795],{"class":414},[360,23308,2311],{"class":366},[360,23310,23311],{"class":677},"after",[360,23313,2691],{"class":366},[360,23315,23316],{"class":397},"\"Y3Vyc29yMQ==\"",[360,23318,681],{"class":366},[360,23320,23321],{"class":362,"line":478},[360,23322,23323],{"class":578},"      totalCount\n",[360,23325,23326,23329],{"class":362,"line":483},[360,23327,23328],{"class":578},"      edges",[360,23330,896],{"class":366},[360,23332,23333,23336],{"class":362,"line":489},[360,23334,23335],{"class":578},"        node",[360,23337,896],{"class":366},[360,23339,23340],{"class":362,"line":494},[360,23341,23342],{"class":578},"          name\n",[360,23344,23345],{"class":362,"line":712},[360,23346,2840],{"class":366},[360,23348,23349],{"class":362,"line":331},[360,23350,23351],{"class":578},"        cursor\n",[360,23353,23354],{"class":362,"line":762},[360,23355,23356],{"class":366},"      }\n",[360,23358,23359,23362],{"class":362,"line":781},[360,23360,23361],{"class":578},"      pageInfo",[360,23363,896],{"class":366},[360,23365,23366],{"class":362,"line":804},[360,23367,23368],{"class":578},"        endCursor\n",[360,23370,23371],{"class":362,"line":817},[360,23372,23373],{"class":578},"        hasNextPage\n",[360,23375,23376],{"class":362,"line":823},[360,23377,23356],{"class":366},[360,23379,23380],{"class":362,"line":844},[360,23381,2927],{"class":366},[360,23383,23384],{"class":362,"line":1441},[360,23385,820],{"class":366},[360,23387,23388],{"class":362,"line":1462},[360,23389,847],{"class":366},[12,23391,23392,23393],{},"On peut retrouver la spécification de ce modèle de pagination sur le site de ",[47,23394,23397],{"href":23395,"rel":23396},"https:\u002F\u002Frelay.dev\u002Fgraphql\u002Fconnections.htm",[51],"relay.dev",[1901,23399,23401],{"id":23400},"query-cache-control","Query - Cache - Control",[12,23403,23404],{},"Contrairement au REST où on peut peut utiliser les header HTTP, pour contrôler le cache, en GraphQL une requête peut avoir des limites d'âge différentes sur les différentes resources\nappelées. Il faut donc trouver d'autres moyens de gérer le cache.",[12,23406,23407],{},"C'est pour moi un des points les plus gênants de GraphQL.",[12,23409,23410,23411,31],{},"Sur le serveur, il y a plusieurs manières complémentaires (à différentes fins) de gérer le cache. Nous allons nous concentrer sur la librairie ",[344,23412,23413],{},"apollo-server",[12,23415,23416,23417,23420,23421,23424],{},"La 1ère manière s'apparentant au cache-control des requêtes HTTP peut être utilisée avec la directive ",[344,23418,23419],{},"@cacheControl"," ou au niveau du resolver. Elle ne permet pas de cacher directement la donnée\nmais de donner une indication au client sur combien de temps cette donnée peut-être cachée. Si la librairie utilisée côté client est également ",[344,23422,23423],{},"apollo"," elle utilisera alors ces indications pour\ngérer le cache de la donnée (et donc ne pas ré-effectuer la requête.)",[352,23426,23428],{"className":22026,"code":23427,"language":22028,"meta":291,"style":291},"scalar Date\n\n\"\"\"\nDefine the state of the queue\n\"\"\"\ntype QueueStats @cacheControl(maxAge: 60) {\n  \"\"\"\n  Number of task waiting in queue\n  \"\"\"\n  waiting: Int!\n  \"\"\"\n  Number of task active in queue\n  \"\"\"\n  active: Int!\n  \"\"\"\n  Number of task that have failed\n  \"\"\"\n  failed: Int!\n  \"\"\"\n  Date of the last execution\n  \"\"\"\n  lastExecution: Date! @cacheControl(maxAge: 3600)\n  \"\"\"\n  Date of the next wakeup\n  \"\"\"\n  nextWakeup: Date! @cacheControl(maxAge: 3600)\n}\n",[344,23429,23430,23436,23440,23444,23448,23452,23473,23477,23481,23485,23491,23495,23499,23503,23509,23513,23517,23521,23527,23531,23535,23539,23559,23563,23567,23571,23589],{"__ignoreMap":291},[360,23431,23432,23434],{"class":362,"line":363},[360,23433,22193],{"class":574},[360,23435,22196],{"class":366},[360,23437,23438],{"class":362,"line":292},[360,23439,372],{"emptyLinePlaceholder":320},[360,23441,23442],{"class":362,"line":375},[360,23443,22205],{"class":644},[360,23445,23446],{"class":362,"line":433},[360,23447,22210],{"class":644},[360,23449,23450],{"class":362,"line":478},[360,23451,22205],{"class":644},[360,23453,23454,23456,23459,23461,23463,23466,23468,23471],{"class":362,"line":483},[360,23455,19774],{"class":574},[360,23457,23458],{"class":366}," QueueStats ",[360,23460,23419],{"class":381},[360,23462,671],{"class":366},[360,23464,23465],{"class":677},"maxAge",[360,23467,2691],{"class":366},[360,23469,23470],{"class":414},"60",[360,23472,681],{"class":366},[360,23474,23475],{"class":362,"line":489},[360,23476,22226],{"class":644},[360,23478,23479],{"class":362,"line":494},[360,23480,22231],{"class":644},[360,23482,23483],{"class":362,"line":712},[360,23484,22226],{"class":644},[360,23486,23487,23489],{"class":362,"line":331},[360,23488,22240],{"class":578},[360,23490,22243],{"class":366},[360,23492,23493],{"class":362,"line":762},[360,23494,22226],{"class":644},[360,23496,23497],{"class":362,"line":781},[360,23498,22252],{"class":644},[360,23500,23501],{"class":362,"line":804},[360,23502,22226],{"class":644},[360,23504,23505,23507],{"class":362,"line":817},[360,23506,22261],{"class":578},[360,23508,22243],{"class":366},[360,23510,23511],{"class":362,"line":823},[360,23512,22226],{"class":644},[360,23514,23515],{"class":362,"line":844},[360,23516,22272],{"class":644},[360,23518,23519],{"class":362,"line":1441},[360,23520,22226],{"class":644},[360,23522,23523,23525],{"class":362,"line":1462},[360,23524,22281],{"class":578},[360,23526,22243],{"class":366},[360,23528,23529],{"class":362,"line":1485},[360,23530,22226],{"class":644},[360,23532,23533],{"class":362,"line":1497},[360,23534,22292],{"class":644},[360,23536,23537],{"class":362,"line":3161},[360,23538,22226],{"class":644},[360,23540,23541,23543,23546,23548,23550,23552,23554,23557],{"class":362,"line":3167},[360,23542,22301],{"class":578},[360,23544,23545],{"class":366},": Date! ",[360,23547,23419],{"class":381},[360,23549,671],{"class":366},[360,23551,23465],{"class":677},[360,23553,2691],{"class":366},[360,23555,23556],{"class":414},"3600",[360,23558,2922],{"class":366},[360,23560,23561],{"class":362,"line":3194},[360,23562,22226],{"class":644},[360,23564,23565],{"class":362,"line":3224},[360,23566,22313],{"class":644},[360,23568,23569],{"class":362,"line":3239},[360,23570,22226],{"class":644},[360,23572,23573,23575,23577,23579,23581,23583,23585,23587],{"class":362,"line":3256},[360,23574,22322],{"class":578},[360,23576,23545],{"class":366},[360,23578,23419],{"class":381},[360,23580,671],{"class":366},[360,23582,23465],{"class":677},[360,23584,2691],{"class":366},[360,23586,23556],{"class":414},[360,23588,2922],{"class":366},[360,23590,23591],{"class":362,"line":3276},[360,23592,847],{"class":366},[12,23594,23595,23596,23601],{},"Je vous invite à lire la ",[47,23597,23600],{"href":23598,"rel":23599},"https:\u002F\u002Fwww.apollographql.com\u002Fdocs\u002Fapollo-server\u002Fperformance\u002Fcaching\u002F",[51],"documentation d'apollo"," qui contient énormément d'informations. Cette méthode permet d'ajouter\ndes header http pour cacher les requêtes dans un CDN intérmédiaire, ou dans une base redis attachée au serveur, ou dans le cache navigateur, voir également au niveau même du client.",[1901,23603,23605],{"id":23604},"query-cache-dataloader","Query - Cache - DataLoader",[12,23607,23608,23609,23614],{},"La 2nd méthode de cache consiste à l'utilisation de ",[47,23610,23613],{"href":23611,"rel":23612},"https:\u002F\u002Fgithub.com\u002Fgraphql\u002Fdataloader",[51],"DataLoader",". L'ajout d'un dataloader a pour but de cacher le temps d'une requête les différents éléments pour éviter de multiplier les appels.\nLe but n'étant pas de réellement faire du cache mais plutôt de pouvoir traiter une requête batch le plus rapidement possible.",[12,23616,23617],{},"Imaginons par exemple la requête suivante :",[352,23619,23621],{"className":22026,"code":23620,"language":22028,"meta":291,"style":291},"query TestDataLoader {\n  backups {\n    id\n    startDate\n    endDate\n    user {\n      firstName\n      lastName\n    }\n  }\n}\n",[344,23622,23623,23632,23639,23644,23649,23654,23661,23666,23671,23675,23679],{"__ignoreMap":291},[360,23624,23625,23627,23630],{"class":362,"line":363},[360,23626,22035],{"class":574},[360,23628,23629],{"class":381}," TestDataLoader",[360,23631,896],{"class":366},[360,23633,23634,23637],{"class":362,"line":292},[360,23635,23636],{"class":578},"  backups",[360,23638,896],{"class":366},[360,23640,23641],{"class":362,"line":375},[360,23642,23643],{"class":578},"    id\n",[360,23645,23646],{"class":362,"line":433},[360,23647,23648],{"class":578},"    startDate\n",[360,23650,23651],{"class":362,"line":478},[360,23652,23653],{"class":578},"    endDate\n",[360,23655,23656,23659],{"class":362,"line":483},[360,23657,23658],{"class":578},"    user",[360,23660,896],{"class":366},[360,23662,23663],{"class":362,"line":489},[360,23664,23665],{"class":578},"      firstName\n",[360,23667,23668],{"class":362,"line":494},[360,23669,23670],{"class":578},"      lastName\n",[360,23672,23673],{"class":362,"line":712},[360,23674,2927],{"class":366},[360,23676,23677],{"class":362,"line":331},[360,23678,820],{"class":366},[360,23680,23681],{"class":362,"line":762},[360,23682,847],{"class":366},[12,23684,23685],{},"Dans le cas présent, on souhaite récupérer les backups, mais également pour chaque backup récupérer l'utilisateur. Si l'utilisateur est le même pour chaque backup, on se retouve alors à charger\nl'utilisateur plusieurs fois. Le fait d'utiliser un dataloader permettra dans le cas présent de ne les charger qu'une fois.",[12,23687,23688,23689,23694],{},"Pour utiliser le système de data loader, on peut utiliser la bibliothèque du même nom: [",[47,23690,23693],{"href":23691,"rel":23692},"https:\u002F\u002Fgithub.com\u002Fgraphql\u002Fdataloader%5D(Github",[51],"https:\u002F\u002Fgithub.com\u002Fgraphql\u002Fdataloader](Github",": graphql\u002Fdataloader). Il nous faut alors créer un dataloader pour\nun type d'objet.",[352,23696,23698],{"className":6044,"code":23697,"language":6046,"meta":291,"style":291},"import DataLoader from \"dataloader\";\n\nconst userLoader = new DataLoader((keys) => service.getUsers(keys));\n",[344,23699,23700,23714,23718],{"__ignoreMap":291},[360,23701,23702,23704,23707,23709,23712],{"class":362,"line":363},[360,23703,14036],{"class":574},[360,23705,23706],{"class":578}," DataLoader",[360,23708,14046],{"class":574},[360,23710,23711],{"class":397}," \"dataloader\"",[360,23713,735],{"class":366},[360,23715,23716],{"class":362,"line":292},[360,23717,372],{"emptyLinePlaceholder":320},[360,23719,23720,23722,23725,23727,23729,23731,23733,23736,23738,23740,23742,23744,23747,23749,23751],{"class":362,"line":375},[360,23721,6053],{"class":574},[360,23723,23724],{"class":662}," userLoader",[360,23726,401],{"class":582},[360,23728,3040],{"class":574},[360,23730,23706],{"class":381},[360,23732,7148],{"class":366},[360,23734,23735],{"class":677},"keys",[360,23737,3972],{"class":366},[360,23739,6331],{"class":574},[360,23741,19311],{"class":662},[360,23743,31],{"class":366},[360,23745,23746],{"class":381},"getUsers",[360,23748,671],{"class":366},[360,23750,23735],{"class":578},[360,23752,4081],{"class":366},[12,23754,23755],{},"Ensuite dans les resolvers, au lieu de récupérer les utilisateurs directement à partir du service, on utilise le data loader pour récupérer la valeur :",[352,23757,23759],{"className":6044,"code":23758,"language":6046,"meta":291,"style":291},"const resolvers = {\n  async backups() {\n    return service.find();\n  },\n  Backup: {\n    async user(ctx, { id }) {\n      return await userLoader.load(id);\n    },\n  },\n};\n",[344,23760,23761,23771,23779,23791,23795,23802,23822,23841,23845,23849],{"__ignoreMap":291},[360,23762,23763,23765,23767,23769],{"class":362,"line":363},[360,23764,6053],{"class":574},[360,23766,22548],{"class":662},[360,23768,401],{"class":582},[360,23770,896],{"class":366},[360,23772,23773,23775,23777],{"class":362,"line":292},[360,23774,17493],{"class":574},[360,23776,4949],{"class":381},[360,23778,2172],{"class":366},[360,23780,23781,23783,23785,23787,23789],{"class":362,"line":375},[360,23782,1386],{"class":574},[360,23784,19311],{"class":662},[360,23786,31],{"class":366},[360,23788,5606],{"class":381},[360,23790,2204],{"class":366},[360,23792,23793],{"class":362,"line":433},[360,23794,6758],{"class":366},[360,23796,23797,23800],{"class":362,"line":478},[360,23798,23799],{"class":578},"  Backup",[360,23801,6359],{"class":366},[360,23803,23804,23806,23809,23811,23814,23817,23819],{"class":362,"line":483},[360,23805,22584],{"class":574},[360,23807,23808],{"class":381}," user",[360,23810,671],{"class":366},[360,23812,23813],{"class":677},"ctx",[360,23815,23816],{"class":366},", { ",[360,23818,18908],{"class":677},[360,23820,23821],{"class":366}," }) {\n",[360,23823,23824,23826,23828,23830,23832,23835,23837,23839],{"class":362,"line":489},[360,23825,18932],{"class":574},[360,23827,15801],{"class":574},[360,23829,23724],{"class":662},[360,23831,31],{"class":366},[360,23833,23834],{"class":381},"load",[360,23836,671],{"class":366},[360,23838,18908],{"class":578},[360,23840,801],{"class":366},[360,23842,23843],{"class":362,"line":494},[360,23844,6505],{"class":366},[360,23846,23847],{"class":362,"line":712},[360,23848,6758],{"class":366},[360,23850,23851],{"class":362,"line":331},[360,23852,1036],{"class":366},[12,23854,23855,23858],{},[344,23856,23857],{},"Dataloader"," n'est par contre pas fait pour être utilisé en tant que cache applicatif et ne remplace donc pas un memcached ou un redis.",[1901,23860,23862],{"id":23861},"query-batch","Query - Batch",[12,23864,23865,23867],{},[344,23866,22010],{}," côté client propose de pouvoir faire du batching de requêtes. Cela consiste à attendre un léger laps de temps pour regrouper en une seule requête plusieurs requêtes.",[12,23869,23870],{},"Attention néanmoins, mettre en place le batching de requêtes implique:",[140,23872,23873,23876,23879],{},[143,23874,23875],{},"qu'on attend (pas très longtemps) pour envoyer les requêtes",[143,23877,23878],{},"qu'on attend l'aggrégat des réponses avant de les recevoir",[143,23880,23881],{},"qu'on ne bénéficie pas du multiplexing des requêtes de HTTP\u002F2.",[12,23883,23884],{},"Il est alors conseillé d'abord de faire d'autres types d'optimisations (comme utiliser les requêtes persistentes, un cache dans un CDN des réponses, utiliser HTTP\u002F2 jusqu'au NodeJS)\navant de mettre en place le système de batch.",[12,23886,23887,23888,31],{},"Si vous voulez le mettre tout de même en place, vous pouvez regarder la ",[47,23889,23892],{"href":23890,"rel":23891},"https:\u002F\u002Fwww.apollographql.com\u002Fdocs\u002Flink\u002Flinks\u002Fbatch-http\u002F",[51],"documentation d'Apollo sur ce sujet",[1901,23894,23896],{"id":23895},"query-transfert-réseau","Query - Transfert réseau",[12,23898,23899],{},"Pour une API Web, les requêtes et les réponses sont transférées en utilisant le protocole HTTP. Pour améliorer les performances il est\npossible d'utiliser plusieurs méthodes:",[140,23901,23902,23905,23912,23915],{},[143,23903,23904],{},"Comme en REST, activer la compression GZIP coté serveur, permet de réduire les flux réseaux",[143,23906,23907,23908],{},"Utiliser les requêtes persistentes (stocké coté serveur) : ",[47,23909,23910],{"href":23910,"rel":23911},"https:\u002F\u002Fwww.apollographql.com\u002Fdocs\u002Fapollo-server\u002Fperformance\u002Fapq\u002F",[51],[143,23913,23914],{},"Utiliser les fragments pour réutiliser certaines parties des requêtes qui peuvent se répéter.",[143,23916,23917],{},"Utiliser HTTP\u002F2 et le multiplexing des requêtes. Faire une seule grosse requête peut être contre-productif avec HTTP\u002F2. En effet il faut attendre la fin de la résolution de l'ensemble des resolvers\ncôté serveur avant d'avoir la réponse. Faire plusieurs requêtes peut permettre d'avoir certaines parties de la requête plus vite. De plus HTTP\u002F2 permet de mieux paralléliser les requêtes. Il faut donc\ntrouver le bon nombre de requêtes à executer pour avoir les meilleurs performances.",[1901,23919,23921],{"id":23920},"mutation","Mutation",[12,23923,23924,23925,31],{},"Nous avons énormément parlé de toute la partie requête de GraphQL. GraphQL permet également de faire des modifications via des ",[344,23926,23927],{},"mutations",[12,23929,23930],{},"Une mutation est similaire à une requête :",[352,23932,23934],{"className":22026,"code":23933,"language":22028,"meta":291,"style":291},"mutation CreateBackup($backup: CreateBackupInput!) {\n  createBackup(backup: $backup) {\n    statusCode\n    message\n    error\n    errorCode\n    backup {\n      id\n      state\n      user {\n        id\n      }\n    }\n  }\n",[344,23935,23936,23951,23966,23971,23976,23981,23986,23993,23998,24003,24010,24015,24019,24023],{"__ignoreMap":291},[360,23937,23938,23940,23943,23945,23948],{"class":362,"line":363},[360,23939,23920],{"class":574},[360,23941,23942],{"class":381}," CreateBackup",[360,23944,671],{"class":366},[360,23946,23947],{"class":677},"$backup",[360,23949,23950],{"class":366},": CreateBackupInput!) {\n",[360,23952,23953,23956,23958,23960,23962,23964],{"class":362,"line":292},[360,23954,23955],{"class":578},"  createBackup",[360,23957,671],{"class":366},[360,23959,6017],{"class":677},[360,23961,2691],{"class":366},[360,23963,23947],{"class":578},[360,23965,681],{"class":366},[360,23967,23968],{"class":362,"line":375},[360,23969,23970],{"class":578},"    statusCode\n",[360,23972,23973],{"class":362,"line":433},[360,23974,23975],{"class":578},"    message\n",[360,23977,23978],{"class":362,"line":478},[360,23979,23980],{"class":578},"    error\n",[360,23982,23983],{"class":362,"line":483},[360,23984,23985],{"class":578},"    errorCode\n",[360,23987,23988,23991],{"class":362,"line":489},[360,23989,23990],{"class":578},"    backup",[360,23992,896],{"class":366},[360,23994,23995],{"class":362,"line":494},[360,23996,23997],{"class":578},"      id\n",[360,23999,24000],{"class":362,"line":712},[360,24001,24002],{"class":578},"      state\n",[360,24004,24005,24008],{"class":362,"line":331},[360,24006,24007],{"class":578},"      user",[360,24009,896],{"class":366},[360,24011,24012],{"class":362,"line":762},[360,24013,24014],{"class":578},"        id\n",[360,24016,24017],{"class":362,"line":781},[360,24018,23356],{"class":366},[360,24020,24021],{"class":362,"line":804},[360,24022,2927],{"class":366},[360,24024,24025],{"class":362,"line":817},[360,24026,820],{"class":366},[12,24028,24029],{},"Nous retrouvons la partie input, et la partie query (sur la réponse). Alors que généralement sur query on va retrouver des types primitifs en paramètres, on va plutôt retrouver\nen paramètre d'une mutation un objet de type Input. Sur le résultat le fonctionnement est lui le même que sur une Query.",[12,24031,24032],{},"Nous pouvons d'ailleurs utiliser les mêmes resolvers sur les réponses que dans les queries (et ainsi récupérer l'utilisateur de la backup de la même manière).",[12,24034,24035],{},"En bonne pratique, ce que nous pouvons retrouver sur les mutations sont:",[140,24037,24038,24041,24052,24057,24069],{},[143,24039,24040],{},"Ne pas renvoyer l'objet créé\u002Fmodifié directement. Renvoyer un objet permettant à l'utilisateur de récupérer l'erreur fonctionnelle ou l'objet selon le cas. Cela permettra de faire\névoluer plus facilement le résultat si nécessaire.",[143,24042,24043,24044,24047,24048,24051],{},"De la même manière, ",[28,24045,24046],{},"même"," si la mutation a besoin de très peu de paramètres en entrée, il vaut mieux créer un objet de type ",[344,24049,24050],{},"input"," afin de passer les paramètres. Ceci également\nafin de pouvoir évoluer facilement avec l'API au fur et à mesure des évolutions.",[143,24053,24054,24055,31],{},"Eviter pour le paramètre principal ou la sortie principale de réutiliser un objet. Il vaut mieux en créer un propre à la ",[344,24056,23920],{},[143,24058,24059,24060,24062,24063,24065,24066,24068],{},"Contrairement à REST, les ",[344,24061,23927],{}," GraphQL ressemblent plus à du RPC. Il vaut mieux alors éviter de penser ressources mais plutôt actions. Quels sont les actions que l'on souhaite\npouvoir faire depuis l'IHM.",[13844,24064],{},"Il ne faut pas hésiter à découper ces actions en petites actions que l'utilisateur peut choisir d'appeler ou non (il est possible d'appeler plusieurs ",[344,24067,23927],{}," en un seul appel).",[143,24070,24071,24072,24074],{},"Penser les ",[344,24073,23927],{}," en fonction des appels de vos clients.",[12,24076,24077],{},"Si on reprend le schéma suivant:",[352,24079,24081],{"className":22026,"code":24080,"language":22028,"meta":291,"style":291},"input InputUser {\n  name: String!\n}\n\ninput CreateBackupInput {\n  host: String!\n  user: InputUser!\n}\n\ntype Backup {\n  host: String!\n  id: Int!\n  startDate: Date\n  endDate: Date\n  user: User\n}\n\ntype User {\n  name: String\n  backups: [Backup!]\n}\n\ntype CreateBackupResponse {\n  statusCode: Int!\n  message: String\n  error: String\n  errorCode: String\n  backup: Backup\n}\n",[344,24082,24083,24090,24097,24101,24105,24112,24118,24125,24129,24133,24140,24146,24153,24161,24168,24175,24179,24183,24190,24197,24204,24208,24212,24219,24226,24232,24239,24246,24254],{"__ignoreMap":291},[360,24084,24085,24087],{"class":362,"line":363},[360,24086,24050],{"class":574},[360,24088,24089],{"class":366}," InputUser {\n",[360,24091,24092,24094],{"class":362,"line":292},[360,24093,18163],{"class":578},[360,24095,24096],{"class":366},": String!\n",[360,24098,24099],{"class":362,"line":375},[360,24100,847],{"class":366},[360,24102,24103],{"class":362,"line":433},[360,24104,372],{"emptyLinePlaceholder":320},[360,24106,24107,24109],{"class":362,"line":478},[360,24108,24050],{"class":574},[360,24110,24111],{"class":366}," CreateBackupInput {\n",[360,24113,24114,24116],{"class":362,"line":483},[360,24115,22344],{"class":578},[360,24117,24096],{"class":366},[360,24119,24120,24122],{"class":362,"line":489},[360,24121,21744],{"class":578},[360,24123,24124],{"class":366},": InputUser!\n",[360,24126,24127],{"class":362,"line":494},[360,24128,847],{"class":366},[360,24130,24131],{"class":362,"line":712},[360,24132,372],{"emptyLinePlaceholder":320},[360,24134,24135,24137],{"class":362,"line":331},[360,24136,19774],{"class":574},[360,24138,24139],{"class":366}," Backup {\n",[360,24141,24142,24144],{"class":362,"line":762},[360,24143,22344],{"class":578},[360,24145,24096],{"class":366},[360,24147,24148,24151],{"class":362,"line":781},[360,24149,24150],{"class":578},"  id",[360,24152,22243],{"class":366},[360,24154,24155,24158],{"class":362,"line":804},[360,24156,24157],{"class":578},"  startDate",[360,24159,24160],{"class":366},": Date\n",[360,24162,24163,24166],{"class":362,"line":817},[360,24164,24165],{"class":578},"  endDate",[360,24167,24160],{"class":366},[360,24169,24170,24172],{"class":362,"line":823},[360,24171,21744],{"class":578},[360,24173,24174],{"class":366},": User\n",[360,24176,24177],{"class":362,"line":844},[360,24178,847],{"class":366},[360,24180,24181],{"class":362,"line":1441},[360,24182,372],{"emptyLinePlaceholder":320},[360,24184,24185,24187],{"class":362,"line":1462},[360,24186,19774],{"class":574},[360,24188,24189],{"class":366}," User {\n",[360,24191,24192,24194],{"class":362,"line":1485},[360,24193,18163],{"class":578},[360,24195,24196],{"class":366},": String\n",[360,24198,24199,24201],{"class":362,"line":1497},[360,24200,23636],{"class":578},[360,24202,24203],{"class":366},": [Backup!]\n",[360,24205,24206],{"class":362,"line":3161},[360,24207,847],{"class":366},[360,24209,24210],{"class":362,"line":3167},[360,24211,372],{"emptyLinePlaceholder":320},[360,24213,24214,24216],{"class":362,"line":3194},[360,24215,19774],{"class":574},[360,24217,24218],{"class":366}," CreateBackupResponse {\n",[360,24220,24221,24224],{"class":362,"line":3224},[360,24222,24223],{"class":578},"  statusCode",[360,24225,22243],{"class":366},[360,24227,24228,24230],{"class":362,"line":3239},[360,24229,14340],{"class":578},[360,24231,24196],{"class":366},[360,24233,24234,24237],{"class":362,"line":3256},[360,24235,24236],{"class":578},"  error",[360,24238,24196],{"class":366},[360,24240,24241,24244],{"class":362,"line":3276},[360,24242,24243],{"class":578},"  errorCode",[360,24245,24196],{"class":366},[360,24247,24248,24251],{"class":362,"line":3281},[360,24249,24250],{"class":578},"  backup",[360,24252,24253],{"class":366},": Backup\n",[360,24255,24256],{"class":362,"line":3305},[360,24257,847],{"class":366},[12,24259,24260,24261,24263],{},"Contrairement aux paramètres de sortie, il n'est pas possible sur les ",[344,24262,24050],{}," de faire des dépendances circulaires. Un input doit donc être lié à l'action faite\npar la mutation.\nCela veux dire aussi qu'il n'est pas possible de réutiliser un type de sortie en input pour l'entrée. Le point d'exclamation n'est plus un indicateur de non nullité\nmais un indicateur de paramètre obligatoire.",[12,24265,24266],{},"Lors de la conception des ces inputs il faut d'ailleurs penser à plusieurs choses:",[140,24268,24269,24272],{},[143,24270,24271],{},"Certain champs en sortie dans un type sont là pour representer un calcul ou un état qui fait sens mais que l'utilisateur ne peut pas modifier. Il ne faut donc pas\nle mettre en entrée.",[143,24273,24274],{},"Un paramètre qui peut être non nul en sortie n'est pas forcément obligatoire en entrée (et inversement).",[12,24276,24277],{},"Pour une application possédant beaucoup de formulaires et d'écrans de modifications ou d'actions, il peut être donc compliqué d'écrire les requêtes et les mutations associées.",[12,24279,24280,24281,24286],{},"Il peut peut-être être intéressant d'utiliser un transpiler comme ",[47,24282,24285],{"href":24283,"rel":24284},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fgraphql-s2s",[51],"graphql-s2s"," qui permet de simplifier certaines choses\ndans l'écriture du schéma.\nLors de son utilisation sur un projet possédant un gros schéma, il a permis la reprise d'une API Rest existante plus facilement.",[12,24288,24289],{},"Il permet entre autres:",[140,24291,24292,24295],{},[143,24293,24294],{},"de ne pas répéter les champs de l'interface lors de l'héritage d'un type.",[143,24296,24297],{},"de définir des types génériques (qui à la compilation créeront des vrais types).",[1901,24299,24301],{"id":24300},"subscription","Subscription",[12,24303,24304,24305,24308],{},"Un des points que j'adore avec GraphQL c'est la facilité d'implémentation qu'apporte Apollo avec les ",[344,24306,24307],{},"Subscritpions",". Quand on souhaite remonter des informations\ndu serveur au client, on peut mettre en place des WebSockets ou des Server-Side-Events. Il faut alors définir un potocole entre le client et le serveur.",[12,24310,24311],{},"GraphQL utilise de façon transparente une WebSocket dans le cadre des souscriptions. L'avantage c'est que le protocole est le même que pour les query. On effectue une\ndemande et au lieu d'avoir une réponse, une fois, on reçois les mise à jours sur la souscription.",[12,24313,24314],{},"Cela permet de mettre en place facilement des pages dynamiques qui évoluent sans actions utilisateurs (progression, chat, ...) sans se casser la tête.",[12,24316,24317],{},"Pour définir une souscription on peut utiliser une requête comme celle-ci:",[352,24319,24321],{"className":22026,"code":24320,"language":22028,"meta":291,"style":291},"#import \".\u002FFragmentJob.graphql\"\n\nsubscription QueueTasksJobUpdated {\n  jobUpdated {\n    ...FragmentJob\n  }\n}\n",[344,24322,24323,24327,24331,24340,24347,24353,24357],{"__ignoreMap":291},[360,24324,24325],{"class":362,"line":363},[360,24326,23119],{"class":644},[360,24328,24329],{"class":362,"line":292},[360,24330,372],{"emptyLinePlaceholder":320},[360,24332,24333,24335,24338],{"class":362,"line":375},[360,24334,24300],{"class":381},[360,24336,24337],{"class":381}," QueueTasksJobUpdated",[360,24339,896],{"class":366},[360,24341,24342,24345],{"class":362,"line":433},[360,24343,24344],{"class":578},"  jobUpdated",[360,24346,896],{"class":366},[360,24348,24349,24351],{"class":362,"line":478},[360,24350,21138],{"class":366},[360,24352,23161],{"class":578},[360,24354,24355],{"class":362,"line":483},[360,24356,820],{"class":366},[360,24358,24359],{"class":362,"line":489},[360,24360,847],{"class":366},[12,24362,24363],{},"Dans l'exemple ci-dessous je réutilise le fragment d'un job défini dans une query. La souscription dans apollo va automatiquement mettre à jour le résultat et\nrafraichir l'IHM.",[12,24365,24366,24367,18695],{},"Par exemple avec vue cela donne (cf la doc de ",[47,24368,24371],{"href":24369,"rel":24370},"https:\u002F\u002Fapollo.vuejs.org\u002Fguide\u002Fapollo\u002Fsubscriptions.html#subscribe-to-more",[51],"vue-apollo",[352,24373,24375],{"className":6044,"code":24374,"language":6046,"meta":291,"style":291},"apollo: {\n  tags: {\n    query: TAGS_QUERY,\n    subscribeToMore: {\n      document: gql`subscription name($param: String!) {\n        itemAdded(param: $param) {\n          id\n          label\n        }\n      }`,\n      \u002F\u002F Variables passed to the subscription. Since we're using a function,\n      \u002F\u002F they are reactive\n      variables () {\n        return {\n          param: this.param,\n        }\n      },\n      \u002F\u002F Mutate the previous result\n      updateQuery: (previousResult, { subscriptionData }) => {\n        \u002F\u002F Here, return the new result from the previous with the new data\n      },\n    }\n  }\n}\n",[344,24376,24377,24383,24390,24402,24409,24422,24427,24432,24437,24441,24448,24453,24458,24466,24473,24489,24493,24497,24502,24525,24530,24534,24538,24542],{"__ignoreMap":291},[360,24378,24379,24381],{"class":362,"line":363},[360,24380,23423],{"class":578},[360,24382,6359],{"class":366},[360,24384,24385,24388],{"class":362,"line":292},[360,24386,24387],{"class":578},"  tags",[360,24389,6359],{"class":366},[360,24391,24392,24395,24397,24400],{"class":362,"line":375},[360,24393,24394],{"class":578},"    query",[360,24396,2691],{"class":366},[360,24398,24399],{"class":662},"TAGS_QUERY",[360,24401,2968],{"class":366},[360,24403,24404,24407],{"class":362,"line":433},[360,24405,24406],{"class":578},"    subscribeToMore",[360,24408,6359],{"class":366},[360,24410,24411,24414,24416,24419],{"class":362,"line":478},[360,24412,24413],{"class":578},"      document",[360,24415,2691],{"class":366},[360,24417,24418],{"class":381},"gql",[360,24420,24421],{"class":397},"`subscription name($param: String!) {\n",[360,24423,24424],{"class":362,"line":483},[360,24425,24426],{"class":397},"        itemAdded(param: $param) {\n",[360,24428,24429],{"class":362,"line":489},[360,24430,24431],{"class":397},"          id\n",[360,24433,24434],{"class":362,"line":494},[360,24435,24436],{"class":397},"          label\n",[360,24438,24439],{"class":362,"line":712},[360,24440,2840],{"class":397},[360,24442,24443,24446],{"class":362,"line":331},[360,24444,24445],{"class":397},"      }`",[360,24447,2968],{"class":366},[360,24449,24450],{"class":362,"line":762},[360,24451,24452],{"class":644},"      \u002F\u002F Variables passed to the subscription. Since we're using a function,\n",[360,24454,24455],{"class":362,"line":781},[360,24456,24457],{"class":644},"      \u002F\u002F they are reactive\n",[360,24459,24460,24463],{"class":362,"line":804},[360,24461,24462],{"class":381},"      variables",[360,24464,24465],{"class":366}," () {\n",[360,24467,24468,24471],{"class":362,"line":817},[360,24469,24470],{"class":574},"        return",[360,24472,896],{"class":366},[360,24474,24475,24478,24480,24482,24484,24487],{"class":362,"line":823},[360,24476,24477],{"class":578},"          param",[360,24479,2691],{"class":366},[360,24481,14158],{"class":662},[360,24483,31],{"class":366},[360,24485,24486],{"class":578},"param",[360,24488,2968],{"class":366},[360,24490,24491],{"class":362,"line":844},[360,24492,2840],{"class":366},[360,24494,24495],{"class":362,"line":1441},[360,24496,10551],{"class":366},[360,24498,24499],{"class":362,"line":1462},[360,24500,24501],{"class":644},"      \u002F\u002F Mutate the previous result\n",[360,24503,24504,24507,24510,24513,24515,24518,24521,24523],{"class":362,"line":1485},[360,24505,24506],{"class":578},"      updateQuery",[360,24508,24509],{"class":366},": (",[360,24511,24512],{"class":677},"previousResult",[360,24514,23816],{"class":366},[360,24516,24517],{"class":677},"subscriptionData",[360,24519,24520],{"class":366}," }) ",[360,24522,6331],{"class":574},[360,24524,896],{"class":366},[360,24526,24527],{"class":362,"line":1497},[360,24528,24529],{"class":644},"        \u002F\u002F Here, return the new result from the previous with the new data\n",[360,24531,24532],{"class":362,"line":3161},[360,24533,10551],{"class":366},[360,24535,24536],{"class":362,"line":3167},[360,24537,2927],{"class":366},[360,24539,24540],{"class":362,"line":3194},[360,24541,820],{"class":366},[360,24543,24544],{"class":362,"line":3224},[360,24545,847],{"class":366},[12,24547,24548,24549,24552],{},"La requête initiale est faite grâce à ",[344,24550,24551],{},"TAG_QUERY",", puis toutes les mises à jours se font via la souscription. L'IHM est alors automatiquement mise à jour.",[1901,24554,251],{"id":250},[12,24556,24557],{},"GraphQL est super puissant et facilite l'écriture d'API et son utilisation par des clients. Par contre la montée en compétence pour faire du GraphQL est un\npeu plus élevée que pour faire du REST (Bien qu'il n'est pas facile de faire du bon REST).",[12,24559,24560],{},"Il peut toujours être utile de proposer des API Rest en plus des API GraphQL. Pour par exemple permettre au client de choisir ce qu'il souhaite utiliser ou\nmême par exemple pour des cas d'usage particuliers. (Par exemple le téléchargement\u002Fl'upload d'un document binaire est plus facile en REST que en GraphQL).",[1901,24562,24564],{"id":24563},"références","Références",[140,24566,24567,24574,24580,24587,24593,24600,24605],{},[143,24568,24569],{},[47,24570,24573],{"href":24571,"rel":24572},"https:\u002F\u002Fgraphql.org\u002Flearn\u002Fqueries\u002F",[51],"GraphQL",[143,24575,24576,31],{},[47,24577,22010],{"href":24578,"rel":24579},"https:\u002F\u002Fwww.apollographql.com\u002Fdocs\u002Fapollo-server\u002Fdata\u002Fresolvers\u002F",[51],[143,24581,24582],{},[47,24583,24586],{"href":24584,"rel":24585},"https:\u002F\u002Fwww.moesif.com\u002Fblog\u002Ftechnical\u002Fapi-design\u002FBest-Practices-for-Versioning-REST-and-GraphQL-APIs\u002F",[51],"Best Practices for Versioning REST and GraphQL APIs",[143,24588,24589],{},[47,24590,24592],{"href":23197,"rel":24591},[51],"GraphQL Versioning",[143,24594,24595],{},[47,24596,24599],{"href":24597,"rel":24598},"https:\u002F\u002Ftowardsdatascience.com\u002Fgraphql-best-practices-3fda586538c4",[51],"GraphQL Best Practices",[143,24601,24602],{},[47,24603,24584],{"href":24584,"rel":24604},[51],[143,24606,24607],{},[47,24608,23197],{"href":23197,"rel":24609},[51],[1613,24611,24612],{},"html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sLaUg, html code.shiki .sLaUg{--shiki-default:#FFFFFF}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}",{"title":291,"searchDepth":292,"depth":292,"links":24614},[24615,24616],{"id":21626,"depth":292,"text":21627},{"id":21986,"depth":292,"text":21987,"children":24617},[24618,24619,24620,24621,24622,24623,24624,24625,24626,24627,24628,24629,24630,24631,24632,24633],{"id":22016,"depth":375,"text":22017},{"id":22160,"depth":375,"text":22161},{"id":22179,"depth":375,"text":22180},{"id":22840,"depth":375,"text":22841},{"id":22859,"depth":375,"text":22860},{"id":22940,"depth":375,"text":22941},{"id":23179,"depth":375,"text":23180},{"id":23219,"depth":375,"text":23220},{"id":23400,"depth":375,"text":23401},{"id":23604,"depth":375,"text":23605},{"id":23861,"depth":375,"text":23862},{"id":23895,"depth":375,"text":23896},{"id":23920,"depth":375,"text":23921},{"id":24300,"depth":375,"text":24301},{"id":250,"depth":375,"text":251},{"id":24563,"depth":375,"text":24564},"2020-11-29",{"type":9,"value":24636},[24637,24639,24641,24655],[12,24638,21597],{},[12,24640,21600],{},[140,24642,24643,24647,24651],{},[143,24644,24645],{},[47,24646,21608],{"href":21607},[143,24648,24649],{},[47,24650,21614],{"href":21613},[143,24652,24653],{},[47,24654,21620],{"href":21619},[12,24656,21623],{},{"planet":320},"\u002Fpost\u002Fcreation-api-3",{"title":21592,"description":21597},"creation-api-3","posts\u002FProgrammation\u002F2020-11-29_creation-api-3",[24663,22028,24664,1765,1766],"api","rest","HYw0wo6aBhxcGM0oSLGWN8-QiSEHsmV51HJU8dZLB8E",{"id":24667,"title":24668,"author":7,"body":24669,"category":300,"categorySlug":301,"date":28659,"description":24673,"excerpt":28660,"extension":317,"location":318,"meta":28692,"navigation":320,"path":28693,"published":320,"seo":28694,"slug":28695,"stem":28696,"tags":28697,"timeToRead":762,"__hash__":28699},"posts\u002Fposts\u002FProgrammation\u002F2020-11-14_application_du_confinement.md","L'Application du confinement pour se déplacer",{"type":9,"value":24670,"toc":28649},[24671,24674,24677,24686,24694,24697,24700,24703,24717,24721,24740,24743,24757,24760,24763,24766,24773,24776,24780,24785,24891,24894,25160,25163,25166,25169,25568,25582,25591,25594,25776,25779,25911,25915,25918,25921,25986,25994,26036,26039,26147,26150,26391,26394,26657,26660,26910,26928,26939,26943,26950,26956,27078,27092,27095,27259,27262,27268,27275,27278,27562,27565,27568,27672,27682,27692,28022,28025,28031,28582,28585,28589,28592,28607,28610,28626,28646],[12,24672,24673],{},"Préambule: A cause du temps de validation du PlayStore, je publie cet article avec une semaine de retard.",[12,24675,24676],{},"Cela fait plus d'une semaine (quand j'écris ces lignes) que le re-confinement à commencé. Quand je vais courir, je dois me cantonner à\n1km autour de chez moi. Mais quand je cours j'aimerais que mon téléphone intelligent me prévienne quand j'approche du rayon de 1km ou\nquand je le dépasse. Je ne souhaite pas avoir le nez sur une carte de mon téléphone.",[12,24678,24679,24680,24685],{},"Je regarde ce qui se fait. J'ai trouvé l'application suivante sur le play store : ",[47,24681,24684],{"href":24682,"rel":24683},"https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.BETechnology.unkm",[51],"1km",".\nL'application m'avait l'air de répondre à mes critères mais ne fonctionnait pas lors de mon utilisation (en plus il y avait de la pub).",[12,24687,24688,24689,24693],{},"Une autre application ",[47,24690,24684],{"href":24691,"rel":24692},"https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.apps100101.a1km",[51]," pourrait répondre à mon besoin mais\nje ne l'ai pas testé.",[12,24695,24696],{},"Beaucoup d'applications ont pour but de dessiner un cercle sur une carte.",[12,24698,24699],{},"J'ai finalement décidé d'écrire ma propre application (en plus elle sera open source).",[12,24701,24702],{},"Voici ce dont j'ai besoin:",[140,24704,24705,24708,24711,24714],{},[143,24706,24707],{},"une application open source",[143,24709,24710],{},"un gros bouton pour démarrer la surveillance (à partir de mon point de départ)",[143,24712,24713],{},"un avertissement quand on approche du rayon max des 1km.",[143,24715,24716],{},"un avertissement régulier qand on dépasse les 1km.",[33,24718,24720],{"id":24719},"lapplication","L'application",[12,24722,24723,24724,24727,24728,24731,24732,24735,24736,24739],{},"Pour développer une application Android je vais démarrer ",[105,24725,24726],{},"Android Studio"," et commencer à développer le 1er écran. Je choisis le\nlanguage ",[105,24729,24730],{},"Java"," que je maîtrise plus que le language ",[105,24733,24734],{},"Kotlin"," et le SDK Minimum de ",[105,24737,24738],{},"Android 6.0"," pour toucher 85% des\nutilisateurs (si l'application peut interesser d'autres personnes).",[12,24741,24742],{},"J'imagine l'application découpée en deux parties:",[140,24744,24745,24754],{},[143,24746,24747,24748,24753],{},"L'activité",[15680,24749,24750],{},[47,24751,1944],{"href":15684,"ariaDescribedBy":24752,"dataFootnoteRef":291,"id":15687},[15686]," principale de l'application qui contiendra mon gros bouton, la position de départ, la position courante, et la\ndistance à vol d'oiseau du point de départ.",[143,24755,24756],{},"Un service, dont le but est quand l'application est démarrée, de surveiller les déplacements et d'informer l'utilisateur.",[12,24758,24759],{},"Nous allons donc commencer par développer l'activité",[33,24761,24747],{"id":24762},"lactivité",[12,24764,24765],{},"Je ne suis pas graphiste ni UI\u002FUX designer. Le design de cette première interface va alors être très simple et très sobre. Un\ngros bouton + les différentes informations dont j'ai besoin quand l'application est démarrée :",[12,24767,24768],{},[69,24769],{"alt":24770,"className":24771,"src":24772},"Screenshoot page principale",[73],"\u002FProgrammation\u002F1kmarround\u002Fscreenshoot1.png",[12,24774,24775],{},"Lors du démarrage de l'application, j'ai besoin que celle-ci écoute le changement, les positions de l'utilisateur afin de\ndéfinir le point de départ. Comme ce service d'écoute me sera utile également pour le service, je développe une classe à coté.",[1901,24777,24779],{"id":24778},"arroundlocationmanager","ArroundLocationManager",[12,24781,24782,24783,14024],{},"Voici donc la classe ",[28,24784,24779],{},[352,24786,24790],{"className":24787,"code":24788,"language":24789,"meta":291,"style":291},"language-java shiki shiki-themes one-dark-pro","class ArroundLocationManager extends Thread {\n    private static final String TAG = \"ArroundLocationManager\";\n\n    private LocationManager mLocationManager = null;\n    private static final int LOCATION_INTERVAL = 1000;\n    private static final float LOCATION_DISTANCE = 50f;\n","java",[344,24791,24792,24807,24830,24834,24850,24870],{"__ignoreMap":291},[360,24793,24794,24796,24799,24802,24805],{"class":362,"line":363},[360,24795,18818],{"class":574},[360,24797,24798],{"class":662}," ArroundLocationManager",[360,24800,24801],{"class":574}," extends",[360,24803,24804],{"class":662}," Thread",[360,24806,896],{"class":366},[360,24808,24809,24811,24814,24817,24820,24823,24825,24828],{"class":362,"line":292},[360,24810,19308],{"class":574},[360,24812,24813],{"class":574}," static",[360,24815,24816],{"class":574}," final",[360,24818,24819],{"class":662}," String",[360,24821,24822],{"class":578}," TAG ",[360,24824,583],{"class":582},[360,24826,24827],{"class":397}," \"ArroundLocationManager\"",[360,24829,735],{"class":366},[360,24831,24832],{"class":362,"line":375},[360,24833,372],{"emptyLinePlaceholder":320},[360,24835,24836,24838,24841,24844,24846,24848],{"class":362,"line":433},[360,24837,19308],{"class":574},[360,24839,24840],{"class":662}," LocationManager",[360,24842,24843],{"class":578}," mLocationManager ",[360,24845,583],{"class":582},[360,24847,19007],{"class":414},[360,24849,735],{"class":366},[360,24851,24852,24854,24856,24858,24860,24863,24865,24868],{"class":362,"line":478},[360,24853,19308],{"class":574},[360,24855,24813],{"class":574},[360,24857,24816],{"class":574},[360,24859,1091],{"class":574},[360,24861,24862],{"class":578}," LOCATION_INTERVAL ",[360,24864,583],{"class":582},[360,24866,24867],{"class":414}," 1000",[360,24869,735],{"class":366},[360,24871,24872,24874,24876,24878,24881,24884,24886,24889],{"class":362,"line":483},[360,24873,19308],{"class":574},[360,24875,24813],{"class":574},[360,24877,24816],{"class":574},[360,24879,24880],{"class":574}," float",[360,24882,24883],{"class":578}," LOCATION_DISTANCE ",[360,24885,583],{"class":582},[360,24887,24888],{"class":414}," 50f",[360,24890,735],{"class":366},[12,24892,24893],{},"Pour commencer définissons quelques constantes: je souhaite avoir la position, tous les 50m et au maximum toutes les secondes\n(m'enfin quelqu'un qui fait plus de 50m en une seconde à pied est trop fort pour moi).",[352,24895,24897],{"className":24787,"code":24896,"language":24789,"meta":291,"style":291},"    private List\u003CArroundLocationManager.ArrroundLocationListener> listener = new ArrayList\u003C>();\n\n    public interface ArrroundLocationListener {\n        void updateLocation(Location startLocation);\n    }\n\n    private ArroundLocationManager.LocationListener[] mLocationListeners = new ArroundLocationManager.LocationListener[]{\n            new ArroundLocationManager.LocationListener(LocationManager.GPS_PROVIDER),\n            new ArroundLocationManager.LocationListener(LocationManager.NETWORK_PROVIDER)\n    };\n\n    public void addListener(ArroundLocationManager.ArrroundLocationListener l) {\n        listener.add(l);\n    }\n\n    private void callListener(Location location) {\n        for( ArroundLocationManager.ArrroundLocationListener l : listener) {\n            l.updateLocation(location);\n        }\n    }\n",[344,24898,24899,24935,24939,24952,24970,24974,24978,25005,25028,25049,25056,25060,25081,25094,25098,25102,25118,25139,25152,25156],{"__ignoreMap":291},[360,24900,24901,24903,24906,24908,24910,24912,24915,24918,24921,24923,24925,24928,24931,24933],{"class":362,"line":363},[360,24902,19308],{"class":574},[360,24904,24905],{"class":662}," List",[360,24907,1358],{"class":366},[360,24909,24779],{"class":662},[360,24911,31],{"class":366},[360,24913,24914],{"class":662},"ArrroundLocationListener",[360,24916,24917],{"class":366},">",[360,24919,24920],{"class":578}," listener ",[360,24922,583],{"class":582},[360,24924,3040],{"class":574},[360,24926,24927],{"class":662}," ArrayList",[360,24929,24930],{"class":366},"\u003C>",[360,24932,16052],{"class":578},[360,24934,735],{"class":366},[360,24936,24937],{"class":362,"line":292},[360,24938,372],{"emptyLinePlaceholder":320},[360,24940,24941,24944,24947,24950],{"class":362,"line":375},[360,24942,24943],{"class":574},"    public",[360,24945,24946],{"class":574}," interface",[360,24948,24949],{"class":662}," ArrroundLocationListener",[360,24951,896],{"class":366},[360,24953,24954,24957,24960,24962,24965,24968],{"class":362,"line":433},[360,24955,24956],{"class":574},"        void",[360,24958,24959],{"class":381}," updateLocation",[360,24961,671],{"class":366},[360,24963,24964],{"class":662},"Location",[360,24966,24967],{"class":677}," startLocation",[360,24969,801],{"class":366},[360,24971,24972],{"class":362,"line":478},[360,24973,2927],{"class":366},[360,24975,24976],{"class":362,"line":483},[360,24977,372],{"emptyLinePlaceholder":320},[360,24979,24980,24982,24984,24986,24989,24992,24994,24996,24998,25000,25002],{"class":362,"line":489},[360,24981,19308],{"class":574},[360,24983,24798],{"class":662},[360,24985,31],{"class":366},[360,24987,24988],{"class":662},"LocationListener",[360,24990,24991],{"class":578},"[] mLocationListeners ",[360,24993,583],{"class":582},[360,24995,3040],{"class":574},[360,24997,24798],{"class":662},[360,24999,31],{"class":366},[360,25001,24988],{"class":662},[360,25003,25004],{"class":578},"[]{\n",[360,25006,25007,25010,25012,25014,25016,25018,25021,25023,25026],{"class":362,"line":494},[360,25008,25009],{"class":574},"            new",[360,25011,24798],{"class":578},[360,25013,31],{"class":366},[360,25015,24988],{"class":381},[360,25017,671],{"class":366},[360,25019,25020],{"class":662},"LocationManager",[360,25022,31],{"class":366},[360,25024,25025],{"class":662},"GPS_PROVIDER",[360,25027,5405],{"class":366},[360,25029,25030,25032,25034,25036,25038,25040,25042,25044,25047],{"class":362,"line":712},[360,25031,25009],{"class":574},[360,25033,24798],{"class":578},[360,25035,31],{"class":366},[360,25037,24988],{"class":381},[360,25039,671],{"class":366},[360,25041,25020],{"class":662},[360,25043,31],{"class":366},[360,25045,25046],{"class":662},"NETWORK_PROVIDER",[360,25048,2922],{"class":366},[360,25050,25051,25054],{"class":362,"line":331},[360,25052,25053],{"class":578},"    }",[360,25055,735],{"class":366},[360,25057,25058],{"class":362,"line":762},[360,25059,372],{"emptyLinePlaceholder":320},[360,25061,25062,25064,25067,25070,25072,25074,25076,25078],{"class":362,"line":781},[360,25063,24943],{"class":574},[360,25065,25066],{"class":574}," void",[360,25068,25069],{"class":381}," addListener",[360,25071,671],{"class":578},[360,25073,24779],{"class":662},[360,25075,31],{"class":366},[360,25077,24914],{"class":662},[360,25079,25080],{"class":578}," l) {\n",[360,25082,25083,25086,25088,25091],{"class":362,"line":804},[360,25084,25085],{"class":662},"        listener",[360,25087,31],{"class":366},[360,25089,25090],{"class":381},"add",[360,25092,25093],{"class":366},"(l);\n",[360,25095,25096],{"class":362,"line":817},[360,25097,2927],{"class":578},[360,25099,25100],{"class":362,"line":823},[360,25101,372],{"emptyLinePlaceholder":320},[360,25103,25104,25106,25108,25111,25113,25115],{"class":362,"line":844},[360,25105,19308],{"class":574},[360,25107,25066],{"class":574},[360,25109,25110],{"class":381}," callListener",[360,25112,671],{"class":578},[360,25114,24964],{"class":662},[360,25116,25117],{"class":578}," location) {\n",[360,25119,25120,25122,25125,25127,25129,25131,25134,25136],{"class":362,"line":1441},[360,25121,12624],{"class":574},[360,25123,25124],{"class":578},"( ",[360,25126,24779],{"class":662},[360,25128,31],{"class":366},[360,25130,24914],{"class":662},[360,25132,25133],{"class":578}," l ",[360,25135,14024],{"class":574},[360,25137,25138],{"class":578}," listener) {\n",[360,25140,25141,25144,25146,25149],{"class":362,"line":1462},[360,25142,25143],{"class":662},"            l",[360,25145,31],{"class":366},[360,25147,25148],{"class":381},"updateLocation",[360,25150,25151],{"class":366},"(location);\n",[360,25153,25154],{"class":362,"line":1485},[360,25155,2840],{"class":578},[360,25157,25158],{"class":362,"line":1497},[360,25159,2927],{"class":578},[12,25161,25162],{},"Viens ensuite la définition d'un listener pour que les applications qui s'abonnent à cette classe puissent bénéficier d'un\nlistener et recevoir des notifications lors de la mise à jour des positions.",[12,25164,25165],{},"Comme on peut le constater je fais tourner cette classe dans un thread. Lors de mon développement je me suis rendu compte que\nlorsque je quittais l'application, le service était tué également. Une des raisons à cela est que le service est dans le même\nthread que l'activité principale. L'ajout de ce thread (ainsi que d'autre chose) ont résolu le problème. (Mais il est possible\nque ce soit plus lié aux autres choses qu'au thread lui même).",[12,25167,25168],{},"Voici le coeur du thread:",[352,25170,25172],{"className":24787,"code":25171,"language":24789,"meta":291,"style":291},"    public void run() {\n        Looper.prepare();\n\n        initializeLocationManager();\n\n        Looper.loop();\n\n        \u002F\u002F Never called, loop is killed when activity or thread stopped\n        finalizeLocationManager();\n    }\n\n    private ArroundLocationManager.LocationListener[] mLocationListeners = new ArroundLocationManager.LocationListener[]{\n        new ArroundLocationManager.LocationListener(LocationManager.GPS_PROVIDER),\n        new ArroundLocationManager.LocationListener(LocationManager.NETWORK_PROVIDER)\n    };\n\n    public void initializeLocationManager() {\n        try {\n            mLocationManager.requestLocationUpdates(\n                    LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,\n                    mLocationListeners[1]);\n        } catch (java.lang.SecurityException ex) {\n            Log.i(TAG, \"fail to request location update, ignore\", ex);\n        } catch (IllegalArgumentException ex) {\n            Log.d(TAG, \"network provider does not exist, \" + ex.getMessage());\n        }\n\n        try {\n            mLocationManager.requestLocationUpdates(\n                    LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,\n                    mLocationListeners[0]);\n        } catch (java.lang.SecurityException ex) {\n            Log.i(TAG, \"fail to request location update, ignore\", ex);\n        } catch (IllegalArgumentException ex) {\n            Log.d(TAG, \"gps provider does not exist \" + ex.getMessage());\n        }\n    }\n",[344,25173,25174,25185,25197,25201,25210,25214,25225,25229,25234,25243,25247,25251,25275,25296,25316,25322,25326,25337,25344,25356,25368,25377,25394,25412,25427,25453,25457,25461,25467,25477,25487,25495,25509,25523,25537,25560,25564],{"__ignoreMap":291},[360,25175,25176,25178,25180,25183],{"class":362,"line":363},[360,25177,24943],{"class":574},[360,25179,25066],{"class":574},[360,25181,25182],{"class":381}," run",[360,25184,2172],{"class":578},[360,25186,25187,25190,25192,25195],{"class":362,"line":292},[360,25188,25189],{"class":662},"        Looper",[360,25191,31],{"class":366},[360,25193,25194],{"class":381},"prepare",[360,25196,2204],{"class":366},[360,25198,25199],{"class":362,"line":375},[360,25200,372],{"emptyLinePlaceholder":320},[360,25202,25203,25206,25208],{"class":362,"line":433},[360,25204,25205],{"class":381},"        initializeLocationManager",[360,25207,16052],{"class":578},[360,25209,735],{"class":366},[360,25211,25212],{"class":362,"line":478},[360,25213,372],{"emptyLinePlaceholder":320},[360,25215,25216,25218,25220,25223],{"class":362,"line":483},[360,25217,25189],{"class":662},[360,25219,31],{"class":366},[360,25221,25222],{"class":381},"loop",[360,25224,2204],{"class":366},[360,25226,25227],{"class":362,"line":489},[360,25228,372],{"emptyLinePlaceholder":320},[360,25230,25231],{"class":362,"line":494},[360,25232,25233],{"class":644},"        \u002F\u002F Never called, loop is killed when activity or thread stopped\n",[360,25235,25236,25239,25241],{"class":362,"line":712},[360,25237,25238],{"class":381},"        finalizeLocationManager",[360,25240,16052],{"class":578},[360,25242,735],{"class":366},[360,25244,25245],{"class":362,"line":331},[360,25246,2927],{"class":578},[360,25248,25249],{"class":362,"line":762},[360,25250,372],{"emptyLinePlaceholder":320},[360,25252,25253,25255,25257,25259,25261,25263,25265,25267,25269,25271,25273],{"class":362,"line":781},[360,25254,19308],{"class":574},[360,25256,24798],{"class":662},[360,25258,31],{"class":366},[360,25260,24988],{"class":662},[360,25262,24991],{"class":578},[360,25264,583],{"class":582},[360,25266,3040],{"class":574},[360,25268,24798],{"class":662},[360,25270,31],{"class":366},[360,25272,24988],{"class":662},[360,25274,25004],{"class":578},[360,25276,25277,25280,25282,25284,25286,25288,25290,25292,25294],{"class":362,"line":804},[360,25278,25279],{"class":574},"        new",[360,25281,24798],{"class":578},[360,25283,31],{"class":366},[360,25285,24988],{"class":381},[360,25287,671],{"class":366},[360,25289,25020],{"class":662},[360,25291,31],{"class":366},[360,25293,25025],{"class":662},[360,25295,5405],{"class":366},[360,25297,25298,25300,25302,25304,25306,25308,25310,25312,25314],{"class":362,"line":817},[360,25299,25279],{"class":574},[360,25301,24798],{"class":578},[360,25303,31],{"class":366},[360,25305,24988],{"class":381},[360,25307,671],{"class":366},[360,25309,25020],{"class":662},[360,25311,31],{"class":366},[360,25313,25046],{"class":662},[360,25315,2922],{"class":366},[360,25317,25318,25320],{"class":362,"line":823},[360,25319,25053],{"class":578},[360,25321,735],{"class":366},[360,25323,25324],{"class":362,"line":844},[360,25325,372],{"emptyLinePlaceholder":320},[360,25327,25328,25330,25332,25335],{"class":362,"line":1441},[360,25329,24943],{"class":574},[360,25331,25066],{"class":574},[360,25333,25334],{"class":381}," initializeLocationManager",[360,25336,2172],{"class":578},[360,25338,25339,25342],{"class":362,"line":1462},[360,25340,25341],{"class":574},"        try",[360,25343,896],{"class":578},[360,25345,25346,25349,25351,25354],{"class":362,"line":1485},[360,25347,25348],{"class":662},"            mLocationManager",[360,25350,31],{"class":366},[360,25352,25353],{"class":381},"requestLocationUpdates",[360,25355,1395],{"class":366},[360,25357,25358,25361,25363,25365],{"class":362,"line":1497},[360,25359,25360],{"class":662},"                    LocationManager",[360,25362,31],{"class":366},[360,25364,25046],{"class":662},[360,25366,25367],{"class":366},", LOCATION_INTERVAL, LOCATION_DISTANCE,\n",[360,25369,25370,25373,25375],{"class":362,"line":3161},[360,25371,25372],{"class":366},"                    mLocationListeners[",[360,25374,1944],{"class":414},[360,25376,4969],{"class":366},[360,25378,25379,25382,25384,25386,25389,25392],{"class":362,"line":3167},[360,25380,25381],{"class":578},"        } ",[360,25383,7242],{"class":574},[360,25385,743],{"class":578},[360,25387,25388],{"class":662},"java.lang.SecurityException",[360,25390,25391],{"class":677}," ex",[360,25393,681],{"class":578},[360,25395,25396,25399,25401,25403,25406,25409],{"class":362,"line":3194},[360,25397,25398],{"class":662},"            Log",[360,25400,31],{"class":366},[360,25402,6187],{"class":381},[360,25404,25405],{"class":366},"(TAG, ",[360,25407,25408],{"class":397},"\"fail to request location update, ignore\"",[360,25410,25411],{"class":366},", ex);\n",[360,25413,25414,25416,25418,25420,25423,25425],{"class":362,"line":3224},[360,25415,25381],{"class":578},[360,25417,7242],{"class":574},[360,25419,743],{"class":578},[360,25421,25422],{"class":662},"IllegalArgumentException",[360,25424,25391],{"class":677},[360,25426,681],{"class":578},[360,25428,25429,25431,25433,25436,25438,25441,25444,25446,25448,25451],{"class":362,"line":3239},[360,25430,25398],{"class":662},[360,25432,31],{"class":366},[360,25434,25435],{"class":381},"d",[360,25437,25405],{"class":366},[360,25439,25440],{"class":397},"\"network provider does not exist, \"",[360,25442,25443],{"class":582}," +",[360,25445,25391],{"class":662},[360,25447,31],{"class":366},[360,25449,25450],{"class":381},"getMessage",[360,25452,841],{"class":366},[360,25454,25455],{"class":362,"line":3256},[360,25456,2840],{"class":578},[360,25458,25459],{"class":362,"line":3276},[360,25460,372],{"emptyLinePlaceholder":320},[360,25462,25463,25465],{"class":362,"line":3281},[360,25464,25341],{"class":574},[360,25466,896],{"class":578},[360,25468,25469,25471,25473,25475],{"class":362,"line":3305},[360,25470,25348],{"class":662},[360,25472,31],{"class":366},[360,25474,25353],{"class":381},[360,25476,1395],{"class":366},[360,25478,25479,25481,25483,25485],{"class":362,"line":3320},[360,25480,25360],{"class":662},[360,25482,31],{"class":366},[360,25484,25025],{"class":662},[360,25486,25367],{"class":366},[360,25488,25489,25491,25493],{"class":362,"line":3325},[360,25490,25372],{"class":366},[360,25492,1344],{"class":414},[360,25494,4969],{"class":366},[360,25496,25497,25499,25501,25503,25505,25507],{"class":362,"line":3361},[360,25498,25381],{"class":578},[360,25500,7242],{"class":574},[360,25502,743],{"class":578},[360,25504,25388],{"class":662},[360,25506,25391],{"class":677},[360,25508,681],{"class":578},[360,25510,25511,25513,25515,25517,25519,25521],{"class":362,"line":3380},[360,25512,25398],{"class":662},[360,25514,31],{"class":366},[360,25516,6187],{"class":381},[360,25518,25405],{"class":366},[360,25520,25408],{"class":397},[360,25522,25411],{"class":366},[360,25524,25525,25527,25529,25531,25533,25535],{"class":362,"line":3405},[360,25526,25381],{"class":578},[360,25528,7242],{"class":574},[360,25530,743],{"class":578},[360,25532,25422],{"class":662},[360,25534,25391],{"class":677},[360,25536,681],{"class":578},[360,25538,25539,25541,25543,25545,25547,25550,25552,25554,25556,25558],{"class":362,"line":3411},[360,25540,25398],{"class":662},[360,25542,31],{"class":366},[360,25544,25435],{"class":381},[360,25546,25405],{"class":366},[360,25548,25549],{"class":397},"\"gps provider does not exist \"",[360,25551,25443],{"class":582},[360,25553,25391],{"class":662},[360,25555,31],{"class":366},[360,25557,25450],{"class":381},[360,25559,841],{"class":366},[360,25561,25562],{"class":362,"line":3426},[360,25563,2840],{"class":578},[360,25565,25566],{"class":362,"line":3432},[360,25567,2927],{"class":578},[12,25569,25570,25571,25573,25574,25577,25578,25581],{},"On utilise le service ",[344,25572,25020],{}," d'android pour écouter la position de l'utilisateur. On écoute la position venant\ndu ",[105,25575,25576],{},"Network"," qui permet d'avoir une position moins fiable mais rapide, puis celle venant du ",[105,25579,25580],{},"GPS"," permettant d'avoir une\nposition fiable (mais lente à obtenir).",[12,25583,25584,25585,25590],{},"Afin d'avoir une position la plus précise aussi, je me suis inspiré du code suivant:\n",[47,25586,25589],{"href":25587,"rel":25588},"https:\u002F\u002Fstuff.mit.edu\u002Fafs\u002Fsipb\u002Fproject\u002Fandroid\u002Fdocs\u002Ftraining\u002Fbasics\u002Flocation\u002Fcurrentlocation.html",[51],"Obtaining the Current Location",".\nLe code en question permet de choisir entre deux positions la plus précise (entre la position NETWORK et la position GPS).",[12,25592,25593],{},"On notifie les appelants:",[352,25595,25597],{"className":24787,"code":25596,"language":24789,"meta":291,"style":291},"    private class LocationListener implements android.location.LocationListener {\n        public LocationListener(String provider) {\n            Log.e(TAG, \"LocationListener \" + provider);\n            mLocation = new Location(provider);\n        }\n\n        @Override\n        public void onLocationChanged(Location location) {\n            Log.e(TAG, \"onLocationChanged: \" + location);\n            if (isBetterLocation(location, mLocation)) {\n                mLocation.set(location);\n            }\n\n            callListener(mLocation);\n        }\n        ...\n    }\n",[344,25598,25599,25618,25636,25654,25669,25673,25677,25685,25705,25723,25735,25747,25751,25755,25763,25767,25772],{"__ignoreMap":291},[360,25600,25601,25603,25605,25608,25611,25614,25616],{"class":362,"line":363},[360,25602,19308],{"class":574},[360,25604,17459],{"class":574},[360,25606,25607],{"class":662}," LocationListener",[360,25609,25610],{"class":574}," implements",[360,25612,25613],{"class":578}," android.location.",[360,25615,24988],{"class":662},[360,25617,896],{"class":366},[360,25619,25620,25623,25625,25627,25629,25632,25634],{"class":362,"line":292},[360,25621,25622],{"class":574},"        public",[360,25624,25607],{"class":381},[360,25626,671],{"class":366},[360,25628,11350],{"class":662},[360,25630,25631],{"class":677}," provider",[360,25633,16112],{"class":366},[360,25635,896],{"class":366},[360,25637,25638,25640,25642,25644,25646,25649,25651],{"class":362,"line":375},[360,25639,25398],{"class":662},[360,25641,31],{"class":366},[360,25643,3864],{"class":381},[360,25645,25405],{"class":366},[360,25647,25648],{"class":397},"\"LocationListener \"",[360,25650,25443],{"class":582},[360,25652,25653],{"class":366}," provider);\n",[360,25655,25656,25659,25661,25663,25666],{"class":362,"line":433},[360,25657,25658],{"class":366},"            mLocation ",[360,25660,583],{"class":582},[360,25662,3040],{"class":574},[360,25664,25665],{"class":381}," Location",[360,25667,25668],{"class":366},"(provider);\n",[360,25670,25671],{"class":362,"line":478},[360,25672,2840],{"class":366},[360,25674,25675],{"class":362,"line":483},[360,25676,372],{"emptyLinePlaceholder":320},[360,25678,25679,25682],{"class":362,"line":489},[360,25680,25681],{"class":366},"        @",[360,25683,25684],{"class":662},"Override\n",[360,25686,25687,25689,25691,25694,25696,25698,25701,25703],{"class":362,"line":494},[360,25688,25622],{"class":574},[360,25690,25066],{"class":574},[360,25692,25693],{"class":381}," onLocationChanged",[360,25695,671],{"class":366},[360,25697,24964],{"class":662},[360,25699,25700],{"class":677}," location",[360,25702,16112],{"class":366},[360,25704,896],{"class":366},[360,25706,25707,25709,25711,25713,25715,25718,25720],{"class":362,"line":712},[360,25708,25398],{"class":662},[360,25710,31],{"class":366},[360,25712,3864],{"class":381},[360,25714,25405],{"class":366},[360,25716,25717],{"class":397},"\"onLocationChanged: \"",[360,25719,25443],{"class":582},[360,25721,25722],{"class":366}," location);\n",[360,25724,25725,25727,25729,25732],{"class":362,"line":331},[360,25726,3284],{"class":574},[360,25728,743],{"class":366},[360,25730,25731],{"class":381},"isBetterLocation",[360,25733,25734],{"class":366},"(location, mLocation)) {\n",[360,25736,25737,25740,25742,25745],{"class":362,"line":762},[360,25738,25739],{"class":662},"                mLocation",[360,25741,31],{"class":366},[360,25743,25744],{"class":381},"set",[360,25746,25151],{"class":366},[360,25748,25749],{"class":362,"line":781},[360,25750,3435],{"class":366},[360,25752,25753],{"class":362,"line":804},[360,25754,372],{"emptyLinePlaceholder":320},[360,25756,25757,25760],{"class":362,"line":817},[360,25758,25759],{"class":381},"            callListener",[360,25761,25762],{"class":366},"(mLocation);\n",[360,25764,25765],{"class":362,"line":823},[360,25766,2840],{"class":366},[360,25768,25769],{"class":362,"line":844},[360,25770,25771],{"class":366},"        ...\n",[360,25773,25774],{"class":362,"line":1441},[360,25775,2927],{"class":366},[12,25777,25778],{},"Enfin on a une méthode pour calculer les distances avec Android.:",[352,25780,25782],{"className":24787,"code":25781,"language":24789,"meta":291,"style":291},"    public static float getDistance(Location startLocation, Location lastLocation) {\n        float[] results = new float[1];\n        Location.distanceBetween(startLocation.getLatitude(), startLocation.getLongitude(), lastLocation.getLatitude(), lastLocation.getLongitude(), results);\n        float distance = results[0];\n        return distance;\n    }\n",[344,25783,25784,25808,25831,25880,25898,25907],{"__ignoreMap":291},[360,25785,25786,25788,25790,25792,25795,25797,25799,25801,25803,25805],{"class":362,"line":363},[360,25787,24943],{"class":574},[360,25789,24813],{"class":574},[360,25791,24880],{"class":574},[360,25793,25794],{"class":381}," getDistance",[360,25796,671],{"class":578},[360,25798,24964],{"class":662},[360,25800,24967],{"class":578},[360,25802,22488],{"class":366},[360,25804,25665],{"class":662},[360,25806,25807],{"class":578}," lastLocation) {\n",[360,25809,25810,25813,25816,25818,25820,25822,25824,25826,25829],{"class":362,"line":292},[360,25811,25812],{"class":574},"        float",[360,25814,25815],{"class":578},"[] results ",[360,25817,583],{"class":582},[360,25819,3040],{"class":574},[360,25821,24880],{"class":574},[360,25823,2385],{"class":578},[360,25825,1944],{"class":414},[360,25827,25828],{"class":578},"]",[360,25830,735],{"class":366},[360,25832,25833,25836,25838,25841,25843,25846,25848,25851,25853,25855,25857,25860,25862,25865,25867,25869,25871,25873,25875,25877],{"class":362,"line":375},[360,25834,25835],{"class":662},"        Location",[360,25837,31],{"class":366},[360,25839,25840],{"class":381},"distanceBetween",[360,25842,671],{"class":366},[360,25844,25845],{"class":662},"startLocation",[360,25847,31],{"class":366},[360,25849,25850],{"class":381},"getLatitude",[360,25852,6378],{"class":366},[360,25854,25845],{"class":662},[360,25856,31],{"class":366},[360,25858,25859],{"class":381},"getLongitude",[360,25861,6378],{"class":366},[360,25863,25864],{"class":662},"lastLocation",[360,25866,31],{"class":366},[360,25868,25850],{"class":381},[360,25870,6378],{"class":366},[360,25872,25864],{"class":662},[360,25874,31],{"class":366},[360,25876,25859],{"class":381},[360,25878,25879],{"class":366},"(), results);\n",[360,25881,25882,25884,25887,25889,25892,25894,25896],{"class":362,"line":433},[360,25883,25812],{"class":574},[360,25885,25886],{"class":578}," distance ",[360,25888,583],{"class":582},[360,25890,25891],{"class":578}," results[",[360,25893,1344],{"class":414},[360,25895,25828],{"class":578},[360,25897,735],{"class":366},[360,25899,25900,25902,25905],{"class":362,"line":478},[360,25901,24470],{"class":574},[360,25903,25904],{"class":578}," distance",[360,25906,735],{"class":366},[360,25908,25909],{"class":362,"line":483},[360,25910,2927],{"class":578},[1901,25912,25914],{"id":25913},"mainactivity","MainActivity",[12,25916,25917],{},"Retournons dans notre activité principale. Je passe la création du layout qui est fort simple.",[12,25919,25920],{},"Dans l'activité, nous allons commencer par implémenter la phase de création du cycle de vie de notre activité:",[352,25922,25924],{"className":24787,"code":25923,"language":24789,"meta":291,"style":291},"    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n",[344,25925,25926,25933,25950,25963],{"__ignoreMap":291},[360,25927,25928,25931],{"class":362,"line":363},[360,25929,25930],{"class":366},"    @",[360,25932,25684],{"class":662},[360,25934,25935,25937,25939,25942,25944,25947],{"class":362,"line":292},[360,25936,24943],{"class":574},[360,25938,25066],{"class":574},[360,25940,25941],{"class":381}," onCreate",[360,25943,671],{"class":578},[360,25945,25946],{"class":662},"Bundle",[360,25948,25949],{"class":578}," savedInstanceState) {\n",[360,25951,25952,25955,25957,25960],{"class":362,"line":375},[360,25953,25954],{"class":662},"        super",[360,25956,31],{"class":366},[360,25958,25959],{"class":381},"onCreate",[360,25961,25962],{"class":366},"(savedInstanceState);\n",[360,25964,25965,25968,25970,25972,25974,25977,25979,25982,25984],{"class":362,"line":433},[360,25966,25967],{"class":381},"        setContentView",[360,25969,671],{"class":578},[360,25971,2688],{"class":662},[360,25973,31],{"class":366},[360,25975,25976],{"class":662},"layout",[360,25978,31],{"class":366},[360,25980,25981],{"class":662},"activity_main",[360,25983,16112],{"class":578},[360,25985,735],{"class":366},[12,25987,25988,25989,31],{},"Depuis Android 6.0, il faut demander à l'utilisateur la permission d'utiliser la position de l'utilisateur. Du coup\non commence par demander la permission à l'utilisateur d'avoir accès à sa position",[15680,25990,25991],{},[47,25992,795],{"href":16257,"ariaDescribedBy":25993,"dataFootnoteRef":291,"id":16259},[15686],[352,25995,25997],{"className":24787,"code":25996,"language":24789,"meta":291,"style":291},"        requestPermissionsIfNecessary(new String[]{\n                Manifest.permission.ACCESS_FINE_LOCATION,\n        });\n",[344,25998,25999,26012,26029],{"__ignoreMap":291},[360,26000,26001,26004,26006,26008,26010],{"class":362,"line":363},[360,26002,26003],{"class":381},"        requestPermissionsIfNecessary",[360,26005,671],{"class":578},[360,26007,2221],{"class":574},[360,26009,24819],{"class":662},[360,26011,25004],{"class":578},[360,26013,26014,26017,26019,26022,26024,26027],{"class":362,"line":292},[360,26015,26016],{"class":662},"                Manifest",[360,26018,31],{"class":366},[360,26020,26021],{"class":662},"permission",[360,26023,31],{"class":366},[360,26025,26026],{"class":662},"ACCESS_FINE_LOCATION",[360,26028,2968],{"class":366},[360,26030,26031,26034],{"class":362,"line":375},[360,26032,26033],{"class":578},"        })",[360,26035,735],{"class":366},[12,26037,26038],{},"Ensuite on appelle notre location manager et on écoute les changements de positions. Pour chaque changement de position\non met à jour la position et on met à jour les textes.",[352,26040,26042],{"className":24787,"code":26041,"language":24789,"meta":291,"style":291},"        locationManager = new ArroundLocationManager(this);\n        locationManager.addListener((location) -> {\n            if (!isMyServiceRunning(ArroundService.class)) {\n                startLocation = location;\n            }\n            MainActivity.this.updateTextLocation();\n        });\n        locationManager.start();\n",[344,26043,26044,26063,26080,26102,26112,26116,26132,26136],{"__ignoreMap":291},[360,26045,26046,26049,26051,26053,26055,26057,26059,26061],{"class":362,"line":363},[360,26047,26048],{"class":578},"        locationManager ",[360,26050,583],{"class":582},[360,26052,3040],{"class":574},[360,26054,24798],{"class":381},[360,26056,671],{"class":578},[360,26058,14158],{"class":662},[360,26060,16112],{"class":578},[360,26062,735],{"class":366},[360,26064,26065,26068,26070,26073,26076,26078],{"class":362,"line":292},[360,26066,26067],{"class":662},"        locationManager",[360,26069,31],{"class":366},[360,26071,26072],{"class":381},"addListener",[360,26074,26075],{"class":366},"((location) ",[360,26077,2376],{"class":574},[360,26079,896],{"class":366},[360,26081,26082,26084,26086,26088,26091,26093,26096,26098,26100],{"class":362,"line":375},[360,26083,3284],{"class":574},[360,26085,743],{"class":366},[360,26087,1448],{"class":582},[360,26089,26090],{"class":381},"isMyServiceRunning",[360,26092,671],{"class":366},[360,26094,26095],{"class":662},"ArroundService",[360,26097,31],{"class":366},[360,26099,18818],{"class":662},[360,26101,21314],{"class":366},[360,26103,26104,26107,26109],{"class":362,"line":433},[360,26105,26106],{"class":366},"                startLocation ",[360,26108,583],{"class":582},[360,26110,26111],{"class":366}," location;\n",[360,26113,26114],{"class":362,"line":478},[360,26115,3435],{"class":366},[360,26117,26118,26121,26123,26125,26127,26130],{"class":362,"line":483},[360,26119,26120],{"class":662},"            MainActivity",[360,26122,31],{"class":366},[360,26124,14158],{"class":662},[360,26126,31],{"class":366},[360,26128,26129],{"class":381},"updateTextLocation",[360,26131,2204],{"class":366},[360,26133,26134],{"class":362,"line":489},[360,26135,9044],{"class":366},[360,26137,26138,26140,26142,26145],{"class":362,"line":494},[360,26139,26067],{"class":662},[360,26141,31],{"class":366},[360,26143,26144],{"class":381},"start",[360,26146,2204],{"class":366},[12,26148,26149],{},"Enfin on initialise l'IHM.",[352,26151,26153],{"className":24787,"code":26152,"language":24789,"meta":291,"style":291},"        distanceText = findViewById(R.id.distance);\n        startText = findViewById(R.id.start);\n        locationText = findViewById(R.id.location);\n\n        goButton = findViewById(R.id.goButton);\n        stopButton = findViewById(R.id.stopButton);\n        goButton.setOnClickListener(v -> {\n            setStart(true);\n        });\n        stopButton.setOnClickListener(v -> {\n            setStart(false);\n        });\n        setStart(isMyServiceRunning(ArroundService.class));\n        MainActivity.this.updateTextLocation();\n    }\n",[344,26154,26155,26182,26207,26233,26237,26263,26289,26306,26317,26321,26336,26346,26350,26372,26387],{"__ignoreMap":291},[360,26156,26157,26160,26162,26165,26167,26169,26171,26173,26175,26178,26180],{"class":362,"line":363},[360,26158,26159],{"class":578},"        distanceText ",[360,26161,583],{"class":582},[360,26163,26164],{"class":381}," findViewById",[360,26166,671],{"class":578},[360,26168,2688],{"class":662},[360,26170,31],{"class":366},[360,26172,18908],{"class":662},[360,26174,31],{"class":366},[360,26176,26177],{"class":662},"distance",[360,26179,16112],{"class":578},[360,26181,735],{"class":366},[360,26183,26184,26187,26189,26191,26193,26195,26197,26199,26201,26203,26205],{"class":362,"line":292},[360,26185,26186],{"class":578},"        startText ",[360,26188,583],{"class":582},[360,26190,26164],{"class":381},[360,26192,671],{"class":578},[360,26194,2688],{"class":662},[360,26196,31],{"class":366},[360,26198,18908],{"class":662},[360,26200,31],{"class":366},[360,26202,26144],{"class":662},[360,26204,16112],{"class":578},[360,26206,735],{"class":366},[360,26208,26209,26212,26214,26216,26218,26220,26222,26224,26226,26229,26231],{"class":362,"line":375},[360,26210,26211],{"class":578},"        locationText ",[360,26213,583],{"class":582},[360,26215,26164],{"class":381},[360,26217,671],{"class":578},[360,26219,2688],{"class":662},[360,26221,31],{"class":366},[360,26223,18908],{"class":662},[360,26225,31],{"class":366},[360,26227,26228],{"class":662},"location",[360,26230,16112],{"class":578},[360,26232,735],{"class":366},[360,26234,26235],{"class":362,"line":433},[360,26236,372],{"emptyLinePlaceholder":320},[360,26238,26239,26242,26244,26246,26248,26250,26252,26254,26256,26259,26261],{"class":362,"line":478},[360,26240,26241],{"class":578},"        goButton ",[360,26243,583],{"class":582},[360,26245,26164],{"class":381},[360,26247,671],{"class":578},[360,26249,2688],{"class":662},[360,26251,31],{"class":366},[360,26253,18908],{"class":662},[360,26255,31],{"class":366},[360,26257,26258],{"class":662},"goButton",[360,26260,16112],{"class":578},[360,26262,735],{"class":366},[360,26264,26265,26268,26270,26272,26274,26276,26278,26280,26282,26285,26287],{"class":362,"line":483},[360,26266,26267],{"class":578},"        stopButton ",[360,26269,583],{"class":582},[360,26271,26164],{"class":381},[360,26273,671],{"class":578},[360,26275,2688],{"class":662},[360,26277,31],{"class":366},[360,26279,18908],{"class":662},[360,26281,31],{"class":366},[360,26283,26284],{"class":662},"stopButton",[360,26286,16112],{"class":578},[360,26288,735],{"class":366},[360,26290,26291,26294,26296,26299,26302,26304],{"class":362,"line":489},[360,26292,26293],{"class":662},"        goButton",[360,26295,31],{"class":366},[360,26297,26298],{"class":381},"setOnClickListener",[360,26300,26301],{"class":366},"(v ",[360,26303,2376],{"class":574},[360,26305,896],{"class":366},[360,26307,26308,26311,26313,26315],{"class":362,"line":494},[360,26309,26310],{"class":381},"            setStart",[360,26312,671],{"class":366},[360,26314,3081],{"class":414},[360,26316,801],{"class":366},[360,26318,26319],{"class":362,"line":712},[360,26320,9044],{"class":366},[360,26322,26323,26326,26328,26330,26332,26334],{"class":362,"line":331},[360,26324,26325],{"class":662},"        stopButton",[360,26327,31],{"class":366},[360,26329,26298],{"class":381},[360,26331,26301],{"class":366},[360,26333,2376],{"class":574},[360,26335,896],{"class":366},[360,26337,26338,26340,26342,26344],{"class":362,"line":762},[360,26339,26310],{"class":381},[360,26341,671],{"class":366},[360,26343,16837],{"class":414},[360,26345,801],{"class":366},[360,26347,26348],{"class":362,"line":781},[360,26349,9044],{"class":366},[360,26351,26352,26355,26357,26359,26361,26363,26365,26367,26370],{"class":362,"line":804},[360,26353,26354],{"class":381},"        setStart",[360,26356,671],{"class":578},[360,26358,26090],{"class":381},[360,26360,671],{"class":578},[360,26362,26095],{"class":662},[360,26364,31],{"class":366},[360,26366,18818],{"class":662},[360,26368,26369],{"class":578},"))",[360,26371,735],{"class":366},[360,26373,26374,26377,26379,26381,26383,26385],{"class":362,"line":817},[360,26375,26376],{"class":662},"        MainActivity",[360,26378,31],{"class":366},[360,26380,14158],{"class":662},[360,26382,31],{"class":366},[360,26384,26129],{"class":381},[360,26386,2204],{"class":366},[360,26388,26389],{"class":362,"line":823},[360,26390,2927],{"class":578},[12,26392,26393],{},"Comme le LocationManager est un thread, nous devons faire attention à repasser dans le thread de l'UI afin de mettre\nà jour les labels :",[352,26395,26397],{"className":24787,"code":26396,"language":24789,"meta":291,"style":291},"    public void updateTextLocation() {\n        runOnUiThread(() -> {\n            if (this.startLocation != null && this.runLocation != null) {\n                distanceText.setText(getString(R.string.distanceLabel, (int) ArroundLocationManager.getDistance(startLocation, runLocation)));\n            } else {\n                distanceText.setText(\"\");\n            }\n            if (this.startLocation != null) {\n                startText.setText(getAddress(startLocation));\n            } else {\n                startText.setText(\"\");\n            }\n            if (this.runLocation != null) {\n                locationText.setText(getAddress(runLocation));\n            } else {\n                locationText.setText(\"\");\n            }\n        });\n    }\n",[344,26398,26399,26410,26422,26453,26499,26507,26522,26526,26544,26561,26569,26583,26587,26605,26621,26629,26643,26647,26653],{"__ignoreMap":291},[360,26400,26401,26403,26405,26408],{"class":362,"line":363},[360,26402,24943],{"class":574},[360,26404,25066],{"class":574},[360,26406,26407],{"class":381}," updateTextLocation",[360,26409,2172],{"class":578},[360,26411,26412,26415,26418,26420],{"class":362,"line":292},[360,26413,26414],{"class":381},"        runOnUiThread",[360,26416,26417],{"class":578},"(() ",[360,26419,2376],{"class":574},[360,26421,896],{"class":578},[360,26423,26424,26426,26428,26430,26432,26434,26436,26438,26440,26442,26444,26447,26449,26451],{"class":362,"line":375},[360,26425,3284],{"class":574},[360,26427,743],{"class":578},[360,26429,14158],{"class":662},[360,26431,31],{"class":366},[360,26433,25845],{"class":662},[360,26435,3901],{"class":582},[360,26437,19007],{"class":414},[360,26439,754],{"class":582},[360,26441,14110],{"class":662},[360,26443,31],{"class":366},[360,26445,26446],{"class":662},"runLocation",[360,26448,3901],{"class":582},[360,26450,19007],{"class":414},[360,26452,681],{"class":578},[360,26454,26455,26458,26460,26463,26465,26468,26470,26472,26474,26476,26478,26481,26484,26487,26489,26491,26493,26496],{"class":362,"line":433},[360,26456,26457],{"class":662},"                distanceText",[360,26459,31],{"class":366},[360,26461,26462],{"class":381},"setText",[360,26464,671],{"class":366},[360,26466,26467],{"class":381},"getString",[360,26469,671],{"class":366},[360,26471,2688],{"class":662},[360,26473,31],{"class":366},[360,26475,17505],{"class":662},[360,26477,31],{"class":366},[360,26479,26480],{"class":662},"distanceLabel",[360,26482,26483],{"class":366},", (",[360,26485,26486],{"class":574},"int",[360,26488,3972],{"class":366},[360,26490,24779],{"class":662},[360,26492,31],{"class":366},[360,26494,26495],{"class":381},"getDistance",[360,26497,26498],{"class":366},"(startLocation, runLocation)));\n",[360,26500,26501,26503,26505],{"class":362,"line":478},[360,26502,21342],{"class":578},[360,26504,2488],{"class":574},[360,26506,896],{"class":578},[360,26508,26509,26511,26513,26515,26517,26520],{"class":362,"line":483},[360,26510,26457],{"class":662},[360,26512,31],{"class":366},[360,26514,26462],{"class":381},[360,26516,671],{"class":366},[360,26518,26519],{"class":397},"\"\"",[360,26521,801],{"class":366},[360,26523,26524],{"class":362,"line":489},[360,26525,3435],{"class":578},[360,26527,26528,26530,26532,26534,26536,26538,26540,26542],{"class":362,"line":494},[360,26529,3284],{"class":574},[360,26531,743],{"class":578},[360,26533,14158],{"class":662},[360,26535,31],{"class":366},[360,26537,25845],{"class":662},[360,26539,3901],{"class":582},[360,26541,19007],{"class":414},[360,26543,681],{"class":578},[360,26545,26546,26549,26551,26553,26555,26558],{"class":362,"line":712},[360,26547,26548],{"class":662},"                startText",[360,26550,31],{"class":366},[360,26552,26462],{"class":381},[360,26554,671],{"class":366},[360,26556,26557],{"class":381},"getAddress",[360,26559,26560],{"class":366},"(startLocation));\n",[360,26562,26563,26565,26567],{"class":362,"line":331},[360,26564,21342],{"class":578},[360,26566,2488],{"class":574},[360,26568,896],{"class":578},[360,26570,26571,26573,26575,26577,26579,26581],{"class":362,"line":762},[360,26572,26548],{"class":662},[360,26574,31],{"class":366},[360,26576,26462],{"class":381},[360,26578,671],{"class":366},[360,26580,26519],{"class":397},[360,26582,801],{"class":366},[360,26584,26585],{"class":362,"line":781},[360,26586,3435],{"class":578},[360,26588,26589,26591,26593,26595,26597,26599,26601,26603],{"class":362,"line":804},[360,26590,3284],{"class":574},[360,26592,743],{"class":578},[360,26594,14158],{"class":662},[360,26596,31],{"class":366},[360,26598,26446],{"class":662},[360,26600,3901],{"class":582},[360,26602,19007],{"class":414},[360,26604,681],{"class":578},[360,26606,26607,26610,26612,26614,26616,26618],{"class":362,"line":817},[360,26608,26609],{"class":662},"                locationText",[360,26611,31],{"class":366},[360,26613,26462],{"class":381},[360,26615,671],{"class":366},[360,26617,26557],{"class":381},[360,26619,26620],{"class":366},"(runLocation));\n",[360,26622,26623,26625,26627],{"class":362,"line":823},[360,26624,21342],{"class":578},[360,26626,2488],{"class":574},[360,26628,896],{"class":578},[360,26630,26631,26633,26635,26637,26639,26641],{"class":362,"line":844},[360,26632,26609],{"class":662},[360,26634,31],{"class":366},[360,26636,26462],{"class":381},[360,26638,671],{"class":366},[360,26640,26519],{"class":397},[360,26642,801],{"class":366},[360,26644,26645],{"class":362,"line":1441},[360,26646,3435],{"class":578},[360,26648,26649,26651],{"class":362,"line":1462},[360,26650,26033],{"class":578},[360,26652,735],{"class":366},[360,26654,26655],{"class":362,"line":1485},[360,26656,2927],{"class":578},[12,26658,26659],{},"Pour ma part je ne connais pas la position GPS de ma maison par coeur, ni de là ou je me trouve. Cela tombe bien. Android\npropose une API pour geocoder une adresse. C'est à dire que l'on transforme une position en latitude, longitude en adresse\nlisible:",[352,26661,26663],{"className":24787,"code":26662,"language":24789,"meta":291,"style":291},"    String getAddress(Location location) {\n        Geocoder geocoder;\n        List\u003CAddress> addresses;\n\n        try {\n            geocoder = new Geocoder(this, Locale.getDefault());\n\n            addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);\n\n            if (addresses.size() > 0 && addresses.get(0).getMaxAddressLineIndex() >= 0) {\n                return addresses.get(0).getAddressLine(0);\n            }\n            return \"Unknown\";\n        } catch (IOException e) {\n            return e.getMessage();\n        }\n    }\n",[344,26664,26665,26679,26689,26706,26710,26716,26748,26752,26788,26792,26836,26861,26865,26874,26890,26902,26906],{"__ignoreMap":291},[360,26666,26667,26670,26673,26675,26677],{"class":362,"line":363},[360,26668,26669],{"class":662},"    String",[360,26671,26672],{"class":381}," getAddress",[360,26674,671],{"class":578},[360,26676,24964],{"class":662},[360,26678,25117],{"class":578},[360,26680,26681,26684,26687],{"class":362,"line":292},[360,26682,26683],{"class":662},"        Geocoder",[360,26685,26686],{"class":578}," geocoder",[360,26688,735],{"class":366},[360,26690,26691,26694,26696,26699,26701,26704],{"class":362,"line":375},[360,26692,26693],{"class":662},"        List",[360,26695,1358],{"class":366},[360,26697,26698],{"class":662},"Address",[360,26700,24917],{"class":366},[360,26702,26703],{"class":578}," addresses",[360,26705,735],{"class":366},[360,26707,26708],{"class":362,"line":433},[360,26709,372],{"emptyLinePlaceholder":320},[360,26711,26712,26714],{"class":362,"line":478},[360,26713,25341],{"class":574},[360,26715,896],{"class":578},[360,26717,26718,26721,26723,26725,26728,26730,26732,26734,26737,26739,26742,26744,26746],{"class":362,"line":483},[360,26719,26720],{"class":578},"            geocoder ",[360,26722,583],{"class":582},[360,26724,3040],{"class":574},[360,26726,26727],{"class":381}," Geocoder",[360,26729,671],{"class":578},[360,26731,14158],{"class":662},[360,26733,22488],{"class":366},[360,26735,26736],{"class":662}," Locale",[360,26738,31],{"class":366},[360,26740,26741],{"class":381},"getDefault",[360,26743,16052],{"class":366},[360,26745,16112],{"class":578},[360,26747,735],{"class":366},[360,26749,26750],{"class":362,"line":489},[360,26751,372],{"emptyLinePlaceholder":320},[360,26753,26754,26757,26759,26761,26763,26766,26768,26770,26772,26774,26776,26778,26780,26782,26784,26786],{"class":362,"line":494},[360,26755,26756],{"class":578},"            addresses ",[360,26758,583],{"class":582},[360,26760,26686],{"class":662},[360,26762,31],{"class":366},[360,26764,26765],{"class":381},"getFromLocation",[360,26767,671],{"class":366},[360,26769,26228],{"class":662},[360,26771,31],{"class":366},[360,26773,25850],{"class":381},[360,26775,6378],{"class":366},[360,26777,26228],{"class":662},[360,26779,31],{"class":366},[360,26781,25859],{"class":381},[360,26783,6378],{"class":366},[360,26785,1944],{"class":414},[360,26787,801],{"class":366},[360,26789,26790],{"class":362,"line":712},[360,26791,372],{"emptyLinePlaceholder":320},[360,26793,26794,26796,26798,26801,26803,26805,26807,26809,26811,26813,26815,26817,26819,26821,26823,26825,26828,26830,26832,26834],{"class":362,"line":331},[360,26795,3284],{"class":574},[360,26797,743],{"class":578},[360,26799,26800],{"class":662},"addresses",[360,26802,31],{"class":366},[360,26804,6141],{"class":381},[360,26806,16052],{"class":366},[360,26808,3538],{"class":582},[360,26810,1457],{"class":414},[360,26812,754],{"class":582},[360,26814,26703],{"class":662},[360,26816,31],{"class":366},[360,26818,17563],{"class":381},[360,26820,671],{"class":366},[360,26822,1344],{"class":414},[360,26824,2198],{"class":366},[360,26826,26827],{"class":381},"getMaxAddressLineIndex",[360,26829,16052],{"class":366},[360,26831,4519],{"class":582},[360,26833,1457],{"class":414},[360,26835,681],{"class":578},[360,26837,26838,26840,26842,26844,26846,26848,26850,26852,26855,26857,26859],{"class":362,"line":762},[360,26839,3871],{"class":574},[360,26841,26703],{"class":662},[360,26843,31],{"class":366},[360,26845,17563],{"class":381},[360,26847,671],{"class":366},[360,26849,1344],{"class":414},[360,26851,2198],{"class":366},[360,26853,26854],{"class":381},"getAddressLine",[360,26856,671],{"class":366},[360,26858,1344],{"class":414},[360,26860,801],{"class":366},[360,26862,26863],{"class":362,"line":781},[360,26864,3435],{"class":578},[360,26866,26867,26869,26872],{"class":362,"line":804},[360,26868,2821],{"class":574},[360,26870,26871],{"class":397}," \"Unknown\"",[360,26873,735],{"class":366},[360,26875,26876,26878,26880,26882,26885,26888],{"class":362,"line":817},[360,26877,25381],{"class":578},[360,26879,7242],{"class":574},[360,26881,743],{"class":578},[360,26883,26884],{"class":662},"IOException",[360,26886,26887],{"class":677}," e",[360,26889,681],{"class":578},[360,26891,26892,26894,26896,26898,26900],{"class":362,"line":823},[360,26893,2821],{"class":574},[360,26895,26887],{"class":662},[360,26897,31],{"class":366},[360,26899,25450],{"class":381},[360,26901,2204],{"class":366},[360,26903,26904],{"class":362,"line":844},[360,26905,2840],{"class":578},[360,26907,26908],{"class":362,"line":1441},[360,26909,2927],{"class":578},[12,26911,26912,26913,26915,26916,26918,26919],{},"@Override\npublic void onRequestPermissionsResult(int requestCode, String",[360,26914],{}," permissions, int",[360,26917],{}," grantResults) {\nArrayList",[17505,26920,26921,26922,26924,26925,26927],{}," permissionsToRequest = new ArrayList\u003C>();\nfor (int i = 0; i \u003C grantResults.length; i++) {\npermissionsToRequest.add(permissions",[360,26923,6187],{},");\n}\nif (permissionsToRequest.size() > 0) {\nActivityCompat.requestPermissions(this, permissionsToRequest.toArray(new String",[360,26926,1344],{},"), REQUEST_PERMISSIONS_REQUEST_CODE);\n}\n}",[12,26929,26930,26931,26933,26934],{},"private void requestPermissionsIfNecessary(String",[360,26932],{}," permissions) {\nArrayList",[17505,26935,26936,26937,26927],{}," permissionsToRequest = new ArrayList\u003C>();\nfor (String permission : permissions) {\nif (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {\n\u002F\u002F Permission is not granted\npermissionsToRequest.add(permission);\n}\n}\nif (permissionsToRequest.size() > 0) {\nActivityCompat.requestPermissions(this, permissionsToRequest.toArray(new String",[360,26938,1344],{},[33,26940,26942],{"id":26941},"le-service","Le service",[12,26944,26945,26946,26949],{},"Le service est démarré par l'application et doit ensuite survivre à la fermeture de l'application. Pour cela nous\nallons créer un ",[105,26947,26948],{},"foreground service"," qui, contrairement aux services en tâche de fond qui sont déclenchés sur un évènement avec\nune durée de vie relativement courte, va tourner au premier plan en affichant une notification.",[12,26951,26952,26953,14024],{},"Pour démarrer le service depuis l'activité principale nous avons ajouté la méthode ",[344,26954,26955],{},"startServer",[352,26957,26959],{"className":24787,"code":26958,"language":24789,"meta":291,"style":291},"    private void startServer() {\n        if (!mBounded) {\n            Intent mIntent = new Intent(this, ArroundService.class);\n            mIntent.putExtra(\"startLocation\", startLocation);\n            ContextCompat.startForegroundService(this, mIntent);\n            bindService(mIntent, mConnection, BIND_AUTO_CREATE);\n        }\n    }\n",[344,26960,26961,26972,26983,27015,27033,27050,27070,27074],{"__ignoreMap":291},[360,26962,26963,26965,26967,26970],{"class":362,"line":363},[360,26964,19308],{"class":574},[360,26966,25066],{"class":574},[360,26968,26969],{"class":381}," startServer",[360,26971,2172],{"class":578},[360,26973,26974,26976,26978,26980],{"class":362,"line":292},[360,26975,2780],{"class":574},[360,26977,743],{"class":578},[360,26979,1448],{"class":582},[360,26981,26982],{"class":578},"mBounded) {\n",[360,26984,26985,26988,26991,26993,26995,26998,27000,27002,27004,27007,27009,27011,27013],{"class":362,"line":375},[360,26986,26987],{"class":662},"            Intent",[360,26989,26990],{"class":578}," mIntent ",[360,26992,583],{"class":582},[360,26994,3040],{"class":574},[360,26996,26997],{"class":381}," Intent",[360,26999,671],{"class":578},[360,27001,14158],{"class":662},[360,27003,22488],{"class":366},[360,27005,27006],{"class":662}," ArroundService",[360,27008,31],{"class":366},[360,27010,18818],{"class":662},[360,27012,16112],{"class":578},[360,27014,735],{"class":366},[360,27016,27017,27020,27022,27025,27027,27030],{"class":362,"line":433},[360,27018,27019],{"class":662},"            mIntent",[360,27021,31],{"class":366},[360,27023,27024],{"class":381},"putExtra",[360,27026,671],{"class":366},[360,27028,27029],{"class":397},"\"startLocation\"",[360,27031,27032],{"class":366},", startLocation);\n",[360,27034,27035,27038,27040,27043,27045,27047],{"class":362,"line":478},[360,27036,27037],{"class":662},"            ContextCompat",[360,27039,31],{"class":366},[360,27041,27042],{"class":381},"startForegroundService",[360,27044,671],{"class":366},[360,27046,14158],{"class":662},[360,27048,27049],{"class":366},", mIntent);\n",[360,27051,27052,27055,27058,27060,27063,27065,27068],{"class":362,"line":483},[360,27053,27054],{"class":381},"            bindService",[360,27056,27057],{"class":578},"(mIntent",[360,27059,22488],{"class":366},[360,27061,27062],{"class":578}," mConnection",[360,27064,22488],{"class":366},[360,27066,27067],{"class":578}," BIND_AUTO_CREATE)",[360,27069,735],{"class":366},[360,27071,27072],{"class":362,"line":489},[360,27073,2840],{"class":578},[360,27075,27076],{"class":362,"line":494},[360,27077,2927],{"class":578},[12,27079,27080,27081,27083,27084,27087,27088,27091],{},"Ce qui est important c'est la méthode ",[344,27082,27042],{}," dont le but est de démarrer le service en mode ",[105,27085,27086],{},"Foreground",".\nCette méthode a son pendant dans le service qui est ",[344,27089,27090],{},"startForeground",". Si cette dernière n'est pas appelée dans le service\nune erreur sera remontée par Android.",[12,27093,27094],{},"Du coup on implémente le service et on commence par l'initialisation :",[352,27096,27098],{"className":24787,"code":27097,"language":24789,"meta":291,"style":291},"    @Override\n    public void onCreate() {\n        super.onCreate();\n        notificationManager = new ArroundNotificationManager(this);\n        locationManager = new ArroundLocationManager(this);\n        locationManager.addListener(location -> {\n            runLocation = location;\n            callListener(location);\n            notificationManager.send(getDistance());\n            speakDistance();\n        });\n        locationManager.start();\n        textToSpeech = new TextToSpeech(this, this);\n    }\n",[344,27099,27100,27106,27116,27126,27146,27164,27179,27188,27194,27210,27217,27221,27231,27255],{"__ignoreMap":291},[360,27101,27102,27104],{"class":362,"line":363},[360,27103,25930],{"class":366},[360,27105,25684],{"class":662},[360,27107,27108,27110,27112,27114],{"class":362,"line":292},[360,27109,24943],{"class":574},[360,27111,25066],{"class":574},[360,27113,25941],{"class":381},[360,27115,2172],{"class":578},[360,27117,27118,27120,27122,27124],{"class":362,"line":375},[360,27119,25954],{"class":662},[360,27121,31],{"class":366},[360,27123,25959],{"class":381},[360,27125,2204],{"class":366},[360,27127,27128,27131,27133,27135,27138,27140,27142,27144],{"class":362,"line":433},[360,27129,27130],{"class":578},"        notificationManager ",[360,27132,583],{"class":582},[360,27134,3040],{"class":574},[360,27136,27137],{"class":381}," ArroundNotificationManager",[360,27139,671],{"class":578},[360,27141,14158],{"class":662},[360,27143,16112],{"class":578},[360,27145,735],{"class":366},[360,27147,27148,27150,27152,27154,27156,27158,27160,27162],{"class":362,"line":478},[360,27149,26048],{"class":578},[360,27151,583],{"class":582},[360,27153,3040],{"class":574},[360,27155,24798],{"class":381},[360,27157,671],{"class":578},[360,27159,14158],{"class":662},[360,27161,16112],{"class":578},[360,27163,735],{"class":366},[360,27165,27166,27168,27170,27172,27175,27177],{"class":362,"line":483},[360,27167,26067],{"class":662},[360,27169,31],{"class":366},[360,27171,26072],{"class":381},[360,27173,27174],{"class":366},"(location ",[360,27176,2376],{"class":574},[360,27178,896],{"class":366},[360,27180,27181,27184,27186],{"class":362,"line":489},[360,27182,27183],{"class":366},"            runLocation ",[360,27185,583],{"class":582},[360,27187,26111],{"class":366},[360,27189,27190,27192],{"class":362,"line":494},[360,27191,25759],{"class":381},[360,27193,25151],{"class":366},[360,27195,27196,27199,27201,27204,27206,27208],{"class":362,"line":712},[360,27197,27198],{"class":662},"            notificationManager",[360,27200,31],{"class":366},[360,27202,27203],{"class":381},"send",[360,27205,671],{"class":366},[360,27207,26495],{"class":381},[360,27209,841],{"class":366},[360,27211,27212,27215],{"class":362,"line":331},[360,27213,27214],{"class":381},"            speakDistance",[360,27216,2204],{"class":366},[360,27218,27219],{"class":362,"line":762},[360,27220,9044],{"class":366},[360,27222,27223,27225,27227,27229],{"class":362,"line":781},[360,27224,26067],{"class":662},[360,27226,31],{"class":366},[360,27228,26144],{"class":381},[360,27230,2204],{"class":366},[360,27232,27233,27236,27238,27240,27243,27245,27247,27249,27251,27253],{"class":362,"line":804},[360,27234,27235],{"class":578},"        textToSpeech ",[360,27237,583],{"class":582},[360,27239,3040],{"class":574},[360,27241,27242],{"class":381}," TextToSpeech",[360,27244,671],{"class":578},[360,27246,14158],{"class":662},[360,27248,22488],{"class":366},[360,27250,14110],{"class":662},[360,27252,16112],{"class":578},[360,27254,735],{"class":366},[360,27256,27257],{"class":362,"line":817},[360,27258,2927],{"class":578},[12,27260,27261],{},"On démarre le notification manager qui a pour but de notifier l'utilisateur de l'existence d'un service qui tourne au\n1er plan. La notification est d'ailleurs nécessaire pour un service foreground.",[12,27263,27264,27265,27267],{},"On écoute aussi notre ",[344,27266,24779],{}," qui lors des modifications s'occupe de mettre à jour la nouvelle position\net communique le changement de distance à l'utilisateur par voix et par notification.",[12,27269,27270,27271,27274],{},"On retrouve un ",[344,27272,27273],{},"callListener"," pour avertir l'utilisateur sur l'activité principale quand cette dernière est démarrée.",[12,27276,27277],{},"Ensuite le service démarre:",[352,27279,27281],{"className":24787,"code":27280,"language":24789,"meta":291,"style":291},"    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        Log.e(TAG, \"onStartCommand\");\n\n        PowerManager powerService = (PowerManager) getSystemService(Context.POWER_SERVICE);\n        wakeLock = powerService.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"ArroundService::lock\");\n        wakeLock.acquire();\n\n        Bundle extras = intent.getExtras();\n        Location location = (Location) extras.get(\"startLocation\");\n        if (location != null) {\n            this.startLocation = location;\n        }\n\n        Notification notification = notificationManager.notifyDistance(0);\n        startForeground(ArroundNotificationManager.ARROUND_ID, notification);\n\n        return START_STICKY;\n    }\n",[344,27282,27283,27289,27320,27336,27340,27370,27402,27414,27418,27437,27462,27476,27491,27495,27499,27523,27545,27549,27558],{"__ignoreMap":291},[360,27284,27285,27287],{"class":362,"line":363},[360,27286,25930],{"class":366},[360,27288,25684],{"class":662},[360,27290,27291,27293,27295,27298,27300,27303,27306,27308,27310,27313,27315,27317],{"class":362,"line":292},[360,27292,24943],{"class":574},[360,27294,1091],{"class":574},[360,27296,27297],{"class":381}," onStartCommand",[360,27299,671],{"class":578},[360,27301,27302],{"class":662},"Intent",[360,27304,27305],{"class":578}," intent",[360,27307,22488],{"class":366},[360,27309,1091],{"class":574},[360,27311,27312],{"class":578}," flags",[360,27314,22488],{"class":366},[360,27316,1091],{"class":574},[360,27318,27319],{"class":578}," startId) {\n",[360,27321,27322,27325,27327,27329,27331,27334],{"class":362,"line":375},[360,27323,27324],{"class":662},"        Log",[360,27326,31],{"class":366},[360,27328,3864],{"class":381},[360,27330,25405],{"class":366},[360,27332,27333],{"class":397},"\"onStartCommand\"",[360,27335,801],{"class":366},[360,27337,27338],{"class":362,"line":433},[360,27339,372],{"emptyLinePlaceholder":320},[360,27341,27342,27345,27348,27350,27353,27356,27358,27361,27363,27366,27368],{"class":362,"line":478},[360,27343,27344],{"class":662},"        PowerManager",[360,27346,27347],{"class":578}," powerService ",[360,27349,583],{"class":582},[360,27351,27352],{"class":578}," (PowerManager) ",[360,27354,27355],{"class":381},"getSystemService",[360,27357,671],{"class":578},[360,27359,27360],{"class":662},"Context",[360,27362,31],{"class":366},[360,27364,27365],{"class":662},"POWER_SERVICE",[360,27367,16112],{"class":578},[360,27369,735],{"class":366},[360,27371,27372,27375,27377,27380,27382,27385,27387,27390,27392,27395,27397,27400],{"class":362,"line":483},[360,27373,27374],{"class":578},"        wakeLock ",[360,27376,583],{"class":582},[360,27378,27379],{"class":662}," powerService",[360,27381,31],{"class":366},[360,27383,27384],{"class":381},"newWakeLock",[360,27386,671],{"class":366},[360,27388,27389],{"class":662},"PowerManager",[360,27391,31],{"class":366},[360,27393,27394],{"class":662},"PARTIAL_WAKE_LOCK",[360,27396,2311],{"class":366},[360,27398,27399],{"class":397},"\"ArroundService::lock\"",[360,27401,801],{"class":366},[360,27403,27404,27407,27409,27412],{"class":362,"line":489},[360,27405,27406],{"class":662},"        wakeLock",[360,27408,31],{"class":366},[360,27410,27411],{"class":381},"acquire",[360,27413,2204],{"class":366},[360,27415,27416],{"class":362,"line":494},[360,27417,372],{"emptyLinePlaceholder":320},[360,27419,27420,27423,27426,27428,27430,27432,27435],{"class":362,"line":712},[360,27421,27422],{"class":662},"        Bundle",[360,27424,27425],{"class":578}," extras ",[360,27427,583],{"class":582},[360,27429,27305],{"class":662},[360,27431,31],{"class":366},[360,27433,27434],{"class":381},"getExtras",[360,27436,2204],{"class":366},[360,27438,27439,27441,27444,27446,27449,27452,27454,27456,27458,27460],{"class":362,"line":331},[360,27440,25835],{"class":662},[360,27442,27443],{"class":578}," location ",[360,27445,583],{"class":582},[360,27447,27448],{"class":578}," (Location) ",[360,27450,27451],{"class":662},"extras",[360,27453,31],{"class":366},[360,27455,17563],{"class":381},[360,27457,671],{"class":366},[360,27459,27029],{"class":397},[360,27461,801],{"class":366},[360,27463,27464,27466,27469,27472,27474],{"class":362,"line":762},[360,27465,2780],{"class":574},[360,27467,27468],{"class":578}," (location ",[360,27470,27471],{"class":582},"!=",[360,27473,19007],{"class":414},[360,27475,681],{"class":578},[360,27477,27478,27481,27483,27485,27487,27489],{"class":362,"line":781},[360,27479,27480],{"class":662},"            this",[360,27482,31],{"class":366},[360,27484,25845],{"class":662},[360,27486,401],{"class":582},[360,27488,25700],{"class":578},[360,27490,735],{"class":366},[360,27492,27493],{"class":362,"line":804},[360,27494,2840],{"class":578},[360,27496,27497],{"class":362,"line":817},[360,27498,372],{"emptyLinePlaceholder":320},[360,27500,27501,27504,27507,27509,27512,27514,27517,27519,27521],{"class":362,"line":823},[360,27502,27503],{"class":662},"        Notification",[360,27505,27506],{"class":578}," notification ",[360,27508,583],{"class":582},[360,27510,27511],{"class":662}," notificationManager",[360,27513,31],{"class":366},[360,27515,27516],{"class":381},"notifyDistance",[360,27518,671],{"class":366},[360,27520,1344],{"class":414},[360,27522,801],{"class":366},[360,27524,27525,27528,27530,27533,27535,27538,27540,27543],{"class":362,"line":844},[360,27526,27527],{"class":381},"        startForeground",[360,27529,671],{"class":578},[360,27531,27532],{"class":662},"ArroundNotificationManager",[360,27534,31],{"class":366},[360,27536,27537],{"class":662},"ARROUND_ID",[360,27539,22488],{"class":366},[360,27541,27542],{"class":578}," notification)",[360,27544,735],{"class":366},[360,27546,27547],{"class":362,"line":1441},[360,27548,372],{"emptyLinePlaceholder":320},[360,27550,27551,27553,27556],{"class":362,"line":1462},[360,27552,24470],{"class":574},[360,27554,27555],{"class":578}," START_STICKY",[360,27557,735],{"class":366},[360,27559,27560],{"class":362,"line":1485},[360,27561,2927],{"class":578},[12,27563,27564],{},"Afin qu'Android et son système de gestion d'nergie ne tuent pas notre service pendant que l'on court, nous commençons\npar mettre un PARTIAL_WAKE_LOCK. Ensuite nous récupérons la position (sauf si nous sommes issus d'un redémarrage de\nl'application) et appelons la méthode startForeground avec une notification persistante que nous avons créé.",[12,27566,27567],{},"Surtout après l'acquision du Wake Lock, il est important de le relâcher lors de la fermeture (quand l'utilisateur\nclique sur stop):",[352,27569,27571],{"className":24787,"code":27570,"language":24789,"meta":291,"style":291},"    public void stop() {\n        if (wakeLock != null) {\n            if (wakeLock.isHeld()) {\n                wakeLock.release();\n                wakeLock = null;\n            }\n        }\n        stopForeground(true);\n        stopSelf();\n    }\n",[344,27572,27573,27584,27597,27615,27627,27638,27642,27646,27659,27668],{"__ignoreMap":291},[360,27574,27575,27577,27579,27582],{"class":362,"line":363},[360,27576,24943],{"class":574},[360,27578,25066],{"class":574},[360,27580,27581],{"class":381}," stop",[360,27583,2172],{"class":578},[360,27585,27586,27588,27591,27593,27595],{"class":362,"line":292},[360,27587,2780],{"class":574},[360,27589,27590],{"class":578}," (wakeLock ",[360,27592,27471],{"class":582},[360,27594,19007],{"class":414},[360,27596,681],{"class":578},[360,27598,27599,27601,27603,27606,27608,27611,27613],{"class":362,"line":375},[360,27600,3284],{"class":574},[360,27602,743],{"class":578},[360,27604,27605],{"class":662},"wakeLock",[360,27607,31],{"class":366},[360,27609,27610],{"class":381},"isHeld",[360,27612,16052],{"class":366},[360,27614,681],{"class":578},[360,27616,27617,27620,27622,27625],{"class":362,"line":433},[360,27618,27619],{"class":662},"                wakeLock",[360,27621,31],{"class":366},[360,27623,27624],{"class":381},"release",[360,27626,2204],{"class":366},[360,27628,27629,27632,27634,27636],{"class":362,"line":478},[360,27630,27631],{"class":578},"                wakeLock ",[360,27633,583],{"class":582},[360,27635,19007],{"class":414},[360,27637,735],{"class":366},[360,27639,27640],{"class":362,"line":483},[360,27641,3435],{"class":578},[360,27643,27644],{"class":362,"line":489},[360,27645,2840],{"class":578},[360,27647,27648,27651,27653,27655,27657],{"class":362,"line":494},[360,27649,27650],{"class":381},"        stopForeground",[360,27652,671],{"class":578},[360,27654,3081],{"class":414},[360,27656,16112],{"class":578},[360,27658,735],{"class":366},[360,27660,27661,27664,27666],{"class":362,"line":712},[360,27662,27663],{"class":381},"        stopSelf",[360,27665,16052],{"class":578},[360,27667,735],{"class":366},[360,27669,27670],{"class":362,"line":331},[360,27671,2927],{"class":578},[12,27673,27674,27675,27678,27679,2198],{},"On en profite pour arrêter la notification (avec ̀",[344,27676,27677],{},"stopForeground",") et arrêter le service (avec ",[344,27680,27681],{},"stopSelf",[12,27683,27684,27685,27688,27689,14024],{},"Pour lire à l'utilisateur la distance, nous utilisons ",[344,27686,27687],{},"android.speech.tts.TextToSpeech",". Son utilisation\nest fort simple et se fait lors de l'appel à ",[344,27690,27691],{},"speakDistance",[352,27693,27695],{"className":24787,"code":27694,"language":24789,"meta":291,"style":291},"    private void speakDistance() {\n        int distance = (int) getDistance();\n        if (Math.abs(lastDistance - distance) > 100) {\n            int stringId;\n            if (distance > 1000) {\n                stringId = R.string.speaker_meters_alert;\n            } else if (distance > 900) {\n                stringId = R.string.speaker_meters_warn;\n            } else {\n                stringId = R.string.speaker_meters_info;\n            }\n\n            String text = getString(stringId, distance);\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);\n            } else {\n                textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null);\n            }\n\n            lastDistance = distance;\n        }\n    }\n",[344,27696,27697,27708,27729,27757,27767,27780,27801,27818,27837,27845,27864,27868,27872,27894,27898,27934,27965,27973,27995,27999,28003,28014,28018],{"__ignoreMap":291},[360,27698,27699,27701,27703,27706],{"class":362,"line":363},[360,27700,19308],{"class":574},[360,27702,25066],{"class":574},[360,27704,27705],{"class":381}," speakDistance",[360,27707,2172],{"class":578},[360,27709,27710,27713,27715,27717,27719,27721,27723,27725,27727],{"class":362,"line":292},[360,27711,27712],{"class":574},"        int",[360,27714,25886],{"class":578},[360,27716,583],{"class":582},[360,27718,743],{"class":578},[360,27720,26486],{"class":574},[360,27722,3972],{"class":578},[360,27724,26495],{"class":381},[360,27726,16052],{"class":578},[360,27728,735],{"class":366},[360,27730,27731,27733,27735,27737,27739,27742,27745,27747,27750,27752,27755],{"class":362,"line":375},[360,27732,2780],{"class":574},[360,27734,743],{"class":578},[360,27736,6227],{"class":662},[360,27738,31],{"class":366},[360,27740,27741],{"class":381},"abs",[360,27743,27744],{"class":366},"(lastDistance ",[360,27746,1491],{"class":582},[360,27748,27749],{"class":366}," distance)",[360,27751,3538],{"class":582},[360,27753,27754],{"class":414}," 100",[360,27756,681],{"class":578},[360,27758,27759,27762,27765],{"class":362,"line":433},[360,27760,27761],{"class":574},"            int",[360,27763,27764],{"class":578}," stringId",[360,27766,735],{"class":366},[360,27768,27769,27771,27774,27776,27778],{"class":362,"line":478},[360,27770,3284],{"class":574},[360,27772,27773],{"class":578}," (distance ",[360,27775,24917],{"class":582},[360,27777,24867],{"class":414},[360,27779,681],{"class":578},[360,27781,27782,27785,27787,27790,27792,27794,27796,27799],{"class":362,"line":483},[360,27783,27784],{"class":578},"                stringId ",[360,27786,583],{"class":582},[360,27788,27789],{"class":662}," R",[360,27791,31],{"class":366},[360,27793,17505],{"class":662},[360,27795,31],{"class":366},[360,27797,27798],{"class":662},"speaker_meters_alert",[360,27800,735],{"class":366},[360,27802,27803,27805,27807,27809,27811,27813,27816],{"class":362,"line":489},[360,27804,21342],{"class":578},[360,27806,2488],{"class":574},[360,27808,2491],{"class":574},[360,27810,27773],{"class":578},[360,27812,24917],{"class":582},[360,27814,27815],{"class":414}," 900",[360,27817,681],{"class":578},[360,27819,27820,27822,27824,27826,27828,27830,27832,27835],{"class":362,"line":494},[360,27821,27784],{"class":578},[360,27823,583],{"class":582},[360,27825,27789],{"class":662},[360,27827,31],{"class":366},[360,27829,17505],{"class":662},[360,27831,31],{"class":366},[360,27833,27834],{"class":662},"speaker_meters_warn",[360,27836,735],{"class":366},[360,27838,27839,27841,27843],{"class":362,"line":712},[360,27840,21342],{"class":578},[360,27842,2488],{"class":574},[360,27844,896],{"class":578},[360,27846,27847,27849,27851,27853,27855,27857,27859,27862],{"class":362,"line":331},[360,27848,27784],{"class":578},[360,27850,583],{"class":582},[360,27852,27789],{"class":662},[360,27854,31],{"class":366},[360,27856,17505],{"class":662},[360,27858,31],{"class":366},[360,27860,27861],{"class":662},"speaker_meters_info",[360,27863,735],{"class":366},[360,27865,27866],{"class":362,"line":762},[360,27867,3435],{"class":578},[360,27869,27870],{"class":362,"line":781},[360,27871,372],{"emptyLinePlaceholder":320},[360,27873,27874,27877,27880,27882,27885,27888,27890,27892],{"class":362,"line":804},[360,27875,27876],{"class":662},"            String",[360,27878,27879],{"class":578}," text ",[360,27881,583],{"class":582},[360,27883,27884],{"class":381}," getString",[360,27886,27887],{"class":578},"(stringId",[360,27889,22488],{"class":366},[360,27891,27749],{"class":578},[360,27893,735],{"class":366},[360,27895,27896],{"class":362,"line":817},[360,27897,372],{"emptyLinePlaceholder":320},[360,27899,27900,27902,27904,27907,27909,27912,27914,27917,27919,27922,27924,27927,27929,27932],{"class":362,"line":823},[360,27901,3284],{"class":574},[360,27903,743],{"class":578},[360,27905,27906],{"class":662},"Build",[360,27908,31],{"class":366},[360,27910,27911],{"class":662},"VERSION",[360,27913,31],{"class":366},[360,27915,27916],{"class":662},"SDK_INT",[360,27918,4519],{"class":582},[360,27920,27921],{"class":662}," Build",[360,27923,31],{"class":366},[360,27925,27926],{"class":662},"VERSION_CODES",[360,27928,31],{"class":366},[360,27930,27931],{"class":662},"LOLLIPOP",[360,27933,681],{"class":578},[360,27935,27936,27939,27941,27944,27947,27950,27952,27955,27957,27959,27961,27963],{"class":362,"line":844},[360,27937,27938],{"class":662},"                textToSpeech",[360,27940,31],{"class":366},[360,27942,27943],{"class":381},"speak",[360,27945,27946],{"class":366},"(text, ",[360,27948,27949],{"class":662},"TextToSpeech",[360,27951,31],{"class":366},[360,27953,27954],{"class":662},"QUEUE_FLUSH",[360,27956,2311],{"class":366},[360,27958,16849],{"class":414},[360,27960,2311],{"class":366},[360,27962,16849],{"class":414},[360,27964,801],{"class":366},[360,27966,27967,27969,27971],{"class":362,"line":1441},[360,27968,21342],{"class":578},[360,27970,2488],{"class":574},[360,27972,896],{"class":578},[360,27974,27975,27977,27979,27981,27983,27985,27987,27989,27991,27993],{"class":362,"line":1462},[360,27976,27938],{"class":662},[360,27978,31],{"class":366},[360,27980,27943],{"class":381},[360,27982,27946],{"class":366},[360,27984,27949],{"class":662},[360,27986,31],{"class":366},[360,27988,27954],{"class":662},[360,27990,2311],{"class":366},[360,27992,16849],{"class":414},[360,27994,801],{"class":366},[360,27996,27997],{"class":362,"line":1485},[360,27998,3435],{"class":578},[360,28000,28001],{"class":362,"line":1497},[360,28002,372],{"emptyLinePlaceholder":320},[360,28004,28005,28008,28010,28012],{"class":362,"line":3161},[360,28006,28007],{"class":578},"            lastDistance ",[360,28009,583],{"class":582},[360,28011,25904],{"class":578},[360,28013,735],{"class":366},[360,28015,28016],{"class":362,"line":3167},[360,28017,2840],{"class":578},[360,28019,28020],{"class":362,"line":3194},[360,28021,2927],{"class":578},[12,28023,28024],{},"Enfin le dernier point concerne la création des notifications. Depuis la version Android O, l'application doit\nassocier une notification à un channel. Cela permet à Android de présenter à l'utilisateur une interface avec les\nnotifications possibles et de pouvoir désactiver\u002Factiver ces dernières au cas par cas.",[12,28026,28027,28030],{},[344,28028,28029],{},"AndroidNotificationManager"," est là pour ce but. Il va créer le channel de notification et notifier la distance à\nl'utilisateur.",[352,28032,28034],{"className":24787,"code":28033,"language":24789,"meta":291,"style":291},"    private static final String CHANNEL_DEFAULT_IMPORTANCE = \"Running\";\n    public static final int ARROUND_ID = 1;\n\n    private void createNotificationChannel() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            CharSequence name = context.getString(R.string.channel_name);\n            String description = context.getString(R.string.channel_description);\n            NotificationChannel channel = new NotificationChannel(CHANNEL_DEFAULT_IMPORTANCE, name, NotificationManager.IMPORTANCE_DEFAULT);\n            channel.setDescription(description);\n            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);\n            notificationManager.createNotificationChannel(channel);\n        }\n    }\n\n    public Notification createNotification(float distance) {\n        Intent notificationIntent = new Intent(context, MainActivity.class);\n        PendingIntent pendingIntent =\n                PendingIntent.getActivity(context, 0, notificationIntent, 0);\n\n        return new NotificationCompat.Builder(context, CHANNEL_DEFAULT_IMPORTANCE)\n                .setContentTitle(context.getText(R.string.notification_title))\n                .setContentText(context.getString(R.string.notification_message, (int) distance))\n                .setSmallIcon(android.R.drawable.ic_menu_mylocation)\n                .setContentIntent(pendingIntent)\n                .build();\n    }\n\n    public void notifyDistance(float distance) {\n        Notification n = this.createNotification(distance);\n        NotificationManager notificationManager = context.getSystemService(NotificationManager.class);\n        notificationManager.notify(ARROUND_ID, n);\n    }\n",[344,28035,28036,28056,28075,28079,28090,28121,28153,28183,28219,28232,28259,28271,28275,28279,28283,28301,28331,28341,28363,28367,28384,28417,28452,28479,28489,28498,28502,28506,28521,28540,28565,28578],{"__ignoreMap":291},[360,28037,28038,28040,28042,28044,28046,28049,28051,28054],{"class":362,"line":363},[360,28039,19308],{"class":574},[360,28041,24813],{"class":574},[360,28043,24816],{"class":574},[360,28045,24819],{"class":662},[360,28047,28048],{"class":578}," CHANNEL_DEFAULT_IMPORTANCE ",[360,28050,583],{"class":582},[360,28052,28053],{"class":397}," \"Running\"",[360,28055,735],{"class":366},[360,28057,28058,28060,28062,28064,28066,28069,28071,28073],{"class":362,"line":292},[360,28059,24943],{"class":574},[360,28061,24813],{"class":574},[360,28063,24816],{"class":574},[360,28065,1091],{"class":574},[360,28067,28068],{"class":578}," ARROUND_ID ",[360,28070,583],{"class":582},[360,28072,1099],{"class":414},[360,28074,735],{"class":366},[360,28076,28077],{"class":362,"line":375},[360,28078,372],{"emptyLinePlaceholder":320},[360,28080,28081,28083,28085,28088],{"class":362,"line":433},[360,28082,19308],{"class":574},[360,28084,25066],{"class":574},[360,28086,28087],{"class":381}," createNotificationChannel",[360,28089,2172],{"class":578},[360,28091,28092,28094,28096,28098,28100,28102,28104,28106,28108,28110,28112,28114,28116,28119],{"class":362,"line":478},[360,28093,2780],{"class":574},[360,28095,743],{"class":578},[360,28097,27906],{"class":662},[360,28099,31],{"class":366},[360,28101,27911],{"class":662},[360,28103,31],{"class":366},[360,28105,27916],{"class":662},[360,28107,4519],{"class":582},[360,28109,27921],{"class":662},[360,28111,31],{"class":366},[360,28113,27926],{"class":662},[360,28115,31],{"class":366},[360,28117,28118],{"class":662},"O",[360,28120,681],{"class":578},[360,28122,28123,28126,28129,28131,28134,28136,28138,28140,28142,28144,28146,28148,28151],{"class":362,"line":483},[360,28124,28125],{"class":662},"            CharSequence",[360,28127,28128],{"class":578}," name ",[360,28130,583],{"class":582},[360,28132,28133],{"class":662}," context",[360,28135,31],{"class":366},[360,28137,26467],{"class":381},[360,28139,671],{"class":366},[360,28141,2688],{"class":662},[360,28143,31],{"class":366},[360,28145,17505],{"class":662},[360,28147,31],{"class":366},[360,28149,28150],{"class":662},"channel_name",[360,28152,801],{"class":366},[360,28154,28155,28157,28160,28162,28164,28166,28168,28170,28172,28174,28176,28178,28181],{"class":362,"line":489},[360,28156,27876],{"class":662},[360,28158,28159],{"class":578}," description ",[360,28161,583],{"class":582},[360,28163,28133],{"class":662},[360,28165,31],{"class":366},[360,28167,26467],{"class":381},[360,28169,671],{"class":366},[360,28171,2688],{"class":662},[360,28173,31],{"class":366},[360,28175,17505],{"class":662},[360,28177,31],{"class":366},[360,28179,28180],{"class":662},"channel_description",[360,28182,801],{"class":366},[360,28184,28185,28188,28191,28193,28195,28198,28201,28203,28205,28207,28210,28212,28215,28217],{"class":362,"line":494},[360,28186,28187],{"class":662},"            NotificationChannel",[360,28189,28190],{"class":578}," channel ",[360,28192,583],{"class":582},[360,28194,3040],{"class":574},[360,28196,28197],{"class":381}," NotificationChannel",[360,28199,28200],{"class":578},"(CHANNEL_DEFAULT_IMPORTANCE",[360,28202,22488],{"class":366},[360,28204,14661],{"class":578},[360,28206,22488],{"class":366},[360,28208,28209],{"class":662}," NotificationManager",[360,28211,31],{"class":366},[360,28213,28214],{"class":662},"IMPORTANCE_DEFAULT",[360,28216,16112],{"class":578},[360,28218,735],{"class":366},[360,28220,28221,28224,28226,28229],{"class":362,"line":712},[360,28222,28223],{"class":662},"            channel",[360,28225,31],{"class":366},[360,28227,28228],{"class":381},"setDescription",[360,28230,28231],{"class":366},"(description);\n",[360,28233,28234,28237,28240,28242,28244,28246,28248,28250,28253,28255,28257],{"class":362,"line":331},[360,28235,28236],{"class":662},"            NotificationManager",[360,28238,28239],{"class":578}," notificationManager ",[360,28241,583],{"class":582},[360,28243,28133],{"class":662},[360,28245,31],{"class":366},[360,28247,27355],{"class":381},[360,28249,671],{"class":366},[360,28251,28252],{"class":662},"NotificationManager",[360,28254,31],{"class":366},[360,28256,18818],{"class":662},[360,28258,801],{"class":366},[360,28260,28261,28263,28265,28268],{"class":362,"line":762},[360,28262,27198],{"class":662},[360,28264,31],{"class":366},[360,28266,28267],{"class":381},"createNotificationChannel",[360,28269,28270],{"class":366},"(channel);\n",[360,28272,28273],{"class":362,"line":781},[360,28274,2840],{"class":578},[360,28276,28277],{"class":362,"line":804},[360,28278,2927],{"class":578},[360,28280,28281],{"class":362,"line":817},[360,28282,372],{"emptyLinePlaceholder":320},[360,28284,28285,28287,28290,28293,28295,28298],{"class":362,"line":823},[360,28286,24943],{"class":574},[360,28288,28289],{"class":662}," Notification",[360,28291,28292],{"class":381}," createNotification",[360,28294,671],{"class":578},[360,28296,28297],{"class":574},"float",[360,28299,28300],{"class":578}," distance) {\n",[360,28302,28303,28306,28309,28311,28313,28315,28318,28320,28323,28325,28327,28329],{"class":362,"line":844},[360,28304,28305],{"class":662},"        Intent",[360,28307,28308],{"class":578}," notificationIntent ",[360,28310,583],{"class":582},[360,28312,3040],{"class":574},[360,28314,26997],{"class":381},[360,28316,28317],{"class":578},"(context",[360,28319,22488],{"class":366},[360,28321,28322],{"class":662}," MainActivity",[360,28324,31],{"class":366},[360,28326,18818],{"class":662},[360,28328,16112],{"class":578},[360,28330,735],{"class":366},[360,28332,28333,28336,28339],{"class":362,"line":1441},[360,28334,28335],{"class":662},"        PendingIntent",[360,28337,28338],{"class":578}," pendingIntent ",[360,28340,5271],{"class":582},[360,28342,28343,28346,28348,28351,28354,28356,28359,28361],{"class":362,"line":1462},[360,28344,28345],{"class":662},"                PendingIntent",[360,28347,31],{"class":366},[360,28349,28350],{"class":381},"getActivity",[360,28352,28353],{"class":366},"(context, ",[360,28355,1344],{"class":414},[360,28357,28358],{"class":366},", notificationIntent, ",[360,28360,1344],{"class":414},[360,28362,801],{"class":366},[360,28364,28365],{"class":362,"line":1485},[360,28366,372],{"emptyLinePlaceholder":320},[360,28368,28369,28371,28373,28376,28378,28381],{"class":362,"line":1497},[360,28370,24470],{"class":574},[360,28372,3040],{"class":574},[360,28374,28375],{"class":578}," NotificationCompat",[360,28377,31],{"class":366},[360,28379,28380],{"class":381},"Builder",[360,28382,28383],{"class":366},"(context, CHANNEL_DEFAULT_IMPORTANCE)\n",[360,28385,28386,28389,28392,28394,28397,28399,28402,28404,28406,28408,28410,28412,28415],{"class":362,"line":3161},[360,28387,28388],{"class":366},"                .",[360,28390,28391],{"class":381},"setContentTitle",[360,28393,671],{"class":366},[360,28395,28396],{"class":662},"context",[360,28398,31],{"class":366},[360,28400,28401],{"class":381},"getText",[360,28403,671],{"class":366},[360,28405,2688],{"class":662},[360,28407,31],{"class":366},[360,28409,17505],{"class":662},[360,28411,31],{"class":366},[360,28413,28414],{"class":662},"notification_title",[360,28416,5038],{"class":366},[360,28418,28419,28421,28424,28426,28428,28430,28432,28434,28436,28438,28440,28442,28445,28447,28449],{"class":362,"line":3167},[360,28420,28388],{"class":366},[360,28422,28423],{"class":381},"setContentText",[360,28425,671],{"class":366},[360,28427,28396],{"class":662},[360,28429,31],{"class":366},[360,28431,26467],{"class":381},[360,28433,671],{"class":366},[360,28435,2688],{"class":662},[360,28437,31],{"class":366},[360,28439,17505],{"class":662},[360,28441,31],{"class":366},[360,28443,28444],{"class":662},"notification_message",[360,28446,26483],{"class":366},[360,28448,26486],{"class":574},[360,28450,28451],{"class":366},") distance))\n",[360,28453,28454,28456,28459,28461,28463,28465,28467,28469,28472,28474,28477],{"class":362,"line":3194},[360,28455,28388],{"class":366},[360,28457,28458],{"class":381},"setSmallIcon",[360,28460,671],{"class":366},[360,28462,330],{"class":662},[360,28464,31],{"class":366},[360,28466,2688],{"class":662},[360,28468,31],{"class":366},[360,28470,28471],{"class":662},"drawable",[360,28473,31],{"class":366},[360,28475,28476],{"class":662},"ic_menu_mylocation",[360,28478,2922],{"class":366},[360,28480,28481,28483,28486],{"class":362,"line":3224},[360,28482,28388],{"class":366},[360,28484,28485],{"class":381},"setContentIntent",[360,28487,28488],{"class":366},"(pendingIntent)\n",[360,28490,28491,28493,28496],{"class":362,"line":3239},[360,28492,28388],{"class":366},[360,28494,28495],{"class":381},"build",[360,28497,2204],{"class":366},[360,28499,28500],{"class":362,"line":3256},[360,28501,2927],{"class":578},[360,28503,28504],{"class":362,"line":3276},[360,28505,372],{"emptyLinePlaceholder":320},[360,28507,28508,28510,28512,28515,28517,28519],{"class":362,"line":3281},[360,28509,24943],{"class":574},[360,28511,25066],{"class":574},[360,28513,28514],{"class":381}," notifyDistance",[360,28516,671],{"class":578},[360,28518,28297],{"class":574},[360,28520,28300],{"class":578},[360,28522,28523,28525,28528,28530,28532,28534,28537],{"class":362,"line":3305},[360,28524,27503],{"class":662},[360,28526,28527],{"class":578}," n ",[360,28529,583],{"class":582},[360,28531,14110],{"class":662},[360,28533,31],{"class":366},[360,28535,28536],{"class":381},"createNotification",[360,28538,28539],{"class":366},"(distance);\n",[360,28541,28542,28545,28547,28549,28551,28553,28555,28557,28559,28561,28563],{"class":362,"line":3320},[360,28543,28544],{"class":662},"        NotificationManager",[360,28546,28239],{"class":578},[360,28548,583],{"class":582},[360,28550,28133],{"class":662},[360,28552,31],{"class":366},[360,28554,27355],{"class":381},[360,28556,671],{"class":366},[360,28558,28252],{"class":662},[360,28560,31],{"class":366},[360,28562,18818],{"class":662},[360,28564,801],{"class":366},[360,28566,28567,28570,28572,28575],{"class":362,"line":3325},[360,28568,28569],{"class":662},"        notificationManager",[360,28571,31],{"class":366},[360,28573,28574],{"class":381},"notify",[360,28576,28577],{"class":366},"(ARROUND_ID, n);\n",[360,28579,28580],{"class":362,"line":3361},[360,28581,2927],{"class":578},[12,28583,28584],{},"Il est important lors de l'appel à notifyDistance de toujours utiliser le même identifiant de notification afin\nque cette dernière soit remplacée (et non ajouté). Cela permet de mettre à jour le contenu de la notification.",[33,28586,28588],{"id":28587},"pour-finir","Pour finir",[12,28590,28591],{},"Pour finir je suis content d'avoir développé cette application qui n'est pas exempte de bug, mais qui m'a pris\ntrès peu de temps de développement.",[12,28593,28594,28595,28600,28601,28606],{},"Vous pouvez retrouver le code source sur ",[47,28596,28599],{"href":28597,"rel":28598},"https:\u002F\u002Fgithub.com\u002Fphoenix741\u002F1kmarround",[51],"Github: phoenix741\u002F1kmarround","\net sur le ",[47,28602,28605],{"href":28603,"rel":28604},"https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=org.shadoware.a1kmarroud",[51],"PlayStore"," (à ce jour l'application\nn'a pas encore été validé dans les stores et n'est donc pas disponible).",[12,28608,28609],{},"Le plus long dans ce développement aura été:",[140,28611,28612,28620,28623],{},[143,28613,28614,28615,16112],{},"faire l'icône (à partir d'une image se trouvant sur ",[47,28616,28619],{"href":28617,"rel":28618},"https:\u002F\u002Fundraw.co\u002F",[51],"undraw.co",[143,28621,28622],{},"faire le layout (même si elle est simple)",[143,28624,28625],{},"remplir la fiche du playstore pour mettre l'application dans les stores.",[21499,28627,28629,28632],{"className":28628,"dataFootnotes":291},[21502],[33,28630,21507],{"className":28631,"id":15686},[21506],[13835,28633,28634,28640],{},[143,28635,28636,28637],{"id":21512},"Une activité est l'équivalent d'un écran dans Android. ",[47,28638,21520],{"href":21516,"ariaLabel":21517,"className":28639,"dataFootnoteBackref":291},[21519],[143,28641,28642,28643],{"id":21523},"Pour demander les permissions je me suis basé sur le code suivant: ",[47,28644,21520],{"href":21531,"ariaLabel":21532,"className":28645,"dataFootnoteBackref":291},[21519],[1613,28647,28648],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}",{"title":291,"searchDepth":292,"depth":292,"links":28650},[28651,28652,28656,28657,28658],{"id":24719,"depth":292,"text":24720},{"id":24762,"depth":292,"text":24747,"children":28653},[28654,28655],{"id":24778,"depth":375,"text":24779},{"id":25913,"depth":375,"text":25914},{"id":26941,"depth":292,"text":26942},{"id":28587,"depth":292,"text":28588},{"id":15686,"depth":292,"text":21507},"2020-11-14",{"type":9,"value":28661},[28662,28664,28666,28671,28676,28678,28680,28682],[12,28663,24673],{},[12,28665,24676],{},[12,28667,24679,28668,24685],{},[47,28669,24684],{"href":24682,"rel":28670},[51],[12,28672,24688,28673,24693],{},[47,28674,24684],{"href":24691,"rel":28675},[51],[12,28677,24696],{},[12,28679,24699],{},[12,28681,24702],{},[140,28683,28684,28686,28688,28690],{},[143,28685,24707],{},[143,28687,24710],{},[143,28689,24713],{},[143,28691,24716],{},{"planet":320},"\u002Fpost\u002Fapplication_du_confinement",{"title":24668,"description":24673},"application_du_confinement","posts\u002FProgrammation\u002F2020-11-14_application_du_confinement",[330,301,24789,28698],"confinement","H4G4WeTzcsmG6glUDJrc_7H09bZb4hoavg3yFXRDN3A",{"id":28701,"title":28702,"author":7,"body":28703,"category":300,"categorySlug":301,"date":30530,"description":21597,"excerpt":30531,"extension":317,"location":318,"meta":30561,"navigation":320,"path":30562,"published":320,"seo":30563,"slug":30564,"stem":30565,"tags":30566,"timeToRead":1462,"__hash__":30567},"posts\u002Fposts\u002FProgrammation\u002F2020-11-02_creation-api-2.md","Comment créer une bonne API Web - Partie 2",{"type":9,"value":28704,"toc":30518},[28705,28707,28709,28723,28727,28730,28733,28740,28744,28751,28761,28764,28769,28806,28811,28880,28885,28951,28954,28958,28961,28963,29001,29008,29015,29018,29022,29031,29040,29044,29049,29055,29062,29065,29073,29086,29095,29098,29110,29112,29126,29134,29148,29153,29156,29168,29177,29234,29237,29240,29255,29258,29264,29494,29497,29505,29511,29576,29579,29587,29595,29599,29604,29616,29623,29632,29636,29646,29654,29658,29664,29667,29670,29687,29690,29693,29696,29700,29704,29707,29713,29716,29719,29724,29727,29730,29733,29736,29750,29753,29756,29769,29772,29778,29782,29785,29791,29795,29799,29805,29808,29812,29818,29827,29831,29839,29845,29848,29852,29866,29869,29890,29894,29900,29905,29909,29913,29916,29919,29923,29926,29929,29933,29936,29939,29942,29945,29948,29952,29955,29959,29962,29966,29972,29976,29979,29983,29987,29990,29993,29997,30000,30004,30007,30011,30014,30017,30020,30034,30037,30040,30379,30382,30386,30389,30392,30395,30399,30402,30405,30419,30425,30429,30432,30435,30438,30442,30474,30515],[12,28706,21597],{},[12,28708,21600],{},[140,28710,28711,28715,28719],{},[143,28712,28713],{},[47,28714,21608],{"href":21607},[143,28716,28717],{},[47,28718,21614],{"href":21613},[143,28720,28721],{},[47,28722,21620],{"href":21619},[33,28724,28726],{"id":28725},"quest-quune-api-rest","Qu'est qu'une API REST",[12,28728,28729],{},"REST est une norme dont voici les grandes lignes. Il n'est pas dans mon but de faire un cours sur REST (et il y en\ndéjà de très bons sur internet). Je souhaiterais surtout parler des points qui me semblent importants. N'hésitez pas à venir\nme dire si vous pensez qu'il manque des points importants.\nJe viendrai alors compléter mon article.",[12,28731,28732],{},"Le principe de REST est de séparer l'API en différentes ressources logiques qui peuvent être manipulées par les verbes\nHTTP (GET, POST, ...). La réponse de son côté se base également sur les codes http.",[12,28734,28735,28736,28739],{},"Le contenu de la requête et de la réponse peut être dans le format objet de votre choix (json, yaml, xml, ...). On\nutilise alors le header ",[344,28737,28738],{},"Content-Type"," pour définir le contenu. Une API peut d'ailleurs gérer plusieurs formats et\nrépondre au client le bon format en fonction de la demande du client.",[1901,28741,28743],{"id":28742},"basé-sur-des-ressources","Basé sur des ressources",[12,28745,28746,28747,28750],{},"Quand on parle de REST, il faut penser ",[105,28748,28749],{},"ressources",". Mais qu'est qu'une ressource ?",[12,28752,28753,28754,28757,28758,28760],{},"Une ressource c'est un concept abstrait de REST. Une ressource c'est ce qui va être représenté par les données JSON\nque vous allez manipuler. Pour représenter une ressource on n'utilise pas un verbe, ou une action mais un ",[28,28755,28756],{},"nom",".\nL'utilisation du ",[28,28759,28756],{}," est important car le verbe est representé par la méthode HTTP.",[12,28762,28763],{},"Une ressource peut:",[140,28765,28766],{},[143,28767,28768],{},"être un singleton",[352,28770,28772],{"className":16331,"code":28771,"language":16333,"meta":291,"style":291},"GET \u002Fapi\u002Fhosts\u002F:id\n\n{\n  \"id\": 1,\n  ...\n}\n",[344,28773,28774,28779,28783,28787,28798,28802],{"__ignoreMap":291},[360,28775,28776],{"class":362,"line":363},[360,28777,28778],{"class":366},"GET \u002Fapi\u002Fhosts\u002F:id\n",[360,28780,28781],{"class":362,"line":292},[360,28782,372],{"emptyLinePlaceholder":320},[360,28784,28785],{"class":362,"line":375},[360,28786,16340],{"class":366},[360,28788,28789,28792,28794,28796],{"class":362,"line":433},[360,28790,28791],{"class":578},"  \"id\"",[360,28793,2691],{"class":366},[360,28795,1944],{"class":414},[360,28797,2968],{"class":366},[360,28799,28800],{"class":362,"line":478},[360,28801,16470],{"class":17414},[360,28803,28804],{"class":362,"line":483},[360,28805,847],{"class":366},[140,28807,28808],{},[143,28809,28810],{},"être une collection",[352,28812,28814],{"className":16331,"code":28813,"language":16333,"meta":291,"style":291},"GET \u002Fapi\u002Fhosts\n\n[\n  {\n    \"id\": 1,\n    ...\n  },\n  {\n    \"id\": 2,\n    ...\n  },\n]\n",[344,28815,28816,28821,28825,28829,28834,28845,28850,28854,28858,28868,28872,28876],{"__ignoreMap":291},[360,28817,28818],{"class":362,"line":363},[360,28819,28820],{"class":366},"GET \u002Fapi\u002Fhosts\n",[360,28822,28823],{"class":362,"line":292},[360,28824,372],{"emptyLinePlaceholder":320},[360,28826,28827],{"class":362,"line":375},[360,28828,8979],{"class":366},[360,28830,28831],{"class":362,"line":433},[360,28832,28833],{"class":366},"  {\n",[360,28835,28836,28839,28841,28843],{"class":362,"line":478},[360,28837,28838],{"class":578},"    \"id\"",[360,28840,2691],{"class":366},[360,28842,1944],{"class":414},[360,28844,2968],{"class":366},[360,28846,28847],{"class":362,"line":483},[360,28848,28849],{"class":17414},"    ...\n",[360,28851,28852],{"class":362,"line":489},[360,28853,6758],{"class":366},[360,28855,28856],{"class":362,"line":494},[360,28857,28833],{"class":366},[360,28859,28860,28862,28864,28866],{"class":362,"line":712},[360,28861,28838],{"class":578},[360,28863,2691],{"class":366},[360,28865,795],{"class":414},[360,28867,2968],{"class":366},[360,28869,28870],{"class":362,"line":331},[360,28871,28849],{"class":17414},[360,28873,28874],{"class":362,"line":762},[360,28875,6758],{"class":366},[360,28877,28878],{"class":362,"line":781},[360,28879,21698],{"class":366},[140,28881,28882],{},[143,28883,28884],{},"être une sous-ressource",[352,28886,28888],{"className":16331,"code":28887,"language":16333,"meta":291,"style":291},"GET \u002Fapi\u002Fhosts\u002F:id\u002Fbackups\n\n[\n  {\n    \"id\": 1,\n    ...\n  },\n  {\n    \"id\": 2,\n    ...\n  },\n]\n",[344,28889,28890,28895,28899,28903,28907,28917,28921,28925,28929,28939,28943,28947],{"__ignoreMap":291},[360,28891,28892],{"class":362,"line":363},[360,28893,28894],{"class":366},"GET \u002Fapi\u002Fhosts\u002F:id\u002Fbackups\n",[360,28896,28897],{"class":362,"line":292},[360,28898,372],{"emptyLinePlaceholder":320},[360,28900,28901],{"class":362,"line":375},[360,28902,8979],{"class":366},[360,28904,28905],{"class":362,"line":433},[360,28906,28833],{"class":366},[360,28908,28909,28911,28913,28915],{"class":362,"line":478},[360,28910,28838],{"class":578},[360,28912,2691],{"class":366},[360,28914,1944],{"class":414},[360,28916,2968],{"class":366},[360,28918,28919],{"class":362,"line":483},[360,28920,28849],{"class":17414},[360,28922,28923],{"class":362,"line":489},[360,28924,6758],{"class":366},[360,28926,28927],{"class":362,"line":494},[360,28928,28833],{"class":366},[360,28930,28931,28933,28935,28937],{"class":362,"line":712},[360,28932,28838],{"class":578},[360,28934,2691],{"class":366},[360,28936,795],{"class":414},[360,28938,2968],{"class":366},[360,28940,28941],{"class":362,"line":331},[360,28942,28849],{"class":17414},[360,28944,28945],{"class":362,"line":762},[360,28946,6758],{"class":366},[360,28948,28949],{"class":362,"line":781},[360,28950,21698],{"class":366},[12,28952,28953],{},"La ressource est généralement nommée au pluriel et pour des raisons de consistance, doit toujours être nommée de\nla même manière même si le but est de récupérer un unique élément.",[1901,28955,28957],{"id":28956},"utilise-les-verbes-http","Utilise les verbes HTTP",[12,28959,28960],{},"Donc une API REST ce sont des ressources qui peuvent être manipulées par les verbes HTTP. Du coup l'action n'est pas\nportée par le nom de la ressource mais par la méthode. Quels sont donc ces méthodes ?",[23034,28962,21707],{"id":17563},[12,28964,28965,28967,28968,28970,28971,28974,28975,28982,28983,28985,28986,28993,28994,2311,28997,29000],{},[344,28966,21707],{}," est utilisé pour récupérer une ressource. En aucun cas ",[344,28969,21707],{}," doit être utilisé pour effectuer une modification\n(ce serait comme effectuer des modifications dans le ",[344,28972,28973],{},"getter"," d'une classe",[15680,28976,28977],{},[47,28978,1944],{"href":28979,"ariaDescribedBy":28980,"dataFootnoteRef":291,"id":28981},"#user-content-fn-getter",[15686],"user-content-fnref-getter",").\n",[344,28984,21707],{}," ne doit pas modifier l'état de la ressource et doit être idempotent",[15680,28987,28988],{},[47,28989,795],{"href":28990,"ariaDescribedBy":28991,"dataFootnoteRef":291,"id":28992},"#user-content-fn-idempotent",[15686],"user-content-fnref-idempotent",". On peut donc appeler autant de fois que\nl'on souhaite la méthode GET, le résultat doit toujours être le même tant qu'une autre méthode (",[344,28995,28996],{},"POST",[344,28998,28999],{},"PUT",", ...)\nne vient pas modifier l'état de la ressource.",[12,29002,29003,29004,29007],{},"Si la ressource peut être produite par le serveur, le code HTTP de réponse doit être ",[344,29005,29006],{},"200 OK"," et contenir le contenu de\nla ressource de la réponse dans le corps.",[12,29009,29010,29011,29014],{},"Le client peut alors cacher la requête s'il le souhaite, et il est possible d'utiliser les headers HTTP standards pour lui\nindiquer combien de temps (cf header Cache-Control). Attention ce header peut être ignoré ou peut être utilisé par le\nclient afin d'agir sur son ",[105,29012,29013],{},"rate limit",". A aucun moment il ne faut faire confiance au client et il faut préférer cacher\nles requêtes en interne (via un mêmcached) et définir une limite d'appels plutôt que de solliciter son back si ce\ndernier ne peut pas tenir la charge.",[12,29016,29017],{},"ne doit pas avoir d'impact\u002Fd'effet de bord dans l'application.",[23034,29019,29021],{"id":29020},"head","HEAD",[12,29023,29024,29025,29027,29028,29030],{},"La méthode ",[344,29026,29021],{}," a le même effet que ",[344,29029,21707],{}," mais ne retourne pas de contenu. Le header peut-être utilisé pour vérifier\nl'état de la ressource (et voir si le cache doit être invalidé).",[12,29032,29033,29034,854,29037,31],{},"La méthode est considéré comme ",[105,29035,29036],{},"safe",[105,29038,29039],{},"idempotent",[23034,29041,29043],{"id":29042},"option","OPTION",[12,29045,29024,29046,29048],{},[344,29047,29043],{}," est utilisée pour vérifier les capacités de la méthode HTTP. Il est notament utilisé par les\nnavigateurs pour vérifier les entêtes CORS d'une API (en mode preflight) avant d'effectuer la véritable requête.",[12,29050,29051,29052,29054],{},"Pour interroger le serveur de facon générale ",[344,29053,925],{}," peut être utilisé à la place de l'URI. Ce seront donc les capacités\nglobales du serveur qui seront retournées",[12,29056,29057,29058,854,29060,31],{},"La méthode est considérée comme ",[105,29059,29036],{},[105,29061,29039],{},[23034,29063,28996],{"id":29064},"post",[12,29066,29067,29069,29070,29072],{},[344,29068,28996],{}," doit être utilisé pour créer une nouvelle ressource associée à la requête demandée. ",[344,29071,28996],{}," est utilisé pour\najouter un nouvel élément à une collection.",[12,29074,29075,29076,29079,29080,29082,29083,29085],{},"Lorsque la ressource a été créé, la réponse doit être ",[344,29077,29078],{},"201 Created"," et le corps du message ne doit pas contenir\nd'informations. A la place on laisse le client récuperer la ressource en utilisant la méthode ",[344,29081,21707],{}," ci-dessus. Pour cela,\nle lien d'accès à la ressource doit être positionné dans le header ",[344,29084,24964],{}," de la réponse HTTP.",[12,29087,29088,29089,2623,29092,29094],{},"Si toutefois la création de la ressource ne peut pas être liée à une ressource identifiable par un URI, la méthode peut\nalors retourner ",[344,29090,29091],{},"204 No Content",[344,29093,29006],{}," suivant si la réponse possède un contenu ou non.",[12,29096,29097],{},"La réponse ne peut pas être cachée (sauf indication contraire par header HTTP).",[12,29099,29100,29101,29103,29104,29106,29107,29109],{},"Les requêtes ",[344,29102,28996],{}," ne sont pas ",[105,29105,29039],{}," et peuvent changer l'état de la ressource. Dans ce cas le client devra\nd'ailleurs invalider son cache. Deux appels identiques ",[344,29108,28996],{}," peuvent génerer des résultats différents.",[23034,29111,28999],{"id":19134},[12,29113,29114,29115,854,29117,29119,29120,29122,29123,29125],{},"La différence la plus importante entre ",[344,29116,28996],{},[344,29118,28999],{}," se situe sur l'URI. La méthode ",[344,29121,28999],{}," est utilisée sur les URI\navec un identifiant (et donc unique), alors que la méthode ",[344,29124,28996],{}," est utilisée sur URI représentant une collection.",[12,29127,29128,29130,29131,31],{},[344,29129,28999],{}," doit alors être utilisé pour mettre à jour une ressource existante (voir en créer une nouvelle si elle n'existe\npas). La ressource intégrale doit être passée. Pour une mise à jour partielle, il faut voir la méthode ",[344,29132,29133],{},"PATCH",[12,29135,29136,29137,29139,29140,29142,29143,2623,29145,29147],{},"S'il y a création d'une ressource, comme pour ",[344,29138,28996],{},", l'API doit retourner un ",[344,29141,29078],{},". Dans le cas d'une mise à\njour la méthode retourne alors ",[344,29144,29091],{},[344,29146,29006],{}," suivant que la réponse possède un contenu ou non.",[12,29149,29100,29150,29152],{},[344,29151,28999],{}," mettant à jour la ressource, le client devra invalider son cache sur la base de l'URI. La méthode est\nconsidérée comme idempotent car c'est la ressource entière qui est remplacée.",[23034,29154,29133],{"id":29155},"patch",[12,29157,29158,29160,29161,31],{},[344,29159,29133],{}," est utilisé pour mettre à jour une ressource partiellement. La mise à jour doit être également atomique",[15680,29162,29163],{},[47,29164,1954],{"href":29165,"ariaDescribedBy":29166,"dataFootnoteRef":291,"id":29167},"#user-content-fn-atomic",[15686],"user-content-fnref-atomic",[12,29169,29170,29171,29176],{},"Dans la RFC ",[47,29172,29175],{"href":29173,"rel":29174},"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc5789",[51],"RFC 5789"," de la méthode PATCH, il y est écrit que le contenu doit\ncontenir la description des modifications :",[352,29178,29180],{"className":16331,"code":29179,"language":16333,"meta":291,"style":291},"PATCH \u002Ffile.txt HTTP\u002F1.1\nHost: www.example.com\nContent-Type: application\u002Fexample\nIf-Match: \"e0023aa4e\"\nContent-Length: 100\n\n[description of changes]\n",[344,29181,29182,29190,29195,29200,29208,29216,29220],{"__ignoreMap":291},[360,29183,29184,29187],{"class":362,"line":363},[360,29185,29186],{"class":366},"PATCH \u002Ffile.txt HTTP\u002F",[360,29188,29189],{"class":414},"1.1\n",[360,29191,29192],{"class":362,"line":292},[360,29193,29194],{"class":366},"Host: www.example.com\n",[360,29196,29197],{"class":362,"line":375},[360,29198,29199],{"class":366},"Content-Type: application\u002Fexample\n",[360,29201,29202,29205],{"class":362,"line":433},[360,29203,29204],{"class":366},"If-Match: ",[360,29206,29207],{"class":397},"\"e0023aa4e\"\n",[360,29209,29210,29213],{"class":362,"line":478},[360,29211,29212],{"class":366},"Content-Length: ",[360,29214,29215],{"class":414},"100\n",[360,29217,29218],{"class":362,"line":483},[360,29219,372],{"emptyLinePlaceholder":320},[360,29221,29222,29224,29227,29229,29232],{"class":362,"line":489},[360,29223,2385],{"class":366},[360,29225,29226],{"class":17414},"description",[360,29228,529],{"class":17414},[360,29230,29231],{"class":17414}," changes",[360,29233,21698],{"class":366},[12,29235,29236],{},"Utiliser une implémentation free-style de la description des changements risque d'être source d'erreurs pour le client\ncomme pour le serveur. En effet, le client pourrait s'attendre dans certains cas à des ajouts dans un tableau, ou au\nremplacement du tableau.",[12,29238,29239],{},"Il existe différentes RFC décrivant la bonne manière de faire pour PATCHer un document JSON. Il vaut mieux alors se baser\ndessus pour développer nos API. Cela permet d'être clair sur le fonctionnement de la méthode.",[12,29241,29242,29243,29248,29249,29254],{},"On peut alors se baser sur les ",[47,29244,29247],{"href":29245,"rel":29246},"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc6902",[51],"RFC 6902"," et\n",[47,29250,29253],{"href":29251,"rel":29252},"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7396",[51],"RFC 7396"," pour décrire le contenu de cette description des modifications.",[12,29256,29257],{},"Pour les API basées sur des XML, référez-vous aux RFC équivalents décrivant les méthodes de PATCH pour le XML.",[12,29259,29260,29261,29263],{},"Si on se base sur la ",[344,29262,29247],{}," on peut alors reprendre l'exemple qui décrit un changement comme étant une liste de\ndifférences à appliquer (noté le Content-Type):",[352,29265,29267],{"className":16331,"code":29266,"language":16333,"meta":291,"style":291},"PATCH \u002Fmy\u002Fdata HTTP\u002F1.1\nHost: example.org\nContent-Length: 326\nContent-Type: application\u002Fjson-patch+json\nIf-Match: \"abc123\"\n\n[\n  { \"op\": \"test\", \"path\": \"\u002Fa\u002Fb\u002Fc\", \"value\": \"foo\" },\n  { \"op\": \"remove\", \"path\": \"\u002Fa\u002Fb\u002Fc\" },\n  { \"op\": \"add\", \"path\": \"\u002Fa\u002Fb\u002Fc\", \"value\": [ \"foo\", \"bar\" ] },\n  { \"op\": \"replace\", \"path\": \"\u002Fa\u002Fb\u002Fc\", \"value\": 42 },\n  { \"op\": \"move\", \"from\": \"\u002Fa\u002Fb\u002Fc\", \"path\": \"\u002Fa\u002Fb\u002Fd\" },\n  { \"op\": \"copy\", \"from\": \"\u002Fa\u002Fb\u002Fd\", \"path\": \"\u002Fa\u002Fb\u002Fe\" }\n]\n",[344,29268,29269,29276,29281,29288,29293,29300,29304,29308,29342,29363,29399,29429,29460,29490],{"__ignoreMap":291},[360,29270,29271,29274],{"class":362,"line":363},[360,29272,29273],{"class":366},"PATCH \u002Fmy\u002Fdata HTTP\u002F",[360,29275,29189],{"class":414},[360,29277,29278],{"class":362,"line":292},[360,29279,29280],{"class":366},"Host: example.org\n",[360,29282,29283,29285],{"class":362,"line":375},[360,29284,29212],{"class":366},[360,29286,29287],{"class":414},"326\n",[360,29289,29290],{"class":362,"line":433},[360,29291,29292],{"class":366},"Content-Type: application\u002Fjson-patch+json\n",[360,29294,29295,29297],{"class":362,"line":478},[360,29296,29204],{"class":366},[360,29298,29299],{"class":397},"\"abc123\"\n",[360,29301,29302],{"class":362,"line":483},[360,29303,372],{"emptyLinePlaceholder":320},[360,29305,29306],{"class":362,"line":489},[360,29307,8979],{"class":366},[360,29309,29310,29313,29316,29318,29320,29322,29325,29327,29330,29332,29335,29337,29340],{"class":362,"line":494},[360,29311,29312],{"class":366},"  { ",[360,29314,29315],{"class":578},"\"op\"",[360,29317,2691],{"class":366},[360,29319,7232],{"class":397},[360,29321,2311],{"class":366},[360,29323,29324],{"class":578},"\"path\"",[360,29326,2691],{"class":366},[360,29328,29329],{"class":397},"\"\u002Fa\u002Fb\u002Fc\"",[360,29331,2311],{"class":366},[360,29333,29334],{"class":578},"\"value\"",[360,29336,2691],{"class":366},[360,29338,29339],{"class":397},"\"foo\"",[360,29341,6397],{"class":366},[360,29343,29344,29346,29348,29350,29353,29355,29357,29359,29361],{"class":362,"line":712},[360,29345,29312],{"class":366},[360,29347,29315],{"class":578},[360,29349,2691],{"class":366},[360,29351,29352],{"class":397},"\"remove\"",[360,29354,2311],{"class":366},[360,29356,29324],{"class":578},[360,29358,2691],{"class":366},[360,29360,29329],{"class":397},[360,29362,6397],{"class":366},[360,29364,29365,29367,29369,29371,29374,29376,29378,29380,29382,29384,29386,29389,29391,29393,29396],{"class":362,"line":331},[360,29366,29312],{"class":366},[360,29368,29315],{"class":578},[360,29370,2691],{"class":366},[360,29372,29373],{"class":397},"\"add\"",[360,29375,2311],{"class":366},[360,29377,29324],{"class":578},[360,29379,2691],{"class":366},[360,29381,29329],{"class":397},[360,29383,2311],{"class":366},[360,29385,29334],{"class":578},[360,29387,29388],{"class":366},": [ ",[360,29390,29339],{"class":397},[360,29392,2311],{"class":366},[360,29394,29395],{"class":397},"\"bar\"",[360,29397,29398],{"class":366}," ] },\n",[360,29400,29401,29403,29405,29407,29410,29412,29414,29416,29418,29420,29422,29424,29427],{"class":362,"line":762},[360,29402,29312],{"class":366},[360,29404,29315],{"class":578},[360,29406,2691],{"class":366},[360,29408,29409],{"class":397},"\"replace\"",[360,29411,2311],{"class":366},[360,29413,29324],{"class":578},[360,29415,2691],{"class":366},[360,29417,29329],{"class":397},[360,29419,2311],{"class":366},[360,29421,29334],{"class":578},[360,29423,2691],{"class":366},[360,29425,29426],{"class":414},"42",[360,29428,6397],{"class":366},[360,29430,29431,29433,29435,29437,29440,29442,29445,29447,29449,29451,29453,29455,29458],{"class":362,"line":781},[360,29432,29312],{"class":366},[360,29434,29315],{"class":578},[360,29436,2691],{"class":366},[360,29438,29439],{"class":397},"\"move\"",[360,29441,2311],{"class":366},[360,29443,29444],{"class":578},"\"from\"",[360,29446,2691],{"class":366},[360,29448,29329],{"class":397},[360,29450,2311],{"class":366},[360,29452,29324],{"class":578},[360,29454,2691],{"class":366},[360,29456,29457],{"class":397},"\"\u002Fa\u002Fb\u002Fd\"",[360,29459,6397],{"class":366},[360,29461,29462,29464,29466,29468,29471,29473,29475,29477,29479,29481,29483,29485,29488],{"class":362,"line":804},[360,29463,29312],{"class":366},[360,29465,29315],{"class":578},[360,29467,2691],{"class":366},[360,29469,29470],{"class":397},"\"copy\"",[360,29472,2311],{"class":366},[360,29474,29444],{"class":578},[360,29476,2691],{"class":366},[360,29478,29457],{"class":397},[360,29480,2311],{"class":366},[360,29482,29324],{"class":578},[360,29484,2691],{"class":366},[360,29486,29487],{"class":397},"\"\u002Fa\u002Fb\u002Fe\"",[360,29489,21961],{"class":366},[360,29491,29492],{"class":362,"line":817},[360,29493,21698],{"class":366},[12,29495,29496],{},"Le format à l'avantage d'être complet et standard.",[12,29498,29499,29500,2198],{},"Pour gérer le format dans l'application, on peut retrouver des librairies capables de lire et de générer ce genre de\ndifférenciel (par exemple ",[47,29501,29504],{"href":29502,"rel":29503},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Ffast-json-patch",[51],"fast-json-patch",[12,29506,29507,29508,29510],{},"Avec la ",[344,29509,29253],{},", on peut adapter le Content-Type et avoir un format de patch plus lisible :",[352,29512,29514],{"className":16331,"code":29513,"language":16333,"meta":291,"style":291},"PATCH \u002Ftarget HTTP\u002F1.1\nHost: example.org\nContent-Type: application\u002Fmerge-patch+json\n\n{\n  \"a\":\"z\",\n  \"c\": {\n    \"f\": null\n  }\n}\n",[344,29515,29516,29523,29527,29532,29536,29540,29552,29559,29568,29572],{"__ignoreMap":291},[360,29517,29518,29521],{"class":362,"line":363},[360,29519,29520],{"class":366},"PATCH \u002Ftarget HTTP\u002F",[360,29522,29189],{"class":414},[360,29524,29525],{"class":362,"line":292},[360,29526,29280],{"class":366},[360,29528,29529],{"class":362,"line":375},[360,29530,29531],{"class":366},"Content-Type: application\u002Fmerge-patch+json\n",[360,29533,29534],{"class":362,"line":433},[360,29535,372],{"emptyLinePlaceholder":320},[360,29537,29538],{"class":362,"line":478},[360,29539,16340],{"class":366},[360,29541,29542,29545,29547,29550],{"class":362,"line":483},[360,29543,29544],{"class":578},"  \"a\"",[360,29546,14024],{"class":366},[360,29548,29549],{"class":397},"\"z\"",[360,29551,2968],{"class":366},[360,29553,29554,29557],{"class":362,"line":489},[360,29555,29556],{"class":578},"  \"c\"",[360,29558,6359],{"class":366},[360,29560,29561,29564,29566],{"class":362,"line":494},[360,29562,29563],{"class":578},"    \"f\"",[360,29565,2691],{"class":366},[360,29567,17029],{"class":414},[360,29569,29570],{"class":362,"line":712},[360,29571,820],{"class":366},[360,29573,29574],{"class":362,"line":331},[360,29575,847],{"class":366},[12,29577,29578],{},"Par contre ce format a ses limitations :",[140,29580,29581,29584],{},[143,29582,29583],{},"il ne peut que mettre à jour des éléments (pas de suppression)",[143,29585,29586],{},"dans le cadre de valeurs comme des tableaux, c'est le contenu intégral qui est remplacé. Pas d'ajout ou de merge.",[12,29588,29589],{},[28,29590,29591,29592,29594],{},"Il est alors très important de définir dans sa documentation la liste des ",[344,29593,28738],{}," accepté par sont API",[23034,29596,29598],{"id":29597},"delete","DELETE",[12,29600,29024,29601,29603],{},[344,29602,29598],{}," porte bien son nom car elle sert à supprimer une ressource identifiée par son URI.",[12,29605,29606,29607,29609,29610,29612,29613,31],{},"Si la suppression a été effectuée, l'API retourne un ",[344,29608,29006],{}," si le contenu de la réponse inclut un status de la\nsuppression ou un ",[344,29611,29091],{}," sinon. Si la ressource n'existe pas, l'API retourne alors un ",[344,29614,29615],{},"404 Not Found",[12,29617,29618,29619,29622],{},"L'API peut retourner un ",[344,29620,29621],{},"202 Accepted"," si la demande a été prise en compte mais sera traitée\nultérieurement.",[12,29624,29625,29626,29628,29629,29631],{},"Plusieurs appels à la méthode ",[344,29627,29598],{}," sur une même URI ne doivent pas avoir d'effets de bord. La seule différence est\nsur la réponse qui passe à ",[344,29630,29615],{}," une fois que la ressource a été supprimée.",[23034,29633,29635],{"id":29634},"link-et-unlink","LINK et UNLINK",[12,29637,29638,29639,854,29642,29645],{},"Les méthodes ",[344,29640,29641],{},"LINK",[344,29643,29644],{},"UNLINK"," servent à lier\u002Fdélier des ressources entre elles.",[12,29647,29648,29649,31],{},"Je ne détaillerai pas leurs utilisations car elles sont peut utilisées. Vous pouvez en lire plus sur le site de\nl'",[47,29650,29653],{"href":29651,"rel":29652},"https:\u002F\u002Ftools.ietf.org\u002Fid\u002Fdraft-snell-link-method-01.html",[51],"IETF",[1901,29655,29657],{"id":29656},"respecter-les-codes-retour-http","Respecter les codes retour HTTP",[12,29659,29660,29661,29663],{},"La norme REST se base sur les code de retour HTTP. Par exemple un code HTTP ",[344,29662,29615],{}," signifie que la ressource ne\npeut pas être trouvée. Il est important pour les applications clientes de respecter ses codes HTTP.",[12,29665,29666],{},"Commençons par un petit rappel sur les codes de retour.",[12,29668,29669],{},"Ces derniers sont classés en 5 catégories:",[140,29671,29672,29675,29678,29681,29684],{},[143,29673,29674],{},"1xx: Informationnel. Ces codes HTTP sont utilisés pour communiquer des informations sur l'état du transfert à un\nniveau protocolaire (donc pas au niveau applicatif).",[143,29676,29677],{},"2xx: Succès. Ces codes HTTP sont utilisés pour signifier le succès de la requête.",[143,29679,29680],{},"3xx: Redirection. Le client doit prendre des actions supplémentaires afin de terminer la requête.",[143,29682,29683],{},"4xx: Erreur dûe à la requête du client. C'est de la faute du client si la réponse ne peut pas être fournie. Il doit\nla reformuler (si la requête est mauvaise) ou attendre dans le cas d'un rate limit.",[143,29685,29686],{},"5xx: Erreur dûe au serveur. Le serveur n'a pas réussi à répondre au client, et c'est de son entière responsabilité.",[12,29688,29689],{},"Il est important de bien choisir son code de retour pour que le client puisse bien comprendre quelles actions il peut\nentreprendre pour avoir sa réponse. Envoyer un code 5xx alors que la requête ne contient pas tout les champs\nobligatoires est le meilleur moyen pour remplir votre boîte de support.",[12,29691,29692],{},"Inversement renvoyer un code 4xx pour une erreur côté serveur, risque de perturber l'utilisateur qui ne comprendra pas\npourquoi l'API ne fonctionne pas comme attendu.",[12,29694,29695],{},"Passons en revue quelques exemples de codes utilisables (j'ai fait uniquement une sélection de codes qui peuvent avoir un intérêt\npour une API REST) :",[23034,29697,29699],{"id":29698},"_2xx","2xx",[29701,29702,29006],"h5",{"id":29703},"_200-ok",[12,29705,29706],{},"Parfait, pas de problème, c'est le succès complet.",[12,29708,29709,29710,29712],{},"Contrairement à la réponse 204 ci-dessous, il est nécessaire de fournir un corps au message (sauf pour le header\n",[344,29711,29021],{}," qui ne renvoit jamais de corps de message).",[29701,29714,29078],{"id":29715},"_201-created",[12,29717,29718],{},"Une nouvelle ressource a été créé avec succès et ajoutée à la collection. Le corps du message doit être vide.\nLe client peut invalider le cache de la collection.",[12,29720,29721,29722,31],{},"Ce code de retour doit être utilisé une fois que la ressource a été créé par le serveur et l'emplacement de celle-ci\ndoit être retourné dans le header HTTP ",[344,29723,24964],{},[12,29725,29726],{},"Si la ressource ne peut être créé tout de suite, alors voir le header suivant.",[29701,29728,29621],{"id":29729},"_202-accepted",[12,29731,29732],{},"La requête a bien été reçue et sera traitée ultérieurement (via un batch par exemple). La création peut se produire, ou\nune erreur peut arriver ultérieurement.",[12,29734,29735],{},"Dans le corps du message le serveur doit retourner au client le maximum d'informations qui permettent à ce dernier de\nsavoir quand sa demande sera traitée. Par exemple on peut mettre dans le corps du message :",[140,29737,29738,29741,29744,29747],{},[143,29739,29740],{},"Le statut de la demande",[143,29742,29743],{},"La date d'exécution du process",[143,29745,29746],{},"L'URI pour accéder à la demande et obtenir son statut",[143,29748,29749],{},"Une estimation du temps de traitement.",[29701,29751,29091],{"id":29752},"_204-no-content",[12,29754,29755],{},"Le serveur a bien traité la demande mais aucune information ne sera retournée dans le body.",[12,29757,29758,29759,2311,29761,2311,29763,29765,29766,29768],{},"Ce code HTTP est généralement utilisé avec les méthodes ",[344,29760,28996],{},[344,29762,28999],{},[344,29764,29598],{}," quand le serveur n'a aucune information\n(au dela du header Location) à retourner au client. Il peut également être utilisé avec les méthodes ",[344,29767,21707],{}," pour indiquer\nque la ressource existe (contrairement au 404) mais aucune représentation de la ressource n'existe.",[12,29770,29771],{},"La réponse ne doit jamais contenir de contenu.",[12,29773,29774,29775,29777],{},"Sauf si un header (tel que ",[344,29776,24964],{},") l'indique, le client n'a pas besoin de modifier son cache.",[29701,29779,29781],{"id":29780},"_206-partial-content","206 Partial Content",[12,29783,29784],{},"Utilisé avec le header Range dans la requête pour n'envoyer qu'un résultat partiel.",[12,29786,29787,29788,31],{},"Cette réponse peut-être utilisée dans les requêtes de pagination en conjonction uniquement avec le header ",[344,29789,29790],{},"Range",[23034,29792,29794],{"id":29793},"_3xx","3xx",[29701,29796,29798],{"id":29797},"_301-moved-permanently","301 Moved Permanently",[12,29800,29801,29802,29804],{},"La ressource a été déplacée définitivement à un autre endroit. Le header ",[344,29803,24964],{}," contient le nouvel emplacement. Le\nrésultat de la requête peut être caché.",[12,29806,29807],{},"On peut utiliser ce retour pour signifier un changement de l'API suffisamment important pour que cette version ne soit\nplus à jour, mais il est préférable de versionner l'API, plutôt que d'utiliser les redirections.",[29701,29809,29811],{"id":29810},"_302-found","302 Found",[12,29813,29814,29815,29817],{},"La ressource a été déplacée temporairement à un autre endroit. Le header ",[344,29816,24964],{}," contient l'emplacement. La requête\nne peut être cachée que si les headers de caches sont présents.",[12,29819,29820,29821,29823,29824,29826],{},"Le client doit refaire exactement la même requête mais sur le nouvel emplacement défini dans le header ",[344,29822,24964],{},".\nCette règle n'est pas respectée par les navigateurs qui remplacent la méthode par ",[344,29825,21707],{}," et c'est pour ça que les codes\n303 et 307 ont été créés.",[29701,29828,29830],{"id":29829},"_303-see-other","303 See Other",[12,29832,29833,29834,2623,29836,29838],{},"Ce code de retour, généralement utilisé avec des ",[344,29835,28999],{},[344,29837,28996],{}," indique que le serveur a terminé son travail mais\npréfère retourner au client une URI où trouver la ressource ou un message de status.",[12,29840,29841,29842,29844],{},"Le client peut alors décider ou non d'aller voir à l'adresse donnée via la méthode ",[344,29843,21707],{}," uniquement.",[12,29846,29847],{},"La réponse ne peut pas être modifiée.",[29701,29849,29851],{"id":29850},"_304-not-modified","304 Not Modified",[12,29853,29854,29855,2623,29857,29859,29860,854,29863,2198],{},"Utilisé généralement avec une requête ",[344,29856,21707],{},[344,29858,29021],{}," pour indiquer que la ressource n'a pas été modifiée par rapport aux\ninformations spécifiées dans le header (",[344,29861,29862],{},"If-None-Match",[344,29864,29865],{},"If-Modified-Since",[12,29867,29868],{},"Cette réponse est utilisée pour économiser du temps de traitement et de la bande passsante côté serveur et côté client,\nvu que le client peut reprendre la réponse qui se présente dans son cache.",[12,29870,29871,29872,2968,29875,2311,29878,2311,29880,2311,29883,29886,29887,31],{},"Généralement, une réponse précédente a été déjà envoyée au client avec les headers suivants: ",[344,29873,29874],{},"Cache-Control",[344,29876,29877],{},"Content-Location",[344,29879,7026],{},[344,29881,29882],{},"ETag",[344,29884,29885],{},"Expires",", et ",[344,29888,29889],{},"Vary",[29701,29891,29893],{"id":29892},"_307-temporary-redirect","307 Temporary Redirect",[12,29895,29896,29897,29899],{},"Le serveur indique que la ressource doit être récupérée à un autre endroit en ré-envoyant la requête telle quelle à\nl'URI spécifiée dans le header ",[344,29898,24964],{},". Toute future requête doit continuer à être envoyée au endpoint actuel.",[12,29901,29902,29903,31],{},"La différence entre une réponse 302 et 307 réside dans le fait que la requête ne doit pas être modifiée lors de l'appel\nà l'URI de la réponse retournée par la 307. Avec une 302, certains clients changent incorectement cette valeur en ",[344,29904,21707],{},[23034,29906,29908],{"id":29907},"_4xx","4xx",[29701,29910,29912],{"id":29911},"_400-bad-request","400 Bad Request",[12,29914,29915],{},"Le serveur ne comprend pas la requête à cause de sa syntaxe. Le client ne doit pas répéter sa requête sans\nmodification.",[12,29917,29918],{},"Ce message peut être utilisé quand aucun autre message de type 4xx n'est approprié.",[29701,29920,29922],{"id":29921},"_401-unauthorized","401 Unauthorized",[12,29924,29925],{},"La ressource nécessite une authentification. Le client peut répéter sa requête s'il possède le bon header\nd'Authorization.",[12,29927,29928],{},"Si le header d'authentification est présent mais que le serveur retourne une 401, cela signifie que\nl'authentification a été refusée avec ces paramètres.",[29701,29930,29932],{"id":29931},"_403-forbidden","403 Forbidden",[12,29934,29935],{},"L'authentification du client est bien reconnue par le serveur, mais le client ne possède pas les autorisations\nnécessaires pour accéder à la ressource.",[12,29937,29938],{},"Le client ne doit pas répéter la demande.",[29701,29940,29615],{"id":29941},"_404-not-found",[12,29943,29944],{},"La ressource n'existe pas sur le serveur, pour le moment. Le client peut potentiellement refaire la requête plus tard.",[12,29946,29947],{},"Ce status est également utilisé lorsque le serveur ne veut pas révéler pourquoi la requête a été refusée.",[29701,29949,29951],{"id":29950},"_409-conflict","409 Conflict",[12,29953,29954],{},"La requête est bien formée (contrairement à 400) mais elle ne peut pas être complétée dû à l'état de la ressource.",[29701,29956,29958],{"id":29957},"_410-gone","410 Gone",[12,29960,29961],{},"La ressource n'existe pas sur le serveur, mais le serveur sait (par un moyen interne) que la ressource a existé par le\npassé et qu'il n'est pas dans la capacité de fournir une URI où trouver la nouvelle version.",[29701,29963,29965],{"id":29964},"_416-requested-range-not-satisfiable","416 Requested Range Not Satisfiable",[12,29967,29968,29969,29971],{},"L'intervalle utilisé dans le header ",[344,29970,29790],{}," ne peut pas être satisfait.",[29701,29973,29975],{"id":29974},"_429-too-many-requests","429 Too Many Requests",[12,29977,29978],{},"Utilisé pour prévenir le client qu'il a atteint ses limites (rate limit)",[23034,29980,29982],{"id":29981},"_5xx","5xx",[29701,29984,29986],{"id":29985},"_500-internal-server-error","500 Internal Server Error",[12,29988,29989],{},"Le serveur clame haut et fort \"Une erreur inattendue s’est produite\".",[12,29991,29992],{},"L'erreur 500 n'est jamais de la faute du client. Le client peut donc retenter sa requête plus tard.",[29701,29994,29996],{"id":29995},"_501-not-implemented","501 Not Implemented",[12,29998,29999],{},"Pratique pour les API en cours de développement, l'API existe mais n'a pas encore été implémentée.",[29701,30001,30003],{"id":30002},"_503-service-unavailable","503 Service Unavailable",[12,30005,30006],{},"Le serveur n'est pas encore prêt à répondre à la requête (par exemple il démarre ou il s'arrête).",[1901,30008,30010],{"id":30009},"utilise-la-notion-de-lien-hypermedia-hateoas","Utilise la notion de lien hypermedia (HATEOAS)",[12,30012,30013],{},"HATEOAS, c'est pour Hypermedia As The Engine Of Application State.",[12,30015,30016],{},"Peu d'API sont REST HATEOAS. Le but est de REST HATEOAS est de lier les réponses REST les unes aux autres tout comme\nle Web lie les pages les unes aux autres. Le principe est donc d'ajouter la notion de lien hypermédia dans une API.",[12,30018,30019],{},"Dans la théorie, un client pourra donc s'adapter aux changement de l'API grâce à ces liens.",[12,30021,30022,30023,30028,30029,31],{},"Pour cela vous pouvez pouvez dans cadre du JSON vous baser sur\n",[47,30024,30027],{"href":30025,"rel":30026},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHypertext_Application_Language",[51],"HAL"," ou sur ",[47,30030,30033],{"href":30031,"rel":30032},"https:\u002F\u002Fjsonapi.org\u002F",[51],"JSON:API",[23034,30035,30033],{"id":30036},"jsonapi",[12,30038,30039],{},"Voici un exemple utilisant la syntaxe JSON:API.",[352,30041,30043],{"className":16331,"code":30042,"language":16333,"meta":291,"style":291},"{\n  \"links\": {\n    \"self\": \"\u002Fapi\u002Fhosts\",\n    \"next\": \"\u002Fapi\u002Fhosts?page[offset]=2\",\n    \"last\": \"\u002Fapi\u002Fhosts?page[offset]=10\"\n  },\n  \"data\": [\n    {\n      \"type\": \"hosts\",\n      \"id\": \"pc-ulrich\",\n      \"attributes\": {\n        \"dhcp\": [\n          {\n            \"address\": \"192.168.101\",\n            \"start\": 0,\n            \"end\": 50\n          }\n        ]\n      },\n      \"relationships\": {\n        \"backups\": {\n          \"links\": {\n            \"self\": \"\u002Fapi\u002Fhosts\u002Fpc-ulrich\u002Frelationships\u002Fbackups\",\n            \"related\": \"\u002Fapi\u002Fhosts\u002Fpc-ulrich\u002Fbackups\"\n          },\n          \"data\": [\n            { \"type\": \"backups\", \"id\": 0 },\n            { \"type\": \"backups\", \"id\": 1 },\n            { \"type\": \"backups\", \"id\": 2 },\n            { \"type\": \"backups\", \"id\": 3 }\n          ]\n        }\n      },\n      \"links\": {\n        \"self\": \"\u002Fhosts\u002Fpc-ulrich\"\n      }\n    }\n  ]\n}\n",[344,30044,30045,30049,30056,30068,30080,30090,30094,30101,30105,30117,30129,30136,30143,30148,30160,30171,30181,30185,30190,30194,30201,30208,30215,30227,30237,30242,30249,30273,30293,30313,30333,30338,30342,30346,30353,30363,30367,30371,30375],{"__ignoreMap":291},[360,30046,30047],{"class":362,"line":363},[360,30048,16340],{"class":366},[360,30050,30051,30054],{"class":362,"line":292},[360,30052,30053],{"class":578},"  \"links\"",[360,30055,6359],{"class":366},[360,30057,30058,30061,30063,30066],{"class":362,"line":375},[360,30059,30060],{"class":578},"    \"self\"",[360,30062,2691],{"class":366},[360,30064,30065],{"class":397},"\"\u002Fapi\u002Fhosts\"",[360,30067,2968],{"class":366},[360,30069,30070,30073,30075,30078],{"class":362,"line":433},[360,30071,30072],{"class":578},"    \"next\"",[360,30074,2691],{"class":366},[360,30076,30077],{"class":397},"\"\u002Fapi\u002Fhosts?page[offset]=2\"",[360,30079,2968],{"class":366},[360,30081,30082,30085,30087],{"class":362,"line":478},[360,30083,30084],{"class":578},"    \"last\"",[360,30086,2691],{"class":366},[360,30088,30089],{"class":397},"\"\u002Fapi\u002Fhosts?page[offset]=10\"\n",[360,30091,30092],{"class":362,"line":483},[360,30093,6758],{"class":366},[360,30095,30096,30099],{"class":362,"line":489},[360,30097,30098],{"class":578},"  \"data\"",[360,30100,16499],{"class":366},[360,30102,30103],{"class":362,"line":494},[360,30104,16504],{"class":366},[360,30106,30107,30110,30112,30115],{"class":362,"line":712},[360,30108,30109],{"class":578},"      \"type\"",[360,30111,2691],{"class":366},[360,30113,30114],{"class":397},"\"hosts\"",[360,30116,2968],{"class":366},[360,30118,30119,30122,30124,30127],{"class":362,"line":331},[360,30120,30121],{"class":578},"      \"id\"",[360,30123,2691],{"class":366},[360,30125,30126],{"class":397},"\"pc-ulrich\"",[360,30128,2968],{"class":366},[360,30130,30131,30134],{"class":362,"line":762},[360,30132,30133],{"class":578},"      \"attributes\"",[360,30135,6359],{"class":366},[360,30137,30138,30141],{"class":362,"line":781},[360,30139,30140],{"class":578},"        \"dhcp\"",[360,30142,16499],{"class":366},[360,30144,30145],{"class":362,"line":804},[360,30146,30147],{"class":366},"          {\n",[360,30149,30150,30153,30155,30158],{"class":362,"line":817},[360,30151,30152],{"class":578},"            \"address\"",[360,30154,2691],{"class":366},[360,30156,30157],{"class":397},"\"192.168.101\"",[360,30159,2968],{"class":366},[360,30161,30162,30165,30167,30169],{"class":362,"line":823},[360,30163,30164],{"class":578},"            \"start\"",[360,30166,2691],{"class":366},[360,30168,1344],{"class":414},[360,30170,2968],{"class":366},[360,30172,30173,30176,30178],{"class":362,"line":844},[360,30174,30175],{"class":578},"            \"end\"",[360,30177,2691],{"class":366},[360,30179,30180],{"class":414},"50\n",[360,30182,30183],{"class":362,"line":1441},[360,30184,21368],{"class":366},[360,30186,30187],{"class":362,"line":1462},[360,30188,30189],{"class":366},"        ]\n",[360,30191,30192],{"class":362,"line":1485},[360,30193,10551],{"class":366},[360,30195,30196,30199],{"class":362,"line":1497},[360,30197,30198],{"class":578},"      \"relationships\"",[360,30200,6359],{"class":366},[360,30202,30203,30206],{"class":362,"line":3161},[360,30204,30205],{"class":578},"        \"backups\"",[360,30207,6359],{"class":366},[360,30209,30210,30213],{"class":362,"line":3167},[360,30211,30212],{"class":578},"          \"links\"",[360,30214,6359],{"class":366},[360,30216,30217,30220,30222,30225],{"class":362,"line":3194},[360,30218,30219],{"class":578},"            \"self\"",[360,30221,2691],{"class":366},[360,30223,30224],{"class":397},"\"\u002Fapi\u002Fhosts\u002Fpc-ulrich\u002Frelationships\u002Fbackups\"",[360,30226,2968],{"class":366},[360,30228,30229,30232,30234],{"class":362,"line":3224},[360,30230,30231],{"class":578},"            \"related\"",[360,30233,2691],{"class":366},[360,30235,30236],{"class":397},"\"\u002Fapi\u002Fhosts\u002Fpc-ulrich\u002Fbackups\"\n",[360,30238,30239],{"class":362,"line":3239},[360,30240,30241],{"class":366},"          },\n",[360,30243,30244,30247],{"class":362,"line":3256},[360,30245,30246],{"class":578},"          \"data\"",[360,30248,16499],{"class":366},[360,30250,30251,30254,30257,30259,30262,30264,30267,30269,30271],{"class":362,"line":3276},[360,30252,30253],{"class":366},"            { ",[360,30255,30256],{"class":578},"\"type\"",[360,30258,2691],{"class":366},[360,30260,30261],{"class":397},"\"backups\"",[360,30263,2311],{"class":366},[360,30265,30266],{"class":578},"\"id\"",[360,30268,2691],{"class":366},[360,30270,1344],{"class":414},[360,30272,6397],{"class":366},[360,30274,30275,30277,30279,30281,30283,30285,30287,30289,30291],{"class":362,"line":3281},[360,30276,30253],{"class":366},[360,30278,30256],{"class":578},[360,30280,2691],{"class":366},[360,30282,30261],{"class":397},[360,30284,2311],{"class":366},[360,30286,30266],{"class":578},[360,30288,2691],{"class":366},[360,30290,1944],{"class":414},[360,30292,6397],{"class":366},[360,30294,30295,30297,30299,30301,30303,30305,30307,30309,30311],{"class":362,"line":3305},[360,30296,30253],{"class":366},[360,30298,30256],{"class":578},[360,30300,2691],{"class":366},[360,30302,30261],{"class":397},[360,30304,2311],{"class":366},[360,30306,30266],{"class":578},[360,30308,2691],{"class":366},[360,30310,795],{"class":414},[360,30312,6397],{"class":366},[360,30314,30315,30317,30319,30321,30323,30325,30327,30329,30331],{"class":362,"line":3320},[360,30316,30253],{"class":366},[360,30318,30256],{"class":578},[360,30320,2691],{"class":366},[360,30322,30261],{"class":397},[360,30324,2311],{"class":366},[360,30326,30266],{"class":578},[360,30328,2691],{"class":366},[360,30330,1954],{"class":414},[360,30332,21961],{"class":366},[360,30334,30335],{"class":362,"line":3325},[360,30336,30337],{"class":366},"          ]\n",[360,30339,30340],{"class":362,"line":3361},[360,30341,2840],{"class":366},[360,30343,30344],{"class":362,"line":3380},[360,30345,10551],{"class":366},[360,30347,30348,30351],{"class":362,"line":3405},[360,30349,30350],{"class":578},"      \"links\"",[360,30352,6359],{"class":366},[360,30354,30355,30358,30360],{"class":362,"line":3411},[360,30356,30357],{"class":578},"        \"self\"",[360,30359,2691],{"class":366},[360,30361,30362],{"class":397},"\"\u002Fhosts\u002Fpc-ulrich\"\n",[360,30364,30365],{"class":362,"line":3426},[360,30366,23356],{"class":366},[360,30368,30369],{"class":362,"line":3432},[360,30370,2927],{"class":366},[360,30372,30373],{"class":362,"line":3438},[360,30374,16771],{"class":366},[360,30376,30377],{"class":362,"line":3443},[360,30378,847],{"class":366},[12,30380,30381],{},"Comme vous pouvez voir, l'idée est de pouvoir à la lecture de la réponse comprendre automatiquement les relations\nentre les différents composants de l'API.",[23034,30383,30385],{"id":30384},"faut-il-faire-une-api-hateaos","Faut-il faire une API HATEAOS",[12,30387,30388],{},"Le but d'une telle API est de permettre au client de la découvrir automatiquement. Il serait envisageable alors de\ncréer un client capable, sur la base de l'API et des types de données qui y sont décrits, de pouvoir génerer une IHM\ndirectement.",[12,30390,30391],{},"Même si le principe d'une API HATEAOS est louable, le temps d'écriture d'une telle API est très consommatrice de temps.\nDe plus, généralement, un client est généralement créé pour des utilisateurs et non par une API.",[12,30393,30394],{},"Une bonne documentation peut amplement suffir pour développer une application, et comprendre les interactions entre\nles différentes APIs ?",[1901,30396,30398],{"id":30397},"générér-sa-documentation-avec-swagger","Générér sa documentation avec Swagger",[12,30400,30401],{},"Il existe de très bon outils pour écrire sa documentation.",[12,30403,30404],{},"L'un d'entre eux s'appelle Swagger basé sur la spécification OpenAPI. Il y a alors plusieurs manières de faire pour\ngénérer sa documention qui dépendent également des capacités du language.",[140,30406,30407,30410,30416],{},[143,30408,30409],{},"Sur un language typé, on peut générer sa documentation à partir du code. Il est alors possible via des annotations\nou des commentaires du code de définir les informations.",[143,30411,30412,30413,30415],{},"Il est également possible d'écrire le Swagger directement, et de générer le code après coup. Cela à l'avantage de\npouvoir travailler l'API avant sans écrire une ligne de code.",[13844,30414],{},"L'important sur ces deux méthodes c'est que le code de l'application et le code du Swagger soient synchronisé.",[143,30417,30418],{},"Si l'API a déjà été développée, il est beaucoup plus dur de générer une API par dessus. Surtout si le language est\nnon typé, et que toute la description doit être synchronisée à la main avec les objets de l'application, il y aura\nalors un risque que la documentation ne soit pas à jour.",[12,30420,30421],{},[69,30422],{"alt":30423,"src":30424},"Swagger WoodstockBackup","\u002FProgrammation\u002Fcreation-api\u002Fdocumentation-swagger.png",[1901,30426,30428],{"id":30427},"cacher-ses-requêtes","Cacher ses requêtes",[12,30430,30431],{},"Il est important côté client de cacher les requêtes afin de rester en dessous du Rate Limit, et aussi d'économiser les\nressources de bande passante de l'application.",[12,30433,30434],{},"Comme dit plus haut par contre, il ne faut pas que le serveur prenne comme hypothèse que le client va cacher les\nrequêtes au risque de se faire saturer par des requêtes. Côté serveur, il faut définir des limites d'accès de l'API,\net surtout définir également les headers de Cache qui vont bien afin d'avertir le client de la durée pendant laquelle\nil doit garder la requête.",[12,30436,30437],{},"En effet seul le serveur connaît fonctionnellement combien de temps une donnée peut être gardée.",[1901,30439,30441],{"id":30440},"quelques-références","Quelques références",[140,30443,30444,30450,30456,30462,30468],{},[143,30445,30446],{},[47,30447,30448],{"href":30448,"rel":30449},"https:\u002F\u002Fzestedesavoir.com\u002Ftutoriels\u002F299\u002Fla-theorie-rest-restful-et-hateoas\u002F",[51],[143,30451,30452],{},[47,30453,30454],{"href":30454,"rel":30455},"https:\u002F\u002Fwww.vinaysahni.com\u002Fbest-practices-for-a-pragmatic-restful-api",[51],[143,30457,30458],{},[47,30459,30460],{"href":30460,"rel":30461},"https:\u002F\u002Fstackoverflow.blog\u002F2020\u002F03\u002F02\u002Fbest-practices-for-rest-api-design\u002F",[51],[143,30463,30464],{},[47,30465,30466],{"href":30466,"rel":30467},"https:\u002F\u002Frestfulapi.net\u002Fhttp-methods\u002F",[51],[143,30469,30470],{},[47,30471,30472],{"href":30472,"rel":30473},"https:\u002F\u002Fwilliamdurand.fr\u002F2014\u002F02\u002F14\u002Fplease-do-not-patch-like-an-idiot\u002F",[51],[21499,30475,30477,30480],{"className":30476,"dataFootnotes":291},[21502],[33,30478,21507],{"className":30479,"id":15686},[21506],[13835,30481,30482,30493,30506],{},[143,30483,30485,30486,30488,30489],{"id":30484},"user-content-fn-getter","Ce que j'ai déjà vu faire. Pour préciser les choses, un getter doit être ",[105,30487,29036],{},". Cela signifie que l'appel ",[47,30490,21520],{"href":30491,"ariaLabel":21517,"className":30492,"dataFootnoteBackref":291},"#user-content-fnref-getter",[21519],[143,30494,30496,30501,30502],{"id":30495},"user-content-fn-idempotent",[47,30497,30500],{"href":30498,"rel":30499},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FIdempotence#:~:text=En%20math%C3%A9matiques%20et%20en%20informatique,applique%20une%20ou%20plusieurs%20fois.",[51],"En mathématiques et en informatique, l'idempotence signifie qu'une opération a le même effet qu'on l'applique une ou plusieurs fois.",": Dans notre cas cela signifie qu'elles n'ont pas d'effets de bord. ",[47,30503,21520],{"href":30504,"ariaLabel":21532,"className":30505,"dataFootnoteBackref":291},"#user-content-fnref-idempotent",[21519],[143,30507,30509,30510],{"id":30508},"user-content-fn-atomic","Ce qui veux dire que tout est fait ou rien. ",[47,30511,21520],{"href":30512,"ariaLabel":30513,"className":30514,"dataFootnoteBackref":291},"#user-content-fnref-atomic","Back to reference 3",[21519],[1613,30516,30517],{},"html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sLaUg, html code.shiki .sLaUg{--shiki-default:#FFFFFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}",{"title":291,"searchDepth":292,"depth":292,"links":30519},[30520,30529],{"id":28725,"depth":292,"text":28726,"children":30521},[30522,30523,30524,30525,30526,30527,30528],{"id":28742,"depth":375,"text":28743},{"id":28956,"depth":375,"text":28957},{"id":29656,"depth":375,"text":29657},{"id":30009,"depth":375,"text":30010},{"id":30397,"depth":375,"text":30398},{"id":30427,"depth":375,"text":30428},{"id":30440,"depth":375,"text":30441},{"id":15686,"depth":292,"text":21507},"2020-11-02",{"type":9,"value":30532},[30533,30535,30537,30551,30553,30555,30557],[12,30534,21597],{},[12,30536,21600],{},[140,30538,30539,30543,30547],{},[143,30540,30541],{},[47,30542,21608],{"href":21607},[143,30544,30545],{},[47,30546,21614],{"href":21613},[143,30548,30549],{},[47,30550,21620],{"href":21619},[33,30552,28726],{"id":28725},[12,30554,28729],{},[12,30556,28732],{},[12,30558,28735,30559,28739],{},[344,30560,28738],{},{"planet":320},"\u002Fpost\u002Fcreation-api-2",{"title":28702,"description":21597},"creation-api-2","posts\u002FProgrammation\u002F2020-11-02_creation-api-2",[24663,22028,24664,1765,1766],"qRIJgww-9nhPwt3g0Lbn9M52urBRQ1PwFy4IGXjFHQI",{"id":30569,"title":30570,"author":7,"body":30571,"category":300,"categorySlug":301,"date":31428,"description":21597,"excerpt":31429,"extension":317,"location":318,"meta":31453,"navigation":320,"path":31454,"published":320,"seo":31455,"slug":31456,"stem":31457,"tags":31458,"timeToRead":762,"__hash__":31459},"posts\u002Fposts\u002FProgrammation\u002F2020-10-11_creation-api-1.md","Comment créer une bonne API Web - Partie 1",{"type":9,"value":30572,"toc":31418},[30573,30575,30578,30592,30595,30598,30601,30604,30610,30627,30630,30647,30650,30654,30665,30668,30674,30677,30680,30683,30686,30689,30692,30696,30699,30702,30707,30710,30730,30733,30761,30767,30770,30774,30777,30780,30799,30802,30805,30899,30910,30914,30917,30930,31043,31049,31052,31157,31160,31166,31290,31294,31297,31347,31351,31354,31357,31360,31363,31366,31369,31391,31394,31396,31399,31415],[12,30574,21597],{},[12,30576,30577],{},"Je souhaite vous parler de l'écriture d'API. Je vais découper cet article en 3 parties:",[140,30579,30580,30584,30588],{},[143,30581,30582],{},[47,30583,21608],{"href":21607},[143,30585,30586],{},[47,30587,21614],{"href":21613},[143,30589,30590],{},[47,30591,21620],{"href":21619},[12,30593,30594],{},"Je me limiterai au WEB et aux normes REST et GraphQL même s'il y a d'autres normes\u002Fframeworks pour écrire des API.",[12,30596,30597],{},"Commençons donc par le début ! Qu'est-ce qu'une API ? API signifie Application Programming Interface. C'est une\ninterface de programmation prête à être consommée par un client.",[12,30599,30600],{},"Par exemple quand on développe une librairie (en C\u002FC++, voir un module NodeJS, ...), on définit une liste de méthodes\nque l'on rend publique et qui sont utilisées pour appeler cette librairie. Ces méthodes sont alors utilisées par des\nclients. L'API c'est ce contrat entre la librairie et le client.",[12,30602,30603],{},"Dans le cadre d'un site internet, l'API est le contrat entre un site internet et le client qui l'appelle. Comme tout\ncontrat il faut que celui-ci soit clairement défini si on veut que ça se passe bien entre les clients et les services.",[12,30605,30606,30607,14024],{},"Il est important pour une bonne API ",[28,30608,30609],{},"public",[140,30611,30612,30615,30618,30621,30624],{},[143,30613,30614],{},"d'être stable dans le temps, ceci afin qu'un client qui utilise une API puisse continuer à l'utiliser sans devoir\ntout réécrire entre chaque version,",[143,30616,30617],{},"d'être fiable, cela va sans dire mais une API qui retourne des erreurs une fois sur deux ou qui ne fait pas ce qu'on\nlui demande va vite être abandonnée,",[143,30619,30620],{},"d'être simple d'utilisation et bien documentée, afin que le développeur passe le moins de temps possible à apprendre à\nl'utiliser,",[143,30622,30623],{},"d'avoir une bonne gestion des erreurs,",[143,30625,30626],{},"d'être performante.",[12,30628,30629],{},"Dans le monde du web, il existe plusieurs protocole\u002Fnorme afin de faciliter l'écriture de ce contrat d'interface, on\npeut citer par exemple:",[140,30631,30632,30635,30638,30641,30644],{},[143,30633,30634],{},"SOAP (Simple Object Access Protocol)",[143,30636,30637],{},"REST (Representational State Transfer)",[143,30639,30640],{},"XML-RPC (XML Remote Procedure Call)",[143,30642,30643],{},"GraphQL (créé par Facebook)",[143,30645,30646],{},"Falcor (qui est un protocole basé sur une implémentation de référence ; créé par Netflix)",[12,30648,30649],{},"Il existe plein de manières d'écrire des API. On peut aussi en écrire à base de socket réseau. Dans cet article je ne\nvais pas détailler toutes les méthodes possibles mais je vais présenter uniquement une selection d'API Web (Rest et\nGraphQL).",[33,30651,30653],{"id":30652},"pourquoi-écrire-une-api-web","Pourquoi écrire une API Web",[12,30655,30656,30657,30664],{},"Pour commencer si votre application web est une SPA",[15680,30658,30659],{},[47,30660,1944],{"href":30661,"ariaDescribedBy":30662,"dataFootnoteRef":291,"id":30663},"#user-content-fn-spa",[15686],"user-content-fnref-spa",", il sera nécessaire d'avoir un contrat d'interface entre le client (SPA)\net le serveur (sauf s'il n'y a pas de serveur...). Ce contrat est généralement implicite.",[12,30666,30667],{},"Même pour un site web statique, ou pour un site dont les pages HTML sont générées coté serveur, nous pouvons considérer\nque l'API (l'interface de programation exposée) de l'application sont ses pages HTML. En effet, il existe des web\nscrapper qui lisent le contenu HTML des pages afin d'en lire le contenu (voir même qui en expose une API plus compréhensible).",[12,30669,30670,30671,31],{},"Du coup, la question la plus importante est ",[105,30672,30673],{},"\"Faut-il que mon interface de programmation soit publique ou privée ? Faut-il qu'elle\nsoit simple d'utilisation\"",[12,30675,30676],{},"Pour un site, dont les pages sont générées côté serveur et dont le rendu est en HTML, l'API n'est ni simple\nd'utilisation, ni documentable. Pour une SPA (Single Page Application), l'écriture d'une API utilisable par un\nprogramme est la norme et elle sera alors consumée par Angular, Vue, React, jQuery ....",[12,30678,30679],{},"Souhaite-t-on alors que notre application soit utilisable publiquement ?",[12,30681,30682],{},"Souhaite-t-on que d'autres applications développées par des tiers puisse utiliser notre API, librement ? gratuitement ?",[12,30684,30685],{},"Si oui, dois-je mettre en place une politique sur le nombre de requêtes maximales par utilisateur (OUI) ? Et de combien ?\nVais-je pouvoir supporter la charge ?",[12,30687,30688],{},"Prenez en considération dans votre décision que de tout facon, les gens feront ce qu'ils veulent. Après tout, si un\nhumain peut visualiser la page, un programme le peu également (WebScrapper).",[12,30690,30691],{},"communique avec le serveur via ses API. C'est en quelque sorte une application lourde mais écrite en JavaScript. Au démarrage du\nsite l'interface (le client) est chargée en mémoire (par morceau si on prend le lazy loading) et l'interface est ensuite générée à la\nvolée. Les pages HTML sont donc générées côté client et non coté serveur.",[33,30693,30695],{"id":30694},"quest-quune-bonne-documentation","Qu'est qu'une bonne documentation",[12,30697,30698],{},"Si on veux que l'API soit utilisée, il faut qu'elle soit bien documentée et surtout à jour. Sans cela personne ne voudra\nl'utiliser.",[12,30700,30701],{},"Pour faciliter l'écriture de la documentation certains outils permettent de générer celle-ci à partir du code (des\ntypes de données, du nom des méthodes, d'annotation ...), ce qui permet de maintenir plus facilement sa documentation avec\nl'évolution du code.\nPar contre, l'utilisation de générateur ne dédouanne pas de l'écriture de la partie qui ne peux pas être documentée (comme\nles descriptions, les exemples, ...).",[12,30703,30704],{},[69,30705],{"alt":30423,"src":30706},"\u002FProgrammation\u002Fcreation-api\u002Fdocumentation-swagger-head.png",[12,30708,30709],{},"La documentation doit contenir :",[140,30711,30712,30715,30718,30721,30724,30727],{},[143,30713,30714],{},"des exemples d'appels",[143,30716,30717],{},"des descriptions détaillées de ce que fait chaque point d'entrée,",[143,30719,30720],{},"quels type de données sont présentes en entrée et comment les utiliser,",[143,30722,30723],{},"mais aussi le type des données que l'on a en sortie,",[143,30725,30726],{},"les erreurs que peut retourner le endpoint et dans quelles circonstances,",[143,30728,30729],{},"comment seront traitées les données en entrée (batch, immédiat).",[12,30731,30732],{},"Au début de la documentation, ne pas oublier de documenter:",[140,30734,30735,30738],{},[143,30736,30737],{},"le fonctionnement de l'authentification",[143,30739,30740,30741],{},"les règles d'utilisation\n",[140,30742,30743,30746,30749,30758],{},[143,30744,30745],{},"ce qu'on est autorisé à faire",[143,30747,30748],{},"ce qu'on n'est pas autorisé à faire",[143,30750,30751,30752,30757],{},"le nombre d'appel par seconde\u002Fminutes\u002Fheures\u002F...et quels sont les headers HTTP permettant de récuperer le résultat\n(par exemple dans l'",[47,30753,30756],{"href":30754,"rel":30755},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Frest\u002Foverview\u002Fresources-in-the-rest-api#rate-limiting",[51],"API Github",",\non peut retrouver les headers: X-RateLimit-Limit, X-RateLimit-Remaining)",[143,30759,30760],{},"le fonctionnement de la pagination dans l'API",[12,30762,30763,30764,30766],{},"Il peut être efficace d'avoir une page au démarrage de l'API (",[105,30765,15251],{},") donnant un première exemple complet d'un\npremier appel à l'API.",[12,30768,30769],{},"Dans le développement de l'API, l'écriture de la documentation est aussi important que l'écriture du code.",[33,30771,30773],{"id":30772},"gestion-des-erreurs","Gestion des erreurs",[12,30775,30776],{},"Pour la gestion des erreurs, l'API doit retourner le maximum d'informations pour que le développeur puisse comprendre\nl'erreur et effectuer une correction mais également suffisament d'informations pour que le développeur puisse les utiliser\ndans son programme pour retourner les problèmes fonctionnels à l'utilisateur final.",[12,30778,30779],{},"Par exemple dans une API Rest, il est important que les différents cas d'erreur soit explicités:",[140,30781,30782,30785,30791,30794],{},[143,30783,30784],{},"400 - BadRequest: The request is malformed.",[143,30786,30787,30788,30790],{},"404 - NotFound: The resource ",[105,30789,6017],{}," can't be found",[143,30792,30793],{},"401 - Unauthorized: The user is not authentified.",[143,30795,30796,30797,31],{},"403 - Forbidden: The user is not authorized to access to the resource ",[105,30798,6017],{},[12,30800,30801],{},"Ceci afin d'aider les développeurs à traiter tout les cas d'erreurs et d'afficher un message cohérent à l'utilisateur.",[12,30803,30804],{},"Lors d'une erreur, le retour de la requête doit toujours être le même. Voici un exemple de requête:",[352,30806,30808],{"className":16331,"code":30807,"language":16333,"meta":291,"style":291},"GET http:\u002F\u002F192.168.101.205:3000\u002Fapi\u002Fhosts\u002Funknownhost\n\n{\n  \"statusCode\": 404,\n  \"message\": \"Can't find configuration for the host with name unknownhost\",\n  \"error\": \"Not Found\",\n  \"errorCode\": \"HOST_NOT_FOUND\",\n  \"params\": {\n      \"host\": \"unknownhost\"\n  }\n}\n",[344,30809,30810,30818,30822,30826,30838,30850,30862,30874,30881,30891,30895],{"__ignoreMap":291},[360,30811,30812,30815],{"class":362,"line":363},[360,30813,30814],{"class":366},"GET http:",[360,30816,30817],{"class":644},"\u002F\u002F192.168.101.205:3000\u002Fapi\u002Fhosts\u002Funknownhost\n",[360,30819,30820],{"class":362,"line":292},[360,30821,372],{"emptyLinePlaceholder":320},[360,30823,30824],{"class":362,"line":375},[360,30825,16340],{"class":366},[360,30827,30828,30831,30833,30836],{"class":362,"line":433},[360,30829,30830],{"class":578},"  \"statusCode\"",[360,30832,2691],{"class":366},[360,30834,30835],{"class":414},"404",[360,30837,2968],{"class":366},[360,30839,30840,30843,30845,30848],{"class":362,"line":478},[360,30841,30842],{"class":578},"  \"message\"",[360,30844,2691],{"class":366},[360,30846,30847],{"class":397},"\"Can't find configuration for the host with name unknownhost\"",[360,30849,2968],{"class":366},[360,30851,30852,30855,30857,30860],{"class":362,"line":483},[360,30853,30854],{"class":578},"  \"error\"",[360,30856,2691],{"class":366},[360,30858,30859],{"class":397},"\"Not Found\"",[360,30861,2968],{"class":366},[360,30863,30864,30867,30869,30872],{"class":362,"line":489},[360,30865,30866],{"class":578},"  \"errorCode\"",[360,30868,2691],{"class":366},[360,30870,30871],{"class":397},"\"HOST_NOT_FOUND\"",[360,30873,2968],{"class":366},[360,30875,30876,30879],{"class":362,"line":494},[360,30877,30878],{"class":578},"  \"params\"",[360,30880,6359],{"class":366},[360,30882,30883,30886,30888],{"class":362,"line":712},[360,30884,30885],{"class":578},"      \"host\"",[360,30887,2691],{"class":366},[360,30889,30890],{"class":397},"\"unknownhost\"\n",[360,30892,30893],{"class":362,"line":331},[360,30894,820],{"class":366},[360,30896,30897],{"class":362,"line":762},[360,30898,847],{"class":366},[12,30900,30901,30902,30905,30906,30909],{},"Dans l'exemple ci-dessus, ",[344,30903,30904],{},"errorCode"," peut être utilisé pour indiquer à l'utilisateur, un champ obligatoire, (avec dans ",[344,30907,30908],{},"params"," le\nnom du champ) ou une règle de gestion mal utilisée.\nCe code erreur pourra alors être remontée à l'utilisateur final directement pour rendre l'interface plus réactive.",[33,30911,30913],{"id":30912},"cohérence","Cohérence",[12,30915,30916],{},"Pour faire une bonne documentation il faut également de bonnes bases. Pour cela il faut que l'API soit cohérente dans\nson fonctionnement. La cohérence est importante tant au niveau des paramètres que dans le contenu de la requête ou de la\nréponse.",[12,30918,30919,30920,30923,30924,854,30927,14024],{},"Par exemple, sur une API REST, imaginons que pour gérer la pagination un ",[105,30921,30922],{},"endpoint"," demande les paramètres ",[344,30925,30926],{},"skip",[344,30928,30929],{},"limit",[352,30931,30933],{"className":16331,"code":30932,"language":16333,"meta":291,"style":291},"GET \u002Fhosts\u002Fpc-ulrich\u002Fbackups?skip=5&limit=10\n\n{\n    \"skip\": 5,\n    \"limit\": 10,\n    \"size\": 100,\n    \"result\": [\n        {\n            \"id\": 1\n        },\n        {\n            \"id\": 2\n        }\n    ]\n}\n",[344,30934,30935,30949,30953,30957,30968,30980,30991,30998,31003,31013,31017,31021,31030,31034,31039],{"__ignoreMap":291},[360,30936,30937,30940,30943,30946],{"class":362,"line":363},[360,30938,30939],{"class":366},"GET \u002Fhosts\u002Fpc-ulrich\u002Fbackups?skip=",[360,30941,30942],{"class":414},"5",[360,30944,30945],{"class":366},"&limit=",[360,30947,30948],{"class":414},"10\n",[360,30950,30951],{"class":362,"line":292},[360,30952,372],{"emptyLinePlaceholder":320},[360,30954,30955],{"class":362,"line":375},[360,30956,16340],{"class":366},[360,30958,30959,30962,30964,30966],{"class":362,"line":433},[360,30960,30961],{"class":578},"    \"skip\"",[360,30963,2691],{"class":366},[360,30965,30942],{"class":414},[360,30967,2968],{"class":366},[360,30969,30970,30973,30975,30978],{"class":362,"line":478},[360,30971,30972],{"class":578},"    \"limit\"",[360,30974,2691],{"class":366},[360,30976,30977],{"class":414},"10",[360,30979,2968],{"class":366},[360,30981,30982,30985,30987,30989],{"class":362,"line":483},[360,30983,30984],{"class":578},"    \"size\"",[360,30986,2691],{"class":366},[360,30988,6349],{"class":414},[360,30990,2968],{"class":366},[360,30992,30993,30996],{"class":362,"line":489},[360,30994,30995],{"class":578},"    \"result\"",[360,30997,16499],{"class":366},[360,30999,31000],{"class":362,"line":494},[360,31001,31002],{"class":366},"        {\n",[360,31004,31005,31008,31010],{"class":362,"line":712},[360,31006,31007],{"class":578},"            \"id\"",[360,31009,2691],{"class":366},[360,31011,31012],{"class":414},"1\n",[360,31014,31015],{"class":362,"line":331},[360,31016,11013],{"class":366},[360,31018,31019],{"class":362,"line":762},[360,31020,31002],{"class":366},[360,31022,31023,31025,31027],{"class":362,"line":781},[360,31024,31007],{"class":578},[360,31026,2691],{"class":366},[360,31028,31029],{"class":414},"2\n",[360,31031,31032],{"class":362,"line":804},[360,31033,2840],{"class":366},[360,31035,31036],{"class":362,"line":817},[360,31037,31038],{"class":366},"    ]\n",[360,31040,31041],{"class":362,"line":823},[360,31042,847],{"class":366},[12,31044,31045,31046,31048],{},"N'utilisez pas pour un autre ",[105,31047,30922],{}," de votre application des paramètres différents. De même, n'utilisez pas dans\nle résultat de la requête des noms différents de ceux utilisés dans les paramètres.",[12,31050,31051],{},"Enfin structurez le contenu de la réponse toujours de la même manière, pour que vos utilisateurs puissent développer\ndes méthodes génériques lors de l'utilisation de votre API (Par exemple une méthode de pagination générique).",[352,31053,31055],{"className":16331,"code":31054,"language":16333,"meta":291,"style":291},"GET \u002Fhosts?start=5&size=10\n\n{\n    \"debut\": 5,\n    \"taille\": 10,\n    \"fin\": 100,\n    \"liste\": [\n        {\n            \"id\": 1\n        },\n        {\n            \"id\": 2\n        }\n    ]\n}\n",[344,31056,31057,31069,31073,31077,31088,31099,31110,31117,31121,31129,31133,31137,31145,31149,31153],{"__ignoreMap":291},[360,31058,31059,31062,31064,31067],{"class":362,"line":363},[360,31060,31061],{"class":366},"GET \u002Fhosts?start=",[360,31063,30942],{"class":414},[360,31065,31066],{"class":366},"&size=",[360,31068,30948],{"class":414},[360,31070,31071],{"class":362,"line":292},[360,31072,372],{"emptyLinePlaceholder":320},[360,31074,31075],{"class":362,"line":375},[360,31076,16340],{"class":366},[360,31078,31079,31082,31084,31086],{"class":362,"line":433},[360,31080,31081],{"class":578},"    \"debut\"",[360,31083,2691],{"class":366},[360,31085,30942],{"class":414},[360,31087,2968],{"class":366},[360,31089,31090,31093,31095,31097],{"class":362,"line":478},[360,31091,31092],{"class":578},"    \"taille\"",[360,31094,2691],{"class":366},[360,31096,30977],{"class":414},[360,31098,2968],{"class":366},[360,31100,31101,31104,31106,31108],{"class":362,"line":483},[360,31102,31103],{"class":578},"    \"fin\"",[360,31105,2691],{"class":366},[360,31107,6349],{"class":414},[360,31109,2968],{"class":366},[360,31111,31112,31115],{"class":362,"line":489},[360,31113,31114],{"class":578},"    \"liste\"",[360,31116,16499],{"class":366},[360,31118,31119],{"class":362,"line":494},[360,31120,31002],{"class":366},[360,31122,31123,31125,31127],{"class":362,"line":712},[360,31124,31007],{"class":578},[360,31126,2691],{"class":366},[360,31128,31012],{"class":414},[360,31130,31131],{"class":362,"line":331},[360,31132,11013],{"class":366},[360,31134,31135],{"class":362,"line":762},[360,31136,31002],{"class":366},[360,31138,31139,31141,31143],{"class":362,"line":781},[360,31140,31007],{"class":578},[360,31142,2691],{"class":366},[360,31144,31029],{"class":414},[360,31146,31147],{"class":362,"line":804},[360,31148,2840],{"class":366},[360,31150,31151],{"class":362,"line":817},[360,31152,31038],{"class":366},[360,31154,31155],{"class":362,"line":823},[360,31156,847],{"class":366},[12,31158,31159],{},"Cela aurait comme conséquence de perdre les utilisateurs (développeurs) qui utiliseront votre API.",[12,31161,31162,31163,31165],{},"Les structures, les champs utilisés sur les différents ",[105,31164,30922],{}," de votre API doivent toujours suivre la même\nlogique et par exemple:",[140,31167,31168,31174,31284,31287],{},[143,31169,31170,31171,22488],{},"nommer toujours les champs ayant la même fonction de la même manière: toujours nommer la date de création ",[344,31172,31173],{},"createdAt",[143,31175,31176,31177,31180,31236,31238,31239],{},"toujours retourner la resource demandé directement ",[105,31178,31179],{},"ou inversement toujours encapsuler la resource demandée dans un\nsous-objet",[352,31181,31183],{"className":16331,"code":31182,"language":16333,"meta":291,"style":291},"{\n  \"result\": [\n    {\n      \"id\": 1\n    },\n    {\n      \"id\": 2\n    }\n  ]\n}\n",[344,31184,31185,31189,31196,31200,31208,31212,31216,31224,31228,31232],{"__ignoreMap":291},[360,31186,31187],{"class":362,"line":363},[360,31188,16340],{"class":366},[360,31190,31191,31194],{"class":362,"line":292},[360,31192,31193],{"class":578},"  \"result\"",[360,31195,16499],{"class":366},[360,31197,31198],{"class":362,"line":375},[360,31199,16504],{"class":366},[360,31201,31202,31204,31206],{"class":362,"line":433},[360,31203,30121],{"class":578},[360,31205,2691],{"class":366},[360,31207,31012],{"class":414},[360,31209,31210],{"class":362,"line":478},[360,31211,6505],{"class":366},[360,31213,31214],{"class":362,"line":483},[360,31215,16504],{"class":366},[360,31217,31218,31220,31222],{"class":362,"line":489},[360,31219,30121],{"class":578},[360,31221,2691],{"class":366},[360,31223,31029],{"class":414},[360,31225,31226],{"class":362,"line":494},[360,31227,2927],{"class":366},[360,31229,31230],{"class":362,"line":712},[360,31231,16771],{"class":366},[360,31233,31234],{"class":362,"line":331},[360,31235,847],{"class":366},[13844,31237],{},"vs",[352,31240,31242],{"className":16331,"code":31241,"language":16333,"meta":291,"style":291},"[\n  {\n    \"id\": 1\n  },\n  {\n    \"id\": 2\n  }\n]\n",[344,31243,31244,31248,31252,31260,31264,31268,31276,31280],{"__ignoreMap":291},[360,31245,31246],{"class":362,"line":363},[360,31247,8979],{"class":366},[360,31249,31250],{"class":362,"line":292},[360,31251,28833],{"class":366},[360,31253,31254,31256,31258],{"class":362,"line":375},[360,31255,28838],{"class":578},[360,31257,2691],{"class":366},[360,31259,31012],{"class":414},[360,31261,31262],{"class":362,"line":433},[360,31263,6758],{"class":366},[360,31265,31266],{"class":362,"line":478},[360,31267,28833],{"class":366},[360,31269,31270,31272,31274],{"class":362,"line":483},[360,31271,28838],{"class":578},[360,31273,2691],{"class":366},[360,31275,31029],{"class":414},[360,31277,31278],{"class":362,"line":489},[360,31279,820],{"class":366},[360,31281,31282],{"class":362,"line":494},[360,31283,21698],{"class":366},[143,31285,31286],{},"toujours gérer la pagination de la même manière dans la réponse (par des entête http, ou directement dans le body,\nmais surtout avec les mêmes noms de champs).",[143,31288,31289],{},"toujours gérer les erreurs de la même manière.",[33,31291,31293],{"id":31292},"gérer-le-versionning-de-lapi","Gérer le versionning de l'API",[12,31295,31296],{},"Si vous souhaitez changer le fonctionnement de l'API, surtout ne cassez pas la cohérence de l'API, ni la version\nutilisée par tous. Pour cela vous avez plusieurs choix, et ils sont complémentaires:",[140,31298,31299,31319,31335],{},[143,31300,31301,31302,31304,31305,31308,31309,31312,31313,31315,31316,31318],{},"Vous pouvez créer une nouvelle version de l'API.",[13844,31303],{},"En créant une nouvelle version de l'API (passage de ",[344,31306,31307],{},"\u002Fapi\u002Fv1\u002F..."," à ",[344,31310,31311],{},"\u002Fapi\u002Fv2\u002F...","), vous vous assurez que l'ancienne\nversion fonctionne toujours et que les clients pourront migrer doucement de l'ancienne version vers la nouvelle.",[13844,31314],{},"Si vous souhaitez casser la cohérence de l'API (par exemple remonter les infos skip et limit du body dans des headers\nX-Pagination-Skip et X-Pagination-Limit), vous pouvez le faire une à une sur chaque API.",[13844,31317],{},"Pensez à un plan de décommissionnement pour ne pas maintenir 50 versions d'API différentes. Prévenez vos utilisateurs\nque les anciennes versions vont être décommissionées avec une date raisonable pour qu'ils puissent modifier leurs\napplications.",[143,31320,31321,31322,31325,31326,31328,31329,31331,31332,31334],{},"Lors de la création d'une nouvelle API, il peut être intéressant de ",[105,31323,31324],{},"déprécier"," les attributs de l'ancienne API, cela\nvous permet de prévenir l'utilisateur qu'il utilise un champ déprécié et qu'il sera décommisionné.",[13844,31327],{},"L'ajout d'attribut ne pose généralement pas de problème, mais cela peut vous permettre de supprimer des attributs\naprès avoir veillé à prévenir vos utilisateurs de leur obsolescence future sans forcément créer une nouvelle API.",[13844,31330],{},"Par contre cela nécessite de faire des modifications peu structurantes.",[13844,31333],{},"Pour des modifications plus structurantes vous devrez alors créer des nouveaux endpoint au coeur de l'API au risque\nde perdre l'utilisateur.",[143,31336,31337,31338,31340,31341,31343,31344,31346],{},"Monitorer votre API et son utilisation (analytics).",[13844,31339],{},"Cela vous permettra de savoir si vos API sont utilisées, leurs taux d'utilisation.",[13844,31342],{},"Etudier le taux d'utilisation vous permet ainsi de savoir le risque à décommissionner une API, mais aussi peut vous\nmotiver à améliorer les API les plus utilisées.",[13844,31345],{},"Avec certains framework (GraphQL) il est même possible de monitorer l'utilisation des attributs de votre API. Cela\nvous permet de plus facilement décommissionner les attributs de votre API au fur et à mesure de leur dépréciation.",[33,31348,31350],{"id":31349},"pour-le-client","Pour le client",[12,31352,31353],{},"Une bonne API doit être écrite pour le client qui va l'utiliser.",[12,31355,31356],{},"Il est important de ne pas créer son API en se basant sur son modèle interne mais en créant son API sur son usage.",[12,31358,31359],{},"Un appel d'API peut nécessiter plusieurs appels internes, et inversement plusieurs API peuvent faire appel aux mêmes\ndonnées internes. C'est au serveur derrière l'API ensuite de gérer un système de cache (avec invalidation de celui-ci)\npour limiter les appels à son back, ou sa base de données trop régulièrement.",[12,31361,31362],{},"De la même manière certains champs internes peuvent nécessiter d'être transformés pour être intégrés ou pour être exposés.",[12,31364,31365],{},"Certaines données internes n'ont parfois même pas besoin d'être exposées.",[12,31367,31368],{},"Du coup il faut se poser les bonnes questions lors de la création de son API :",[140,31370,31371,31374,31377],{},[143,31372,31373],{},"Qui sont les clients qui vont appeler mon API ?",[143,31375,31376],{},"Quelles cinématiques utilisateurs se cachent derrière ses clients ?",[143,31378,31379,31380],{},"Lors de chaque appel de quelles données auront besoin les clients ?\n",[140,31381,31382,31385,31388],{},[143,31383,31384],{},"Dois-je regrouper certains champs dans une même resource pour limiter le nombre d'appels ?",[143,31386,31387],{},"Dois-je déplacer certaines données dans des sous-resources pour limiter la quantité de données lors d'un appel ?",[143,31389,31390],{},"Dois-je ajouter de la pagination, de la projection, de la recherche pour limiter la quantité de données qui\nressortira de mon API ?",[12,31392,31393],{},"Il faut prendre en compte qu'en fonction de l'appelant le résultat peut être différent. Une application mobile ne\nprésentera pas forcément les données de la même manière qu'un site WEB. Est-ce que l'API doit savoir répondre aux deux ?\n(Certains framework savent mieux répondre à ce genre de questions que d'autres).",[33,31395,251],{"id":250},[12,31397,31398],{},"Si vous avez aimé cet article, je vous invite à lire la suite qui paraitera bientôt.",[21499,31400,31402,31405],{"className":31401,"dataFootnotes":291},[21502],[33,31403,21507],{"className":31404,"id":15686},[21506],[13835,31406,31407],{},[143,31408,31410,31411],{"id":31409},"user-content-fn-spa","une SPA (Single Page Application) est une application dont l'interface Web est entièrement écrite en javascript et qui ",[47,31412,21520],{"href":31413,"ariaLabel":21517,"className":31414,"dataFootnoteBackref":291},"#user-content-fnref-spa",[21519],[1613,31416,31417],{},"html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":291,"searchDepth":292,"depth":292,"links":31419},[31420,31421,31422,31423,31424,31425,31426,31427],{"id":30652,"depth":292,"text":30653},{"id":30694,"depth":292,"text":30695},{"id":30772,"depth":292,"text":30773},{"id":30912,"depth":292,"text":30913},{"id":31292,"depth":292,"text":31293},{"id":31349,"depth":292,"text":31350},{"id":250,"depth":292,"text":251},{"id":15686,"depth":292,"text":21507},"2020-10-11",{"type":9,"value":31430},[31431,31433,31435,31449,31451],[12,31432,21597],{},[12,31434,30577],{},[140,31436,31437,31441,31445],{},[143,31438,31439],{},[47,31440,21608],{"href":21607},[143,31442,31443],{},[47,31444,21614],{"href":21613},[143,31446,31447],{},[47,31448,21620],{"href":21619},[12,31450,30594],{},[12,31452,30597],{},{"planet":320},"\u002Fpost\u002Fcreation-api-1",{"title":30570,"description":21597},"creation-api-1","posts\u002FProgrammation\u002F2020-10-11_creation-api-1",[24663,22028,24664,1765,1766],"TBg-AMlBnBvdkbTX1a-CGytRJUL2yk4FcVzMHR6lj6c",{"id":31461,"title":31462,"author":7,"body":31463,"category":300,"categorySlug":301,"date":32896,"description":291,"excerpt":32897,"extension":317,"location":318,"meta":32918,"navigation":320,"path":32919,"published":320,"seo":32920,"slug":32921,"stem":32922,"tags":32923,"timeToRead":781,"__hash__":32928},"posts\u002Fposts\u002FProgrammation\u002F2016-12-10-findsimilarity.md","FindSimilarity - Trouver les différences entre plusieurs vidéos",{"type":9,"value":31464,"toc":32884},[31465,31467,31469,31472,31475,31478,31483,31490,31494,31497,31500,31529,31532,31583,31587,31590,31604,31610,31618,31621,31630,31633,31636,31639,32022,32024,32027,32036,32039,32042,32068,32071,32193,32196,32204,32219,32222,32225,32756,32766,32770,32773,32777,32780,32783,32789,32792,32796,32802,32812,32815,32832,32849,32853,32856,32862,32865,32871,32876,32878,32881],[1901,31466,6028],{"id":6027},[12,31468,21597],{},[12,31470,31471],{},"Je souhaite vous présenter une petite expérience que je viens d'écrire.",[12,31473,31474],{},"Cela fait plusieurs années que je souhaitais m'amuser sur la librairie OpenCV mais sans jamais en avoir eu l'utilité. J'ai profité d'avoir un peu de temps libre, pour écrire un petit\nprogramme dont le but est de comparer un ensemble de vidéos.",[12,31476,31477],{},"Le but est ensuite de dire si dans cet ensemble de vidéos, deux vidéos sont identiques, ou se ressemblent, ou sont trop éloignées.",[12,31479,31480],{},[105,31481,31482],{},"J'ai souhaité faire cette expérience par amusement, je n'ai donc pas passé beaucoup de temps sur la qualité du code écrit. Ce dernier aurait pu être mieux découpé, posséder des\ncommentaires, des tests unitaires, ... . Si vous voulez utiliser ce code pour un véritable usage production, n'hésitez pas à améliorer celui ci.",[12,31484,31485,31486,31],{},"Vous pouvez trouver le code source de cette expérience à l'adresse suivante : ",[47,31487,31488],{"href":31488,"rel":31489},"https:\u002F\u002Fgogs.shadoware.org\u002FShadowareOrg\u002Ffind-similarity",[51],[1901,31491,31493],{"id":31492},"le-jeux-de-données","Le jeux de données",[12,31495,31496],{},"J'ai pris plusieurs films en DVD que je possède. Possédant un NAS, et une chromecast, j'encode ces DVD au format vidéo et je les y dépose. Malheureusement la qualité est dégradée\npar rapport au DVD.",[12,31498,31499],{},"Pour constituer le jeu de données, je prends ces films encodés, que je dépose dans un dossier. Je copie certains d'entre eux telquel",[352,31501,31503],{"className":565,"code":31502,"language":567,"meta":291,"style":291},"mkdir example\ncd example\ncp ..\u002Ffilm1.avi film1_copy.avi\n",[344,31504,31505,31512,31518],{"__ignoreMap":291},[360,31506,31507,31509],{"class":362,"line":363},[360,31508,15350],{"class":381},[360,31510,31511],{"class":397}," example\n",[360,31513,31514,31516],{"class":362,"line":292},[360,31515,15342],{"class":582},[360,31517,31511],{"class":397},[360,31519,31520,31523,31526],{"class":362,"line":375},[360,31521,31522],{"class":381},"cp",[360,31524,31525],{"class":397}," ..\u002Ffilm1.avi",[360,31527,31528],{"class":397}," film1_copy.avi\n",[12,31530,31531],{},"J'encode certains de ces films avec une résolution différente :",[352,31533,31535],{"className":565,"code":31534,"language":567,"meta":291,"style":291},"avconv -i film2.m4v  -preset veryslow -s 320x240 film2.320x240.m4v\navconv -i film2.m4v  -preset veryslow -s 640x480 film2.640x480.m4v\n",[344,31536,31537,31563],{"__ignoreMap":291},[360,31538,31539,31542,31545,31548,31551,31554,31557,31560],{"class":362,"line":363},[360,31540,31541],{"class":381},"avconv",[360,31543,31544],{"class":414}," -i",[360,31546,31547],{"class":397}," film2.m4v",[360,31549,31550],{"class":414},"  -preset",[360,31552,31553],{"class":397}," veryslow",[360,31555,31556],{"class":414}," -s",[360,31558,31559],{"class":397}," 320x240",[360,31561,31562],{"class":397}," film2.320x240.m4v\n",[360,31564,31565,31567,31569,31571,31573,31575,31577,31580],{"class":362,"line":292},[360,31566,31541],{"class":381},[360,31568,31544],{"class":414},[360,31570,31547],{"class":397},[360,31572,31550],{"class":414},[360,31574,31553],{"class":397},[360,31576,31556],{"class":414},[360,31578,31579],{"class":397}," 640x480",[360,31581,31582],{"class":397}," film2.640x480.m4v\n",[1901,31584,31586],{"id":31585},"comment-fonctionne-la-comparaison","Comment fonctionne la comparaison",[12,31588,31589],{},"Avant de parler de la comparaison, parlons des fichiers que nous allons comparer. Le programme va se constituer une liste des fichiers à comparer et pour chaque fichier va lire\nles informations suivantes :",[140,31591,31592,31595,31598,31601],{},[143,31593,31594],{},"la durée du film",[143,31596,31597],{},"la largeur",[143,31599,31600],{},"la hauteur",[143,31602,31603],{},"une miniature du film (utilisée pour comparer à l'oeil les vidéos)",[12,31605,31606,31607,31],{},"Ensuite, une fois les méta-données récupérées, le programe se constitue une liste de paires de fichiers à comparer en sélectionnant les fichiers qui ont une durée identique à +\u002F- 5\nsecondes. Ce paramètre est modifiable au niveau de la constante ",[344,31608,31609],{},"DELTA_SEC",[12,31611,31612,31613,31],{},"Enfin vient la comparaison pour laquelle je me suis simplement basé sur les exemples du site OpenCV que vous pouvez trouver dans la rubrique\n",[47,31614,31617],{"href":31615,"rel":31616},"http:\u002F\u002Fdocs.opencv.org\u002F2.4\u002Fdoc\u002Ftutorials\u002Fhighgui\u002Fvideo-input-psnr-ssim\u002Fvideo-input-psnr-ssim.html",[51],"Video Input with OpenCV and similarity measurement",[12,31619,31620],{},"J'ai utilisé l'algorithme PSNR (Peak signal-to-noise ratio) pour déterminer si les deux images de la vidéos sont plutôt proches ou éloignées. Cet algorithme calcul la distorsion\nentre deux images. Il est principalement utilisé pour quantifier la performance réalisée par un encodeur lors de la compression d'une vidéo. Une valeur entre 30 et 50 signifie que\nles images sont relativement proches. Plus la valeur est haute, et plus la qualité d'image est conservée entre les deux images. Si la valeur est inférieure à 30 on peut estimer qu'il\ny a une forte chance pour que les images soit différentes.",[12,31622,31623,31624,31629],{},"Vous pouvez retrouver les formules utilisées par le calcul sur le site d'OpenCV ou sur la page ",[47,31625,31628],{"href":31626,"rel":31627},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FPeak_Signal_to_Noise_Ratio",[51],"Wikipedia",". Est-ce que ce\ncalcul est le meilleur pour trouver les images similaires ? Je ne sais pas. Si vous avez d'autres propositions, on peut les tester.",[12,31631,31632],{},"Sur une vidéo on a une multitude d'images (sur un film d'une heure et demie à 25 images secondes, nous en avons 135 000), on pourrait comparer chaque image de la vidéo pour se faire\nune moyenne, de mon coté j'ai préféré comparer une image au milieu de la vidéo afin de parcourir plus vite les vidéos.",[12,31634,31635],{},"De la même manière pour m'abstraire de la taille de la vidéo qui peut avoir été modififée, je redimensionne, à tort ou à raison, les deux images à une taille identique\n(arbitrairement: 160x120).",[12,31637,31638],{},"Je vous présente donc ci-dessous l'algorithme que vous pouvez retrouver sur le site d'OpenCV. J'ai légèrement modifié l'algorithme pour redimensionner les images ainsi que pour\nretourner une valeur de PSNR infiniment grande quand deux vidéos sont identiques.",[352,31640,31642],{"className":635,"code":31641,"language":637,"meta":291,"style":291},"double getPSNR(const cv::Mat& F1, const cv::Mat& F2) {\n    cv::Mat I1, I2;\n\n    cv::resize(F1, I1, cv::Size(160, 120));\n    cv::resize(F2, I2, cv::Size(160, 120));\n\n    cv::Mat s1;\n    cv::absdiff(I1, I2, s1);   \u002F\u002F |I1 - I2|\n    s1.convertTo(s1, CV_32F);  \u002F\u002F cannot make a square on 8 bits\n    s1 = s1.mul(s1);           \u002F\u002F |I1 - I2|^2\n\n    cv::Scalar s = sum(s1);    \u002F\u002F sum elements per channel\n\n    double sse = s.val[0] + s.val[1] + s.val[2]; \u002F\u002F sum channels\n\n    if( sse \u003C= 1e-10) {        \u002F\u002F for small values return zero\n        return std::numeric_limits\u003Cdouble>::infinity();\n    } else {\n        double mse  = sse \u002F (double)(I1.channels() * I1.total());\n        double psnr = 10.0 * log10((255 * 255) \u002F mse);\n        return psnr;\n    }\n",[344,31643,31644,31683,31688,31692,31718,31739,31743,31748,31761,31777,31798,31802,31817,31821,31877,31881,31905,31926,31934,31977,32011,32018],{"__ignoreMap":291},[360,31645,31646,31649,31652,31654,31656,31659,31662,31665,31668,31670,31672,31674,31676,31678,31681],{"class":362,"line":363},[360,31647,31648],{"class":574},"double",[360,31650,31651],{"class":381}," getPSNR",[360,31653,671],{"class":366},[360,31655,6053],{"class":574},[360,31657,31658],{"class":366}," cv::",[360,31660,31661],{"class":662},"Mat",[360,31663,31664],{"class":574},"&",[360,31666,31667],{"class":677}," F1",[360,31669,2311],{"class":366},[360,31671,6053],{"class":574},[360,31673,31658],{"class":366},[360,31675,31661],{"class":662},[360,31677,31664],{"class":574},[360,31679,31680],{"class":677}," F2",[360,31682,681],{"class":366},[360,31684,31685],{"class":362,"line":292},[360,31686,31687],{"class":366},"    cv::Mat I1, I2;\n",[360,31689,31690],{"class":362,"line":375},[360,31691,372],{"emptyLinePlaceholder":320},[360,31693,31694,31697,31700,31703,31706,31708,31711,31713,31716],{"class":362,"line":433},[360,31695,31696],{"class":366},"    cv::",[360,31698,31699],{"class":381},"resize",[360,31701,31702],{"class":366},"(F1, I1, cv::",[360,31704,31705],{"class":381},"Size",[360,31707,671],{"class":366},[360,31709,31710],{"class":414},"160",[360,31712,2311],{"class":366},[360,31714,31715],{"class":414},"120",[360,31717,4081],{"class":366},[360,31719,31720,31722,31724,31727,31729,31731,31733,31735,31737],{"class":362,"line":478},[360,31721,31696],{"class":366},[360,31723,31699],{"class":381},[360,31725,31726],{"class":366},"(F2, I2, cv::",[360,31728,31705],{"class":381},[360,31730,671],{"class":366},[360,31732,31710],{"class":414},[360,31734,2311],{"class":366},[360,31736,31715],{"class":414},[360,31738,4081],{"class":366},[360,31740,31741],{"class":362,"line":483},[360,31742,372],{"emptyLinePlaceholder":320},[360,31744,31745],{"class":362,"line":489},[360,31746,31747],{"class":366},"    cv::Mat s1;\n",[360,31749,31750,31752,31755,31758],{"class":362,"line":494},[360,31751,31696],{"class":366},[360,31753,31754],{"class":381},"absdiff",[360,31756,31757],{"class":366},"(I1, I2, s1);",[360,31759,31760],{"class":644},"   \u002F\u002F |I1 - I2|\n",[360,31762,31763,31766,31768,31771,31774],{"class":362,"line":712},[360,31764,31765],{"class":662},"    s1",[360,31767,31],{"class":366},[360,31769,31770],{"class":381},"convertTo",[360,31772,31773],{"class":366},"(s1, CV_32F);",[360,31775,31776],{"class":644},"  \u002F\u002F cannot make a square on 8 bits\n",[360,31778,31779,31782,31784,31787,31789,31792,31795],{"class":362,"line":331},[360,31780,31781],{"class":366},"    s1 ",[360,31783,583],{"class":574},[360,31785,31786],{"class":662}," s1",[360,31788,31],{"class":366},[360,31790,31791],{"class":381},"mul",[360,31793,31794],{"class":366},"(s1);",[360,31796,31797],{"class":644},"           \u002F\u002F |I1 - I2|^2\n",[360,31799,31800],{"class":362,"line":762},[360,31801,372],{"emptyLinePlaceholder":320},[360,31803,31804,31807,31809,31812,31814],{"class":362,"line":781},[360,31805,31806],{"class":366},"    cv::Scalar s ",[360,31808,583],{"class":574},[360,31810,31811],{"class":381}," sum",[360,31813,31794],{"class":366},[360,31815,31816],{"class":644},"    \u002F\u002F sum elements per channel\n",[360,31818,31819],{"class":362,"line":804},[360,31820,372],{"emptyLinePlaceholder":320},[360,31822,31823,31826,31829,31831,31834,31836,31839,31841,31843,31845,31847,31849,31851,31853,31855,31857,31859,31861,31863,31865,31867,31869,31871,31874],{"class":362,"line":817},[360,31824,31825],{"class":574},"    double",[360,31827,31828],{"class":366}," sse ",[360,31830,583],{"class":574},[360,31832,31833],{"class":662}," s",[360,31835,31],{"class":366},[360,31837,31838],{"class":578},"val",[360,31840,2385],{"class":366},[360,31842,1344],{"class":414},[360,31844,2390],{"class":366},[360,31846,1310],{"class":574},[360,31848,31833],{"class":662},[360,31850,31],{"class":366},[360,31852,31838],{"class":578},[360,31854,2385],{"class":366},[360,31856,1944],{"class":414},[360,31858,2390],{"class":366},[360,31860,1310],{"class":574},[360,31862,31833],{"class":662},[360,31864,31],{"class":366},[360,31866,31838],{"class":578},[360,31868,2385],{"class":366},[360,31870,795],{"class":414},[360,31872,31873],{"class":366},"];",[360,31875,31876],{"class":644}," \u002F\u002F sum channels\n",[360,31878,31879],{"class":362,"line":823},[360,31880,372],{"emptyLinePlaceholder":320},[360,31882,31883,31885,31888,31891,31893,31895,31897,31899,31902],{"class":362,"line":844},[360,31884,5657],{"class":574},[360,31886,31887],{"class":366},"( sse ",[360,31889,31890],{"class":574},"\u003C=",[360,31892,1099],{"class":414},[360,31894,3864],{"class":578},[360,31896,1491],{"class":366},[360,31898,30977],{"class":414},[360,31900,31901],{"class":366},") {",[360,31903,31904],{"class":644},"        \u002F\u002F for small values return zero\n",[360,31906,31907,31909,31911,31914,31916,31918,31921,31924],{"class":362,"line":1441},[360,31908,24470],{"class":574},[360,31910,829],{"class":366},[360,31912,31913],{"class":662},"numeric_limits",[360,31915,1358],{"class":366},[360,31917,31648],{"class":574},[360,31919,31920],{"class":366},">::",[360,31922,31923],{"class":381},"infinity",[360,31925,2204],{"class":366},[360,31927,31928,31930,31932],{"class":362,"line":1462},[360,31929,18951],{"class":366},[360,31931,2488],{"class":574},[360,31933,896],{"class":366},[360,31935,31936,31939,31942,31944,31946,31948,31950,31952,31955,31958,31960,31963,31965,31967,31970,31972,31975],{"class":362,"line":1485},[360,31937,31938],{"class":574},"        double",[360,31940,31941],{"class":366}," mse  ",[360,31943,583],{"class":574},[360,31945,31828],{"class":366},[360,31947,768],{"class":574},[360,31949,743],{"class":366},[360,31951,31648],{"class":574},[360,31953,31954],{"class":366},")(",[360,31956,31957],{"class":662},"I1",[360,31959,31],{"class":366},[360,31961,31962],{"class":381},"channels",[360,31964,2805],{"class":366},[360,31966,925],{"class":574},[360,31968,31969],{"class":662}," I1",[360,31971,31],{"class":366},[360,31973,31974],{"class":381},"total",[360,31976,841],{"class":366},[360,31978,31979,31981,31984,31986,31989,31991,31994,31996,31999,32001,32004,32006,32008],{"class":362,"line":1497},[360,31980,31938],{"class":574},[360,31982,31983],{"class":366}," psnr ",[360,31985,583],{"class":574},[360,31987,31988],{"class":414}," 10.0",[360,31990,920],{"class":574},[360,31992,31993],{"class":381}," log10",[360,31995,7148],{"class":366},[360,31997,31998],{"class":414},"255",[360,32000,920],{"class":574},[360,32002,32003],{"class":414}," 255",[360,32005,3972],{"class":366},[360,32007,768],{"class":574},[360,32009,32010],{"class":366}," mse);\n",[360,32012,32013,32015],{"class":362,"line":3161},[360,32014,24470],{"class":574},[360,32016,32017],{"class":366}," psnr;\n",[360,32019,32020],{"class":362,"line":3167},[360,32021,2927],{"class":366},[1901,32023,20976],{"id":20975},[12,32025,32026],{},"La raison qui fait que je voulais m'amuser avec OpenCV c'est qu'il permet de faire ces calculs à l'aide du GPU au lieu du CPU.",[12,32028,32029,32030,32035],{},"L'utilisation du GPU permet d'améliorer la vitesse de calcul pour tout ce qui est traitement d'image, ce pour quoi un GPU est prévu pour. Pour plus d'informations sur\nl'utilisation du GPU dans OpenCV peut être trouvé sur la page ",[47,32031,32034],{"href":32032,"rel":32033},"http:\u002F\u002Fopencv.org\u002Fplatforms\u002Fcuda.html",[51],"CUDA"," d'OpenCV.",[12,32037,32038],{},"Le problème est que sur la version de Debian jessie que j'utilise, OpenCV n'est pas compilé avec CUDA, et ne permet donc pas d'utiliser le GPU. J'ai donc dû compiler ma propre\nversion d'OpenCV.",[12,32040,32041],{},"Pour cela la première étape consiste à récupérer le code source et à se positionner sur la branche que l'on souhaite compiler. Pour ma part je préfère compiler sur la branche 2.4,\nplus proche de la version de Debian.",[352,32043,32045],{"className":565,"code":32044,"language":567,"meta":291,"style":291},"git clone https:\u002F\u002Fgithub.com\u002Fopencv\u002Fopencv.git\ngit checkout 2.4\n",[344,32046,32047,32058],{"__ignoreMap":291},[360,32048,32049,32052,32055],{"class":362,"line":363},[360,32050,32051],{"class":381},"git",[360,32053,32054],{"class":397}," clone",[360,32056,32057],{"class":397}," https:\u002F\u002Fgithub.com\u002Fopencv\u002Fopencv.git\n",[360,32059,32060,32062,32065],{"class":362,"line":292},[360,32061,32051],{"class":381},[360,32063,32064],{"class":397}," checkout",[360,32066,32067],{"class":414}," 2.4\n",[12,32069,32070],{},"Viens ensuite la compilation :",[352,32072,32074],{"className":565,"code":32073,"language":567,"meta":291,"style":291},"mkdir build\ncd build\ncmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=\u002Fhome\u002Fphoenix\u002Fusr\u002Flocal  -DENABLE_SSE=ON -DENABLE_SSE2=ON -DENABLE_SSE3=ON -DWITH_TBB=ON -DWITH_1394=ON -DWITH_V4L=ON -DWITH_OPENGL=ON  -DWITH_GTK=ON -DWITH_JASPER=ON -DWITH_JPEG=ON -DWITH_PNG=ON -DWITH_TIFF=ON  -DWITH_OPENEXR=ON -DWITH_PVAPI=ON   -DWITH_EIGEN=ON -DCMAKE_SKIP_RPATH=ON -D WITH_CUDA=ON -D ENABLE_FAST_MATH=1 -D CUDA_FAST_MATH=1 -D WITH_CUBLAS=1 -DWITH_IPP=ON -D CUDA_GENERATION=Auto -D WITH_FFMPEG=ON  ..\u002F\n",[344,32075,32076,32082,32088],{"__ignoreMap":291},[360,32077,32078,32080],{"class":362,"line":363},[360,32079,15350],{"class":381},[360,32081,15353],{"class":397},[360,32083,32084,32086],{"class":362,"line":292},[360,32085,15342],{"class":582},[360,32087,15353],{"class":397},[360,32089,32090,32092,32095,32098,32100,32103,32106,32109,32112,32115,32118,32121,32124,32127,32130,32133,32136,32139,32142,32145,32148,32151,32153,32156,32158,32161,32163,32165,32168,32170,32172,32175,32177,32180,32182,32185,32187,32190],{"class":362,"line":375},[360,32091,15364],{"class":381},[360,32093,32094],{"class":414}," -D",[360,32096,32097],{"class":397}," CMAKE_BUILD_TYPE=RELEASE",[360,32099,32094],{"class":414},[360,32101,32102],{"class":397}," CMAKE_INSTALL_PREFIX=\u002Fhome\u002Fphoenix\u002Fusr\u002Flocal",[360,32104,32105],{"class":414},"  -DENABLE_SSE=ON",[360,32107,32108],{"class":414}," -DENABLE_SSE2=ON",[360,32110,32111],{"class":414}," -DENABLE_SSE3=ON",[360,32113,32114],{"class":414}," -DWITH_TBB=ON",[360,32116,32117],{"class":414}," -DWITH_1394=ON",[360,32119,32120],{"class":414}," -DWITH_V4L=ON",[360,32122,32123],{"class":414}," -DWITH_OPENGL=ON",[360,32125,32126],{"class":414},"  -DWITH_GTK=ON",[360,32128,32129],{"class":414}," -DWITH_JASPER=ON",[360,32131,32132],{"class":414}," -DWITH_JPEG=ON",[360,32134,32135],{"class":414}," -DWITH_PNG=ON",[360,32137,32138],{"class":414}," -DWITH_TIFF=ON",[360,32140,32141],{"class":414},"  -DWITH_OPENEXR=ON",[360,32143,32144],{"class":414}," -DWITH_PVAPI=ON",[360,32146,32147],{"class":414},"   -DWITH_EIGEN=ON",[360,32149,32150],{"class":414}," -DCMAKE_SKIP_RPATH=ON",[360,32152,32094],{"class":414},[360,32154,32155],{"class":397}," WITH_CUDA=ON",[360,32157,32094],{"class":414},[360,32159,32160],{"class":397}," ENABLE_FAST_MATH=",[360,32162,1944],{"class":414},[360,32164,32094],{"class":414},[360,32166,32167],{"class":397}," CUDA_FAST_MATH=",[360,32169,1944],{"class":414},[360,32171,32094],{"class":414},[360,32173,32174],{"class":397}," WITH_CUBLAS=",[360,32176,1944],{"class":414},[360,32178,32179],{"class":414}," -DWITH_IPP=ON",[360,32181,32094],{"class":414},[360,32183,32184],{"class":397}," CUDA_GENERATION=Auto",[360,32186,32094],{"class":414},[360,32188,32189],{"class":397}," WITH_FFMPEG=ON",[360,32191,32192],{"class":397},"  ..\u002F\n",[12,32194,32195],{},"J'active lors de la compilation le maximum d'optimisation dont CUDA. J'active également FFMPEG sans lequel le nombre de fichier reconnu baisse énormément sur ma machine. Après\navoir lancé cmake j'obtiens le résultat suivant :",[352,32197,32202],{"className":32198,"code":32200,"language":32201},[32199],"language-text","-- General configuration for OpenCV 2.4.13.1 =====================================\n--   Version control:               2.4.13.1-48-gac118ae\n--\n--   Platform:\n--     Host:                        Linux 3.16.0-4-amd64 x86_64\n--     CMake:                       3.6.2\n--     CMake generator:             Unix Makefiles\n--     CMake build tool:            \u002Fusr\u002Fbin\u002Fmake\n--     Configuration:               RELEASE\n--\n--   C\u002FC++:\n--     Built as dynamic libs?:      YES\n--     C++ Compiler:                \u002Fusr\u002Fbin\u002Fc++  (ver 4.9.2)\n--     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comment -Wno-array-bounds -Wno-aggressive-loop-optimizations -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -ffunction-sections -O3 -DNDEBUG  -DNDEBUG\n--     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-comment -Wno-array-bounds -Wno-aggressive-loop-optimizations -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -ffunction-sections -g  -O0 -DDEBUG -D_DEBUG\n--     C Compiler:                  \u002Fusr\u002Fbin\u002Fcc\n--     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wno-narrowing -Wno-comment -Wno-array-bounds -Wno-aggressive-loop-optimizations -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -ffunction-sections -O3 -DNDEBUG  -DNDEBUG\n--     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wno-narrowing -Wno-comment -Wno-array-bounds -Wno-aggressive-loop-optimizations -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -ffunction-sections -g  -O0 -DDEBUG -D_DEBUG\n--     Linker flags (Release):\n--     Linker flags (Debug):\n--     ccache:                      NO\n--     Precompiled headers:         YES\n--\n--   OpenCV modules:\n--     To be built:                 core flann imgproc highgui features2d calib3d ml video legacy objdetect photo gpu ocl nonfree contrib java python stitching superres ts videostab\n--     Disabled:                    world\n--     Disabled by dependency:      -\n--     Unavailable:                 androidcamera dynamicuda viz\n--\n--   GUI:\n--     QT:                          NO\n--     GTK+ 2.x:                    YES (ver 2.24.25)\n--     GThread :                    YES (ver 2.42.1)\n--     GtkGlExt:                    NO\n--     OpenGL support:              NO\n--     VTK support:                 NO\n--\n--   Media I\u002FO:\n--     ZLib:                        \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flibz.so (ver 1.2.8)\n--     JPEG:                        \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flibjpeg.so (ver )\n--     PNG:                         \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flibpng.so (ver 1.2.50)\n--     TIFF:                        \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flibtiff.so (ver 42 - 4.0.3)\n--     JPEG 2000:                   \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flibjasper.so (ver 1.900.1)\n--     OpenEXR:                     \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002FlibImath.so \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002FlibIlmImf.so \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002FlibIex.so \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002FlibHalf.so \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002FlibIlmThread.so (ver 1.6.1)\n--\n--   Video I\u002FO:\n--     DC1394 1.x:                  NO\n--     DC1394 2.x:                  YES (ver 2.2.3)\n--     FFMPEG:                      YES\n--       codec:                     YES (ver 56.1.0)\n--       format:                    YES (ver 56.1.0)\n--       util:                      YES (ver 54.3.0)\n--       swscale:                   YES (ver 3.0.0)\n--       resample:                  YES (ver 2.1.0)\n--       gentoo-style:              YES\n--     GStreamer:                   NO\n--     OpenNI:                      NO\n--     OpenNI PrimeSensor Modules:  NO\n--     PvAPI:                       NO\n--     GigEVisionSDK:               NO\n--     UniCap:                      NO\n--     UniCap ucil:                 NO\n--     V4L\u002FV4L2:                    NO\u002FYES\n--     XIMEA:                       NO\n--     Xine:                        NO\n--\n--   Other third-party libraries:\n--     Use IPP:                     IPP not found\n--     Use Eigen:                   NO\n--     Use TBB:                     NO\n--     Use OpenMP:                  NO\n--     Use GCD                      NO\n--     Use Concurrency              NO\n--     Use C=:                      NO\n--     Use Cuda:                    YES (ver 7.5)\n--     Use OpenCL:                  YES\n--\n--   NVIDIA CUDA\n--     Use CUFFT:                   YES\n--     Use CUBLAS:                  YES\n--     USE NVCUVID:                 NO\n--     NVIDIA GPU arch:             21\n--     NVIDIA PTX archs:\n--     Use fast math:               YES\n--     Tiny gpu module:             NO\n--\n--   OpenCL:\n--     Version:                     dynamic\n--     Include path:                \u002Fhome\u002Fphoenix\u002FDeveloppement\u002FExternalSoftware\u002Fopencv\u002F3rdparty\u002Finclude\u002Fopencl\u002F1.2\n--     Use AMD FFT:                 NO\n--     Use AMD BLAS:                NO\n--\n--   Python:\n--     Interpreter:                 \u002Fusr\u002Fbin\u002Fpython2 (ver 2.7.10)\n--     Libraries:                   \u002Fusr\u002Flib\u002Fx86_64-linux-gnu\u002Flibpython2.7.so (ver 2.7.10rc1)\n--     numpy:                       \u002Fusr\u002Flib\u002Fpython2.7\u002Fdist-packages\u002Fnumpy\u002Fcore\u002Finclude (ver 1.8.2)\n--     packages path:               lib\u002Fpython2.7\u002Fdist-packages\n--\n--   Java:\n--     ant:                         \u002Fusr\u002Fbin\u002Fant (ver 1.9.4)\n--     JNI:                         \u002Fusr\u002Flib\u002Fjvm\u002Fjava-7-openjdk-amd64\u002Finclude \u002Fusr\u002Flib\u002Fjvm\u002Fjava-7-openjdk-amd64\u002Finclude \u002Fusr\u002Flib\u002Fjvm\u002Fjava-7-openjdk-amd64\u002Finclude\n--     Java tests:                  YES\n--\n--   Documentation:\n--     Build Documentation:         NO\n--     Sphinx:                      NO\n--     PdfLaTeX compiler:           \u002Fusr\u002Fbin\u002Fpdflatex\n--     Doxygen:                     YES (\u002Fusr\u002Fbin\u002Fdoxygen)\n--\n--   Tests and samples:\n--     Tests:                       YES\n--     Performance tests:           YES\n--     C\u002FC++ Examples:              NO\n--\n--   Install path:                  \u002Fhome\u002Fphoenix\u002Fusr\u002Flocal\n--\n--   cvconfig.h is in:              \u002Fhome\u002Fphoenix\u002FDeveloppement\u002FExternalSoftware\u002Fopencv\u002Fbuild\n-- -----------------------------------------------------------------\n","text",[344,32203,32200],{"__ignoreMap":291},[12,32205,32206,32207,32210,32211,32214,32215,32218],{},"Pour que la compilation se déroule sans problème, il vous faudra installer certains paquets sur votre distribution. Sur Debian Jessie, j'ai installé ",[344,32208,32209],{},"nvidia-cuda-toolkit"," en\nversion ",[344,32212,32213],{},"7.5.18-4~bpo8+1",". Comme vous pouvez les voir c'est une version qui provient du repository de backports. La version ",[344,32216,32217],{},"6.0.37-5"," ne me permettait pas d'activer CUDA. J'ai\ndonc du monter l'ensemble du driver propriétaire sur mon poste de développement.",[12,32220,32221],{},"Rasssurez-vous, si vous ne voulez pas utiliser les backports ou ne pas utiliser de driver propriétaire, vous pouvez tester le programme dans sa version CPU. :)",[12,32223,32224],{},"Voici comment le code a été ré-écrit pour utiliser le GPU à la place du CPU:",[352,32226,32228],{"className":635,"code":32227,"language":637,"meta":291,"style":291},"struct BufferPSNR {                                    \u002F\u002F Optimized GPU versions\n    \u002F\u002F Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later.\n    cv::gpu::GpuMat gF1, gF2, gI1, gI2, gs, t1,t2;\n\n    cv::gpu::GpuMat buf;\n};\n\ndouble getPSNR_GPU_optimized(const cv::Mat& F1, const cv::Mat& F2, BufferPSNR& b) {\n    b.gF1.upload(F1);\n    b.gF2.upload(F2);\n\n    cv::gpu::resize(b.gF1, b.gI1, cv::Size(160, 120));\n    cv::gpu::resize(b.gF2, b.gI2, cv::Size(160, 120));\n\n    b.gI1.convertTo(b.t1, CV_32F);\n    b.gI2.convertTo(b.t2, CV_32F);\n\n    cv::gpu::absdiff(b.t1.reshape(1), b.t2.reshape(1), b.gs);\n    cv::gpu::multiply(b.gs, b.gs, b.gs);\n\n    double sse = cv::gpu::sum(b.gs, b.buf)[0];\n\n    if( sse \u003C= 1e-10) \u002F\u002F for small values return zero\n        return std::numeric_limits\u003Cdouble>::infinity();\n    else {\n        double mse = sse \u002F(double)(F1.channels() * F1.total());\n        double psnr = 10.0*log10((255*255)\u002Fmse);\n        return psnr;\n    }\n}\n",[344,32229,32230,32243,32248,32253,32257,32262,32266,32270,32312,32330,32346,32350,32393,32434,32438,32462,32485,32489,32543,32580,32584,32624,32628,32649,32667,32674,32712,32742,32748,32752],{"__ignoreMap":291},[360,32231,32232,32234,32237,32240],{"class":362,"line":363},[360,32233,890],{"class":574},[360,32235,32236],{"class":662}," BufferPSNR",[360,32238,32239],{"class":366}," {",[360,32241,32242],{"class":644},"                                    \u002F\u002F Optimized GPU versions\n",[360,32244,32245],{"class":362,"line":292},[360,32246,32247],{"class":644},"    \u002F\u002F Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later.\n",[360,32249,32250],{"class":362,"line":375},[360,32251,32252],{"class":366},"    cv::gpu::GpuMat gF1, gF2, gI1, gI2, gs, t1,t2;\n",[360,32254,32255],{"class":362,"line":433},[360,32256,372],{"emptyLinePlaceholder":320},[360,32258,32259],{"class":362,"line":478},[360,32260,32261],{"class":366},"    cv::gpu::GpuMat buf;\n",[360,32263,32264],{"class":362,"line":483},[360,32265,1036],{"class":366},[360,32267,32268],{"class":362,"line":489},[360,32269,372],{"emptyLinePlaceholder":320},[360,32271,32272,32274,32277,32279,32281,32283,32285,32287,32289,32291,32293,32295,32297,32299,32301,32303,32306,32308,32310],{"class":362,"line":494},[360,32273,31648],{"class":574},[360,32275,32276],{"class":381}," getPSNR_GPU_optimized",[360,32278,671],{"class":366},[360,32280,6053],{"class":574},[360,32282,31658],{"class":366},[360,32284,31661],{"class":662},[360,32286,31664],{"class":574},[360,32288,31667],{"class":677},[360,32290,2311],{"class":366},[360,32292,6053],{"class":574},[360,32294,31658],{"class":366},[360,32296,31661],{"class":662},[360,32298,31664],{"class":574},[360,32300,31680],{"class":677},[360,32302,2311],{"class":366},[360,32304,32305],{"class":662},"BufferPSNR",[360,32307,31664],{"class":574},[360,32309,2211],{"class":677},[360,32311,681],{"class":366},[360,32313,32314,32317,32319,32322,32324,32327],{"class":362,"line":712},[360,32315,32316],{"class":662},"    b",[360,32318,31],{"class":366},[360,32320,32321],{"class":662},"gF1",[360,32323,31],{"class":366},[360,32325,32326],{"class":381},"upload",[360,32328,32329],{"class":366},"(F1);\n",[360,32331,32332,32334,32336,32339,32341,32343],{"class":362,"line":331},[360,32333,32316],{"class":662},[360,32335,31],{"class":366},[360,32337,32338],{"class":662},"gF2",[360,32340,31],{"class":366},[360,32342,32326],{"class":381},[360,32344,32345],{"class":366},"(F2);\n",[360,32347,32348],{"class":362,"line":762},[360,32349,372],{"emptyLinePlaceholder":320},[360,32351,32352,32354,32357,32359,32361,32363,32365,32367,32369,32371,32373,32375,32378,32381,32383,32385,32387,32389,32391],{"class":362,"line":781},[360,32353,31696],{"class":366},[360,32355,32356],{"class":662},"gpu",[360,32358,666],{"class":366},[360,32360,31699],{"class":381},[360,32362,671],{"class":366},[360,32364,2252],{"class":662},[360,32366,31],{"class":366},[360,32368,32321],{"class":578},[360,32370,2311],{"class":366},[360,32372,2252],{"class":662},[360,32374,31],{"class":366},[360,32376,32377],{"class":578},"gI1",[360,32379,32380],{"class":366},", cv::",[360,32382,31705],{"class":381},[360,32384,671],{"class":366},[360,32386,31710],{"class":414},[360,32388,2311],{"class":366},[360,32390,31715],{"class":414},[360,32392,4081],{"class":366},[360,32394,32395,32397,32399,32401,32403,32405,32407,32409,32411,32413,32415,32417,32420,32422,32424,32426,32428,32430,32432],{"class":362,"line":804},[360,32396,31696],{"class":366},[360,32398,32356],{"class":662},[360,32400,666],{"class":366},[360,32402,31699],{"class":381},[360,32404,671],{"class":366},[360,32406,2252],{"class":662},[360,32408,31],{"class":366},[360,32410,32338],{"class":578},[360,32412,2311],{"class":366},[360,32414,2252],{"class":662},[360,32416,31],{"class":366},[360,32418,32419],{"class":578},"gI2",[360,32421,32380],{"class":366},[360,32423,31705],{"class":381},[360,32425,671],{"class":366},[360,32427,31710],{"class":414},[360,32429,2311],{"class":366},[360,32431,31715],{"class":414},[360,32433,4081],{"class":366},[360,32435,32436],{"class":362,"line":817},[360,32437,372],{"emptyLinePlaceholder":320},[360,32439,32440,32442,32444,32446,32448,32450,32452,32454,32456,32459],{"class":362,"line":823},[360,32441,32316],{"class":662},[360,32443,31],{"class":366},[360,32445,32377],{"class":662},[360,32447,31],{"class":366},[360,32449,31770],{"class":381},[360,32451,671],{"class":366},[360,32453,2252],{"class":662},[360,32455,31],{"class":366},[360,32457,32458],{"class":578},"t1",[360,32460,32461],{"class":366},", CV_32F);\n",[360,32463,32464,32466,32468,32470,32472,32474,32476,32478,32480,32483],{"class":362,"line":844},[360,32465,32316],{"class":662},[360,32467,31],{"class":366},[360,32469,32419],{"class":662},[360,32471,31],{"class":366},[360,32473,31770],{"class":381},[360,32475,671],{"class":366},[360,32477,2252],{"class":662},[360,32479,31],{"class":366},[360,32481,32482],{"class":578},"t2",[360,32484,32461],{"class":366},[360,32486,32487],{"class":362,"line":1441},[360,32488,372],{"emptyLinePlaceholder":320},[360,32490,32491,32493,32495,32497,32499,32501,32503,32505,32507,32509,32512,32514,32516,32518,32520,32522,32524,32526,32528,32530,32532,32534,32536,32538,32541],{"class":362,"line":1462},[360,32492,31696],{"class":366},[360,32494,32356],{"class":662},[360,32496,666],{"class":366},[360,32498,31754],{"class":381},[360,32500,671],{"class":366},[360,32502,2252],{"class":662},[360,32504,31],{"class":366},[360,32506,32458],{"class":662},[360,32508,31],{"class":366},[360,32510,32511],{"class":381},"reshape",[360,32513,671],{"class":366},[360,32515,1944],{"class":414},[360,32517,6775],{"class":366},[360,32519,2252],{"class":662},[360,32521,31],{"class":366},[360,32523,32482],{"class":662},[360,32525,31],{"class":366},[360,32527,32511],{"class":381},[360,32529,671],{"class":366},[360,32531,1944],{"class":414},[360,32533,6775],{"class":366},[360,32535,2252],{"class":662},[360,32537,31],{"class":366},[360,32539,32540],{"class":578},"gs",[360,32542,801],{"class":366},[360,32544,32545,32547,32549,32551,32554,32556,32558,32560,32562,32564,32566,32568,32570,32572,32574,32576,32578],{"class":362,"line":1485},[360,32546,31696],{"class":366},[360,32548,32356],{"class":662},[360,32550,666],{"class":366},[360,32552,32553],{"class":381},"multiply",[360,32555,671],{"class":366},[360,32557,2252],{"class":662},[360,32559,31],{"class":366},[360,32561,32540],{"class":578},[360,32563,2311],{"class":366},[360,32565,2252],{"class":662},[360,32567,31],{"class":366},[360,32569,32540],{"class":578},[360,32571,2311],{"class":366},[360,32573,2252],{"class":662},[360,32575,31],{"class":366},[360,32577,32540],{"class":578},[360,32579,801],{"class":366},[360,32581,32582],{"class":362,"line":1497},[360,32583,372],{"emptyLinePlaceholder":320},[360,32585,32586,32588,32590,32592,32594,32596,32598,32601,32603,32605,32607,32609,32611,32613,32615,32617,32620,32622],{"class":362,"line":3161},[360,32587,31825],{"class":574},[360,32589,31828],{"class":366},[360,32591,583],{"class":574},[360,32593,31658],{"class":366},[360,32595,32356],{"class":662},[360,32597,666],{"class":366},[360,32599,32600],{"class":381},"sum",[360,32602,671],{"class":366},[360,32604,2252],{"class":662},[360,32606,31],{"class":366},[360,32608,32540],{"class":578},[360,32610,2311],{"class":366},[360,32612,2252],{"class":662},[360,32614,31],{"class":366},[360,32616,2731],{"class":578},[360,32618,32619],{"class":366},")[",[360,32621,1344],{"class":414},[360,32623,4442],{"class":366},[360,32625,32626],{"class":362,"line":3167},[360,32627,372],{"emptyLinePlaceholder":320},[360,32629,32630,32632,32634,32636,32638,32640,32642,32644,32646],{"class":362,"line":3194},[360,32631,5657],{"class":574},[360,32633,31887],{"class":366},[360,32635,31890],{"class":574},[360,32637,1099],{"class":414},[360,32639,3864],{"class":578},[360,32641,1491],{"class":366},[360,32643,30977],{"class":414},[360,32645,16112],{"class":366},[360,32647,32648],{"class":644}," \u002F\u002F for small values return zero\n",[360,32650,32651,32653,32655,32657,32659,32661,32663,32665],{"class":362,"line":3224},[360,32652,24470],{"class":574},[360,32654,829],{"class":366},[360,32656,31913],{"class":662},[360,32658,1358],{"class":366},[360,32660,31648],{"class":574},[360,32662,31920],{"class":366},[360,32664,31923],{"class":381},[360,32666,2204],{"class":366},[360,32668,32669,32672],{"class":362,"line":3239},[360,32670,32671],{"class":574},"    else",[360,32673,896],{"class":366},[360,32675,32676,32678,32681,32683,32685,32687,32689,32691,32693,32696,32698,32700,32702,32704,32706,32708,32710],{"class":362,"line":3256},[360,32677,31938],{"class":574},[360,32679,32680],{"class":366}," mse ",[360,32682,583],{"class":574},[360,32684,31828],{"class":366},[360,32686,768],{"class":574},[360,32688,671],{"class":366},[360,32690,31648],{"class":574},[360,32692,31954],{"class":366},[360,32694,32695],{"class":662},"F1",[360,32697,31],{"class":366},[360,32699,31962],{"class":381},[360,32701,2805],{"class":366},[360,32703,925],{"class":574},[360,32705,31667],{"class":662},[360,32707,31],{"class":366},[360,32709,31974],{"class":381},[360,32711,841],{"class":366},[360,32713,32714,32716,32718,32720,32722,32724,32727,32729,32731,32733,32735,32737,32739],{"class":362,"line":3276},[360,32715,31938],{"class":574},[360,32717,31983],{"class":366},[360,32719,583],{"class":574},[360,32721,31988],{"class":414},[360,32723,925],{"class":574},[360,32725,32726],{"class":381},"log10",[360,32728,7148],{"class":366},[360,32730,31998],{"class":414},[360,32732,925],{"class":574},[360,32734,31998],{"class":414},[360,32736,16112],{"class":366},[360,32738,768],{"class":574},[360,32740,32741],{"class":366},"mse);\n",[360,32743,32744,32746],{"class":362,"line":3281},[360,32745,24470],{"class":574},[360,32747,32017],{"class":366},[360,32749,32750],{"class":362,"line":3305},[360,32751,2927],{"class":366},[360,32753,32754],{"class":362,"line":3320},[360,32755,847],{"class":366},[12,32757,32758,32759,32761,32762,32765],{},"L'utilisation de la structure ",[344,32760,32305],{}," permet de ne pas perdre de performance lors de l'initialisation relativement lourde des objets ",[344,32763,32764],{},"GpuMat",". Sans cela, l'utilisation du Gpu\nserait moins performant que la version Cpu.",[1901,32767,32769],{"id":32768},"lexpérience","L'expérience",[12,32771,32772],{},"Maintenant place à l'expérience. Nous allons lancer notre programme sur notre jeu d'essai comprenant les vidéos issue des DVD, ainsi que les vidéos recompressées pour l'expérience.\nSi l'expérence se déroule bien l'algorithme devrait nous detecter les fichiers dupliqués, ainsi que les fichiers recompressés.",[33,32774,32776],{"id":32775},"lancement-et-selection-des-dossiers","Lancement et selection des dossiers",[12,32778,32779],{},"La première étape est la sélection des dossiers que l'on souhaite comparer. Le programme ira lire récursivement l'ensemble des dossiers pour y trouver l'ensemble des fichiers\nvidéos.",[12,32781,32782],{},"La sélection d'un projet provient de mon envie de départ de pouvoir enregistrer l'avancement du projet au fur et à mesure. Cette étape n'a pas été réalisée mais l'existance du mode\nprojet existe toujours.",[12,32784,32785],{},[69,32786],{"alt":32787,"src":32788},"Selection du projet","\u002FProgrammation\u002Ffind-similarity\u002Ffind-similarity-1.png",[12,32790,32791],{},"Une fois le dossier projet choisi, il faut sélectionner la liste des dossiers contenant les vidéos et lancer le programme ...",[33,32793,32795],{"id":32794},"comparaison-des-vidéos","Comparaison des vidéos",[12,32797,32798,32799,31],{},"Dans cette étape le programme compare l'ensemble des vidéos présentes dans les dossiers. L'ensemble du processus tourne dans des threads afin de ne pas figer l'IHM, grâce à l'API\n",[344,32800,32801],{},"QtConcurrent",[12,32803,32804,32808],{},[69,32805],{"alt":32806,"src":32807},"Recherche","\u002FProgrammation\u002Ffind-similarity\u002Ffind-similarity-2.png",[69,32809],{"alt":32810,"src":32811},"Recherche encore","\u002FProgrammation\u002Ffind-similarity\u002Ffind-similarity-3.png",[12,32813,32814],{},"Les étapes de la recherche sont donc :",[140,32816,32817,32820,32823,32826,32829],{},[143,32818,32819],{},"Constitution de la liste des fichiers",[143,32821,32822],{},"Récupération des méta-données",[143,32824,32825],{},"Création de la liste des paires de fichiers (en filtrant sur la durée)",[143,32827,32828],{},"Calcul du PSNR pour chaque paire de fichiers",[143,32830,32831],{},"Filtrage pour ne garder que les paires de fichiers dont le PSNR est supérieur à 30 db.",[12,32833,32834,32835,32837,32838,32840,32841,32844,32845,32848],{},"Lors de mon développement je me suis basé sur l'API ",[344,32836,32801],{}," pour faire les différentes étapes. Faisant beaucoup de développement NodeJS ces derniers temps je suis habitué à\nl'utilisation des promesses et de leur enchainement pour faire des processus complexes. J'ai trouvé dommage de ne pas retrouver la même chose dans l'API ",[344,32839,32801],{},". Pour\nreproduire un équivalent, lorsqu'un ",[344,32842,32843],{},"QFuture","se termine, le signal émis par ",[344,32846,32847],{},"QFutureWatcher"," est récupérer par un SLOT du moteur qui s'occupe de lancer l'étape suivante.",[33,32850,32852],{"id":32851},"la-page-de-résultat","La page de résultat",[12,32854,32855],{},"La page de résultat liste les vidéos considérées identiques suite à l'étude d'une des images. Un coup d'oeil visuel permet alors de se faire un avis sur la question, et de\nsupprimer la vidéo que l'on souhaite.",[12,32857,32858],{},[69,32859],{"alt":32860,"src":32861},"Résultat 1","\u002FProgrammation\u002Ffind-similarity\u002Ffind-similarity-4.png",[12,32863,32864],{},"Comme on peut le voir le programme retrouve les vidéos dont l'image est identique, ainsi que les films qui ont été redimensionnés sans trop de soucis.\nLe problème se situe alors au niveau du bruit qui est généré. Plusieurs films sont considérés comme proches alors que complètement différents. Pour régler ce problème, comparer\nplusieurs images d'une même vidéo à des timestamps différents pourrait peut-être régler le problème.",[12,32866,32867],{},[69,32868],{"alt":32869,"src":32870},"Résultat 2","\u002FProgrammation\u002Ffind-similarity\u002Ffind-similarity-5.png",[12,32872,32873],{},[28,32874,32875],{},"Je vous conseille de vérifier manuellement la qualité et la similarité de chaque vidéo manuellement avant toute suppression.",[1901,32877,251],{"id":250},[12,32879,32880],{},"En conclusion, j'ai trouvé l'expérience intéressante, et maintenant qu'elle est terminée, je vais pouvoir en tenter une autre ;). Est-ce que le programme continuera d'évoluer ?\nPourquoi pas ? Cela dépendera des PR (Pull Request) et des demandes faites par les utilisateurs, ainsi que du temps que j'ai envie de passer dessus.",[1613,32882,32883],{},"html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}",{"title":291,"searchDepth":292,"depth":292,"links":32885},[32886,32887,32888,32889,32890,32891,32892,32893],{"id":6027,"depth":375,"text":6028},{"id":31492,"depth":375,"text":31493},{"id":31585,"depth":375,"text":31586},{"id":20975,"depth":375,"text":20976},{"id":32768,"depth":375,"text":32769},{"id":32775,"depth":292,"text":32776},{"id":32794,"depth":292,"text":32795},{"id":32851,"depth":292,"text":32852,"children":32894},[32895],{"id":250,"depth":375,"text":251},"2016-12-10",{"type":9,"value":32898},[32899,32901,32903,32905,32907,32909,32913],[1901,32900,6028],{"id":6027},[12,32902,21597],{},[12,32904,31471],{},[12,32906,31474],{},[12,32908,31477],{},[12,32910,32911],{},[105,32912,31482],{},[12,32914,31485,32915,31],{},[47,32916,31488],{"href":31488,"rel":32917},[51],{"planet":320},"\u002Fpost\u002Ffindsimilarity",{"title":31462,"description":291},"findsimilarity","posts\u002FProgrammation\u002F2016-12-10-findsimilarity",[32924,32925,32926,32927],"qt","opencv","video","debian","LR-Ko6CoDmyd4rJj7msRVs_pkiaov-yO2_RYmY_C6cE",{"id":32930,"title":32931,"author":7,"body":32932,"category":300,"categorySlug":301,"date":34717,"description":291,"excerpt":34718,"extension":317,"location":318,"meta":34759,"navigation":320,"path":34760,"published":320,"seo":34761,"slug":34762,"stem":34763,"tags":34764,"timeToRead":712,"__hash__":34765},"posts\u002Fposts\u002FProgrammation\u002F2012-07-01-cross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux.md","Cross-Compilation - Compiler un programme pour MS\u002FWindows sous Gnu\u002FLinux",{"type":9,"value":32933,"toc":34707},[32934,32944,32947,32950,32953,32979,32982,32988,32992,33008,33011,33036,33039,33050,33053,33072,33081,33084,33189,33192,33195,33266,33269,33325,33328,33343,33346,33377,33380,33729,33732,34028,34031,34035,34038,34041,34157,34164,34218,34225,34231,34234,34242,34248,34251,34257,34260,34271,34274,34306,34318,34589,34592,34611,34617,34619,34622,34704],[1901,32935,32937,32938,32943],{"id":32936},"quest-que-la-cross-compilation1","Qu'est que la cross-compilation",[15680,32939,32940],{},[47,32941,1944],{"href":15684,"ariaDescribedBy":32942,"dataFootnoteRef":291,"id":15687},[15686]," ?",[12,32945,32946],{},"La cross compilation est la possibilité sur une machine avec un matériel\nspécifique (architecture) et avec un système d'exploitation donné, de\ncompiler des programmes pour une autre architecture, ou pour un autre\nsystème d'exploitation.",[12,32948,32949],{},"Cela peut être utilisé par exemple pour compiler un programme sur votre\nordinateur de tous les jours (sous Gnu\u002FLinux, avec une architecture\ni386) à destination de votre téléphone mobile, qui lui est sous Symbian\navec un processeur ARM.",[12,32951,32952],{},"Les raisons de faire de la compilation croisée peuvent donc être\nmultiples :",[140,32954,32955,32958,32966,32976],{},[143,32956,32957],{},"Éviter de redémarrer votre machine pour compiler vos binaires.",[143,32959,32960,32961,2198],{},"Disponibilité des outils sur votre machine \u002F Indisponibilité des\noutils de compilation sur la machine de destination (on trouve\nrarement des outils de compilation sur des téléphones\nportables",[15680,32962,32963],{},[47,32964,795],{"href":16257,"ariaDescribedBy":32965,"dataFootnoteRef":291,"id":16259},[15686],[143,32967,32968,32969,2198],{},"Puissances des calculs (la compilation prendra moins de temps sur\nvotre PC de bureau que sur votre appareil mobile",[15680,32970,32971],{},[47,32972,1954],{"href":32973,"ariaDescribedBy":32974,"dataFootnoteRef":291,"id":32975},"#user-content-fn-3",[15686],"user-content-fnref-3",[143,32977,32978],{},"Licence : Vous voulez compiler à destination d'un système\nd'exploitation que vous ne possédez pas",[12,32980,32981],{},"Attention: La compilation croisée ne garantie pas que programme\nfonctionnera, vous devrez toujours faire quelques tests à partir d'un\némulateur ou à partir du système d'exploitation final.",[12,32983,32984,32985,31],{},"Bref, à partir du moment où vous avez besoin de compiler un programme\npour une autre architecture, ou pour un autre système d'exploitation que\nvotre machine actuelle, vous avez besoin de faire de la ",[105,32986,32987],{},"compilation\ncroisée",[1901,32989,32991],{"id":32990},"de-quoi-va-parler-ce-billet","De quoi va parler ce billet ?",[12,32993,32994,32995,32998,32999,33007],{},"Ce billet ne va pas parler de la ",[105,32996,32997],{},"compilation croisée"," entre deux\narchitectures différentes, mais uniquement de la compilation croisée à\ndestination d'une machine Windows à partir d'une machine Linux. La\ncompilation croisée entre architectures pourra être vue dans un\nfutur",[15680,33000,33001],{},[47,33002,33006],{"href":33003,"ariaDescribedBy":33004,"dataFootnoteRef":291,"id":33005},"#user-content-fn-4",[15686],"user-content-fnref-4","4"," article, ou sur d'autres sites.",[12,33009,33010],{},"Afin de pouvoir faire de la compilation croisée, il vous faudra\ninstaller les outils suivants :",[140,33012,33013,33024],{},[143,33014,33015,33016,33023],{},"MinGW",[15680,33017,33018],{},[47,33019,30942],{"href":33020,"ariaDescribedBy":33021,"dataFootnoteRef":291,"id":33022},"#user-content-fn-5",[15686],"user-content-fnref-5"," : utilisé en tant que cross-compilateur, il nous\ngénèrera un exécutable Windows.",[143,33025,33026,33027,33035],{},"Wine",[15680,33028,33029],{},[47,33030,33034],{"href":33031,"ariaDescribedBy":33032,"dataFootnoteRef":291,"id":33033},"#user-content-fn-6",[15686],"user-content-fnref-6","6"," : Qui nous servira à vérifier l'exécutable créé.",[12,33037,33038],{},"Les différentes étapes de la constitution de ce billet seront :",[140,33040,33041,33044,33047],{},[143,33042,33043],{},"Installation des outils",[143,33045,33046],{},"Compilation d'un programme simple",[143,33048,33049],{},"Compilation d'un programme Qt simple",[1901,33051,33043],{"id":33052},"installation-des-outils",[12,33054,33055,33056,33059,33060,33063,33071],{},"Nous y sommes :). Nous allons commencer par installer les outils qui\nnous permettront de faire de la compilation croisée. Sous la\ndistribution de votre choix, il vous faudra donc installer ",[344,33057,33058],{},"mingw"," ainsi\nque ",[344,33061,33062],{},"wine",[15680,33064,33065],{},[47,33066,33070],{"href":33067,"ariaDescribedBy":33068,"dataFootnoteRef":291,"id":33069},"#user-content-fn-7",[15686],"user-content-fnref-7","7",". Sous une Gnu\u002FDebian, on pourra par exemple faire :",[352,33073,33075],{"className":565,"code":33074,"language":567,"meta":291,"style":291},"> sudo aptitude install mingw32-runtime wine\n",[344,33076,33077],{"__ignoreMap":291},[360,33078,33079],{"class":362,"line":363},[360,33080,33074],{"class":366},[12,33082,33083],{},"Pour vérifier la version actuelle de mingw vous pouvez faire :",[352,33085,33087],{"className":565,"code":33086,"language":567,"meta":291,"style":291},"> i586-mingw32msvc-gcc --version\ni586-mingw32msvc-gcc (GCC) 4.2.1-sjlj (mingw32-2)\nCopyright (C) 2007 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",[344,33088,33089,33094,33107,33115,33154],{"__ignoreMap":291},[360,33090,33091],{"class":362,"line":363},[360,33092,33093],{"class":366},"> i586-mingw32msvc-gcc --version\n",[360,33095,33096,33099,33102,33105],{"class":362,"line":292},[360,33097,33098],{"class":381},"i586-mingw32msvc-gcc",[360,33100,33101],{"class":366}," (GCC) 4.2.1-sjlj (",[360,33103,33104],{"class":381},"mingw32-2",[360,33106,2922],{"class":366},[360,33108,33109,33112],{"class":362,"line":375},[360,33110,33111],{"class":381},"Copyright",[360,33113,33114],{"class":366}," (C) 2007 Free Software Foundation, Inc.\n",[360,33116,33117,33120,33123,33126,33129,33131,33133,33135,33138,33140,33143,33146,33149,33151],{"class":362,"line":433},[360,33118,33119],{"class":381},"This",[360,33121,33122],{"class":397}," is",[360,33124,33125],{"class":397}," free",[360,33127,33128],{"class":397}," software",[360,33130,4423],{"class":366},[360,33132,16106],{"class":381},[360,33134,16063],{"class":397},[360,33136,33137],{"class":397}," source",[360,33139,2702],{"class":397},[360,33141,33142],{"class":397}," copying",[360,33144,33145],{"class":397}," conditions.",[360,33147,33148],{"class":397},"  There",[360,33150,33122],{"class":397},[360,33152,33153],{"class":397}," NO\n",[360,33155,33156,33159,33161,33164,33167,33169,33172,33174,33177,33180,33183,33186],{"class":362,"line":478},[360,33157,33158],{"class":381},"warranty",[360,33160,4423],{"class":366},[360,33162,33163],{"class":381},"not",[360,33165,33166],{"class":397}," even",[360,33168,2702],{"class":397},[360,33170,33171],{"class":397}," MERCHANTABILITY",[360,33173,16023],{"class":397},[360,33175,33176],{"class":397}," FITNESS",[360,33178,33179],{"class":397}," FOR",[360,33181,33182],{"class":397}," A",[360,33184,33185],{"class":397}," PARTICULAR",[360,33187,33188],{"class":397}," PURPOSE.\n",[1901,33190,33046],{"id":33191},"compilation-dun-programme-simple",[12,33193,33194],{},"Commençons par le programme le plus simple du monde:",[352,33196,33198],{"className":635,"code":33197,"language":637,"meta":291,"style":291},"#include \u003Ciostream>\n\nint main(int argc, char** argv)\n{\n    std::cout \u003C\u003C \"Hello\" \u003C\u003C std::endl;\n    return 0;\n}\n",[344,33199,33200,33208,33212,33235,33239,33254,33262],{"__ignoreMap":291},[360,33201,33202,33205],{"class":362,"line":363},[360,33203,33204],{"class":574},"#include",[360,33206,33207],{"class":397}," \u003Ciostream>\n",[360,33209,33210],{"class":362,"line":292},[360,33211,372],{"emptyLinePlaceholder":320},[360,33213,33214,33216,33218,33220,33222,33225,33227,33230,33233],{"class":362,"line":375},[360,33215,26486],{"class":574},[360,33217,2169],{"class":381},[360,33219,671],{"class":366},[360,33221,26486],{"class":574},[360,33223,33224],{"class":677}," argc",[360,33226,2311],{"class":366},[360,33228,33229],{"class":574},"char**",[360,33231,33232],{"class":677}," argv",[360,33234,2922],{"class":366},[360,33236,33237],{"class":362,"line":433},[360,33238,16340],{"class":366},[360,33240,33241,33244,33246,33249,33251],{"class":362,"line":478},[360,33242,33243],{"class":366},"    std::cout ",[360,33245,7696],{"class":574},[360,33247,33248],{"class":397}," \"Hello\"",[360,33250,4528],{"class":574},[360,33252,33253],{"class":366}," std::endl;\n",[360,33255,33256,33258,33260],{"class":362,"line":483},[360,33257,1386],{"class":574},[360,33259,1457],{"class":414},[360,33261,735],{"class":366},[360,33263,33264],{"class":362,"line":489},[360,33265,847],{"class":366},[12,33267,33268],{},"Puis compilons :",[352,33270,33272],{"className":565,"code":33271,"language":567,"meta":291,"style":291},"> i586-mingw32msvc-g++ -o test.exe test.cpp\n> ls\ntest.c\ntest.exe\n> file test.exe\ntest.exe: PE32 executable (console) Intel 80386, for MS Windows\n",[344,33273,33274,33279,33284,33292,33299,33304],{"__ignoreMap":291},[360,33275,33276],{"class":362,"line":363},[360,33277,33278],{"class":366},"> i586-mingw32msvc-g++ -o test.exe test.cpp\n",[360,33280,33281],{"class":362,"line":292},[360,33282,33283],{"class":366},"> ls\n",[360,33285,33286,33289],{"class":362,"line":375},[360,33287,33288],{"class":582},"test",[360,33290,33291],{"class":397},".c\n",[360,33293,33294,33296],{"class":362,"line":433},[360,33295,33288],{"class":582},[360,33297,33298],{"class":397},".exe\n",[360,33300,33301],{"class":362,"line":478},[360,33302,33303],{"class":366},"> file test.exe\n",[360,33305,33306,33308,33311,33314,33317,33320,33322],{"class":362,"line":483},[360,33307,33288],{"class":582},[360,33309,33310],{"class":397},".exe:",[360,33312,33313],{"class":397}," PE32",[360,33315,33316],{"class":397}," executable",[360,33318,33319],{"class":366}," (console) Intel 80386, ",[360,33321,6945],{"class":574},[360,33323,33324],{"class":366}," MS Windows\n",[12,33326,33327],{},"Voilà nous avons donc un programme à destination de Windows. Il ne nous\nreste plus qu'à le tester :",[352,33329,33331],{"className":565,"code":33330,"language":567,"meta":291,"style":291},"> wine .\u002Ftest.exe\nHello\n",[344,33332,33333,33338],{"__ignoreMap":291},[360,33334,33335],{"class":362,"line":363},[360,33336,33337],{"class":366},"> wine .\u002Ftest.exe\n",[360,33339,33340],{"class":362,"line":292},[360,33341,33342],{"class":381},"Hello\n",[12,33344,33345],{},"Et voilà, nous avons écrit un petit programme Windows, et nous l'avons\ntesté à l'aide de Wine. Généralement, on utilise l'utilisation de\nMakefile, voir même des générateurs de Makefile. Nous allons compléter\nl'exemple avec CMake. Voici donc un exemple de fichier CMake :",[352,33347,33350],{"className":33348,"code":33349,"language":15364,"meta":291,"style":291},"language-cmake shiki shiki-themes one-dark-pro","project(test)\nadd_executable(test test.cpp)\n",[344,33351,33352,33363],{"__ignoreMap":291},[360,33353,33354,33357,33359,33361],{"class":362,"line":363},[360,33355,33356],{"class":574},"project",[360,33358,671],{"class":366},[360,33360,33288],{"class":574},[360,33362,2922],{"class":366},[360,33364,33365,33368,33370,33372,33374],{"class":362,"line":292},[360,33366,33367],{"class":574},"add_executable",[360,33369,671],{"class":366},[360,33371,33288],{"class":574},[360,33373,11404],{"class":574},[360,33375,33376],{"class":366},".cpp)\n",[12,33378,33379],{},"Nous allons donc lancer la compilation, sous Linux :",[352,33381,33383],{"className":565,"code":33382,"language":567,"meta":291,"style":291},"> mkdir build\n> cd build\n> cmake ..\u002F\n-- The C compiler identification is GNU\n-- The CXX compiler identification is GNU\n-- Check for working C compiler: \u002Fusr\u002Flib\u002Fccache\u002Fgcc\n-- Check for working C compiler: \u002Fusr\u002Flib\u002Fccache\u002Fgcc -- works\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working CXX compiler: \u002Fusr\u002Flib\u002Fccache\u002Fc++\n-- Check for working CXX compiler: \u002Fusr\u002Flib\u002Fccache\u002Fc++ -- works\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: \u002Ftmp\u002Fbuild\n> make\nScanning dependencies of target test\n[100%] Building CXX object CMakeFiles\u002Ftest.dir\u002Ftest.cpp.o\nLinking CXX executable test\n\n[100%] Built target test\n> file test\ntest: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU\u002FLinux 2.6.26, BuildID[sha1]=0xf17337fcecb8f3b6ed589d8dce8978be08f2caca, not stripped\n",[344,33384,33385,33390,33395,33400,33422,33439,33459,33482,33499,33519,33536,33557,33571,33589,33598,33607,33631,33636,33652,33657,33668,33672,33677,33682],{"__ignoreMap":291},[360,33386,33387],{"class":362,"line":363},[360,33388,33389],{"class":366},"> mkdir build\n",[360,33391,33392],{"class":362,"line":292},[360,33393,33394],{"class":366},"> cd build\n",[360,33396,33397],{"class":362,"line":375},[360,33398,33399],{"class":366},"> cmake ..\u002F\n",[360,33401,33402,33405,33408,33411,33414,33417,33419],{"class":362,"line":433},[360,33403,33404],{"class":381},"--",[360,33406,33407],{"class":397}," The",[360,33409,33410],{"class":397}," C",[360,33412,33413],{"class":397}," compiler",[360,33415,33416],{"class":397}," identification",[360,33418,33122],{"class":397},[360,33420,33421],{"class":397}," GNU\n",[360,33423,33424,33426,33428,33431,33433,33435,33437],{"class":362,"line":478},[360,33425,33404],{"class":381},[360,33427,33407],{"class":397},[360,33429,33430],{"class":397}," CXX",[360,33432,33413],{"class":397},[360,33434,33416],{"class":397},[360,33436,33122],{"class":397},[360,33438,33421],{"class":397},[360,33440,33441,33443,33446,33448,33451,33453,33456],{"class":362,"line":483},[360,33442,33404],{"class":381},[360,33444,33445],{"class":397}," Check",[360,33447,2702],{"class":397},[360,33449,33450],{"class":397}," working",[360,33452,33410],{"class":397},[360,33454,33455],{"class":397}," compiler:",[360,33457,33458],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fgcc\n",[360,33460,33461,33463,33465,33467,33469,33471,33473,33476,33479],{"class":362,"line":489},[360,33462,33404],{"class":381},[360,33464,33445],{"class":397},[360,33466,2702],{"class":397},[360,33468,33450],{"class":397},[360,33470,33410],{"class":397},[360,33472,33455],{"class":397},[360,33474,33475],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fgcc",[360,33477,33478],{"class":414}," --",[360,33480,33481],{"class":397}," works\n",[360,33483,33484,33486,33489,33491,33493,33496],{"class":362,"line":494},[360,33485,33404],{"class":381},[360,33487,33488],{"class":397}," Detecting",[360,33490,33410],{"class":397},[360,33492,33413],{"class":397},[360,33494,33495],{"class":397}," ABI",[360,33497,33498],{"class":397}," info\n",[360,33500,33501,33503,33505,33507,33509,33511,33514,33516],{"class":362,"line":712},[360,33502,33404],{"class":381},[360,33504,33488],{"class":397},[360,33506,33410],{"class":397},[360,33508,33413],{"class":397},[360,33510,33495],{"class":397},[360,33512,33513],{"class":397}," info",[360,33515,518],{"class":397},[360,33517,33518],{"class":397}," done\n",[360,33520,33521,33523,33525,33527,33529,33531,33533],{"class":362,"line":331},[360,33522,33404],{"class":381},[360,33524,33445],{"class":397},[360,33526,2702],{"class":397},[360,33528,33450],{"class":397},[360,33530,33430],{"class":397},[360,33532,33455],{"class":397},[360,33534,33535],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fc++\n",[360,33537,33538,33540,33542,33544,33546,33548,33550,33553,33555],{"class":362,"line":762},[360,33539,33404],{"class":381},[360,33541,33445],{"class":397},[360,33543,2702],{"class":397},[360,33545,33450],{"class":397},[360,33547,33430],{"class":397},[360,33549,33455],{"class":397},[360,33551,33552],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fc++",[360,33554,33478],{"class":414},[360,33556,33481],{"class":397},[360,33558,33559,33561,33563,33565,33567,33569],{"class":362,"line":781},[360,33560,33404],{"class":381},[360,33562,33488],{"class":397},[360,33564,33430],{"class":397},[360,33566,33413],{"class":397},[360,33568,33495],{"class":397},[360,33570,33498],{"class":397},[360,33572,33573,33575,33577,33579,33581,33583,33585,33587],{"class":362,"line":804},[360,33574,33404],{"class":381},[360,33576,33488],{"class":397},[360,33578,33430],{"class":397},[360,33580,33413],{"class":397},[360,33582,33495],{"class":397},[360,33584,33513],{"class":397},[360,33586,518],{"class":397},[360,33588,33518],{"class":397},[360,33590,33591,33593,33596],{"class":362,"line":817},[360,33592,33404],{"class":381},[360,33594,33595],{"class":397}," Configuring",[360,33597,33518],{"class":397},[360,33599,33600,33602,33605],{"class":362,"line":823},[360,33601,33404],{"class":381},[360,33603,33604],{"class":397}," Generating",[360,33606,33518],{"class":397},[360,33608,33609,33611,33613,33616,33619,33622,33625,33628],{"class":362,"line":844},[360,33610,33404],{"class":381},[360,33612,27921],{"class":397},[360,33614,33615],{"class":397}," files",[360,33617,33618],{"class":397}," have",[360,33620,33621],{"class":397}," been",[360,33623,33624],{"class":397}," written",[360,33626,33627],{"class":397}," to:",[360,33629,33630],{"class":397}," \u002Ftmp\u002Fbuild\n",[360,33632,33633],{"class":362,"line":1441},[360,33634,33635],{"class":366},"> make\n",[360,33637,33638,33641,33644,33646,33649],{"class":362,"line":1462},[360,33639,33640],{"class":381},"Scanning",[360,33642,33643],{"class":397}," dependencies",[360,33645,529],{"class":397},[360,33647,33648],{"class":397}," target",[360,33650,33651],{"class":397}," test\n",[360,33653,33654],{"class":362,"line":1485},[360,33655,33656],{"class":366},"[100%] Building CXX object CMakeFiles\u002Ftest.dir\u002Ftest.cpp.o\n",[360,33658,33659,33662,33664,33666],{"class":362,"line":1497},[360,33660,33661],{"class":381},"Linking",[360,33663,33430],{"class":397},[360,33665,33316],{"class":397},[360,33667,33651],{"class":397},[360,33669,33670],{"class":362,"line":3161},[360,33671,372],{"emptyLinePlaceholder":320},[360,33673,33674],{"class":362,"line":3167},[360,33675,33676],{"class":366},"[100%] Built target test\n",[360,33678,33679],{"class":362,"line":3194},[360,33680,33681],{"class":366},"> file test\n",[360,33683,33684,33686,33688,33691,33694,33697,33700,33703,33706,33708,33710,33713,33716,33719,33722,33724,33726],{"class":362,"line":3224},[360,33685,33288],{"class":582},[360,33687,14024],{"class":397},[360,33689,33690],{"class":397}," ELF",[360,33692,33693],{"class":397}," 32-bit",[360,33695,33696],{"class":397}," LSB",[360,33698,33699],{"class":397}," executable,",[360,33701,33702],{"class":397}," Intel",[360,33704,33705],{"class":397}," 80386,",[360,33707,15742],{"class":397},[360,33709,1099],{"class":414},[360,33711,33712],{"class":366}," (SYSV), dynamically linked (",[360,33714,33715],{"class":381},"uses",[360,33717,33718],{"class":397}," shared",[360,33720,33721],{"class":397}," libs",[360,33723,6775],{"class":366},[360,33725,6945],{"class":574},[360,33727,33728],{"class":366}," GNU\u002FLinux 2.6.26, BuildID[sha1]=0xf17337fcecb8f3b6ed589d8dce8978be08f2caca, not stripped\n",[12,33730,33731],{},"Nous avons donc un binaire pour Gnu\u002FLinux. Recommençons donc mais avec\nWindows :",[352,33733,33735],{"className":565,"code":33734,"language":567,"meta":291,"style":291},"> cmake -DCMAKE_C_COMPILER=i586-mingw32msvc-gcc -DCMAKE_CXX_COMPILER=i586-mingw32msvc-g++ ..\u002F\n-- The C compiler identification is GNU\n-- The CXX compiler identification is GNU\n-- Check for working C compiler: \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-gcc\n-- Check for working C compiler: \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-gcc -- works\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Check for working CXX compiler: \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-g++\n-- Check for working CXX compiler: \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-g++ -- works\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Configuring done\n-- Generating done\n-- Build files have been written to: \u002Ftmp\u002Fbuild-windows\n> make\nScanning dependencies of target test\n[100%] Building CXX object CMakeFiles\u002Ftest.dir\u002Ftest.cpp.o\n\nLinking CXX executable test\n[100%] Built target test\n> file test\ntest: PE32 executable (console) Intel 80386, for MS Windows\n",[344,33736,33737,33763,33779,33795,33812,33833,33847,33865,33882,33903,33917,33935,33943,33951,33970,33974,33986,33990,33994,34004,34008,34012],{"__ignoreMap":291},[360,33738,33739,33742,33745,33747,33749,33752,33754,33757,33760],{"class":362,"line":363},[360,33740,33741],{"class":366},"> cmake ",[360,33743,33744],{"class":578},"-DCMAKE_C_COMPILER",[360,33746,583],{"class":582},[360,33748,33098],{"class":397},[360,33750,33751],{"class":578}," -DCMAKE_CXX_COMPILER",[360,33753,583],{"class":582},[360,33755,33756],{"class":397},"i586-mingw32msvc-g++",[360,33758,33759],{"class":582}," .",[360,33761,33762],{"class":397},".\u002F\n",[360,33764,33765,33767,33769,33771,33773,33775,33777],{"class":362,"line":292},[360,33766,33404],{"class":381},[360,33768,33407],{"class":397},[360,33770,33410],{"class":397},[360,33772,33413],{"class":397},[360,33774,33416],{"class":397},[360,33776,33122],{"class":397},[360,33778,33421],{"class":397},[360,33780,33781,33783,33785,33787,33789,33791,33793],{"class":362,"line":375},[360,33782,33404],{"class":381},[360,33784,33407],{"class":397},[360,33786,33430],{"class":397},[360,33788,33413],{"class":397},[360,33790,33416],{"class":397},[360,33792,33122],{"class":397},[360,33794,33421],{"class":397},[360,33796,33797,33799,33801,33803,33805,33807,33809],{"class":362,"line":433},[360,33798,33404],{"class":381},[360,33800,33445],{"class":397},[360,33802,2702],{"class":397},[360,33804,33450],{"class":397},[360,33806,33410],{"class":397},[360,33808,33455],{"class":397},[360,33810,33811],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-gcc\n",[360,33813,33814,33816,33818,33820,33822,33824,33826,33829,33831],{"class":362,"line":478},[360,33815,33404],{"class":381},[360,33817,33445],{"class":397},[360,33819,2702],{"class":397},[360,33821,33450],{"class":397},[360,33823,33410],{"class":397},[360,33825,33455],{"class":397},[360,33827,33828],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-gcc",[360,33830,33478],{"class":414},[360,33832,33481],{"class":397},[360,33834,33835,33837,33839,33841,33843,33845],{"class":362,"line":483},[360,33836,33404],{"class":381},[360,33838,33488],{"class":397},[360,33840,33410],{"class":397},[360,33842,33413],{"class":397},[360,33844,33495],{"class":397},[360,33846,33498],{"class":397},[360,33848,33849,33851,33853,33855,33857,33859,33861,33863],{"class":362,"line":489},[360,33850,33404],{"class":381},[360,33852,33488],{"class":397},[360,33854,33410],{"class":397},[360,33856,33413],{"class":397},[360,33858,33495],{"class":397},[360,33860,33513],{"class":397},[360,33862,518],{"class":397},[360,33864,33518],{"class":397},[360,33866,33867,33869,33871,33873,33875,33877,33879],{"class":362,"line":494},[360,33868,33404],{"class":381},[360,33870,33445],{"class":397},[360,33872,2702],{"class":397},[360,33874,33450],{"class":397},[360,33876,33430],{"class":397},[360,33878,33455],{"class":397},[360,33880,33881],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-g++\n",[360,33883,33884,33886,33888,33890,33892,33894,33896,33899,33901],{"class":362,"line":712},[360,33885,33404],{"class":381},[360,33887,33445],{"class":397},[360,33889,2702],{"class":397},[360,33891,33450],{"class":397},[360,33893,33430],{"class":397},[360,33895,33455],{"class":397},[360,33897,33898],{"class":397}," \u002Fusr\u002Flib\u002Fccache\u002Fi586-mingw32msvc-g++",[360,33900,33478],{"class":414},[360,33902,33481],{"class":397},[360,33904,33905,33907,33909,33911,33913,33915],{"class":362,"line":331},[360,33906,33404],{"class":381},[360,33908,33488],{"class":397},[360,33910,33430],{"class":397},[360,33912,33413],{"class":397},[360,33914,33495],{"class":397},[360,33916,33498],{"class":397},[360,33918,33919,33921,33923,33925,33927,33929,33931,33933],{"class":362,"line":762},[360,33920,33404],{"class":381},[360,33922,33488],{"class":397},[360,33924,33430],{"class":397},[360,33926,33413],{"class":397},[360,33928,33495],{"class":397},[360,33930,33513],{"class":397},[360,33932,518],{"class":397},[360,33934,33518],{"class":397},[360,33936,33937,33939,33941],{"class":362,"line":781},[360,33938,33404],{"class":381},[360,33940,33595],{"class":397},[360,33942,33518],{"class":397},[360,33944,33945,33947,33949],{"class":362,"line":804},[360,33946,33404],{"class":381},[360,33948,33604],{"class":397},[360,33950,33518],{"class":397},[360,33952,33953,33955,33957,33959,33961,33963,33965,33967],{"class":362,"line":817},[360,33954,33404],{"class":381},[360,33956,27921],{"class":397},[360,33958,33615],{"class":397},[360,33960,33618],{"class":397},[360,33962,33621],{"class":397},[360,33964,33624],{"class":397},[360,33966,33627],{"class":397},[360,33968,33969],{"class":397}," \u002Ftmp\u002Fbuild-windows\n",[360,33971,33972],{"class":362,"line":823},[360,33973,33635],{"class":366},[360,33975,33976,33978,33980,33982,33984],{"class":362,"line":844},[360,33977,33640],{"class":381},[360,33979,33643],{"class":397},[360,33981,529],{"class":397},[360,33983,33648],{"class":397},[360,33985,33651],{"class":397},[360,33987,33988],{"class":362,"line":1441},[360,33989,33656],{"class":366},[360,33991,33992],{"class":362,"line":1462},[360,33993,372],{"emptyLinePlaceholder":320},[360,33995,33996,33998,34000,34002],{"class":362,"line":1485},[360,33997,33661],{"class":381},[360,33999,33430],{"class":397},[360,34001,33316],{"class":397},[360,34003,33651],{"class":397},[360,34005,34006],{"class":362,"line":1497},[360,34007,33676],{"class":366},[360,34009,34010],{"class":362,"line":3161},[360,34011,33681],{"class":366},[360,34013,34014,34016,34018,34020,34022,34024,34026],{"class":362,"line":3167},[360,34015,33288],{"class":582},[360,34017,14024],{"class":397},[360,34019,33313],{"class":397},[360,34021,33316],{"class":397},[360,34023,33319],{"class":366},[360,34025,6945],{"class":574},[360,34027,33324],{"class":366},[12,34029,34030],{},"Nous avons donc maintenant la possibilité de compiler notre application\nmulti-platformes depuis Linux pour les systèmes Linux, mais aussi pour\nles systèmes Windows.",[1901,34032,34034],{"id":34033},"compilation-dun-programme-écrit-avec-qt","Compilation d'un programme écrit avec Qt",[12,34036,34037],{},"Nous allons maintenant nous compliquer un peu la tâche en compilant un\nprogramme ayant une dépendance avec une librairie externe : Qt. Qt est\nun framework proposant une boîte à outil de classe permettant de faire\ndes interfaces graphiques mais aussi de faire des applications consoles\nrapidement.",[12,34039,34040],{},"Nous allons donc écrire le petit programme suivant, qui affiche une\nboîte de dialogue inutile, avec un bouton inutile :",[352,34042,34044],{"className":635,"code":34043,"language":637,"meta":291,"style":291},"#include \u003CQApplication>\n#include \u003CQPushButton>\n\nint main(int argc, char** argv)\n{\n    QApplication app(argc, argv);\n    QPushButton * btn = new QPushButton(\"Do nothing\");\n    btn->show();\n\n    return app.exec();\n}\n",[344,34045,34046,34053,34060,34064,34084,34088,34099,34123,34135,34139,34153],{"__ignoreMap":291},[360,34047,34048,34050],{"class":362,"line":363},[360,34049,33204],{"class":574},[360,34051,34052],{"class":397}," \u003CQApplication>\n",[360,34054,34055,34057],{"class":362,"line":292},[360,34056,33204],{"class":574},[360,34058,34059],{"class":397}," \u003CQPushButton>\n",[360,34061,34062],{"class":362,"line":375},[360,34063,372],{"emptyLinePlaceholder":320},[360,34065,34066,34068,34070,34072,34074,34076,34078,34080,34082],{"class":362,"line":433},[360,34067,26486],{"class":574},[360,34069,2169],{"class":381},[360,34071,671],{"class":366},[360,34073,26486],{"class":574},[360,34075,33224],{"class":677},[360,34077,2311],{"class":366},[360,34079,33229],{"class":574},[360,34081,33232],{"class":677},[360,34083,2922],{"class":366},[360,34085,34086],{"class":362,"line":478},[360,34087,16340],{"class":366},[360,34089,34090,34093,34096],{"class":362,"line":483},[360,34091,34092],{"class":366},"    QApplication ",[360,34094,34095],{"class":381},"app",[360,34097,34098],{"class":366},"(argc, argv);\n",[360,34100,34101,34104,34106,34109,34111,34113,34116,34118,34121],{"class":362,"line":489},[360,34102,34103],{"class":366},"    QPushButton ",[360,34105,925],{"class":574},[360,34107,34108],{"class":366}," btn ",[360,34110,583],{"class":574},[360,34112,3040],{"class":574},[360,34114,34115],{"class":381}," QPushButton",[360,34117,671],{"class":366},[360,34119,34120],{"class":397},"\"Do nothing\"",[360,34122,801],{"class":366},[360,34124,34125,34128,34130,34133],{"class":362,"line":494},[360,34126,34127],{"class":662},"    btn",[360,34129,2376],{"class":366},[360,34131,34132],{"class":381},"show",[360,34134,2204],{"class":366},[360,34136,34137],{"class":362,"line":712},[360,34138,372],{"emptyLinePlaceholder":320},[360,34140,34141,34143,34146,34148,34151],{"class":362,"line":331},[360,34142,1386],{"class":574},[360,34144,34145],{"class":662}," app",[360,34147,31],{"class":366},[360,34149,34150],{"class":381},"exec",[360,34152,2204],{"class":366},[360,34154,34155],{"class":362,"line":762},[360,34156,847],{"class":366},[12,34158,34159,34160,34163],{},"Avec le fichier ",[344,34161,34162],{},"qmake"," associé tout simple :",[352,34165,34169],{"className":34166,"code":34167,"language":34168,"meta":291,"style":291},"language-ini shiki shiki-themes one-dark-pro","[qmake]\nTEMPLATE = app\nTARGET =\nDEPENDPATH += .\nINCLUDEPATH += .\n\n# Input\nSOURCES += test.cpp\n","ini",[344,34170,34171,34176,34186,34194,34199,34204,34208,34213],{"__ignoreMap":291},[360,34172,34173],{"class":362,"line":363},[360,34174,34175],{"class":381},"[qmake]\n",[360,34177,34178,34181,34183],{"class":362,"line":292},[360,34179,34180],{"class":574},"TEMPLATE",[360,34182,401],{"class":366},[360,34184,34185],{"class":397}," app\n",[360,34187,34188,34191],{"class":362,"line":375},[360,34189,34190],{"class":574},"TARGET",[360,34192,34193],{"class":366}," =\n",[360,34195,34196],{"class":362,"line":433},[360,34197,34198],{"class":397},"DEPENDPATH += .\n",[360,34200,34201],{"class":362,"line":478},[360,34202,34203],{"class":397},"INCLUDEPATH += .\n",[360,34205,34206],{"class":362,"line":483},[360,34207,372],{"emptyLinePlaceholder":320},[360,34209,34210],{"class":362,"line":489},[360,34211,34212],{"class":644},"# Input\n",[360,34214,34215],{"class":362,"line":494},[360,34216,34217],{"class":397},"SOURCES += test.cpp\n",[12,34219,34220,34221,34224],{},"On test la compilation à l'aide de ",[344,34222,34223],{},"qmake ; make"," et on lance le\nprogramme :",[12,34226,34227],{},[69,34228],{"alt":34229,"src":34230},"cross-compil1","\u002FProgrammation\u002Fcross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux\u002Fcross-compil1.png",[12,34232,34233],{},"Maintenant que notre programme compile et fonctionne sous Gnu\u002FLinux,\nnous allons pouvoir faire le même test mais en compilant une version\nWindows. Pour cela, il va nous falloir la version Windows de Qt (nous\nn'allons pas compiler Qt, alors que la librairie existe déjà).",[12,34235,34236,34237,34241],{},"Vous pouvez commencer par télécharger la dernière version de Qt (ou\ncelle qui vous convient) à l'adresse suivante\n",[47,34238,34239],{"href":34239,"rel":34240},"http:\u002F\u002Fqt.nokia.com\u002Fproducts\u002F",[51]," et l'installer. Vous n'avez pas besoin\nde MinGW, ni de QtCreator. Vous pouvez donc télécharger directement la\nversion qui ne contient que la librairie.",[12,34243,34244],{},[69,34245],{"alt":34246,"src":34247},"cross-compil3","\u002FProgrammation\u002Fcross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux\u002Fcross-compil3.png",[12,34249,34250],{},"Si à l'installation, l'application demande l'installation ou\nl'emplacement de MinGW, vous n'avez pas besoin de le renseigner, nous\nutiliserons la version Linux de MinGW.",[12,34252,34253],{},[69,34254],{"alt":34255,"src":34256},"cross-compil2","\u002FProgrammation\u002Fcross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux\u002Fcross-compil2.png",[12,34258,34259],{},"Enfin nous allons faire un peu de paramétrage. Nous allons récupérer le\ndossier de specs Qt pour windows et l'adapter pour MinGW sous Linux. Les\nadaptations à faire sont :",[140,34261,34262,34265,34268],{},[143,34263,34264],{},"Utilisation de MinGW",[143,34266,34267],{},"Définition des dossiers de Qt Windows et MinGW",[143,34269,34270],{},"Suppression de l'extension .exe",[12,34272,34273],{},"Commençons par créer le fichier qmake.conf :",[352,34275,34277],{"className":565,"code":34276,"language":567,"meta":291,"style":291},"sudo cp -Rf \u002Fusr\u002Fshare\u002Fqt4\u002Fmkspecs\u002Fwin32-g++ \u002Fusr\u002Fshare\u002Fqt4\u002Fmkspecs\u002Fwin32-x-g++\nsudo nano \u002Fusr\u002Fshare\u002Fqt4\u002Fmkspecs\u002Fwin32-x-g++\u002Fqmake.conf\n",[344,34278,34279,34296],{"__ignoreMap":291},[360,34280,34281,34284,34287,34290,34293],{"class":362,"line":363},[360,34282,34283],{"class":381},"sudo",[360,34285,34286],{"class":397}," cp",[360,34288,34289],{"class":414}," -Rf",[360,34291,34292],{"class":397}," \u002Fusr\u002Fshare\u002Fqt4\u002Fmkspecs\u002Fwin32-g++",[360,34294,34295],{"class":397}," \u002Fusr\u002Fshare\u002Fqt4\u002Fmkspecs\u002Fwin32-x-g++\n",[360,34297,34298,34300,34303],{"class":362,"line":292},[360,34299,34283],{"class":381},[360,34301,34302],{"class":397}," nano",[360,34304,34305],{"class":397}," \u002Fusr\u002Fshare\u002Fqt4\u002Fmkspecs\u002Fwin32-x-g++\u002Fqmake.conf\n",[12,34307,34308,34309,34317],{},"Voici le fichier de diff",[15680,34310,34311],{},[47,34312,34316],{"href":34313,"ariaDescribedBy":34314,"dataFootnoteRef":291,"id":34315},"#user-content-fn-8",[15686],"user-content-fnref-8","8"," qui contient les choses à modifier, vous pouvez\nle récupérer et utiliser la commande patch pour reporter les\nmodifications, ou faire les modifications à la mains :",[352,34319,34323],{"className":34320,"code":34321,"language":34322,"meta":291,"style":291},"language-diff shiki shiki-themes one-dark-pro","17c17\n\u003C QMAKE_CC              = gcc\n---\n> QMAKE_CC              = i586-mingw32msvc-gcc\n30c30\n\u003C QMAKE_CXX             = g++\n---\n> QMAKE_CXX             = i586-mingw32msvc-g++\n44,46c44,46\n\u003C QMAKE_INCDIR          =\n\u003C QMAKE_INCDIR_QT               = $$[QT_INSTALL_HEADERS]\n\u003C QMAKE_LIBDIR_QT               = $$[QT_INSTALL_LIBS]\n---\n> QMAKE_INCDIR          = \u002Fusr\u002Fi586-mingw32msvc\u002Finclude\n> QMAKE_INCDIR_QT               = \u002Fhome\u002Fphoenix\u002F.wine\u002Fdrive_c\u002FQt\u002F4.8.2\u002Finclude\n> QMAKE_LIBDIR_QT               = \u002Fhome\u002Fphoenix\u002F.wine\u002Fdrive_c\u002FQt\u002F4.8.2\u002Flib\n53,54c53,54\n\u003C QMAKE_LINK            = g++\n\u003C QMAKE_LINK_C          = gcc\n---\n> QMAKE_LINK            = i586-mingw32msvc-g++\n> QMAKE_LINK_C          = i586-mingw32msvc-gcc\n77c77\n\u003C !isEmpty(QMAKE_SH) {\n---\n> #!isEmpty(QMAKE_SH) {\n88,100c88,100\n\u003C } else {\n\u003C       QMAKE_COPY              = copy \u002Fy\n\u003C       QMAKE_COPY_DIR          = xcopy \u002Fs \u002Fq \u002Fy \u002Fi\n\u003C       QMAKE_MOVE              = move\n\u003C       QMAKE_DEL_FILE          = del\n\u003C       QMAKE_MKDIR             = mkdir\n\u003C       QMAKE_DEL_DIR           = rmdir\n\u003C     QMAKE_CHK_DIR_EXISTS      = if not exist\n\u003C }\n\u003C\n\u003C QMAKE_MOC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc.exe\n\u003C QMAKE_UIC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic.exe\n\u003C QMAKE_IDC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc.exe\n---\n> #} else {\n> #     QMAKE_COPY              = copy \u002Fy\n> #     QMAKE_COPY_DIR          = xcopy \u002Fs \u002Fq \u002Fy \u002Fi\n> #     QMAKE_MOVE              = move\n> #     QMAKE_DEL_FILE          = del\n> #     QMAKE_MKDIR             = mkdir\n> #     QMAKE_DEL_DIR           = rmdir\n> #    QMAKE_CHK_DIR_EXISTS     = if not exist\n> #}\n>\n> QMAKE_MOC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc-qt4\n> QMAKE_UIC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic-qt4\n> QMAKE_IDC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc-qt4\n","diff",[344,34324,34325,34330,34335,34340,34345,34350,34355,34359,34364,34369,34374,34379,34384,34388,34393,34398,34403,34408,34413,34418,34422,34427,34432,34437,34442,34446,34451,34456,34461,34466,34471,34476,34481,34486,34491,34496,34501,34506,34511,34516,34521,34525,34530,34535,34540,34545,34550,34555,34560,34565,34570,34574,34579,34584],{"__ignoreMap":291},[360,34326,34327],{"class":362,"line":363},[360,34328,34329],{"class":366},"17c17\n",[360,34331,34332],{"class":362,"line":292},[360,34333,34334],{"class":578},"\u003C QMAKE_CC              = gcc\n",[360,34336,34337],{"class":362,"line":375},[360,34338,34339],{"class":366},"---\n",[360,34341,34342],{"class":362,"line":433},[360,34343,34344],{"class":397},"> QMAKE_CC              = i586-mingw32msvc-gcc\n",[360,34346,34347],{"class":362,"line":478},[360,34348,34349],{"class":366},"30c30\n",[360,34351,34352],{"class":362,"line":483},[360,34353,34354],{"class":578},"\u003C QMAKE_CXX             = g++\n",[360,34356,34357],{"class":362,"line":489},[360,34358,34339],{"class":366},[360,34360,34361],{"class":362,"line":494},[360,34362,34363],{"class":397},"> QMAKE_CXX             = i586-mingw32msvc-g++\n",[360,34365,34366],{"class":362,"line":712},[360,34367,34368],{"class":366},"44,46c44,46\n",[360,34370,34371],{"class":362,"line":331},[360,34372,34373],{"class":578},"\u003C QMAKE_INCDIR          =\n",[360,34375,34376],{"class":362,"line":762},[360,34377,34378],{"class":578},"\u003C QMAKE_INCDIR_QT               = $$[QT_INSTALL_HEADERS]\n",[360,34380,34381],{"class":362,"line":781},[360,34382,34383],{"class":578},"\u003C QMAKE_LIBDIR_QT               = $$[QT_INSTALL_LIBS]\n",[360,34385,34386],{"class":362,"line":804},[360,34387,34339],{"class":366},[360,34389,34390],{"class":362,"line":817},[360,34391,34392],{"class":397},"> QMAKE_INCDIR          = \u002Fusr\u002Fi586-mingw32msvc\u002Finclude\n",[360,34394,34395],{"class":362,"line":823},[360,34396,34397],{"class":397},"> QMAKE_INCDIR_QT               = \u002Fhome\u002Fphoenix\u002F.wine\u002Fdrive_c\u002FQt\u002F4.8.2\u002Finclude\n",[360,34399,34400],{"class":362,"line":844},[360,34401,34402],{"class":397},"> QMAKE_LIBDIR_QT               = \u002Fhome\u002Fphoenix\u002F.wine\u002Fdrive_c\u002FQt\u002F4.8.2\u002Flib\n",[360,34404,34405],{"class":362,"line":1441},[360,34406,34407],{"class":366},"53,54c53,54\n",[360,34409,34410],{"class":362,"line":1462},[360,34411,34412],{"class":578},"\u003C QMAKE_LINK            = g++\n",[360,34414,34415],{"class":362,"line":1485},[360,34416,34417],{"class":578},"\u003C QMAKE_LINK_C          = gcc\n",[360,34419,34420],{"class":362,"line":1497},[360,34421,34339],{"class":366},[360,34423,34424],{"class":362,"line":3161},[360,34425,34426],{"class":397},"> QMAKE_LINK            = i586-mingw32msvc-g++\n",[360,34428,34429],{"class":362,"line":3167},[360,34430,34431],{"class":397},"> QMAKE_LINK_C          = i586-mingw32msvc-gcc\n",[360,34433,34434],{"class":362,"line":3194},[360,34435,34436],{"class":366},"77c77\n",[360,34438,34439],{"class":362,"line":3224},[360,34440,34441],{"class":578},"\u003C !isEmpty(QMAKE_SH) {\n",[360,34443,34444],{"class":362,"line":3239},[360,34445,34339],{"class":366},[360,34447,34448],{"class":362,"line":3256},[360,34449,34450],{"class":397},"> #!isEmpty(QMAKE_SH) {\n",[360,34452,34453],{"class":362,"line":3276},[360,34454,34455],{"class":366},"88,100c88,100\n",[360,34457,34458],{"class":362,"line":3281},[360,34459,34460],{"class":578},"\u003C } else {\n",[360,34462,34463],{"class":362,"line":3305},[360,34464,34465],{"class":578},"\u003C       QMAKE_COPY              = copy \u002Fy\n",[360,34467,34468],{"class":362,"line":3320},[360,34469,34470],{"class":578},"\u003C       QMAKE_COPY_DIR          = xcopy \u002Fs \u002Fq \u002Fy \u002Fi\n",[360,34472,34473],{"class":362,"line":3325},[360,34474,34475],{"class":578},"\u003C       QMAKE_MOVE              = move\n",[360,34477,34478],{"class":362,"line":3361},[360,34479,34480],{"class":578},"\u003C       QMAKE_DEL_FILE          = del\n",[360,34482,34483],{"class":362,"line":3380},[360,34484,34485],{"class":578},"\u003C       QMAKE_MKDIR             = mkdir\n",[360,34487,34488],{"class":362,"line":3405},[360,34489,34490],{"class":578},"\u003C       QMAKE_DEL_DIR           = rmdir\n",[360,34492,34493],{"class":362,"line":3411},[360,34494,34495],{"class":578},"\u003C     QMAKE_CHK_DIR_EXISTS      = if not exist\n",[360,34497,34498],{"class":362,"line":3426},[360,34499,34500],{"class":578},"\u003C }\n",[360,34502,34503],{"class":362,"line":3432},[360,34504,34505],{"class":578},"\u003C\n",[360,34507,34508],{"class":362,"line":3438},[360,34509,34510],{"class":578},"\u003C QMAKE_MOC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc.exe\n",[360,34512,34513],{"class":362,"line":3443},[360,34514,34515],{"class":578},"\u003C QMAKE_UIC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic.exe\n",[360,34517,34518],{"class":362,"line":3462},[360,34519,34520],{"class":578},"\u003C QMAKE_IDC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc.exe\n",[360,34522,34523],{"class":362,"line":3467},[360,34524,34339],{"class":366},[360,34526,34527],{"class":362,"line":3472},[360,34528,34529],{"class":397},"> #} else {\n",[360,34531,34532],{"class":362,"line":3495},[360,34533,34534],{"class":397},"> #     QMAKE_COPY              = copy \u002Fy\n",[360,34536,34537],{"class":362,"line":3500},[360,34538,34539],{"class":397},"> #     QMAKE_COPY_DIR          = xcopy \u002Fs \u002Fq \u002Fy \u002Fi\n",[360,34541,34542],{"class":362,"line":3505},[360,34543,34544],{"class":397},"> #     QMAKE_MOVE              = move\n",[360,34546,34547],{"class":362,"line":3530},[360,34548,34549],{"class":397},"> #     QMAKE_DEL_FILE          = del\n",[360,34551,34552],{"class":362,"line":3545},[360,34553,34554],{"class":397},"> #     QMAKE_MKDIR             = mkdir\n",[360,34556,34557],{"class":362,"line":3558},[360,34558,34559],{"class":397},"> #     QMAKE_DEL_DIR           = rmdir\n",[360,34561,34562],{"class":362,"line":3573},[360,34563,34564],{"class":397},"> #    QMAKE_CHK_DIR_EXISTS     = if not exist\n",[360,34566,34567],{"class":362,"line":3578},[360,34568,34569],{"class":397},"> #}\n",[360,34571,34572],{"class":362,"line":3583},[360,34573,16465],{"class":397},[360,34575,34576],{"class":362,"line":6893},[360,34577,34578],{"class":397},"> QMAKE_MOC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc-qt4\n",[360,34580,34581],{"class":362,"line":6899},[360,34582,34583],{"class":397},"> QMAKE_UIC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic-qt4\n",[360,34585,34586],{"class":362,"line":6905},[360,34587,34588],{"class":397},"> QMAKE_IDC             = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc-qt4\n",[12,34590,34591],{},"Une fois terminé on peut compiler et lancer l'application de la manière\nsuivante :",[352,34593,34595],{"className":565,"code":34594,"language":567,"meta":291,"style":291},"> qmake-qt4 -spec win32-x-g++\n> make\n> wine .\u002Frelease\u002Ftest.exe\n",[344,34596,34597,34602,34606],{"__ignoreMap":291},[360,34598,34599],{"class":362,"line":363},[360,34600,34601],{"class":366},"> qmake-qt4 -spec win32-x-g++\n",[360,34603,34604],{"class":362,"line":292},[360,34605,33635],{"class":366},[360,34607,34608],{"class":362,"line":375},[360,34609,34610],{"class":366},"> wine .\u002Frelease\u002Ftest.exe\n",[12,34612,34613],{},[69,34614],{"alt":34615,"src":34616},"cross-compil4","\u002FProgrammation\u002Fcross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux\u002Fcross-compil4.png",[33,34618,251],{"id":250},[12,34620,34621],{},"Et voilà, vous êtes maintenant capable de faire de la compilation\ncroisée pour des programmes aussi simples que complexes :). Quand vos\nprogrammes ont des dépendances, et si vous le pouvez, préférez la\nversion binaire. Sinon vous devrez compiler les librairies vous-même au\nformat Windows de la même manière avant de compiler votre programme.\nCela peut vous obliger à modifier les scriptes de build.",[21499,34623,34625,34628],{"className":34624,"dataFootnotes":291},[21502],[33,34626,21507],{"className":34627,"id":15686},[21506],[13835,34629,34630,34636,34642,34650,34659,34672,34681,34690],{},[143,34631,34632,34633],{"id":21512},"En français cela donne compilation croisée ",[47,34634,21520],{"href":21516,"ariaLabel":21517,"className":34635,"dataFootnoteBackref":291},[21519],[143,34637,34638,34639],{"id":21523},"bien que ... ",[47,34640,21520],{"href":21531,"ariaLabel":21532,"className":34641,"dataFootnoteBackref":291},[21519],[143,34643,34645,34646],{"id":34644},"user-content-fn-3","là aussi avec les smartphones actuels, on peut en douter ",[47,34647,21520],{"href":34648,"ariaLabel":30513,"className":34649,"dataFootnoteBackref":291},"#user-content-fnref-3",[21519],[143,34651,34653,34654],{"id":34652},"user-content-fn-4","très lointain ",[47,34655,21520],{"href":34656,"ariaLabel":34657,"className":34658,"dataFootnoteBackref":291},"#user-content-fnref-4","Back to reference 4",[21519],[143,34660,34662,34663,34666,34667],{"id":34661},"user-content-fn-5","MinGW est un ",[105,34664,34665],{},"portage"," de gcc pour Window. Il nous permettra donc de générer un executable Windows à partir de notre Gnu\u002FLinux ",[47,34668,21520],{"href":34669,"ariaLabel":34670,"className":34671,"dataFootnoteBackref":291},"#user-content-fnref-5","Back to reference 5",[21519],[143,34673,34675,34676],{"id":34674},"user-content-fn-6","Un émulateur pour démarrer des programmes Windows sous Linux ",[47,34677,21520],{"href":34678,"ariaLabel":34679,"className":34680,"dataFootnoteBackref":291},"#user-content-fnref-6","Back to reference 6",[21519],[143,34682,34684,34685],{"id":34683},"user-content-fn-7","L'installation de wine sous une distribution 64-bit peut-être un peu plus compliqué que prévu, mais reste néanmoins faisable. Référez vous à la documentation de votre distribution. ",[47,34686,21520],{"href":34687,"ariaLabel":34688,"className":34689,"dataFootnoteBackref":291},"#user-content-fnref-7","Back to reference 7",[21519],[143,34691,34693,34694,34698,34699],{"id":34692},"user-content-fn-8","Vous pouvez aussi le télécharger ",[47,34695,34697],{"href":34696},"\u002FProgrammation\u002Fcross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux\u002Fqmake.conf.diff","ici",". ",[47,34700,21520],{"href":34701,"ariaLabel":34702,"className":34703,"dataFootnoteBackref":291},"#user-content-fnref-8","Back to reference 8",[21519],[1613,34705,34706],{},"html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}",{"title":291,"searchDepth":292,"depth":292,"links":34708},[34709,34711,34712,34713,34714,34715,34716],{"id":32936,"depth":375,"text":34710},"Qu'est que la cross-compilation1 ?",{"id":32990,"depth":375,"text":32991},{"id":33052,"depth":375,"text":33043},{"id":33191,"depth":375,"text":33046},{"id":34033,"depth":375,"text":34034},{"id":250,"depth":292,"text":251},{"id":15686,"depth":292,"text":21507},"2012-07-01",{"type":9,"value":34719},[34720,34727,34729,34731,34733,34753,34755],[1901,34721,32937,34722,32943],{"id":32936},[15680,34723,34724],{},[47,34725,1944],{"href":15684,"ariaDescribedBy":34726,"dataFootnoteRef":291,"id":15687},[15686],[12,34728,32946],{},[12,34730,32949],{},[12,34732,32952],{},[140,34734,34735,34737,34744,34751],{},[143,34736,32957],{},[143,34738,32960,34739,2198],{},[15680,34740,34741],{},[47,34742,795],{"href":16257,"ariaDescribedBy":34743,"dataFootnoteRef":291,"id":16259},[15686],[143,34745,32968,34746,2198],{},[15680,34747,34748],{},[47,34749,1954],{"href":32973,"ariaDescribedBy":34750,"dataFootnoteRef":291,"id":32975},[15686],[143,34752,32978],{},[12,34754,32981],{},[12,34756,32984,34757,31],{},[105,34758,32987],{},{},"\u002Fpost\u002Fcross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux",{"title":32931,"description":291},"cross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux","posts\u002FProgrammation\u002F2012-07-01-cross-compilation-compiler-un-programme-pour-ms-windows-sous-gnu-linux",[32924],"xyp3lTmc_CVoPo48zy-LSh68_42nO_FD4l7WdmhTvoA",{"id":34767,"title":34768,"author":7,"body":34769,"category":300,"categorySlug":301,"date":36024,"description":36025,"excerpt":36026,"extension":317,"location":318,"meta":36084,"navigation":320,"path":36085,"published":320,"seo":36086,"slug":36087,"stem":36088,"tags":36089,"timeToRead":483,"__hash__":36090},"posts\u002Fposts\u002FProgrammation\u002F2011-06-26-qt-cmake-et-qt.md","C++\u002FQt - CMake et Qt",{"type":9,"value":34770,"toc":36019},[34771,34803,34823,34831,34838,34855,34859,34870,34874,34887,34915,34919,34925,35195,35198,35233,35237,35249,35332,35339,35343,35356,35372,35378,35387,35394,35406,35410,35426,35626,35629,35644,35648,35655,35658,35667,35671,35677,35686,35690,35700,35709,35713,35716,35723,35727,35762,35766,35825,35829,35832,35835,35838,35884,35891,35895,35921,35925,35928,35964,35975,35978,35990,36016],[12,34772,34773,34774,34778,34779,34784,34785,34790,34791,34796,34797,34800,34801,31],{},"Suite à un ",[47,34775,34777],{"href":34776},"\u002Fpost\u002F2008-01-21-memo-qt\u002F","billet"," datant de 2008, je reviens vers vous pour ajouter\nquelques précisions sur la compilation de programme ",[47,34780,34783],{"href":34781,"rel":34782},"http:\u002F\u002Fqt.nokia.com\u002F",[51],"Qt"," avec\n",[47,34786,34789],{"href":34787,"rel":34788},"http:\u002F\u002Fwww.cmake.org\u002F",[51],"CMake",". En effet, pour mon programme ",[47,34792,34795],{"href":34793,"rel":34794},"http:\u002F\u002Fxinx.shadoware.org?piwik_campaign=Shadoware&piwik_keyword=Billet",[51],"XINX",", j'ai modifié la chaîne\nde compilation actuelle utilisant ",[105,34798,34799],{},"QMake"," par une chaîne de compilation\n",[105,34802,34789],{},[12,34804,34805,34807,34808,34811,34812,34698,34817,34819,34820,34822],{},[105,34806,34789],{}," est un puissant générateur de ",[344,34809,34810],{},"Makefile",", il permet de remplacer\nles anciens (mais pas complètement révolus) ",[47,34813,34816],{"href":34814,"rel":34815},"http:\u002F\u002Fwww.gnu.org\u002Fsoftware\u002Fautoconf\u002F",[51],"autotools",[105,34818,34789],{}," ne\nremplace donc pas le programme ",[344,34821,15381],{}," mais vient se placer en amont.",[12,34824,34825,34827,34828,31],{},[105,34826,34789],{}," permet de compiler un programme à différents endroits du dossier\ndes sources, ce qui permet de garder le répertoire des sources ",[105,34829,34830],{},"propre",[12,34832,34833,34834,34837],{},"Nous allons considérer dans la suite le dossier ",[344,34835,34836],{},"projet"," suivant :",[140,34839,34840],{},[143,34841,34842,34844],{},[344,34843,34836],{},[140,34845,34846,34851],{},[143,34847,34848],{},[344,34849,34850],{},"source",[143,34852,34853],{},[344,34854,28495],{},[1901,34856,34858],{"id":34857},"compilation","Compilation",[12,34860,34861,34862,34864,34865,34869],{},"Nous passerons sous silence la compilation d'un programme non ",[105,34863,34783],{}," qui\npeut être retrouvé dans la ",[47,34866,21638],{"href":34867,"rel":34868},"http:\u002F\u002Fwww.cmake.org\u002Fcmake\u002Fhelp\u002Fcmake_tutorial.html",[51]," et nous nous limiterons aux\nexplications liées aux programmes écrits en ''Qt' (qui peuvent également\nêtre retrouvés dans d'autres tutoriels sur Internet).",[23034,34871,34873],{"id":34872},"package-à-utiliser","Package à utiliser",[12,34875,34876,34877,34880,34881,34883,34884,34886],{},"Pour utiliser ",[105,34878,34879],{},"Qt4"," avec ",[105,34882,34789],{},", il faut inclure le package ",[344,34885,34879],{}," :",[352,34888,34890],{"className":33348,"code":34889,"language":15364,"meta":291,"style":291},"project(lenomdemonprojet)\ncmake_minimum_required(VERSION 2.8.0)\nfind_package(Qt4 REQUIRED)\n",[344,34891,34892,34899,34907],{"__ignoreMap":291},[360,34893,34894,34896],{"class":362,"line":363},[360,34895,33356],{"class":574},[360,34897,34898],{"class":366},"(lenomdemonprojet)\n",[360,34900,34901,34904],{"class":362,"line":292},[360,34902,34903],{"class":574},"cmake_minimum_required",[360,34905,34906],{"class":366},"(VERSION 2.8.0)\n",[360,34908,34909,34912],{"class":362,"line":375},[360,34910,34911],{"class":574},"find_package",[360,34913,34914],{"class":366},"(Qt4 REQUIRED)\n",[23034,34916,34918],{"id":34917},"définir-les-modules-qt-à-utiliser","Définir les modules Qt à utiliser",[12,34920,34921,34922,34924],{},"Il est ensuite possible d'activer ou de désactiver les différents\nmodules de ",[105,34923,34783],{}," à utiliser suivant le programme que vous écrivez :",[352,34926,34928],{"className":33348,"code":34927,"language":15364,"meta":291,"style":291},"set(QT_DONT_USE_QTCORE TRUE)\nset(QT_DONT_USE_QTGUI TRUE)\nset(QT_USE_QT3SUPPORT TRUE)\nset(QT_USE_QTASSISTANT TRUE)\nset(QT_USE_QAXCONTAINER TRUE)\nset(QT_USE_QAXSERVER TRUE)\nset(QT_USE_QTDESIGNER TRUE)\nset(QT_USE_QTMOTIF TRUE)\nset(QT_USE_QTMAIN TRUE)\nset(QT_USE_QTNETWORK TRUE)\nset(QT_USE_QTNSPLUGIN TRUE)\nset(QT_USE_QTOPENGL TRUE)\nset(QT_USE_QTSQL TRUE)\nset(QT_USE_QTXML TRUE)\nset(QT_USE_QTXMLPATTERNS TRUE)\nset(QT_USE_QTWEBKIT TRUE)\nset(QT_USE_QTSVG TRUE)\nset(QT_USE_QTTEST TRUE)\nset(QT_USE_QTUITOOLS TRUE)\nset(QT_USE_QTDBUS TRUE)\nset(QT_USE_QTSCRIPT TRUE)\nset(QT_USE_QTASSISTANTCLIENT TRUE)\nset(QT_USE_QTHELP TRUE)\nset(QT_USE_PHONON TRUE)\n",[344,34929,34930,34942,34953,34964,34975,34986,34997,35008,35019,35030,35041,35052,35063,35074,35085,35096,35107,35118,35129,35140,35151,35162,35173,35184],{"__ignoreMap":291},[360,34931,34932,34934,34937,34940],{"class":362,"line":363},[360,34933,25744],{"class":574},[360,34935,34936],{"class":366},"(QT_DONT_USE_QTCORE ",[360,34938,34939],{"class":574},"TRUE",[360,34941,2922],{"class":366},[360,34943,34944,34946,34949,34951],{"class":362,"line":292},[360,34945,25744],{"class":574},[360,34947,34948],{"class":366},"(QT_DONT_USE_QTGUI ",[360,34950,34939],{"class":574},[360,34952,2922],{"class":366},[360,34954,34955,34957,34960,34962],{"class":362,"line":375},[360,34956,25744],{"class":574},[360,34958,34959],{"class":366},"(QT_USE_QT3SUPPORT ",[360,34961,34939],{"class":574},[360,34963,2922],{"class":366},[360,34965,34966,34968,34971,34973],{"class":362,"line":433},[360,34967,25744],{"class":574},[360,34969,34970],{"class":366},"(QT_USE_QTASSISTANT ",[360,34972,34939],{"class":574},[360,34974,2922],{"class":366},[360,34976,34977,34979,34982,34984],{"class":362,"line":478},[360,34978,25744],{"class":574},[360,34980,34981],{"class":366},"(QT_USE_QAXCONTAINER ",[360,34983,34939],{"class":574},[360,34985,2922],{"class":366},[360,34987,34988,34990,34993,34995],{"class":362,"line":483},[360,34989,25744],{"class":574},[360,34991,34992],{"class":366},"(QT_USE_QAXSERVER ",[360,34994,34939],{"class":574},[360,34996,2922],{"class":366},[360,34998,34999,35001,35004,35006],{"class":362,"line":489},[360,35000,25744],{"class":574},[360,35002,35003],{"class":366},"(QT_USE_QTDESIGNER ",[360,35005,34939],{"class":574},[360,35007,2922],{"class":366},[360,35009,35010,35012,35015,35017],{"class":362,"line":494},[360,35011,25744],{"class":574},[360,35013,35014],{"class":366},"(QT_USE_QTMOTIF ",[360,35016,34939],{"class":574},[360,35018,2922],{"class":366},[360,35020,35021,35023,35026,35028],{"class":362,"line":712},[360,35022,25744],{"class":574},[360,35024,35025],{"class":366},"(QT_USE_QTMAIN ",[360,35027,34939],{"class":574},[360,35029,2922],{"class":366},[360,35031,35032,35034,35037,35039],{"class":362,"line":331},[360,35033,25744],{"class":574},[360,35035,35036],{"class":366},"(QT_USE_QTNETWORK ",[360,35038,34939],{"class":574},[360,35040,2922],{"class":366},[360,35042,35043,35045,35048,35050],{"class":362,"line":762},[360,35044,25744],{"class":574},[360,35046,35047],{"class":366},"(QT_USE_QTNSPLUGIN ",[360,35049,34939],{"class":574},[360,35051,2922],{"class":366},[360,35053,35054,35056,35059,35061],{"class":362,"line":781},[360,35055,25744],{"class":574},[360,35057,35058],{"class":366},"(QT_USE_QTOPENGL ",[360,35060,34939],{"class":574},[360,35062,2922],{"class":366},[360,35064,35065,35067,35070,35072],{"class":362,"line":804},[360,35066,25744],{"class":574},[360,35068,35069],{"class":366},"(QT_USE_QTSQL ",[360,35071,34939],{"class":574},[360,35073,2922],{"class":366},[360,35075,35076,35078,35081,35083],{"class":362,"line":817},[360,35077,25744],{"class":574},[360,35079,35080],{"class":366},"(QT_USE_QTXML ",[360,35082,34939],{"class":574},[360,35084,2922],{"class":366},[360,35086,35087,35089,35092,35094],{"class":362,"line":823},[360,35088,25744],{"class":574},[360,35090,35091],{"class":366},"(QT_USE_QTXMLPATTERNS ",[360,35093,34939],{"class":574},[360,35095,2922],{"class":366},[360,35097,35098,35100,35103,35105],{"class":362,"line":844},[360,35099,25744],{"class":574},[360,35101,35102],{"class":366},"(QT_USE_QTWEBKIT ",[360,35104,34939],{"class":574},[360,35106,2922],{"class":366},[360,35108,35109,35111,35114,35116],{"class":362,"line":1441},[360,35110,25744],{"class":574},[360,35112,35113],{"class":366},"(QT_USE_QTSVG ",[360,35115,34939],{"class":574},[360,35117,2922],{"class":366},[360,35119,35120,35122,35125,35127],{"class":362,"line":1462},[360,35121,25744],{"class":574},[360,35123,35124],{"class":366},"(QT_USE_QTTEST ",[360,35126,34939],{"class":574},[360,35128,2922],{"class":366},[360,35130,35131,35133,35136,35138],{"class":362,"line":1485},[360,35132,25744],{"class":574},[360,35134,35135],{"class":366},"(QT_USE_QTUITOOLS ",[360,35137,34939],{"class":574},[360,35139,2922],{"class":366},[360,35141,35142,35144,35147,35149],{"class":362,"line":1497},[360,35143,25744],{"class":574},[360,35145,35146],{"class":366},"(QT_USE_QTDBUS ",[360,35148,34939],{"class":574},[360,35150,2922],{"class":366},[360,35152,35153,35155,35158,35160],{"class":362,"line":3161},[360,35154,25744],{"class":574},[360,35156,35157],{"class":366},"(QT_USE_QTSCRIPT ",[360,35159,34939],{"class":574},[360,35161,2922],{"class":366},[360,35163,35164,35166,35169,35171],{"class":362,"line":3167},[360,35165,25744],{"class":574},[360,35167,35168],{"class":366},"(QT_USE_QTASSISTANTCLIENT ",[360,35170,34939],{"class":574},[360,35172,2922],{"class":366},[360,35174,35175,35177,35180,35182],{"class":362,"line":3194},[360,35176,25744],{"class":574},[360,35178,35179],{"class":366},"(QT_USE_QTHELP ",[360,35181,34939],{"class":574},[360,35183,2922],{"class":366},[360,35185,35186,35188,35191,35193],{"class":362,"line":3224},[360,35187,25744],{"class":574},[360,35189,35190],{"class":366},"(QT_USE_PHONON ",[360,35192,34939],{"class":574},[360,35194,2922],{"class":366},[12,35196,35197],{},"Par exemple pour faire un programme utilisant le module Xml,\nXmlPatterns, et Webkit il faut ajouter :",[352,35199,35201],{"className":33348,"code":35200,"language":15364,"meta":291,"style":291},"set(QT_USE_QTXML TRUE)\nset(QT_USE_QTXMLPATTERNS TRUE)\nset(QT_USE_QTWEBKIT TRUE)\n",[344,35202,35203,35213,35223],{"__ignoreMap":291},[360,35204,35205,35207,35209,35211],{"class":362,"line":363},[360,35206,25744],{"class":574},[360,35208,35080],{"class":366},[360,35210,34939],{"class":574},[360,35212,2922],{"class":366},[360,35214,35215,35217,35219,35221],{"class":362,"line":292},[360,35216,25744],{"class":574},[360,35218,35091],{"class":366},[360,35220,34939],{"class":574},[360,35222,2922],{"class":366},[360,35224,35225,35227,35229,35231],{"class":362,"line":375},[360,35226,25744],{"class":574},[360,35228,35102],{"class":366},[360,35230,34939],{"class":574},[360,35232,2922],{"class":366},[23034,35234,35236],{"id":35235},"quelques-déclarations-supplémentaires","Quelques déclarations supplémentaires",[12,35238,35239,35240,35242,35243,35245,35246,31],{},"Après avoir compilé les différentes parties du programme avec le\ngénérateur de ",[344,35241,34810],{}," de ",[105,35244,34783],{}," (QMake), j'ai relevé les différentes\ndéfinitions à ajouter lors de la compilation. De plus une fois les\nmodules définis, il faut inclure également le module ",[105,35247,35248],{},"UseQt4",[352,35250,35252],{"className":33348,"code":35251,"language":15364,"meta":291,"style":291},"add_definitions(-DUNICODE)\n# Les Q_ASSERT, Q_ASSERT_X, ... sont désactivés en mode Release\nif(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n    add_definitions(-DQT_NO_DEBUG)\nendif()\n# Include utilisé par Qt (du style include (UseQt4))\ninclude(${QT_USE_FILE})\n# Ajoute les définitions propres à Qt (suivant les modules ajoutés)\nadd_definitions(${QT_DEFINITIONS})\n",[344,35253,35254,35262,35267,35284,35292,35299,35304,35316,35321],{"__ignoreMap":291},[360,35255,35256,35259],{"class":362,"line":363},[360,35257,35258],{"class":574},"add_definitions",[360,35260,35261],{"class":366},"(-DUNICODE)\n",[360,35263,35264],{"class":362,"line":292},[360,35265,35266],{"class":644},"# Les Q_ASSERT, Q_ASSERT_X, ... sont désactivés en mode Release\n",[360,35268,35269,35271,35273,35276,35279,35282],{"class":362,"line":375},[360,35270,2370],{"class":574},[360,35272,671],{"class":366},[360,35274,35275],{"class":578},"CMAKE_BUILD_TYPE",[360,35277,35278],{"class":574}," STREQUAL",[360,35280,35281],{"class":397}," \"Release\"",[360,35283,2922],{"class":366},[360,35285,35286,35289],{"class":362,"line":433},[360,35287,35288],{"class":574},"    add_definitions",[360,35290,35291],{"class":366},"(-DQT_NO_DEBUG)\n",[360,35293,35294,35297],{"class":362,"line":478},[360,35295,35296],{"class":574},"endif",[360,35298,5008],{"class":366},[360,35300,35301],{"class":362,"line":483},[360,35302,35303],{"class":644},"# Include utilisé par Qt (du style include (UseQt4))\n",[360,35305,35306,35309,35311,35314],{"class":362,"line":489},[360,35307,35308],{"class":574},"include",[360,35310,671],{"class":366},[360,35312,35313],{"class":574},"${QT_USE_FILE}",[360,35315,2922],{"class":366},[360,35317,35318],{"class":362,"line":494},[360,35319,35320],{"class":644},"# Ajoute les définitions propres à Qt (suivant les modules ajoutés)\n",[360,35322,35323,35325,35327,35330],{"class":362,"line":712},[360,35324,35258],{"class":574},[360,35326,671],{"class":366},[360,35328,35329],{"class":574},"${QT_DEFINITIONS}",[360,35331,2922],{"class":366},[23034,35333,35335,35336],{"id":35334},"macros-pour-générer-les-fichiers-moc","Macros pour générer les fichiers ",[344,35337,35338],{},"moc",[29701,35340,35342],{"id":35341},"macro-par-défaut","Macro par défaut",[12,35344,35345,35346,35348,35349,35351,31],{},"La facilité de programmation en ",[105,35347,34783],{}," est due à l'ajout par le framework\nde la notion de méta-objet. Cette notion se fait à l'aide d'un\ngénérateur propre à ce framework : ",[344,35350,35338],{},[15680,35352,35353],{},[47,35354,1944],{"href":15684,"ariaDescribedBy":35355,"dataFootnoteRef":291,"id":15687},[15686],[12,35357,35358,35359,35362,35363,35366,35367,31],{},"Pour générer les méta-objets, il faut définir sur les objets descendants\nde ",[344,35360,35361],{},"QObject",", une macro ",[344,35364,35365],{},"Q_OBJECT",". Cette macro ajoute, côté interface,\nla déclaration de méthodes supplémentaires pour la gestion des\nméta-informations, et coté implémentation, ajoute l'implémentation de\nces méta-informations ainsi que la déclaration des signaux et de slots\nde l'objet",[15680,35368,35369],{},[47,35370,795],{"href":16257,"ariaDescribedBy":35371,"dataFootnoteRef":291,"id":16259},[15686],[12,35373,35374,35375,35377],{},"Pour générer les fichiers d'implémentation générés par le compilateur\n",[344,35376,35338],{},", il est possible d'utiliser la macro suivante pour une liste de\nfichier sources (extension .cpp, ou .cxx, ...) :",[352,35379,35381],{"className":33348,"code":35380,"language":15364,"meta":291,"style":291},"qt4_wrap_cpp(outfiles inputfile ... OPTIONS ...)\n",[344,35382,35383],{"__ignoreMap":291},[360,35384,35385],{"class":362,"line":363},[360,35386,35380],{"class":366},[12,35388,35389,35390,35393],{},"Cette macro générera un fichier de type ",[344,35391,35392],{},"moc_nomfichier.cxx"," qu'il\nfaudra inclure dans le ficher CPP (car il n'est pas inclus\nautomatiquement dans la liste des fichiers à compiler.",[352,35395,35397],{"className":635,"code":35396,"language":637,"meta":291,"style":291},"#include \"moc_nomfichier.cxx\"\n",[344,35398,35399],{"__ignoreMap":291},[360,35400,35401,35403],{"class":362,"line":363},[360,35402,33204],{"class":574},[360,35404,35405],{"class":397}," \"moc_nomfichier.cxx\"\n",[29701,35407,35409],{"id":35408},"une-autre-macro","Une autre macro",[12,35411,35412,35413,35242,35416,35418,35419,35422,35423,35425],{},"Autre possibilité, faire comme avec les fichiers ",[344,35414,35415],{},".pro",[105,35417,34799],{}," et\ngénérer un fichier moc pour chaque fichier ",[344,35420,35421],{},".h"," possédant une macro\n",[344,35424,35365],{},". Pour cela j'ai écrit la petite macro suivante :",[352,35427,35429],{"className":33348,"code":35428,"language":15364,"meta":291,"style":291},"macro(xinx_automoc outfiles)\nqt4_get_moc_flags(moc_flags)\nqt4_extract_options(moc_files moc_options ${ARGN})\nforeach (it ${moc_files})\n    get_filename_component(it ${it} ABSOLUTE)\n    if ( EXISTS ${it} )\n        file(READ ${it} _contents)\n        string(REGEX MATCHALL \"Q_OBJECT\" _match \"${_contents}\")\n        if(_match)\n            qt4_make_output_file(${it} moc_ cxx outfile)\n            qt4_create_moc_command(${it} ${outfile} \"${moc_flags}\" \"${moc_options}\")\n            macro_add_file_dependencies(${it} ${outfile})\n            set(${outfiles} ${${outfiles}} ${outfile})\n        endif(_match)\n    endif ( EXISTS ${it} )\nendforeach(it)endmacro(xinx_automoc)\n",[344,35430,35431,35439,35444,35454,35467,35483,35499,35512,35530,35537,35547,35565,35576,35598,35605,35618],{"__ignoreMap":291},[360,35432,35433,35436],{"class":362,"line":363},[360,35434,35435],{"class":574},"macro",[360,35437,35438],{"class":366},"(xinx_automoc outfiles)\n",[360,35440,35441],{"class":362,"line":292},[360,35442,35443],{"class":366},"qt4_get_moc_flags(moc_flags)\n",[360,35445,35446,35449,35452],{"class":362,"line":375},[360,35447,35448],{"class":366},"qt4_extract_options(moc_files moc_options ",[360,35450,35451],{"class":574},"${ARGN}",[360,35453,2922],{"class":366},[360,35455,35456,35459,35462,35465],{"class":362,"line":433},[360,35457,35458],{"class":574},"foreach",[360,35460,35461],{"class":366}," (it ",[360,35463,35464],{"class":574},"${moc_files}",[360,35466,2922],{"class":366},[360,35468,35469,35472,35475,35478,35481],{"class":362,"line":478},[360,35470,35471],{"class":574},"    get_filename_component",[360,35473,35474],{"class":366},"(it ",[360,35476,35477],{"class":574},"${it}",[360,35479,35480],{"class":574}," ABSOLUTE",[360,35482,2922],{"class":366},[360,35484,35485,35487,35490,35493,35496],{"class":362,"line":483},[360,35486,5657],{"class":574},[360,35488,35489],{"class":366}," ( ",[360,35491,35492],{"class":574},"EXISTS",[360,35494,35495],{"class":574}," ${it}",[360,35497,35498],{"class":366}," )\n",[360,35500,35501,35504,35507,35509],{"class":362,"line":489},[360,35502,35503],{"class":574},"        file",[360,35505,35506],{"class":366},"(READ ",[360,35508,35477],{"class":574},[360,35510,35511],{"class":366}," _contents)\n",[360,35513,35514,35516,35519,35522,35525,35528],{"class":362,"line":494},[360,35515,14658],{"class":574},[360,35517,35518],{"class":366},"(REGEX MATCHALL ",[360,35520,35521],{"class":397},"\"Q_OBJECT\"",[360,35523,35524],{"class":366}," _match ",[360,35526,35527],{"class":397},"\"${_contents}\"",[360,35529,2922],{"class":366},[360,35531,35532,35534],{"class":362,"line":712},[360,35533,2780],{"class":574},[360,35535,35536],{"class":366},"(_match)\n",[360,35538,35539,35542,35544],{"class":362,"line":331},[360,35540,35541],{"class":366},"            qt4_make_output_file(",[360,35543,35477],{"class":574},[360,35545,35546],{"class":366}," moc_ cxx outfile)\n",[360,35548,35549,35552,35554,35557,35560,35563],{"class":362,"line":762},[360,35550,35551],{"class":366},"            qt4_create_moc_command(",[360,35553,35477],{"class":574},[360,35555,35556],{"class":574}," ${outfile}",[360,35558,35559],{"class":397}," \"${moc_flags}\"",[360,35561,35562],{"class":397}," \"${moc_options}\"",[360,35564,2922],{"class":366},[360,35566,35567,35570,35572,35574],{"class":362,"line":781},[360,35568,35569],{"class":366},"            macro_add_file_dependencies(",[360,35571,35477],{"class":574},[360,35573,35556],{"class":574},[360,35575,2922],{"class":366},[360,35577,35578,35581,35583,35586,35589,35591,35593,35596],{"class":362,"line":804},[360,35579,35580],{"class":574},"            set",[360,35582,671],{"class":366},[360,35584,35585],{"class":574},"${outfiles}",[360,35587,35588],{"class":366}," ${",[360,35590,35585],{"class":574},[360,35592,2485],{"class":366},[360,35594,35595],{"class":574},"${outfile}",[360,35597,2922],{"class":366},[360,35599,35600,35603],{"class":362,"line":817},[360,35601,35602],{"class":574},"        endif",[360,35604,35536],{"class":366},[360,35606,35607,35610,35612,35614,35616],{"class":362,"line":823},[360,35608,35609],{"class":574},"    endif",[360,35611,35489],{"class":366},[360,35613,35492],{"class":574},[360,35615,35495],{"class":574},[360,35617,35498],{"class":366},[360,35619,35620,35623],{"class":362,"line":844},[360,35621,35622],{"class":574},"endforeach",[360,35624,35625],{"class":366},"(it)endmacro(xinx_automoc)\n",[12,35627,35628],{},"Elle s'utilise ainsi :",[352,35630,35632],{"className":33348,"code":35631,"language":15364,"meta":291,"style":291},"xinx_automoc(moc_headers ${headers})\n",[344,35633,35634],{"__ignoreMap":291},[360,35635,35636,35639,35642],{"class":362,"line":363},[360,35637,35638],{"class":366},"xinx_automoc(moc_headers ",[360,35640,35641],{"class":574},"${headers}",[360,35643,2922],{"class":366},[23034,35645,35647],{"id":35646},"macro-pour-générer-les-fichiers-en-tête-dinterface-graphique","Macro pour générer les fichiers en tête d'interface graphique",[12,35649,35650,35651,35654],{},"Les interfaces graphiques sont développées à l'aide de ",[105,35652,35653],{},"Qt-Designer",".\nCes fichiers sont au format XML.",[12,35656,35657],{},"La macro CMake suivante permet de transformer ces fichiers XML en\nfichier d'entête C.",[352,35659,35661],{"className":33348,"code":35660,"language":15364,"meta":291,"style":291},"qt4_wrap_ui(outfiles inputfile ...)\n",[344,35662,35663],{"__ignoreMap":291},[360,35664,35665],{"class":362,"line":363},[360,35666,35660],{"class":366},[23034,35668,35670],{"id":35669},"macro-pour-compiler-les-fichiers-de-resources","Macro pour compiler les fichiers de resources",[12,35672,35673,35674,35676],{},"La macro CMake suivante permet de compiler le fichier de ressource\n(extension *.qrc) en fichier ",[344,35675,637],{}," qui sera ensuite compilé avec le\nreste du programme :",[352,35678,35680],{"className":33348,"code":35679,"language":15364,"meta":291,"style":291},"qt4_add_resources(outfiles inputfile ... OPTIONS ...)\n",[344,35681,35682],{"__ignoreMap":291},[360,35683,35684],{"class":362,"line":363},[360,35685,35679],{"class":366},[23034,35687,35689],{"id":35688},"macro-pour-compiler-les-fichiers-de-traduction","Macro pour compiler les fichiers de traduction",[12,35691,35692,35693,35695,35696,35699],{},"La macro CMake suivante est utilisée pour compiler un fichier de\ntraduction ",[344,35694,14029],{}," en fichier de traduction compilé ",[344,35697,35698],{},"qm",". Ce dernier est\nensuite à inclure dans le programme (soit par un fichier de ressource,\nsoit dans un dossier à coté).",[352,35701,35703],{"className":33348,"code":35702,"language":15364,"meta":291,"style":291},"qt4_add_translation(qm_files ts_files ...)\n",[344,35704,35705],{"__ignoreMap":291},[360,35706,35707],{"class":362,"line":363},[360,35708,35702],{"class":366},[23034,35710,35712],{"id":35711},"compilation-dun-plugin","Compilation d'un plugin",[12,35714,35715],{},"En plus des options décrites ci-dessus, pour compiler un plugin, il faut\najouter quelques définitions supplémentaires.",[12,35717,35718,35719,35722],{},"Il faut bien faire attention à ce que le plugin soit compilé en mode\n",[344,35720,35721],{},"Release"," si le programme l'est aussi (Ce qui n'est pas forcément\npratique pour faire du debug).",[29701,35724,35726],{"id":35725},"plugin-dynamique","Plugin dynamique",[352,35728,35730],{"className":33348,"code":35729,"language":15364,"meta":291,"style":291},"add_definitions(-DQT_PLUGIN)\nadd_definitions(-DQT_SHARED)\nadd_library(webplugin SHARED ${webplugin_SRCS} ${webplugin_MOC_SRCS})\n",[344,35731,35732,35739,35746],{"__ignoreMap":291},[360,35733,35734,35736],{"class":362,"line":363},[360,35735,35258],{"class":574},[360,35737,35738],{"class":366},"(-DQT_PLUGIN)\n",[360,35740,35741,35743],{"class":362,"line":292},[360,35742,35258],{"class":574},[360,35744,35745],{"class":366},"(-DQT_SHARED)\n",[360,35747,35748,35751,35754,35757,35760],{"class":362,"line":375},[360,35749,35750],{"class":574},"add_library",[360,35752,35753],{"class":366},"(webplugin SHARED ",[360,35755,35756],{"class":574},"${webplugin_SRCS}",[360,35758,35759],{"class":574}," ${webplugin_MOC_SRCS}",[360,35761,2922],{"class":366},[29701,35763,35765],{"id":35764},"plugin-static","Plugin Static",[352,35767,35769],{"className":33348,"code":35768,"language":15364,"meta":291,"style":291},"add_definitions(-DQT_PLUGIN)\nadd_definitions(-DQT_STATICPLUGIN)\nif(CMAKE_SIZEOF_VOID_P MATCHES 8)\n    add_definitions(-fPIC)\nendif()\nadd_library(webplugin STATIC ${webplugin_SRCS} ${webplugin_MOC_SRCS})\n",[344,35770,35771,35777,35784,35799,35806,35812],{"__ignoreMap":291},[360,35772,35773,35775],{"class":362,"line":363},[360,35774,35258],{"class":574},[360,35776,35738],{"class":366},[360,35778,35779,35781],{"class":362,"line":292},[360,35780,35258],{"class":574},[360,35782,35783],{"class":366},"(-DQT_STATICPLUGIN)\n",[360,35785,35786,35788,35790,35793,35796],{"class":362,"line":375},[360,35787,2370],{"class":574},[360,35789,671],{"class":366},[360,35791,35792],{"class":578},"CMAKE_SIZEOF_VOID_P",[360,35794,35795],{"class":574}," MATCHES",[360,35797,35798],{"class":366}," 8)\n",[360,35800,35801,35803],{"class":362,"line":433},[360,35802,35288],{"class":574},[360,35804,35805],{"class":366},"(-fPIC)\n",[360,35807,35808,35810],{"class":362,"line":478},[360,35809,35296],{"class":574},[360,35811,5008],{"class":366},[360,35813,35814,35816,35819,35821,35823],{"class":362,"line":483},[360,35815,35750],{"class":574},[360,35817,35818],{"class":366},"(webplugin STATIC ",[360,35820,35756],{"class":574},[360,35822,35759],{"class":574},[360,35824,2922],{"class":366},[23034,35826,35828],{"id":35827},"ajout-dun-fichier-rc-pour-windows","Ajout d'un fichier RC pour windows",[12,35830,35831],{},"Les fichiers RC Windows contiennent des informations, comme par exemple,\nla version et le nom du programme.",[12,35833,35834],{},"Ces informations peuvent être utilisées par les programmes\nd'installation sous Windows ou aussi par Windows lui-même.",[12,35836,35837],{},"Afin de pouvoir ajouter un fichier RC file au programme, on peut ajouter\nceci :",[352,35839,35841],{"className":33348,"code":35840,"language":15364,"meta":291,"style":291},"if(MINGW)\n        set(CMAKE_RC_COMPILER_INIT windres)\n        enable_language(RC)\n        set(CMAKE_RC_COMPILE_OBJECT \"\u003CCMAKE_RC_COMPILER> \u003CFLAGS> \u003CDEFINES> -O coff -o \u003COBJECT> \u003CSOURCE>\")\nendif(MINGW)\n",[344,35842,35843,35850,35858,35866,35878],{"__ignoreMap":291},[360,35844,35845,35847],{"class":362,"line":363},[360,35846,2370],{"class":574},[360,35848,35849],{"class":366},"(MINGW)\n",[360,35851,35852,35855],{"class":362,"line":292},[360,35853,35854],{"class":574},"        set",[360,35856,35857],{"class":366},"(CMAKE_RC_COMPILER_INIT windres)\n",[360,35859,35860,35863],{"class":362,"line":375},[360,35861,35862],{"class":574},"        enable_language",[360,35864,35865],{"class":366},"(RC)\n",[360,35867,35868,35870,35873,35876],{"class":362,"line":433},[360,35869,35854],{"class":574},[360,35871,35872],{"class":366},"(CMAKE_RC_COMPILE_OBJECT ",[360,35874,35875],{"class":397},"\"\u003CCMAKE_RC_COMPILER> \u003CFLAGS> \u003CDEFINES> -O coff -o \u003COBJECT> \u003CSOURCE>\"",[360,35877,2922],{"class":366},[360,35879,35880,35882],{"class":362,"line":478},[360,35881,35296],{"class":574},[360,35883,35849],{"class":366},[12,35885,35886,35887,35890],{},"Ensuite le fichier RC se compile comme tout autre fichier (",[344,35888,35889],{},"C++",", ...)",[23034,35892,35894],{"id":35893},"compilation-dune-librairie-static","Compilation d'une librairie static",[352,35896,35898],{"className":33348,"code":35897,"language":15364,"meta":291,"style":291},"add_definitions(-DQT_SHARED)\nadd_library(xinxplugins STATIC ${xinxplugins_SRCS} ${xinxplugins_MOC_SRCS})\n",[344,35899,35900,35906],{"__ignoreMap":291},[360,35901,35902,35904],{"class":362,"line":363},[360,35903,35258],{"class":574},[360,35905,35745],{"class":366},[360,35907,35908,35910,35913,35916,35919],{"class":362,"line":292},[360,35909,35750],{"class":574},[360,35911,35912],{"class":366},"(xinxplugins STATIC ",[360,35914,35915],{"class":574},"${xinxplugins_SRCS}",[360,35917,35918],{"class":574}," ${xinxplugins_MOC_SRCS}",[360,35920,2922],{"class":366},[1901,35922,35924],{"id":35923},"utiliser-le-programme-cmake","Utiliser le programme CMake",[12,35926,35927],{},"Une fois le programme configuré, il est possible de compiler ce dernier\nà l'aide des commandes suivantes :",[352,35929,35931],{"className":565,"code":35930,"language":567,"meta":291,"style":291},"mkdir build\ncd build\ncmake ..\u002Fsources\nmake\nmake install\n",[344,35932,35933,35939,35945,35952,35957],{"__ignoreMap":291},[360,35934,35935,35937],{"class":362,"line":363},[360,35936,15350],{"class":381},[360,35938,15353],{"class":397},[360,35940,35941,35943],{"class":362,"line":292},[360,35942,15342],{"class":582},[360,35944,15353],{"class":397},[360,35946,35947,35949],{"class":362,"line":375},[360,35948,15364],{"class":381},[360,35950,35951],{"class":397}," ..\u002Fsources\n",[360,35953,35954],{"class":362,"line":433},[360,35955,35956],{"class":381},"make\n",[360,35958,35959,35961],{"class":362,"line":478},[360,35960,15381],{"class":381},[360,35962,35963],{"class":397}," install\n",[12,35965,35966,35967,35971,35972,31],{},"Sous Windows, il est possible de compiler en utilisant ",[47,35968,33015],{"href":35969,"rel":35970},"http:\u002F\u002Fwww.mingw.org\u002F",[51]," pour\ncompiler ou d'utiliser le compilateur de ",[344,35973,35974],{},"Visual Studio",[12,35976,35977],{},"Il est également possible de définir un emplacement pour l'installation\ndifférent du dossier par défaut :",[352,35979,35981],{"className":565,"code":35980,"language":567,"meta":291,"style":291},"cmake -DCMAKE_INSTALL_PREFIX=\u002Fhome\u002Flogin\u002Fusr\u002F\n",[344,35982,35983],{"__ignoreMap":291},[360,35984,35985,35987],{"class":362,"line":363},[360,35986,15364],{"class":381},[360,35988,35989],{"class":414}," -DCMAKE_INSTALL_PREFIX=\u002Fhome\u002Flogin\u002Fusr\u002F\n",[21499,35991,35993,35996],{"className":35992,"dataFootnotes":291},[21502],[33,35994,21507],{"className":35995,"id":15686},[21506],[13835,35997,35998,36007],{},[143,35999,36000,36001,36003,36004],{"id":21512},"C'est ce qui fait tout l'avantage de ",[105,36002,34783],{}," mais est aussi son inconvénient car il ajoute une couche supplémentaire. C'est ensuite une question de goût. ",[47,36005,21520],{"href":21516,"ariaLabel":21517,"className":36006,"dataFootnoteBackref":291},[21519],[143,36008,36009,36010,36012,36013],{"id":21523},"facilitant la gestion des évènements dans ",[105,36011,34783],{}," ",[47,36014,21520],{"href":21531,"ariaLabel":21532,"className":36015,"dataFootnoteBackref":291},[21519],[1613,36017,36018],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}",{"title":291,"searchDepth":292,"depth":292,"links":36020},[36021,36022,36023],{"id":34857,"depth":375,"text":34858},{"id":35923,"depth":375,"text":35924},{"id":15686,"depth":292,"text":21507},"2011-06-26","Suite à un billet datant de 2008, je reviens vers vous pour ajouter\nquelques précisions sur la compilation de programme Qt avec\nCMake. En effet, pour mon programme XINX, j'ai modifié la chaîne\nde compilation actuelle utilisant QMake par une chaîne de compilation\nCMake.",{"type":9,"value":36027},[36028,36045,36058,36064,36068],[12,36029,34773,36030,34778,36032,34784,36035,34790,36038,34796,36041,34800,36043,31],{},[47,36031,34777],{"href":34776},[47,36033,34783],{"href":34781,"rel":36034},[51],[47,36036,34789],{"href":34787,"rel":36037},[51],[47,36039,34795],{"href":34793,"rel":36040},[51],[105,36042,34799],{},[105,36044,34789],{},[12,36046,36047,34807,36049,34811,36051,34698,36054,34819,36056,34822],{},[105,36048,34789],{},[344,36050,34810],{},[47,36052,34816],{"href":34814,"rel":36053},[51],[105,36055,34789],{},[344,36057,15381],{},[12,36059,36060,34827,36062,31],{},[105,36061,34789],{},[105,36063,34830],{},[12,36065,34833,36066,34837],{},[344,36067,34836],{},[140,36069,36070],{},[143,36071,36072,36074],{},[344,36073,34836],{},[140,36075,36076,36080],{},[143,36077,36078],{},[344,36079,34850],{},[143,36081,36082],{},[344,36083,28495],{},{},"\u002Fpost\u002Fqt-cmake-et-qt",{"title":34768,"description":36025},"qt-cmake-et-qt","posts\u002FProgrammation\u002F2011-06-26-qt-cmake-et-qt",[32924],"z241vjvDaj7TX5NjylClHpgb9g7dVly4_9NxleMnRPU",{"id":36092,"title":36093,"author":7,"body":36094,"category":300,"categorySlug":301,"date":39128,"description":291,"excerpt":39129,"extension":317,"location":318,"meta":39202,"navigation":320,"path":39203,"published":320,"seo":39204,"slug":39205,"stem":39206,"tags":39207,"timeToRead":1485,"__hash__":39210},"posts\u002Fposts\u002FProgrammation\u002F2011-01-25-qt-performance-de-l-utilisation-de-qsharedpointer.md","C++\u002FQt - Performance de l'utilisation de QSharedPointer",{"type":9,"value":36095,"toc":39121},[36096,36100,36109,36129,36138,36199,36203,36207,36211,36224,36235,36241,36245,36266,36290,36386,36393,36403,36408,36451,36457,36480,36490,36504,36534,36552,36607,36620,36626,36635,36700,36710,36716,36762,36784,36790,36924,36940,36948,36965,36968,37114,37137,37144,37217,37221,37224,37227,37510,37513,37788,37791,37797,37800,37803,37926,37948,37952,37962,37979,37992,37996,38005,38013,38157,38172,38190,38281,38284,38287,38317,38319,38325,38339,38342,38346,38353,38356,38370,38373,38392,38395,38409,38413,38417,38426,38429,38438,38562,38626,38630,38633,38655,38659,38665,38729,38733,38739,38745,38786,38789,38846,38850,38853,38957,38963,38966,38969,38973,38980,38997,39118],[1901,36097,36099],{"id":36098},"présentation","Présentation",[12,36101,36102,36104,36105,36108],{},[105,36103,34783],{}," est un framework orienté objet écrit en C++ et permettant de faire\ndes interfaces graphiques. Ce framework est utilisé par le projet ",[105,36106,36107],{},"KDE","\ndepuis ses débuts pour en faire un environnement de bureau très complet.",[12,36110,36111,36113,36114,36117,36122,36123,36125,36126,36128],{},[105,36112,34783],{}," fournit un ensemble de pointeur ",[105,36115,36116],{},"intelligent",[15680,36118,36119],{},[47,36120,1944],{"href":15684,"ariaDescribedBy":36121,"dataFootnoteRef":291,"id":15687},[15686]," permettant\nde gérer plus facilement la mémoire. Le but est alors de ne plus avoir à\nsupprimer des objets. La suppression se fera soit par un pointeur\n",[105,36124,36116],{}," soit par le système de hiérarchie d'objet existant en ",[105,36127,34783],{},"\n(l'objet père qui supprime l'ensemble des objets fils qui lui sont\nrattachés).",[12,36130,36131,36133,36134,36137],{},[105,36132,34783],{}," propose l'ensemble des pointeurs ",[105,36135,36136],{},"intelligents"," suivants:",[140,36139,36140,36163,36177,36185],{},[143,36141,36142,36147,36148,36153,36154,36157,36158,31],{},[47,36143,36146],{"href":36144,"rel":36145},"http:\u002F\u002Fdoc.qt.nokia.com\u002F4.6\u002Fqshareddatapointer.html",[51],"QSharedDataPointer"," \u002F ",[47,36149,36152],{"href":36150,"rel":36151},"http:\u002F\u002Fdoc.qt.nokia.com\u002F4.6\u002Fqshareddata.html",[51],"QSharedData"," : ces deux classes\nutilisées ensemble permettent d'écrire un objet avec partage\nimplicite. Cela signifie que l'objet fonctionnera comme la classe\n",[105,36155,36156],{},"QString",". Tant que l'objet est copié, passé en paramètre, ....\nl'objet n'est pas dupliqué (tous les objets pointes vers le même\nespace mémoire). Au moment où l'objet est modifié, l'objet est\ndupliqué. C'est ce qu'on appelle le COW",[15680,36159,36160],{},[47,36161,795],{"href":16257,"ariaDescribedBy":36162,"dataFootnoteRef":291,"id":16259},[15686],[143,36164,36165,36147,36170,36173,36174,36176],{},[47,36166,36169],{"href":36167,"rel":36168},"http:\u002F\u002Fdoc.qt.nokia.com\u002F4.6\u002Fqexplicitlyshareddatapointer.html",[51],"QExplictlySharedDataPointer",[47,36171,36152],{"href":36150,"rel":36172},[51]," :\nQExplicitlySharedDataPointer est une variante de QSharedDataPointer.\nCe pointeur ",[105,36175,36116],{},", comme son nom l'indique, est détaché\nuniquement lorsque la méthode detach() est appelée explicitement.\nCette classe permet de faire des objets qui fonctionnent comme des\npointeurs mais qui sont utilisés sans la notion de pointeur (le *).\nLa suppression des données partagées se fait donc quand tous les\nobjets ne sont plus utilisés.",[143,36178,36179,36184],{},[47,36180,36183],{"href":36181,"rel":36182},"http:\u002F\u002Fdoc.qt.nokia.com\u002F4.6\u002Fqscopedpointer.html",[51],"QScopedPointer"," : Ce pointeur est le plus simple. Il permet de\ndéclarer un pointeur sur le tas et s'occupe de la destruction de\nl'objet, lorsque le programme sort de la portée du bloc. Cela permet\nde ne plus se soucier de la libération du pointeur dans les cas\nd'erreur (exception, retour avant la fin de la fonction car le\nfichier n'a pu être ouvert, ...).",[143,36186,36187,36192,36193,36198],{},[47,36188,36191],{"href":36189,"rel":36190},"http:\u002F\u002Fdoc.qt.nokia.com\u002F4.6\u002Fqsharedpointer.html",[51],"QSharedPointer"," : Le pointeur dont on parlera dans la suite de ce\nbillet. Il permet de partager non plus des données (comme le fait\nQSharedData) mais de partager un pointeur",[15680,36194,36195],{},[47,36196,1954],{"href":32973,"ariaDescribedBy":36197,"dataFootnoteRef":291,"id":32975},[15686],". Nous allons voir\ndans la suite du billet, comment simplement utiliser ce pointeur, et\nles performances de ce pointeur par rapport à un pointeur standard.",[1901,36200,36202],{"id":36201},"sommaire","Sommaire",[1901,36204,36206],{"id":36205},"utilisation-de-qsharedpointer","Utilisation de QSharedPointer",[23034,36208,36210],{"id":36209},"a-quoi-sert-il","A quoi sert-il ?",[12,36212,36213,36214,36216,36217,36219,36220,36223],{},"L'objet ",[344,36215,36191],{}," fait partie des pointeurs ",[105,36218,36136],{},". Ces\npointeurs permettent de gérer automatiquement la libération de la\nmémoire (plus besoin de faire ",[344,36221,36222],{},"delete ptr;"," quand le pointeur n'est plus\nutilisé) tout en restant utilisable comme un pointeur normal.",[12,36225,36226,36228,36229,36231,36232,36234],{},[344,36227,36191],{}," fonctionne par comptage de référence. Après la\ndéclaration, à chaque affectation, on augmente le compteur de référence,\nlorsqu'on quitte la portée du bloc, on décrémente le compteur de\nréférence. ",[344,36230,36191],{}," détruit donc automatiquement le pointeur\nquand il n'existe plus aucune référence vers ce pointeur.\n",[344,36233,36191],{}," vient donc comme une encapsulation de notre pointeur.",[12,36236,36237],{},[69,36238],{"alt":36239,"src":36240},"QSharedPointer vers la même adresse","\u002FProgrammation\u002Fqt-performance-de-l-utilisation-de-qsharedpointer\u002FQSharedPointer1.png",[23034,36242,36244],{"id":36243},"comment-lutiliser","Comment l'utiliser ?",[12,36246,36247,36248,36251,36252,36255,36256,36259,36260,36262,36263,36265],{},"La déclaration d'un pointeur en C, se fait en écrivant ",[344,36249,36250],{},"MyObject*",". La\nsyntaxe en utilisant un QSharedPointer se fait en écrivant\n",[344,36253,36254],{},"QSharedPointer\u003CMyObject>",". Par la suite dans le programme,\nl'utilisation du pointeur ",[344,36257,36258],{},"QSharedObject"," se fera de la même manière\nqu'un pointeur C. (Avec l'opérateur ",[344,36261,2376],{}," pour appeler un membre, une\nméthode, ...) . Appelons dans la suite pointeur C, les pointeurs\nstandards et ",[344,36264,36191],{},", le pointeur intelligent.",[12,36267,36268,36269,36271,36272,36274,36275,36277,36278,36280,36281,36284,36285,31],{},"Afin d'éviter d'avoir un pointeur normal pouvant être supprimé à tout\nmoment dans l'application, lors de l'utilisation de ",[344,36270,36191],{},", il\nne faut utiliser le pointeur C résultant du ",[344,36273,2221],{}," que pour la création\ndu ",[344,36276,36191],{},". On peut donc directement créer le ",[344,36279,36191],{},"\nen utilisant le constructeur ",[344,36282,36283],{},"QSharedPointer ( T * ptr )"," qui prend en\nparamètre le pointeur C. C'est entre ces parenthèses que nous allons\ncréer le pointeur C",[15680,36286,36287],{},[47,36288,33006],{"href":33003,"ariaDescribedBy":36289,"dataFootnoteRef":291,"id":33005},[15686],[352,36291,36293],{"className":635,"code":36292,"language":637,"meta":291,"style":291},"{\n    \u002F\u002F Création du pointeur intelligent à partir d'un pointeur normal.\n    QSharedPointer\u003CMyObject> ptr(new MyObject());\n\n    \u002F\u002F Utilisation du pointeur intelligent comme un pointeur normal.\n    if (ptr)\n    {\n        ptr->setMembre(maValeur);\n    }\n\n    \u002F\u002F Appel d'une méthode utilisant ce pointeur\n    maMethode(ptr);\n}\n",[344,36294,36295,36299,36304,36328,36332,36337,36344,36348,36361,36365,36369,36374,36382],{"__ignoreMap":291},[360,36296,36297],{"class":362,"line":363},[360,36298,16340],{"class":366},[360,36300,36301],{"class":362,"line":292},[360,36302,36303],{"class":644},"    \u002F\u002F Création du pointeur intelligent à partir d'un pointeur normal.\n",[360,36305,36306,36309,36311,36314,36316,36319,36321,36323,36326],{"class":362,"line":375},[360,36307,36308],{"class":366},"    QSharedPointer",[360,36310,1358],{"class":574},[360,36312,36313],{"class":366},"MyObject",[360,36315,24917],{"class":574},[360,36317,36318],{"class":381}," ptr",[360,36320,671],{"class":366},[360,36322,2221],{"class":574},[360,36324,36325],{"class":381}," MyObject",[360,36327,841],{"class":366},[360,36329,36330],{"class":362,"line":433},[360,36331,372],{"emptyLinePlaceholder":320},[360,36333,36334],{"class":362,"line":478},[360,36335,36336],{"class":644},"    \u002F\u002F Utilisation du pointeur intelligent comme un pointeur normal.\n",[360,36338,36339,36341],{"class":362,"line":483},[360,36340,5657],{"class":574},[360,36342,36343],{"class":366}," (ptr)\n",[360,36345,36346],{"class":362,"line":489},[360,36347,16504],{"class":366},[360,36349,36350,36353,36355,36358],{"class":362,"line":494},[360,36351,36352],{"class":662},"        ptr",[360,36354,2376],{"class":366},[360,36356,36357],{"class":381},"setMembre",[360,36359,36360],{"class":366},"(maValeur);\n",[360,36362,36363],{"class":362,"line":712},[360,36364,2927],{"class":366},[360,36366,36367],{"class":362,"line":331},[360,36368,372],{"emptyLinePlaceholder":320},[360,36370,36371],{"class":362,"line":762},[360,36372,36373],{"class":644},"    \u002F\u002F Appel d'une méthode utilisant ce pointeur\n",[360,36375,36376,36379],{"class":362,"line":781},[360,36377,36378],{"class":381},"    maMethode",[360,36380,36381],{"class":366},"(ptr);\n",[360,36383,36384],{"class":362,"line":804},[360,36385,847],{"class":366},[12,36387,36388,36389,36392],{},"Lorsque l'on quitte le bloc, si le comptage de référence tombe à 0, on\nsupprime le pointeur. A l'intérieur de ",[344,36390,36391],{},"maMethode()"," le nombre de\nréférence sera passé à 2. Si la méthode utilise le pointeur mais ne\nl'assigne nul part, le nombre de référence devrait être retombé à 1 et\ndonc ici sera décrémenté à 0.",[12,36394,36395,36396,36398,36399,36402],{},"Si par contre, ",[344,36397,36391],{}," fait des opérations d'assignation de ",[344,36400,36401],{},"ptr","\net conserve une copie, le comptage ne tombera pas à 0 tant que l'objet\nrestera utilisé (assigné) ailleurs.",[12,36404,36405,36406,34886],{},"Regardons un exemple de ",[344,36407,36391],{},[352,36409,36411],{"className":635,"code":36410,"language":637,"meta":291,"style":291},"void maMethode(QSharedPointer\u003CMyObject> ptr)\n{\n    ptr->setMembre2(maValeur);\n",[344,36412,36413,36435,36439],{"__ignoreMap":291},[360,36414,36415,36418,36421,36423,36425,36427,36429,36431,36433],{"class":362,"line":363},[360,36416,36417],{"class":574},"void",[360,36419,36420],{"class":381}," maMethode",[360,36422,671],{"class":366},[360,36424,36191],{"class":662},[360,36426,1358],{"class":366},[360,36428,36313],{"class":662},[360,36430,2697],{"class":366},[360,36432,36401],{"class":677},[360,36434,2922],{"class":366},[360,36436,36437],{"class":362,"line":292},[360,36438,16340],{"class":366},[360,36440,36441,36444,36446,36449],{"class":362,"line":375},[360,36442,36443],{"class":662},"    ptr",[360,36445,2376],{"class":366},[360,36447,36448],{"class":381},"setMembre2",[360,36450,36360],{"class":366},[12,36452,36453,36454,36456],{},"Au début du bloc, ici le comptage de référence est à 2 et sera\ndécrémenté à la sortie de la méthode. On peut modifier les membres de\n",[344,36455,36401],{},", et dans ce cas pas de changement du comptage de référence.",[352,36458,36460],{"className":635,"code":36459,"language":637,"meta":291,"style":291},"    this->monPtr = ptr;\n}\n",[344,36461,36462,36476],{"__ignoreMap":291},[360,36463,36464,36466,36468,36471,36473],{"class":362,"line":363},[360,36465,18657],{"class":662},[360,36467,2376],{"class":366},[360,36469,36470],{"class":578},"monPtr",[360,36472,401],{"class":574},[360,36474,36475],{"class":366}," ptr;\n",[360,36477,36478],{"class":362,"line":292},[360,36479,847],{"class":366},[12,36481,36482,36483,36486,36487,36489],{},"Au contraire, on peut également l'assigner à un autre objet. Dans ce cas\nle comptage de référence de cet objet passera à 3. A la sortie de la\nméthode il sera décrémenté et passera alors à 2. L'objet ne sera pas\nsupprimé tant qu'on ne fera pas un ",[344,36484,36485],{},"this->monPtr.clear()"," ou que ",[344,36488,14158],{},"\nne sera pas détruit.",[12,36491,36492,36493,36495,36496,36499,36500,36503],{},"Si on veut garder une référence d'un pointeur mais qu'on ne souhaite pas\nque celle-ci incrémente le nombre de référence du ",[344,36494,36191],{},", il\nest possible de créer un pointeur ",[105,36497,36498],{},"faible",". Ce pointeur passe par\nl'objet ",[344,36501,36502],{},"QWeakPointer",". Pour obtenir ce type de pointeur, il suffit de\nfaire :",[352,36505,36507],{"className":635,"code":36506,"language":637,"meta":291,"style":291},"QWeakPointer\u003CMyObject> ptrW = ptr->toWeakRef ();\n",[344,36508,36509],{"__ignoreMap":291},[360,36510,36511,36513,36515,36517,36519,36522,36524,36526,36528,36531],{"class":362,"line":363},[360,36512,36502],{"class":366},[360,36514,1358],{"class":574},[360,36516,36313],{"class":366},[360,36518,24917],{"class":574},[360,36520,36521],{"class":366}," ptrW ",[360,36523,583],{"class":574},[360,36525,36318],{"class":662},[360,36527,2376],{"class":366},[360,36529,36530],{"class":381},"toWeakRef",[360,36532,36533],{"class":366}," ();\n",[12,36535,36536,36539,36540,36542,36543,36546,36547,36549,36550,31],{},[344,36537,36538],{},"ptrW"," n'incrémente donc pas le comptage de référence, cela signifie\ndonc que le pointeur peut être détruit même si un objet ",[344,36541,36502],{},"\nexiste. Il sera alors possible de faire un ",[344,36544,36545],{},"ptrW.isNull()"," pour savoir\nsi le pointeur est toujours valide. Si l'utilisateur a également besoin\nd'avoir accès à un membre de l'objet, il pourra le transformer en\n",[344,36548,36191],{}," avant de l'utiliser sauf si le pointeur est ",[344,36551,16849],{},[352,36553,36555],{"className":635,"code":36554,"language":637,"meta":291,"style":291},"QSharedPointer\u003CMyObject> ptr2 = ptrW->toStrongRef ();\nif (ptr)\n{\n    ptr->maMethodePtr();\n}\n",[344,36556,36557,36582,36588,36592,36603],{"__ignoreMap":291},[360,36558,36559,36561,36563,36565,36567,36570,36572,36575,36577,36580],{"class":362,"line":363},[360,36560,36191],{"class":366},[360,36562,1358],{"class":574},[360,36564,36313],{"class":366},[360,36566,24917],{"class":574},[360,36568,36569],{"class":366}," ptr2 ",[360,36571,583],{"class":574},[360,36573,36574],{"class":662}," ptrW",[360,36576,2376],{"class":366},[360,36578,36579],{"class":381},"toStrongRef",[360,36581,36533],{"class":366},[360,36583,36584,36586],{"class":362,"line":292},[360,36585,2370],{"class":574},[360,36587,36343],{"class":366},[360,36589,36590],{"class":362,"line":375},[360,36591,16340],{"class":366},[360,36593,36594,36596,36598,36601],{"class":362,"line":433},[360,36595,36443],{"class":662},[360,36597,2376],{"class":366},[360,36599,36600],{"class":381},"maMethodePtr",[360,36602,2204],{"class":366},[360,36604,36605],{"class":362,"line":478},[360,36606,847],{"class":366},[12,36608,36609,36610,36613,36614,36616,36617,36619],{},"Il faut tester que ",[344,36611,36612],{},"ptr2"," est encore valide, car tant que la\ntransformation du pointeur ",[105,36615,36498],{}," vers le ",[344,36618,36191],{}," n'a pas\nencore été fait, il est possible que le nombre de référence vers l'objet\nsoit tombé à 0 et qu'il ait été supprimé.",[23034,36621,36623,36624],{"id":36622},"comment-utiliser-this","Comment utiliser ",[344,36625,14158],{},[12,36627,36628,36629,36631,36632,36634],{},"Un des points peu pratique de l'utilisation de ",[344,36630,36191],{}," est que\nle comptage de référence ne fonctionne pas si plusieurs ",[344,36633,36191],{},"\npointent vers le même objet mais ont tous été créés à partir du pointeur\nC. Prenons par exemple, le cas suivant :",[352,36636,36638],{"className":635,"code":36637,"language":637,"meta":291,"style":291},"MyObject * ptr = new MyObject();\n\nQSharedPointer\u003CMyObject> ptr1 = QSharedPointer(ptr);\nQSharedPointer\u003CMyObject> ptr2 = QSharedPointer(ptr);\n",[344,36639,36640,36658,36662,36682],{"__ignoreMap":291},[360,36641,36642,36645,36647,36650,36652,36654,36656],{"class":362,"line":363},[360,36643,36644],{"class":366},"MyObject ",[360,36646,925],{"class":574},[360,36648,36649],{"class":366}," ptr ",[360,36651,583],{"class":574},[360,36653,3040],{"class":574},[360,36655,36325],{"class":381},[360,36657,2204],{"class":366},[360,36659,36660],{"class":362,"line":292},[360,36661,372],{"emptyLinePlaceholder":320},[360,36663,36664,36666,36668,36670,36672,36675,36677,36680],{"class":362,"line":375},[360,36665,36191],{"class":366},[360,36667,1358],{"class":574},[360,36669,36313],{"class":366},[360,36671,24917],{"class":574},[360,36673,36674],{"class":366}," ptr1 ",[360,36676,583],{"class":574},[360,36678,36679],{"class":381}," QSharedPointer",[360,36681,36381],{"class":366},[360,36683,36684,36686,36688,36690,36692,36694,36696,36698],{"class":362,"line":433},[360,36685,36191],{"class":366},[360,36687,1358],{"class":574},[360,36689,36313],{"class":366},[360,36691,24917],{"class":574},[360,36693,36569],{"class":366},[360,36695,583],{"class":574},[360,36697,36679],{"class":381},[360,36699,36381],{"class":366},[12,36701,36702,36703,36706,36707,36709],{},"Le problème d'écrire ces lignes ainsi, et que pour ",[344,36704,36705],{},"ptr1"," comme pour\n",[344,36708,36612],{},", l'objet n'est référencé qu'une fois. Ainsi le premier qui\ntombera à 0 détruira l'objet, alors que l'autre pourrait encore\nl'utiliser. Il faut donc écrire les choses comme suite :",[12,36711,36712],{},[69,36713],{"alt":36714,"src":36715},"Deux QSharedPointer créé vers la même adresse","\u002FProgrammation\u002Fqt-performance-de-l-utilisation-de-qsharedpointer\u002FQSharedPointer2.png",[352,36717,36719],{"className":635,"code":36718,"language":637,"meta":291,"style":291},"QSharedPointer\u003CMyObject> ptr1 = QSharedPointer(new MyObject());\nQSharedPointer\u003CMyObject> ptr2 = ptr1;\n",[344,36720,36721,36745],{"__ignoreMap":291},[360,36722,36723,36725,36727,36729,36731,36733,36735,36737,36739,36741,36743],{"class":362,"line":363},[360,36724,36191],{"class":366},[360,36726,1358],{"class":574},[360,36728,36313],{"class":366},[360,36730,24917],{"class":574},[360,36732,36674],{"class":366},[360,36734,583],{"class":574},[360,36736,36679],{"class":381},[360,36738,671],{"class":366},[360,36740,2221],{"class":574},[360,36742,36325],{"class":381},[360,36744,841],{"class":366},[360,36746,36747,36749,36751,36753,36755,36757,36759],{"class":362,"line":292},[360,36748,36191],{"class":366},[360,36750,1358],{"class":574},[360,36752,36313],{"class":366},[360,36754,24917],{"class":574},[360,36756,36569],{"class":366},[360,36758,583],{"class":574},[360,36760,36761],{"class":366}," ptr1;\n",[12,36763,36764,36765,854,36767,36769,36770,36772,36773,36775,36776,36778,36779,36781,36782,31],{},"Ainsi ",[344,36766,36705],{},[344,36768,36612],{}," ont bien chacun connaissance de l'existence de\nl'autre. Cela contraint donc à remplacer toutes les déclarations du type\n",[344,36771,36250],{}," par ",[344,36774,36254],{},". Ceci est donc à faire dans\nles paramètres des méthodes, dans les membres, dans la déclaration des\nvariables locales, ... . On ne peut donc plus utiliser le pointeur C\n",[344,36777,36250],{}," directement, mais seulement au travers de ",[344,36780,36191],{},"\nou de ",[344,36783,36502],{},[12,36785,36786,36787,36789],{},"Cela commence à poser problème lors de l'utilisation de ",[344,36788,14158],{}," dans un\nobjet. Imaginons une méthode d'un objet mettant à jour des membres fils\navec en paramètre le père. Nous aurions alors tendance à écrire ceci :",[352,36791,36793],{"className":635,"code":36792,"language":637,"meta":291,"style":291},"void Object2::setParent(QSharedPointer\u003CMyObject> parent)\n{\n    ...\n}\n\n....\n\nvoid MyObject::setMember(Object2 * obj)\n{\n    _membre = obj;\n    if (obj)\n    {\n        obj->setParent(QSharedPointer\u003CMyObject>(this));\n    }\n}\n",[344,36794,36795,36821,36825,36829,36833,36837,36842,36846,36868,36872,36882,36889,36893,36916,36920],{"__ignoreMap":291},[360,36796,36797,36799,36802,36804,36807,36809,36811,36813,36815,36817,36819],{"class":362,"line":363},[360,36798,36417],{"class":574},[360,36800,36801],{"class":662}," Object2",[360,36803,666],{"class":366},[360,36805,36806],{"class":381},"setParent",[360,36808,671],{"class":366},[360,36810,36191],{"class":662},[360,36812,1358],{"class":366},[360,36814,36313],{"class":662},[360,36816,2697],{"class":366},[360,36818,22767],{"class":677},[360,36820,2922],{"class":366},[360,36822,36823],{"class":362,"line":292},[360,36824,16340],{"class":366},[360,36826,36827],{"class":362,"line":375},[360,36828,28849],{"class":366},[360,36830,36831],{"class":362,"line":433},[360,36832,847],{"class":366},[360,36834,36835],{"class":362,"line":478},[360,36836,372],{"emptyLinePlaceholder":320},[360,36838,36839],{"class":362,"line":483},[360,36840,36841],{"class":366},"....\n",[360,36843,36844],{"class":362,"line":489},[360,36845,372],{"emptyLinePlaceholder":320},[360,36847,36848,36850,36852,36854,36857,36859,36862,36864,36866],{"class":362,"line":494},[360,36849,36417],{"class":574},[360,36851,36325],{"class":662},[360,36853,666],{"class":366},[360,36855,36856],{"class":381},"setMember",[360,36858,671],{"class":366},[360,36860,36861],{"class":662},"Object2",[360,36863,920],{"class":574},[360,36865,7476],{"class":677},[360,36867,2922],{"class":366},[360,36869,36870],{"class":362,"line":712},[360,36871,16340],{"class":366},[360,36873,36874,36877,36879],{"class":362,"line":331},[360,36875,36876],{"class":366},"    _membre ",[360,36878,583],{"class":574},[360,36880,36881],{"class":366}," obj;\n",[360,36883,36884,36886],{"class":362,"line":762},[360,36885,5657],{"class":574},[360,36887,36888],{"class":366}," (obj)\n",[360,36890,36891],{"class":362,"line":781},[360,36892,16504],{"class":366},[360,36894,36895,36898,36900,36902,36904,36906,36908,36910,36912,36914],{"class":362,"line":804},[360,36896,36897],{"class":662},"        obj",[360,36899,2376],{"class":366},[360,36901,36806],{"class":381},[360,36903,671],{"class":366},[360,36905,36191],{"class":381},[360,36907,1358],{"class":366},[360,36909,36313],{"class":662},[360,36911,17571],{"class":366},[360,36913,14158],{"class":662},[360,36915,4081],{"class":366},[360,36917,36918],{"class":362,"line":817},[360,36919,2927],{"class":366},[360,36921,36922],{"class":362,"line":823},[360,36923,847],{"class":366},[12,36925,36926,36927,36929,36930,34698,36935,36937,36938,31],{},"Ceci ne marchera pas car on créerait un nouvel objet ",[344,36928,36191],{},"\ncommençant son comptage de référence à 1, alors que nous en avons déjà\nau moins un autre pointant vers notre instance",[15680,36931,36932],{},[47,36933,30942],{"href":33020,"ariaDescribedBy":36934,"dataFootnoteRef":291,"id":33022},[15686],[344,36936,36313],{},"\npourrait alors être détruit alors qu'il est encore utilisé par\n",[344,36939,36861],{},[12,36941,36942,36943,36945,36947],{},"Pour éviter cela, il faut alors passer par un pointeur ",[105,36944,36116],{},[344,36946,14158],{},". Pour cela nous allons utiliser deux choses :",[140,36949,36950,36962],{},[143,36951,36952,36953,36956,36957,36959,36961],{},"Un membre nommé ",[344,36954,36955],{},"_this"," de type pointeur ",[105,36958,36116],{},[344,36960,36502],{},", contenant une référence à l'objet lui même. (Nous\nn'utilisons pas un QSharedPointer, pour éviter une référence\ncirculaire, voir le paragraphe suivant).",[143,36963,36964],{},"Une méthode statique utilisée pour la création (nous n'allons plus\nutiliser le constructeur, car à ce moment, il n'existe pas encore de\nQSharedPointer pointant vers notre objet).",[12,36966,36967],{},"Voici un exemple de comment écrire le constructeur maison :",[352,36969,36971],{"className":635,"code":36970,"language":637,"meta":291,"style":291},"class MyObject\n{\npublic:\n    static QSharedPointer\u003CMyObject> create(QString parametre)\n    {\n        QSharedPointer\u003CMyObject> ptr(new MyObject(parametre);\n        ptr->_this = ptr.toWeakRef();\n        return ptr;\n    }\nprivate:\n    MyObject(QString parametre)\n    {\n        ...\n    }\n\n    QWeakPointer\u003CMyObject> _this;\n};\n",[344,36972,36973,36980,36984,36989,37013,37017,37039,37057,37063,37067,37072,37080,37084,37088,37092,37096,37110],{"__ignoreMap":291},[360,36974,36975,36977],{"class":362,"line":363},[360,36976,18818],{"class":574},[360,36978,36979],{"class":662}," MyObject\n",[360,36981,36982],{"class":362,"line":292},[360,36983,16340],{"class":366},[360,36985,36986],{"class":362,"line":375},[360,36987,36988],{"class":574},"public:\n",[360,36990,36991,36994,36996,36998,37000,37002,37004,37006,37008,37011],{"class":362,"line":433},[360,36992,36993],{"class":574},"    static",[360,36995,36679],{"class":662},[360,36997,1358],{"class":366},[360,36999,36313],{"class":662},[360,37001,2697],{"class":366},[360,37003,9380],{"class":381},[360,37005,671],{"class":366},[360,37007,36156],{"class":662},[360,37009,37010],{"class":677}," parametre",[360,37012,2922],{"class":366},[360,37014,37015],{"class":362,"line":478},[360,37016,16504],{"class":366},[360,37018,37019,37022,37024,37026,37028,37030,37032,37034,37036],{"class":362,"line":483},[360,37020,37021],{"class":366},"        QSharedPointer",[360,37023,1358],{"class":574},[360,37025,36313],{"class":366},[360,37027,24917],{"class":574},[360,37029,36318],{"class":381},[360,37031,671],{"class":366},[360,37033,2221],{"class":574},[360,37035,36325],{"class":381},[360,37037,37038],{"class":366},"(parametre);\n",[360,37040,37041,37043,37045,37047,37049,37051,37053,37055],{"class":362,"line":489},[360,37042,36352],{"class":662},[360,37044,2376],{"class":366},[360,37046,36955],{"class":578},[360,37048,401],{"class":574},[360,37050,36318],{"class":662},[360,37052,31],{"class":366},[360,37054,36530],{"class":381},[360,37056,2204],{"class":366},[360,37058,37059,37061],{"class":362,"line":494},[360,37060,24470],{"class":574},[360,37062,36475],{"class":366},[360,37064,37065],{"class":362,"line":712},[360,37066,2927],{"class":366},[360,37068,37069],{"class":362,"line":331},[360,37070,37071],{"class":366},"private:\n",[360,37073,37074,37077],{"class":362,"line":762},[360,37075,37076],{"class":381},"    MyObject",[360,37078,37079],{"class":366},"(QString parametre)\n",[360,37081,37082],{"class":362,"line":781},[360,37083,16504],{"class":366},[360,37085,37086],{"class":362,"line":804},[360,37087,25771],{"class":366},[360,37089,37090],{"class":362,"line":817},[360,37091,2927],{"class":366},[360,37093,37094],{"class":362,"line":823},[360,37095,372],{"emptyLinePlaceholder":320},[360,37097,37098,37101,37103,37105,37107],{"class":362,"line":844},[360,37099,37100],{"class":366},"    QWeakPointer",[360,37102,1358],{"class":574},[360,37104,36313],{"class":366},[360,37106,24917],{"class":574},[360,37108,37109],{"class":366}," _this;\n",[360,37111,37112],{"class":362,"line":1441},[360,37113,1036],{"class":366},[12,37115,37116,37117,37119,37120,37122,37123,37125,37126,37128,37129,37131,37132,37134,37135,31],{},"Le constructeur devient alors privé (ou protégé si on a besoin de la\nnotion d'héritage) afin d'obliger l'utilisateur de la classe à utiliser\nnotre méthode de création. Dans notre nouvelle méthode de création\n",[344,37118,9380],{},", qui est une méthode statique, nous allons créer le pointeur et\ninitialiser le ",[344,37121,36502],{}," de notre objet avec le pointeur\n",[105,37124,36116],{}," que nous venons de créer. Nous retournons un\n",[344,37127,36191],{},". La méthode ",[344,37130,9380],{}," devient alors notre nouveau\nconstructeur, mais créant des instances d'objets de type\n",[344,37133,36254],{}," et non plus des instances d'objet\n",[344,37136,36250],{},[12,37138,37139,37140,37143],{},"Notre méthode ",[344,37141,37142],{},"setMember()"," peut alors être ré-écrite :",[352,37145,37147],{"className":635,"code":37146,"language":637,"meta":291,"style":291},"void MyObject::setMember(Object2 * obj)\n{\n    _membre = obj;\n    if (obj)\n    {\n        obj->setParent(_this.toStrongRef());\n    }\n}\n",[344,37148,37149,37169,37173,37181,37187,37191,37209,37213],{"__ignoreMap":291},[360,37150,37151,37153,37155,37157,37159,37161,37163,37165,37167],{"class":362,"line":363},[360,37152,36417],{"class":574},[360,37154,36325],{"class":662},[360,37156,666],{"class":366},[360,37158,36856],{"class":381},[360,37160,671],{"class":366},[360,37162,36861],{"class":662},[360,37164,920],{"class":574},[360,37166,7476],{"class":677},[360,37168,2922],{"class":366},[360,37170,37171],{"class":362,"line":292},[360,37172,16340],{"class":366},[360,37174,37175,37177,37179],{"class":362,"line":375},[360,37176,36876],{"class":366},[360,37178,583],{"class":574},[360,37180,36881],{"class":366},[360,37182,37183,37185],{"class":362,"line":433},[360,37184,5657],{"class":574},[360,37186,36888],{"class":366},[360,37188,37189],{"class":362,"line":478},[360,37190,16504],{"class":366},[360,37192,37193,37195,37197,37199,37201,37203,37205,37207],{"class":362,"line":483},[360,37194,36897],{"class":662},[360,37196,2376],{"class":366},[360,37198,36806],{"class":381},[360,37200,671],{"class":366},[360,37202,36955],{"class":662},[360,37204,31],{"class":366},[360,37206,36579],{"class":381},[360,37208,841],{"class":366},[360,37210,37211],{"class":362,"line":489},[360,37212,2927],{"class":366},[360,37214,37215],{"class":362,"line":494},[360,37216,847],{"class":366},[23034,37218,37220],{"id":37219},"comment-éviter-les-références-circulaires","Comment éviter les références circulaires",[12,37222,37223],{},"Le principe d'une référence circulaire est qu'un objet A référence\nl'objet B et l'objet B référence l'objet A.",[12,37225,37226],{},"Voici par exemple, un cas de référence circulaire :",[352,37228,37230],{"className":635,"code":37229,"language":637,"meta":291,"style":291},"class A\n{\npublic:\n    static create()\n    {\n        QSharedPointer\u003CA> ptr(new A());\n        return ptr;\n    }\n    ~A()\n    {\n    }\nprivate:\n    A()\n    {\n        b = B::create();\n        b->setA(_this);\n    }\n    QSharedPointer\u003CB> b;\n    QWeakPointer\u003CA> _this;\n};\n\nclass B\n{\npublic:\n    static QSharedPointer\u003CB> create()\n    {\n        QSharedPointer\u003CB> ptr(new B());\n        return ptr;\n    }\n    void setA(QSharedPointer\u003CA> b);\n    QSharedPointer\u003CA> getA();\nprivate:\n    QSharedPointer\u003CA>  a;\n};\n",[344,37231,37232,37239,37243,37247,37256,37260,37281,37287,37291,37298,37302,37306,37310,37317,37321,37335,37348,37352,37366,37378,37382,37386,37393,37397,37401,37417,37421,37442,37448,37452,37474,37489,37493,37506],{"__ignoreMap":291},[360,37233,37234,37236],{"class":362,"line":363},[360,37235,18818],{"class":574},[360,37237,37238],{"class":662}," A\n",[360,37240,37241],{"class":362,"line":292},[360,37242,16340],{"class":366},[360,37244,37245],{"class":362,"line":375},[360,37246,36988],{"class":574},[360,37248,37249,37251,37254],{"class":362,"line":433},[360,37250,36993],{"class":574},[360,37252,37253],{"class":381}," create",[360,37255,5008],{"class":366},[360,37257,37258],{"class":362,"line":478},[360,37259,16504],{"class":366},[360,37261,37262,37264,37266,37269,37271,37273,37275,37277,37279],{"class":362,"line":483},[360,37263,37021],{"class":366},[360,37265,1358],{"class":574},[360,37267,37268],{"class":366},"A",[360,37270,24917],{"class":574},[360,37272,36318],{"class":381},[360,37274,671],{"class":366},[360,37276,2221],{"class":574},[360,37278,33182],{"class":381},[360,37280,841],{"class":366},[360,37282,37283,37285],{"class":362,"line":489},[360,37284,24470],{"class":574},[360,37286,36475],{"class":366},[360,37288,37289],{"class":362,"line":494},[360,37290,2927],{"class":366},[360,37292,37293,37296],{"class":362,"line":712},[360,37294,37295],{"class":381},"    ~A",[360,37297,5008],{"class":366},[360,37299,37300],{"class":362,"line":331},[360,37301,16504],{"class":366},[360,37303,37304],{"class":362,"line":762},[360,37305,2927],{"class":366},[360,37307,37308],{"class":362,"line":781},[360,37309,37071],{"class":574},[360,37311,37312,37315],{"class":362,"line":804},[360,37313,37314],{"class":381},"    A",[360,37316,5008],{"class":366},[360,37318,37319],{"class":362,"line":817},[360,37320,16504],{"class":366},[360,37322,37323,37326,37328,37331,37333],{"class":362,"line":823},[360,37324,37325],{"class":366},"        b ",[360,37327,583],{"class":574},[360,37329,37330],{"class":366}," B::",[360,37332,9380],{"class":381},[360,37334,2204],{"class":366},[360,37336,37337,37340,37342,37345],{"class":362,"line":844},[360,37338,37339],{"class":662},"        b",[360,37341,2376],{"class":366},[360,37343,37344],{"class":381},"setA",[360,37346,37347],{"class":366},"(_this);\n",[360,37349,37350],{"class":362,"line":1441},[360,37351,2927],{"class":366},[360,37353,37354,37356,37358,37361,37363],{"class":362,"line":1462},[360,37355,36308],{"class":366},[360,37357,1358],{"class":574},[360,37359,37360],{"class":366},"B",[360,37362,24917],{"class":574},[360,37364,37365],{"class":366}," b;\n",[360,37367,37368,37370,37372,37374,37376],{"class":362,"line":1485},[360,37369,37100],{"class":366},[360,37371,1358],{"class":574},[360,37373,37268],{"class":366},[360,37375,24917],{"class":574},[360,37377,37109],{"class":366},[360,37379,37380],{"class":362,"line":1497},[360,37381,1036],{"class":366},[360,37383,37384],{"class":362,"line":3161},[360,37385,372],{"emptyLinePlaceholder":320},[360,37387,37388,37390],{"class":362,"line":3167},[360,37389,18818],{"class":574},[360,37391,37392],{"class":662}," B\n",[360,37394,37395],{"class":362,"line":3194},[360,37396,16340],{"class":366},[360,37398,37399],{"class":362,"line":3224},[360,37400,36988],{"class":574},[360,37402,37403,37405,37407,37409,37411,37413,37415],{"class":362,"line":3239},[360,37404,36993],{"class":574},[360,37406,36679],{"class":662},[360,37408,1358],{"class":366},[360,37410,37360],{"class":662},[360,37412,2697],{"class":366},[360,37414,9380],{"class":381},[360,37416,5008],{"class":366},[360,37418,37419],{"class":362,"line":3256},[360,37420,16504],{"class":366},[360,37422,37423,37425,37427,37429,37431,37433,37435,37437,37440],{"class":362,"line":3276},[360,37424,37021],{"class":366},[360,37426,1358],{"class":574},[360,37428,37360],{"class":366},[360,37430,24917],{"class":574},[360,37432,36318],{"class":381},[360,37434,671],{"class":366},[360,37436,2221],{"class":574},[360,37438,37439],{"class":381}," B",[360,37441,841],{"class":366},[360,37443,37444,37446],{"class":362,"line":3281},[360,37445,24470],{"class":574},[360,37447,36475],{"class":366},[360,37449,37450],{"class":362,"line":3305},[360,37451,2927],{"class":366},[360,37453,37454,37457,37460,37462,37464,37466,37468,37470,37472],{"class":362,"line":3320},[360,37455,37456],{"class":574},"    void",[360,37458,37459],{"class":381}," setA",[360,37461,671],{"class":366},[360,37463,36191],{"class":662},[360,37465,1358],{"class":366},[360,37467,37268],{"class":662},[360,37469,2697],{"class":366},[360,37471,2252],{"class":677},[360,37473,801],{"class":366},[360,37475,37476,37478,37480,37482,37484,37487],{"class":362,"line":3325},[360,37477,36308],{"class":662},[360,37479,1358],{"class":366},[360,37481,37268],{"class":662},[360,37483,2697],{"class":366},[360,37485,37486],{"class":381},"getA",[360,37488,2204],{"class":366},[360,37490,37491],{"class":362,"line":3361},[360,37492,37071],{"class":574},[360,37494,37495,37497,37499,37501,37503],{"class":362,"line":3380},[360,37496,36308],{"class":366},[360,37498,1358],{"class":574},[360,37500,37268],{"class":366},[360,37502,24917],{"class":574},[360,37504,37505],{"class":366},"  a;\n",[360,37507,37508],{"class":362,"line":3405},[360,37509,1036],{"class":366},[12,37511,37512],{},"Cela peut-être aussi le cas, si par exemple une instance d'objet C\nréférence des instances d'objets fils C, qui possèdent eux-même un\npointeur vers l'objet C père.",[352,37514,37516],{"className":635,"code":37515,"language":637,"meta":291,"style":291},"class C\n{\npublic:\n    static QSharedPointer\u003CC> create()\n    {\n        QSharedPointer\u003CC> ptr(new C());\n        _this = ptr.toWeakPtr();\n        return ptr;\n    }\n\n    ~C()\n    {\n    }\n\n    void addChild(QSharedPointer\u003CC> c)\n    {\n        _childs.append(c);\n        c->setParent(_this);\n    }\n\n    void setParent(QSharedPointer\u003CC> c);\n    QSharedPointer\u003CC> getParent();\nprivate:\n    C()\n    {\n    }\n\n    QWeakPointer\u003CC> _this;\n    QSharedPointer\u003CC> _parent;\n    QList\u003C QSharedPointer\u003CC> > _childs;\n};\n",[344,37517,37518,37525,37529,37533,37550,37554,37574,37590,37596,37600,37604,37611,37615,37619,37623,37644,37648,37661,37672,37676,37680,37701,37716,37720,37727,37731,37735,37739,37751,37764,37784],{"__ignoreMap":291},[360,37519,37520,37522],{"class":362,"line":363},[360,37521,18818],{"class":574},[360,37523,37524],{"class":662}," C\n",[360,37526,37527],{"class":362,"line":292},[360,37528,16340],{"class":366},[360,37530,37531],{"class":362,"line":375},[360,37532,36988],{"class":574},[360,37534,37535,37537,37539,37541,37544,37546,37548],{"class":362,"line":433},[360,37536,36993],{"class":574},[360,37538,36679],{"class":662},[360,37540,1358],{"class":366},[360,37542,37543],{"class":662},"C",[360,37545,2697],{"class":366},[360,37547,9380],{"class":381},[360,37549,5008],{"class":366},[360,37551,37552],{"class":362,"line":478},[360,37553,16504],{"class":366},[360,37555,37556,37558,37560,37562,37564,37566,37568,37570,37572],{"class":362,"line":483},[360,37557,37021],{"class":366},[360,37559,1358],{"class":574},[360,37561,37543],{"class":366},[360,37563,24917],{"class":574},[360,37565,36318],{"class":381},[360,37567,671],{"class":366},[360,37569,2221],{"class":574},[360,37571,33410],{"class":381},[360,37573,841],{"class":366},[360,37575,37576,37579,37581,37583,37585,37588],{"class":362,"line":489},[360,37577,37578],{"class":366},"        _this ",[360,37580,583],{"class":574},[360,37582,36318],{"class":662},[360,37584,31],{"class":366},[360,37586,37587],{"class":381},"toWeakPtr",[360,37589,2204],{"class":366},[360,37591,37592,37594],{"class":362,"line":494},[360,37593,24470],{"class":574},[360,37595,36475],{"class":366},[360,37597,37598],{"class":362,"line":712},[360,37599,2927],{"class":366},[360,37601,37602],{"class":362,"line":331},[360,37603,372],{"emptyLinePlaceholder":320},[360,37605,37606,37609],{"class":362,"line":762},[360,37607,37608],{"class":381},"    ~C",[360,37610,5008],{"class":366},[360,37612,37613],{"class":362,"line":781},[360,37614,16504],{"class":366},[360,37616,37617],{"class":362,"line":804},[360,37618,2927],{"class":366},[360,37620,37621],{"class":362,"line":817},[360,37622,372],{"emptyLinePlaceholder":320},[360,37624,37625,37627,37630,37632,37634,37636,37638,37640,37642],{"class":362,"line":823},[360,37626,37456],{"class":574},[360,37628,37629],{"class":381}," addChild",[360,37631,671],{"class":366},[360,37633,36191],{"class":662},[360,37635,1358],{"class":366},[360,37637,37543],{"class":662},[360,37639,2697],{"class":366},[360,37641,2358],{"class":677},[360,37643,2922],{"class":366},[360,37645,37646],{"class":362,"line":844},[360,37647,16504],{"class":366},[360,37649,37650,37653,37655,37658],{"class":362,"line":1441},[360,37651,37652],{"class":662},"        _childs",[360,37654,31],{"class":366},[360,37656,37657],{"class":381},"append",[360,37659,37660],{"class":366},"(c);\n",[360,37662,37663,37666,37668,37670],{"class":362,"line":1462},[360,37664,37665],{"class":662},"        c",[360,37667,2376],{"class":366},[360,37669,36806],{"class":381},[360,37671,37347],{"class":366},[360,37673,37674],{"class":362,"line":1485},[360,37675,2927],{"class":366},[360,37677,37678],{"class":362,"line":1497},[360,37679,372],{"emptyLinePlaceholder":320},[360,37681,37682,37684,37687,37689,37691,37693,37695,37697,37699],{"class":362,"line":3161},[360,37683,37456],{"class":574},[360,37685,37686],{"class":381}," setParent",[360,37688,671],{"class":366},[360,37690,36191],{"class":662},[360,37692,1358],{"class":366},[360,37694,37543],{"class":662},[360,37696,2697],{"class":366},[360,37698,2358],{"class":677},[360,37700,801],{"class":366},[360,37702,37703,37705,37707,37709,37711,37714],{"class":362,"line":3167},[360,37704,36308],{"class":662},[360,37706,1358],{"class":366},[360,37708,37543],{"class":662},[360,37710,2697],{"class":366},[360,37712,37713],{"class":381},"getParent",[360,37715,2204],{"class":366},[360,37717,37718],{"class":362,"line":3194},[360,37719,37071],{"class":574},[360,37721,37722,37725],{"class":362,"line":3224},[360,37723,37724],{"class":381},"    C",[360,37726,5008],{"class":366},[360,37728,37729],{"class":362,"line":3239},[360,37730,16504],{"class":366},[360,37732,37733],{"class":362,"line":3256},[360,37734,2927],{"class":366},[360,37736,37737],{"class":362,"line":3276},[360,37738,372],{"emptyLinePlaceholder":320},[360,37740,37741,37743,37745,37747,37749],{"class":362,"line":3281},[360,37742,37100],{"class":366},[360,37744,1358],{"class":574},[360,37746,37543],{"class":366},[360,37748,24917],{"class":574},[360,37750,37109],{"class":366},[360,37752,37753,37755,37757,37759,37761],{"class":362,"line":3305},[360,37754,36308],{"class":366},[360,37756,1358],{"class":574},[360,37758,37543],{"class":366},[360,37760,24917],{"class":574},[360,37762,37763],{"class":366}," _parent;\n",[360,37765,37766,37769,37771,37773,37775,37777,37779,37781],{"class":362,"line":3320},[360,37767,37768],{"class":366},"    QList",[360,37770,1358],{"class":574},[360,37772,36679],{"class":366},[360,37774,1358],{"class":574},[360,37776,37543],{"class":366},[360,37778,24917],{"class":574},[360,37780,3538],{"class":574},[360,37782,37783],{"class":366}," _childs;\n",[360,37785,37786],{"class":362,"line":3325},[360,37787,1036],{"class":366},[12,37789,37790],{},"Dans ces cas là, on a :- L'objet A possède la référence vers l'objet B-\nL'objet B possède une référence vers l'objet A.- Même principe avec\nl'objet C",[12,37792,37793],{},[69,37794],{"alt":37795,"src":37796},"Reference circulaire de QSharedPointer","\u002FProgrammation\u002Fqt-performance-de-l-utilisation-de-qsharedpointer\u002FQSharedPointer3.png",[12,37798,37799],{},"Dans ce cas, il restera alors toujours une référence vers A, et une vers\nB, même si plus aucune variable ne référence ces objets. Cette référence\ncirculaire fait que l'objet ne sera jamais détruit même si on n'a plus\nbesoin de l'objet.",[12,37801,37802],{},"Si on décide que l'objet A sera l'objet maitre (donc que sa destruction\nengendrera la destruction de l'objet B), on peut alors écrire les choses\nainsi pour l'objet B :",[352,37804,37806],{"className":635,"code":37805,"language":637,"meta":291,"style":291},"class B\n{\npublic:\n    static QSharedPointer\u003CB> create()\n    {\n        QSharedPointer\u003CB> ptr(new B());\n        return ptr;\n    }\n    void setA(QWeakPointer\u003CA> b);\n    QWeakPointer\u003CA> getA();\nprivate:\n    QWeakPointer\u003CA>  a;\n};\n",[344,37807,37808,37814,37818,37822,37838,37842,37862,37868,37872,37892,37906,37910,37922],{"__ignoreMap":291},[360,37809,37810,37812],{"class":362,"line":363},[360,37811,18818],{"class":574},[360,37813,37392],{"class":662},[360,37815,37816],{"class":362,"line":292},[360,37817,16340],{"class":366},[360,37819,37820],{"class":362,"line":375},[360,37821,36988],{"class":574},[360,37823,37824,37826,37828,37830,37832,37834,37836],{"class":362,"line":433},[360,37825,36993],{"class":574},[360,37827,36679],{"class":662},[360,37829,1358],{"class":366},[360,37831,37360],{"class":662},[360,37833,2697],{"class":366},[360,37835,9380],{"class":381},[360,37837,5008],{"class":366},[360,37839,37840],{"class":362,"line":478},[360,37841,16504],{"class":366},[360,37843,37844,37846,37848,37850,37852,37854,37856,37858,37860],{"class":362,"line":483},[360,37845,37021],{"class":366},[360,37847,1358],{"class":574},[360,37849,37360],{"class":366},[360,37851,24917],{"class":574},[360,37853,36318],{"class":381},[360,37855,671],{"class":366},[360,37857,2221],{"class":574},[360,37859,37439],{"class":381},[360,37861,841],{"class":366},[360,37863,37864,37866],{"class":362,"line":489},[360,37865,24470],{"class":574},[360,37867,36475],{"class":366},[360,37869,37870],{"class":362,"line":494},[360,37871,2927],{"class":366},[360,37873,37874,37876,37878,37880,37882,37884,37886,37888,37890],{"class":362,"line":712},[360,37875,37456],{"class":574},[360,37877,37459],{"class":381},[360,37879,671],{"class":366},[360,37881,36502],{"class":662},[360,37883,1358],{"class":366},[360,37885,37268],{"class":662},[360,37887,2697],{"class":366},[360,37889,2252],{"class":677},[360,37891,801],{"class":366},[360,37893,37894,37896,37898,37900,37902,37904],{"class":362,"line":331},[360,37895,37100],{"class":662},[360,37897,1358],{"class":366},[360,37899,37268],{"class":662},[360,37901,2697],{"class":366},[360,37903,37486],{"class":381},[360,37905,2204],{"class":366},[360,37907,37908],{"class":362,"line":762},[360,37909,37071],{"class":574},[360,37911,37912,37914,37916,37918,37920],{"class":362,"line":781},[360,37913,37100],{"class":366},[360,37915,1358],{"class":574},[360,37917,37268],{"class":366},[360,37919,24917],{"class":574},[360,37921,37505],{"class":366},[360,37923,37924],{"class":362,"line":804},[360,37925,1036],{"class":366},[12,37927,37928,37929,37931,37932,36012,37934,37936,37937,37942,37943,31],{},"Dans ce cas, avec l'utilisation d'un ",[344,37930,36502],{},", lorsque qu'il\nn'existera plus de référence vers l'objet A, le pointeur ",[105,37933,36498],{},[344,37935,47],{},"\nsera mis à jour comme ne contenant plus de référence",[15680,37938,37939],{},[47,37940,33034],{"href":33031,"ariaDescribedBy":37941,"dataFootnoteRef":291,"id":33033},[15686],".\nL'instance de l'objet A sera réellement détruite. Il n'y aura alors plus\naucune référence vers l'objet B qui sera alors également\ndétruit",[15680,37944,37945],{},[47,37946,33070],{"href":33067,"ariaDescribedBy":37947,"dataFootnoteRef":291,"id":33069},[15686],[23034,37949,37951],{"id":37950},"utilisation-dans-les-applications-multi-thread","Utilisation dans les applications multi-thread",[12,37953,7785,37954,37956,37957,854,37959,37961],{},[344,37955,36191],{}," simplifie l'écriture des applications\nmulti-thread (les objets ",[344,37958,36191],{},[344,37960,36502],{}," sont\nthread-safe).",[12,37963,37964,37965,37970,37971,31],{},"Dans ces applications il n'y a alors plus besoin de se soucier si\nl'objet est en cours d'utilisation ailleurs dans l'application avant de\nle supprimer",[15680,37966,37967],{},[47,37968,34316],{"href":34313,"ariaDescribedBy":37969,"dataFootnoteRef":291,"id":34315},[15686],". Lorsqu'un pointeur ne devient plus utilisé dans\nun thread donné, il ne sera détruit que s'il n'y a pas d'autres\nréférences dans d'autres threads de l'application",[15680,37972,37973],{},[47,37974,37978],{"href":37975,"ariaDescribedBy":37976,"dataFootnoteRef":291,"id":37977},"#user-content-fn-9",[15686],"user-content-fnref-9","9",[12,37980,37981,37982,37984,37985,31],{},"Avec l'utilisation de ",[344,37983,36502],{},", un thread pourra tester\nl'existence du pointeur avant d'effectuer une opération et pourra aviser\nle cas échéant sans faire planter toute l'application",[15680,37986,37987],{},[47,37988,30977],{"href":37989,"ariaDescribedBy":37990,"dataFootnoteRef":291,"id":37991},"#user-content-fn-10",[15686],"user-content-fnref-10",[23034,37993,37995],{"id":37994},"utilisation-dun-pool","Utilisation d'un pool",[12,37997,37998,37999,38004],{},"Si la création et la destruction d'un objet est coûteux, il est\nenvisageable de diminuer le coût de destruction et de création d'un\nthread en utilisant un Pool d'objet. Dans ce cas l'objet ",[47,38000,38003],{"href":38001,"rel":38002},"http:\u002F\u002Fdoc.qt.nokia.com\u002F4.6\u002Fqqueue.html",[51],"QQueue","\npourra être utilisé pour représenter notre Pool.",[12,38006,38007,38008,38010,38011,31],{},"Lors de la demande de création, en utilisant notre méthode ",[344,38009,9380],{},"\nci-dessus, on prend alors une valeur du pool (si disponible) et on la\nretourne sous forme d'un ",[344,38012,36191],{},[352,38014,38016],{"className":635,"code":38015,"language":637,"meta":291,"style":291},"QSharedPointer\u003CMyObject> MyObject::create()\n{\n    MyObject * c_ptr;\n    if (_queue.size())\n    {\n    c_ptr = _queue.dequeue();\n    }\n    else\n    {\n    c_ptr = new MyObject();\n    }\n    QSharedPointer\u003CMyObject> ptr(c_ptr, ReturnToPool);\n    ptr->_this = ptr.toWeakRef();\n    return ptr;\n}\n",[344,38017,38018,38036,38040,38050,38065,38069,38086,38090,38094,38098,38110,38114,38129,38147,38153],{"__ignoreMap":291},[360,38019,38020,38022,38024,38026,38028,38030,38032,38034],{"class":362,"line":363},[360,38021,36191],{"class":662},[360,38023,1358],{"class":366},[360,38025,36313],{"class":662},[360,38027,2697],{"class":366},[360,38029,36313],{"class":662},[360,38031,666],{"class":366},[360,38033,9380],{"class":381},[360,38035,5008],{"class":366},[360,38037,38038],{"class":362,"line":292},[360,38039,16340],{"class":366},[360,38041,38042,38045,38047],{"class":362,"line":375},[360,38043,38044],{"class":366},"    MyObject ",[360,38046,925],{"class":574},[360,38048,38049],{"class":366}," c_ptr;\n",[360,38051,38052,38054,38056,38059,38061,38063],{"class":362,"line":433},[360,38053,5657],{"class":574},[360,38055,743],{"class":366},[360,38057,38058],{"class":662},"_queue",[360,38060,31],{"class":366},[360,38062,6141],{"class":381},[360,38064,3492],{"class":366},[360,38066,38067],{"class":362,"line":478},[360,38068,16504],{"class":366},[360,38070,38071,38074,38076,38079,38081,38084],{"class":362,"line":483},[360,38072,38073],{"class":366},"    c_ptr ",[360,38075,583],{"class":574},[360,38077,38078],{"class":662}," _queue",[360,38080,31],{"class":366},[360,38082,38083],{"class":381},"dequeue",[360,38085,2204],{"class":366},[360,38087,38088],{"class":362,"line":489},[360,38089,2927],{"class":366},[360,38091,38092],{"class":362,"line":494},[360,38093,5702],{"class":574},[360,38095,38096],{"class":362,"line":712},[360,38097,16504],{"class":366},[360,38099,38100,38102,38104,38106,38108],{"class":362,"line":331},[360,38101,38073],{"class":366},[360,38103,583],{"class":574},[360,38105,3040],{"class":574},[360,38107,36325],{"class":381},[360,38109,2204],{"class":366},[360,38111,38112],{"class":362,"line":762},[360,38113,2927],{"class":366},[360,38115,38116,38118,38120,38122,38124,38126],{"class":362,"line":781},[360,38117,36308],{"class":366},[360,38119,1358],{"class":574},[360,38121,36313],{"class":366},[360,38123,24917],{"class":574},[360,38125,36318],{"class":381},[360,38127,38128],{"class":366},"(c_ptr, ReturnToPool);\n",[360,38130,38131,38133,38135,38137,38139,38141,38143,38145],{"class":362,"line":804},[360,38132,36443],{"class":662},[360,38134,2376],{"class":366},[360,38136,36955],{"class":578},[360,38138,401],{"class":574},[360,38140,36318],{"class":662},[360,38142,31],{"class":366},[360,38144,36530],{"class":381},[360,38146,2204],{"class":366},[360,38148,38149,38151],{"class":362,"line":817},[360,38150,1386],{"class":574},[360,38152,36475],{"class":366},[360,38154,38155],{"class":362,"line":823},[360,38156,847],{"class":366},[12,38158,38159,38160,38168,38169,38171],{},"Dans l'exemple ci-dessus",[15680,38161,38162],{},[47,38163,38167],{"href":38164,"ariaDescribedBy":38165,"dataFootnoteRef":291,"id":38166},"#user-content-fn-11",[15686],"user-content-fnref-11","11",", on demande à la queue, qui doit\nêtre une variable globale ou statique, un élément, et si ce n'est pas\npossible, on crée un nouvel objet de type ",[344,38170,36313],{}," (dont on suppose la\ncréation coûteuse).",[12,38173,38174,38175,38177,38178,38181,38182,38185,38186,38189],{},"Lors de la création du ",[344,38176,36191],{}," on utilise alors le constructeur\n",[344,38179,38180],{},"QSharedPointer ( T * ptr, Deleter deleter )"," sur lequel on définit une\nméthode ",[344,38183,38184],{},"Deleter"," nommée ",[344,38187,38188],{},"ReturnToPool"," dont le but est de remettre les\nobjets en pool.",[352,38191,38193],{"className":635,"code":38192,"language":637,"meta":291,"style":291},"static void ReturnToPool(MyObject *obj)\n{\n    if (_queue.size() \u003C MAX_SIZE_QUEUE)\n    {\n        _queue.enqueue(obj);\n    }\n    else\n    {\n        delete obj;\n    }\n}\n",[344,38194,38195,38214,38218,38237,38241,38254,38258,38262,38266,38273,38277],{"__ignoreMap":291},[360,38196,38197,38199,38201,38204,38206,38208,38210,38212],{"class":362,"line":363},[360,38198,5931],{"class":574},[360,38200,25066],{"class":574},[360,38202,38203],{"class":381}," ReturnToPool",[360,38205,671],{"class":366},[360,38207,36313],{"class":662},[360,38209,920],{"class":574},[360,38211,7502],{"class":677},[360,38213,2922],{"class":366},[360,38215,38216],{"class":362,"line":292},[360,38217,16340],{"class":366},[360,38219,38220,38222,38224,38226,38228,38230,38232,38234],{"class":362,"line":375},[360,38221,5657],{"class":574},[360,38223,743],{"class":366},[360,38225,38058],{"class":662},[360,38227,31],{"class":366},[360,38229,6141],{"class":381},[360,38231,2805],{"class":366},[360,38233,1358],{"class":574},[360,38235,38236],{"class":366}," MAX_SIZE_QUEUE)\n",[360,38238,38239],{"class":362,"line":433},[360,38240,16504],{"class":366},[360,38242,38243,38246,38248,38251],{"class":362,"line":478},[360,38244,38245],{"class":662},"        _queue",[360,38247,31],{"class":366},[360,38249,38250],{"class":381},"enqueue",[360,38252,38253],{"class":366},"(obj);\n",[360,38255,38256],{"class":362,"line":483},[360,38257,2927],{"class":366},[360,38259,38260],{"class":362,"line":489},[360,38261,5702],{"class":574},[360,38263,38264],{"class":362,"line":494},[360,38265,16504],{"class":366},[360,38267,38268,38271],{"class":362,"line":712},[360,38269,38270],{"class":574},"        delete",[360,38272,36881],{"class":366},[360,38274,38275],{"class":362,"line":331},[360,38276,2927],{"class":366},[360,38278,38279],{"class":362,"line":762},[360,38280,847],{"class":366},[12,38282,38283],{},"Dans ce cas de retour au pool, si le pool est rempli, on détruit l'objet\n(pour éviter de consommer trop de mémoire), sinon on l'ajoute au pool.\nDans ce cas, le pool est agrandi au fur et à mesure des besoins, jusqu'à\nune taille limite.",[12,38285,38286],{},"Bien sûr il faut que la performance de l'utilisation d'un pool soit plus\nintéressante que celle de la création de l'objet et de son\ninitialisation.",[12,38288,38289],{},[28,38290,38291,38295,38296,38298,38299,38301,38302,38304,38305,38307,38308,38310,38311,38313,38314],{},[38292,38293,38294],"ins",{},"Attention"," : Ce point ne fonctionne, par contre, pas si\nl'objet (",[344,38297,36313],{},") est un descendant de ",[344,38300,35361],{},". En effet ",[344,38303,35361],{},"\ngarde une référence du ",[344,38306,36191],{}," en mémoire et lors de la\nréutilisation du ",[344,38309,35361],{}," une erreur indique que l'objet n'a pas été\ndétruit et est déjà utilisé par un ",[344,38312,36191],{},". On n'a pas le\nproblème avec ",[344,38315,38316],{},"std::tr1::shared_ptr",[1901,38318,15285],{"id":15284},[12,38320,38321,38322,38324],{},"Le but du benchmark est de se faire une idée sur les performances d'une\napplication utilisant des ",[344,38323,36191],{}," à la place des pointeurs\nnormaux. Attention, ce bench ne prend pas en compte le besoin potentiel\nde Mutex, de comptage de référence manuel, ... dans les applications\nmulti-thread qui pourrait être nécessaire pour ne pas supprimer le\npointeur si besoin.",[12,38326,38327,38328,38330,38331,31],{},"Dans ce test nous allons tester également (en comparaison), le pointeur\n",[105,38329,36116],{}," du C++0x",[15680,38332,38333],{},[47,38334,38338],{"href":38335,"ariaDescribedBy":38336,"dataFootnoteRef":291,"id":38337},"#user-content-fn-12",[15686],"user-content-fnref-12","12",[12,38340,38341],{},"Nous allons donc tester les opérations courantes de création,\ndestruction, modification, affectation.",[23034,38343,38345],{"id":38344},"code-source","Code source",[12,38347,38348,38349,38352],{},"Le code source est disponible, attaché au billet. Dans la suite du\nbillet, seuls les morceaux intéressants du benchmark seront décris. Le\nbenchmark utilise QTest. Nous avons créé un objet bidon ",[344,38350,38351],{},"ObjetTest"," qui\ndans le constructeur allouera un pointeur et remplira une liste, et le\ndestructeur supprime ce pointeur (et forcément la liste).",[12,38354,38355],{},"Pour que chaque test soit indépendant, le jeu de test sera initialisé\navant le début de chaque QBENCHMARK et détruit à la fin du bloc. Nous\naurons quatre méthodes :",[140,38357,38358,38361,38364,38367],{},[143,38359,38360],{},"Allocation",[143,38362,38363],{},"Modification",[143,38365,38366],{},"Affectation",[143,38368,38369],{},"Nettoyage",[12,38371,38372],{},"Pour chaque test nous allons faire le test avec",[140,38374,38375,38378,38385],{},[143,38376,38377],{},"un pointeur C standard",[143,38379,38380,38381,35242,38383],{},"le pointeur ",[344,38382,36191],{},[105,38384,34783],{},[143,38386,38380,38387,35242,38389],{},[344,38388,38316],{},[105,38390,38391],{},"C++0x",[12,38393,38394],{},"Pour le test d'allocation et le test de nettoyage, nous allons également\nutiliser l'optimisation possible, vu ci-dessus, d'un Pool d'objet. Nous\nallons faire le test avec :",[140,38396,38397,38403],{},[143,38398,38380,38399,35242,38401],{},[344,38400,36191],{},[105,38402,34783],{},[143,38404,38380,38405,35242,38407],{},[344,38406,38316],{},[105,38408,38391],{},[23034,38410,38412],{"id":38411},"le-jeu-de-test","Le jeu de test",[29701,38414,38416],{"id":38415},"test-de-lallocation","Test de l'allocation",[12,38418,38419,38420,38422,38423,38425],{},"La création du pointeur en utilisant ",[344,38421,36191],{}," instancie le\npointeur ainsi que le ",[344,38424,36191],{},". Le temps d'exécution est donc\npotentiellement deux fois plus long (voir le benchmark à la fin de ce\nbillet).",[12,38427,38428],{},"Pour la création du pool, nous allons utiliser une méthode qui créera le\npointeur s'il n'est pas dans le pool, et sinon prendra le pointeur du\npool. Dans notre cas de test, il y aura toujours une valeur dans le\npool, que l'on aura rempli au préalable.",[12,38430,29024,38431,854,38434,38437],{},[344,38432,38433],{},"createFromPool()",[344,38435,38436],{},"createFromBoostPool()"," est\nsensiblement identique :",[352,38439,38441],{"className":635,"code":38440,"language":637,"meta":291,"style":291},"QSharedPointer\u003CObjetTest> createFromPool()\n{\n    ObjetTest * c_ptr;\n    if (_queue.size())\n    {\n        c_ptr = _queue.dequeue();\n    }\n    else\n    {\n        c_ptr = new ObjetTest();\n    }\n\n    QSharedPointer\u003CObjetTest> ptr(c_ptr, returnToPool);\n    return ptr;\n}\n",[344,38442,38443,38458,38462,38471,38485,38489,38504,38508,38512,38516,38529,38533,38537,38552,38558],{"__ignoreMap":291},[360,38444,38445,38447,38449,38451,38453,38456],{"class":362,"line":363},[360,38446,36191],{"class":662},[360,38448,1358],{"class":366},[360,38450,38351],{"class":662},[360,38452,2697],{"class":366},[360,38454,38455],{"class":381},"createFromPool",[360,38457,5008],{"class":366},[360,38459,38460],{"class":362,"line":292},[360,38461,16340],{"class":366},[360,38463,38464,38467,38469],{"class":362,"line":375},[360,38465,38466],{"class":366},"    ObjetTest ",[360,38468,925],{"class":574},[360,38470,38049],{"class":366},[360,38472,38473,38475,38477,38479,38481,38483],{"class":362,"line":433},[360,38474,5657],{"class":574},[360,38476,743],{"class":366},[360,38478,38058],{"class":662},[360,38480,31],{"class":366},[360,38482,6141],{"class":381},[360,38484,3492],{"class":366},[360,38486,38487],{"class":362,"line":478},[360,38488,16504],{"class":366},[360,38490,38491,38494,38496,38498,38500,38502],{"class":362,"line":483},[360,38492,38493],{"class":366},"        c_ptr ",[360,38495,583],{"class":574},[360,38497,38078],{"class":662},[360,38499,31],{"class":366},[360,38501,38083],{"class":381},[360,38503,2204],{"class":366},[360,38505,38506],{"class":362,"line":489},[360,38507,2927],{"class":366},[360,38509,38510],{"class":362,"line":494},[360,38511,5702],{"class":574},[360,38513,38514],{"class":362,"line":712},[360,38515,16504],{"class":366},[360,38517,38518,38520,38522,38524,38527],{"class":362,"line":331},[360,38519,38493],{"class":366},[360,38521,583],{"class":574},[360,38523,3040],{"class":574},[360,38525,38526],{"class":381}," ObjetTest",[360,38528,2204],{"class":366},[360,38530,38531],{"class":362,"line":762},[360,38532,2927],{"class":366},[360,38534,38535],{"class":362,"line":781},[360,38536,372],{"emptyLinePlaceholder":320},[360,38538,38539,38541,38543,38545,38547,38549],{"class":362,"line":804},[360,38540,36308],{"class":366},[360,38542,1358],{"class":574},[360,38544,38351],{"class":366},[360,38546,24917],{"class":574},[360,38548,36318],{"class":381},[360,38550,38551],{"class":366},"(c_ptr, returnToPool);\n",[360,38553,38554,38556],{"class":362,"line":817},[360,38555,1386],{"class":574},[360,38557,36475],{"class":366},[360,38559,38560],{"class":362,"line":823},[360,38561,847],{"class":366},[1545,38563,38564,38574],{},[1548,38565,38566],{},[1551,38567,38568,38571],{},[1554,38569,38570],{},"Méthode",[1554,38572,38573],{},"Code",[1567,38575,38576,38586,38596,38606,38616],{},[1551,38577,38578,38581],{},[1572,38579,38580],{},"C Pointer",[1572,38582,38583],{},[344,38584,38585],{},"ObjetTest* ptr = new ObjetTest();",[1551,38587,38588,38591],{},[1572,38589,38590],{},"Qt Smart Pointer",[1572,38592,38593],{},[344,38594,38595],{},"QSharedPointer\u003CObjetTest> ptr(new ObjetTest());",[1551,38597,38598,38601],{},[1572,38599,38600],{},"Qt Smart Pointer as Pool",[1572,38602,38603],{},[344,38604,38605],{},"QSharedPointer\u003CObjetTest> ptr = createFromPool ();",[1551,38607,38608,38611],{},[1572,38609,38610],{},"C++0x Smart Pointer",[1572,38612,38613],{},[344,38614,38615],{},"std::tr1::shared_ptr\u003CObjetTest> ptr(new ObjetTest());",[1551,38617,38618,38621],{},[1572,38619,38620],{},"C++0x Smart Pointer as Pool",[1572,38622,38623],{},[344,38624,38625],{},"std::tr1::shared_ptr\u003CObjetTest> ptr = createFromBoostPool ();",[29701,38627,38629],{"id":38628},"test-de-modification-dune-donnée","Test de Modification d'une donnée",[12,38631,38632],{},"Pour la modification d'une donnée, on génère un nombre aléatoire que\nl'on va stocker (toujours le même pour chaque test, cela n'a pas\nd'importance). La génération du nombre aléatoire se fait en dehors du\nbloc, pour éviter de polluer le test avec le calcul d'un nombre\naléatoire. Ici il n'y a pas création d'affectation du pointeur, juste\nune affectation d'une valeur dans le contenu du pointeur. La syntaxe\npour le C, et pour le pointeur intelligent est identique.",[1545,38634,38635,38643],{},[1548,38636,38637],{},[1551,38638,38639,38641],{},[1554,38640,38570],{},[1554,38642,38573],{},[1567,38644,38645],{},[1551,38646,38647,38650],{},[1572,38648,38649],{},"C Pointer \u002F Qt Smart Pointer \u002F C++0x Smart Pointer",[1572,38651,38652],{},[344,38653,38654],{},"obj->value = random_number;",[29701,38656,38658],{"id":38657},"test-daffectation","Test d'affectation",[12,38660,38661,38662,38664],{},"Pour l'affectation nous allons créer une nouvelle variable qui pointera\nsur le même pointeur, et sur lequel on fera une modification. La\ncréation d'un pointeur peut arriver par exemple lors du passage du\npointeur à une fonction, ou lors de la déclaration d'une variable devant\ncontenir la même valeur. Cette déclaration supplémentaire a peu d'impact\npour un pointeur C mais pour un pointeur ",[105,38663,36116],{}," oblige la\ncréation d'un objet, et l'incrément d'un nombre d'instance (qu'on\ndécrémente ici dans la même boucle).",[1545,38666,38667,38675],{},[1548,38668,38669],{},[1551,38670,38671,38673],{},[1554,38672,38570],{},[1554,38674,38573],{},[1567,38676,38677,38686,38695,38704,38712,38721],{},[1551,38678,38679,38681],{},[1572,38680,38580],{},[1572,38682,38683],{},[344,38684,38685],{},"ObjetTest * obj2 = obj;",[1551,38687,38688,38690],{},[1572,38689],{},[1572,38691,38692],{},[344,38693,38694],{},"obj2->value = random_number;",[1551,38696,38697,38699],{},[1572,38698,38590],{},[1572,38700,38701],{},[344,38702,38703],{},"QSharedPointer\u003CObjetTest> obj2 = obj;",[1551,38705,38706,38708],{},[1572,38707],{},[1572,38709,38710],{},[344,38711,38694],{},[1551,38713,38714,38716],{},[1572,38715,38610],{},[1572,38717,38718],{},[344,38719,38720],{},"std::tr1::shared_ptr\u003CObjetTest> obj2 = obj;",[1551,38722,38723,38725],{},[1572,38724],{},[1572,38726,38727],{},[344,38728,38694],{},[29701,38730,38732],{"id":38731},"test-de-destruction","Test de destruction",[12,38734,38735,38736,38738],{},"Pour ce test, nous allons initialiser une liste de pointeur, et pour le\nbenchmark, nous allons supprimer un à un chaque élément de la liste.La\ndestruction du pointeur en C se fait par un ",[344,38737,29597],{},". Pour le pointeur\n''intelligent', il n'y a pas de destruction explicite. Nous allons juste\nsupprimer le pointeur de la liste, le pointeur sera alors\nautomatiquement détruit car il n'y aura plus de référence vers ce\npointeur.",[12,38740,38741,38742,34886],{},"Pour le cas de test utilisant la notion du Pool, on aura créé le\npointeur avec le delete ",[344,38743,38744],{},"returnToPool()",[352,38746,38748],{"className":635,"code":38747,"language":637,"meta":291,"style":291},"void returnToPool(ObjetTest *obj)\n{\n    _queue.enqueue(obj);\n}\n",[344,38749,38750,38767,38771,38782],{"__ignoreMap":291},[360,38751,38752,38754,38757,38759,38761,38763,38765],{"class":362,"line":363},[360,38753,36417],{"class":574},[360,38755,38756],{"class":381}," returnToPool",[360,38758,671],{"class":366},[360,38760,38351],{"class":662},[360,38762,920],{"class":574},[360,38764,7502],{"class":677},[360,38766,2922],{"class":366},[360,38768,38769],{"class":362,"line":292},[360,38770,16340],{"class":366},[360,38772,38773,38776,38778,38780],{"class":362,"line":375},[360,38774,38775],{"class":662},"    _queue",[360,38777,31],{"class":366},[360,38779,38250],{"class":381},[360,38781,38253],{"class":366},[360,38783,38784],{"class":362,"line":433},[360,38785,847],{"class":366},[12,38787,38788],{},"Cette méthode ne fait pas de réelle destruction, mais juste un ajout de\nl'objet au pool.",[1545,38790,38791,38799],{},[1548,38792,38793],{},[1551,38794,38795,38797],{},[1554,38796,38570],{},[1554,38798,38573],{},[1567,38800,38801,38810,38819,38828,38834,38840],{},[1551,38802,38803,38805],{},[1572,38804,38580],{},[1572,38806,38807],{},[344,38808,38809],{},"delete c_ptr_list.at(0);",[1551,38811,38812,38814],{},[1572,38813],{},[1572,38815,38816],{},[344,38817,38818],{},"c_ptr_list.removeFirst ();",[1551,38820,38821,38823],{},[1572,38822,38590],{},[1572,38824,38825],{},[344,38826,38827],{},"smart_ptr_list.removeFirst ();",[1551,38829,38830,38832],{},[1572,38831,38600],{},[1572,38833],{},[1551,38835,38836,38838],{},[1572,38837,38610],{},[1572,38839],{},[1551,38841,38842,38844],{},[1572,38843,38620],{},[1572,38845],{},[29701,38847,38849],{"id":38848},"résultat-du-test","Résultat du test",[12,38851,38852],{},"Le test a été fait en utilisant la version 4.6.3 de Qt. Test effectué\npour 5 000 000 itérations.",[1545,38854,38855,38876],{},[1548,38856,38857],{},[1551,38858,38859,38861,38864,38867,38870,38873],{},[1554,38860],{},[1554,38862,38863],{},"Pointeur C",[1554,38865,38866],{},"Pointeur Qt",[1554,38868,38869],{},"Pointeur C++0x",[1554,38871,38872],{},"Pool en utilisant QSharedPointer",[1554,38874,38875],{},"Pool en utilisant std::tr1::shared_ptr",[1567,38877,38878,38899,38917,38935],{},[1551,38879,38880,38884,38887,38890,38893,38896],{},[1572,38881,38882],{},[344,38883,38360],{},[1572,38885,38886],{},"0.0004275 msec",[1572,38888,38889],{},"0.0007692 msec",[1572,38891,38892],{},"0.0006604 msec",[1572,38894,38895],{},"0.0002590 msec",[1572,38897,38898],{},"0.0002286 msec",[1551,38900,38901,38905,38908,38911,38913,38915],{},[1572,38902,38903],{},[344,38904,38363],{},[1572,38906,38907],{},"0.000010 msec",[1572,38909,38910],{},"0.000012 msec",[1572,38912,38910],{},[1572,38914],{},[1572,38916],{},[1551,38918,38919,38923,38925,38928,38931,38933],{},[1572,38920,38921],{},[344,38922,38366],{},[1572,38924,38907],{},[1572,38926,38927],{},"0.0000386 msec",[1572,38929,38930],{},"0.0000230 msec",[1572,38932],{},[1572,38934],{},[1551,38936,38937,38942,38945,38948,38951,38954],{},[1572,38938,38939],{},[344,38940,38941],{},"Destruction",[1572,38943,38944],{},"0.000190 msec",[1572,38946,38947],{},"0.0003161 msec",[1572,38949,38950],{},"0.0003359 msec",[1572,38952,38953],{},"0.0004003 msec",[1572,38955,38956],{},"0.0003601 msec",[12,38958,38959,38960,38962],{},"Conclusion que l'on peut en tirer, le pointeur C est ce qu'il y a de\nplus rapide à partir du moment où on fait de l'allocation de\nl'affectation ou de la destruction. Par contre il n'apporte pas la\nsouplesse qu'apporte les pointeurs ",[105,38961,36136],{}," entre autre pour les\napplications multi-threadé.",[12,38964,38965],{},"On remarque que le pointeur C++0x est plus rapide pour la création, mais\napparemment plus lent en destruction. Il est également possible avec le\npool de gagner en performance (surtout en création). Par contre le coût\nde destruction de l'objet n'est pas encore assez fort pour y gagner en\nutilisant le pool.",[12,38967,38968],{},"Ensuite il est important de se faire son propre jugement selon ses\nbesoins. Si besoin le source est attaché, vous pouvez faire vos propres\ntests.",[29701,38970,38972],{"id":38971},"source-du-test","Source du test",[12,38974,38975,38976,31],{},"Vous pouvez trouver les sources du test au ",[47,38977,38979],{"href":38978},"\u002FProgrammation\u002Fqt-performance-de-l-utilisation-de-qsharedpointer\u002Fsmart_benchmark.7z","lien suivant",[12,38981,38982,38987,38988,38993,38994,31],{},[47,38983,38986],{"href":38984,"rel":38985},"http:\u002F\u002Fwww.boost.org\u002Fdoc\u002Flibs\u002F1_45_0\u002Flibs\u002Fsmart_ptr\u002Fshared_ptr.htm",[51],"boost::shared_ptr"," du projet ",[47,38989,38992],{"href":38990,"rel":38991},"http:\u002F\u002Fwww.boost.org\u002F",[51],"Boost",". Boost est une librairie qui\najoute beaucoup de facilité pour les programmes en C++, comme par\nexemple les smart-pointer dont certains seront inclus dans C++0x, ou de\nla boucle ",[344,38995,38996],{},"std::for_each",[21499,38998,39000,39003],{"className":38999,"dataFootnotes":291},[21502],[33,39001,21507],{"className":39002,"id":15686},[21506],[13835,39004,39005,39011,39017,39025,39041,39047,39056,39062,39071,39080,39094,39103],{},[143,39006,39007,39008],{"id":21512},"en anglais : smart-pointer ",[47,39009,21520],{"href":21516,"ariaLabel":21517,"className":39010,"dataFootnoteBackref":291},[21519],[143,39012,39013,39014],{"id":21523},"COW = Copy On Write ",[47,39015,21520],{"href":21531,"ariaLabel":21532,"className":39016,"dataFootnoteBackref":291},[21519],[143,39018,39019,39020,36012,39022],{"id":34644},"Ce pointeur est l'équivalent du pointeur ",[105,39021,36116],{},[47,39023,21520],{"href":34648,"ariaLabel":30513,"className":39024,"dataFootnoteBackref":291},[21519],[143,39026,39027,39028,39031,39032,39034,39035,39037,39038],{"id":34652},"Si à un moment donné il faut utiliser le pointeur C pour une\nraison quelconque, on peut utiliser ",[344,39029,39030],{},"ptr.data()"," mais il faut s'assurer\nque le pointeur ne sera pas détruit en déclarant un ",[344,39033,36191],{},"\ndans le même bloc utilisant le pointeur C. Le ",[344,39036,36191],{}," ne devra\nêtre détruit qu'après utilisation du pointeur C. Ceci peut être fait\ndans certain cas pour des raisons de performance. ",[47,39039,21520],{"href":34656,"ariaLabel":34657,"className":39040,"dataFootnoteBackref":291},[21519],[143,39042,39043,39044],{"id":34661},"Sinon nous ne serions plus là pour lancer la méthode ",[47,39045,21520],{"href":34669,"ariaLabel":34670,"className":39046,"dataFootnoteBackref":291},[21519],[143,39048,21790,39049,39052,39053],{"id":34674},[344,39050,39051],{},"QWeakPointeur"," ne gardant pas d'instance d'objet, car il\nn'incrémente pas le compteur de référence ",[47,39054,21520],{"href":34678,"ariaLabel":34679,"className":39055,"dataFootnoteBackref":291},[21519],[143,39057,39058,39059],{"id":34683},"s'il n'existe pas de référence vers l'objet B ailleurs dans\nl'application ",[47,39060,21520],{"href":34687,"ariaLabel":34688,"className":39061,"dataFootnoteBackref":291},[21519],[143,39063,39064,39065,39067,39068],{"id":34692},"Attention quand même, ",[344,39066,36191],{}," protège le pointeur\nmais pas le contenu ",[47,39069,21520],{"href":34701,"ariaLabel":34702,"className":39070,"dataFootnoteBackref":291},[21519],[143,39072,39074,39075],{"id":39073},"user-content-fn-9","d'autres threads pouvant inclure le thread principal ",[47,39076,21520],{"href":39077,"ariaLabel":39078,"className":39079,"dataFootnoteBackref":291},"#user-content-fnref-9","Back to reference 9",[21519],[143,39081,39083,39084,39086,39087,36012,39089],{"id":39082},"user-content-fn-10","Si l'objet est supprimé, ",[344,39085,36502],{},", sera alors remis à\n",[344,39088,16849],{},[47,39090,21520],{"href":39091,"ariaLabel":39092,"className":39093,"dataFootnoteBackref":291},"#user-content-fnref-10","Back to reference 10",[21519],[143,39095,39097,39098],{"id":39096},"user-content-fn-11","Dans le code en question, il faudrait ajouter la notion de\nmutex autour de la gestion de la queue, en cas de création parallèle. ",[47,39099,21520],{"href":39100,"ariaLabel":39101,"className":39102,"dataFootnoteBackref":291},"#user-content-fnref-11","Back to reference 11",[21519],[143,39104,39106,39107,36012,39109,39112,39113],{"id":39105},"user-content-fn-12","Le pointeur ",[105,39108,36116],{},[344,39110,39111],{},"shared_ptr"," de C++0x à pour origine\nle pointeur Boost ",[47,39114,21520],{"href":39115,"ariaLabel":39116,"className":39117,"dataFootnoteBackref":291},"#user-content-fnref-12","Back to reference 12",[21519],[1613,39119,39120],{},"html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}",{"title":291,"searchDepth":292,"depth":292,"links":39122},[39123,39124,39125,39126,39127],{"id":36098,"depth":375,"text":36099},{"id":36201,"depth":375,"text":36202},{"id":36205,"depth":375,"text":36206},{"id":15284,"depth":375,"text":15285},{"id":15686,"depth":292,"text":21507},"2011-01-25",{"type":9,"value":39130},[39131,39133,39139,39154,39160],[1901,39132,36099],{"id":36098},[12,39134,39135,36104,39137,36108],{},[105,39136,34783],{},[105,39138,36107],{},[12,39140,39141,36113,39143,39145,36122,39150,36125,39152,36128],{},[105,39142,34783],{},[105,39144,36116],{},[15680,39146,39147],{},[47,39148,1944],{"href":15684,"ariaDescribedBy":39149,"dataFootnoteRef":291,"id":15687},[15686],[105,39151,36116],{},[105,39153,34783],{},[12,39155,39156,36133,39158,36137],{},[105,39157,34783],{},[105,39159,36136],{},[140,39161,39162,39177,39187,39192],{},[143,39163,39164,36147,39167,36153,39170,36157,39172,31],{},[47,39165,36146],{"href":36144,"rel":39166},[51],[47,39168,36152],{"href":36150,"rel":39169},[51],[105,39171,36156],{},[15680,39173,39174],{},[47,39175,795],{"href":16257,"ariaDescribedBy":39176,"dataFootnoteRef":291,"id":16259},[15686],[143,39178,39179,36147,39182,36173,39185,36176],{},[47,39180,36169],{"href":36167,"rel":39181},[51],[47,39183,36152],{"href":36150,"rel":39184},[51],[105,39186,36116],{},[143,39188,39189,36184],{},[47,39190,36183],{"href":36181,"rel":39191},[51],[143,39193,39194,36192,39197,36198],{},[47,39195,36191],{"href":36189,"rel":39196},[51],[15680,39198,39199],{},[47,39200,1954],{"href":32973,"ariaDescribedBy":39201,"dataFootnoteRef":291,"id":32975},[15686],{},"\u002Fpost\u002Fqt-performance-de-l-utilisation-de-qsharedpointer",{"title":36093,"description":291},"qt-performance-de-l-utilisation-de-qsharedpointer","posts\u002FProgrammation\u002F2011-01-25-qt-performance-de-l-utilisation-de-qsharedpointer",[39208,39209,32924],"kde","performance","XqeYjPQRtPf9XXPuxti7oBEPUUnQd2DT_XGvWB1Y7Ws",{"id":39212,"title":39213,"author":7,"body":39214,"category":300,"categorySlug":301,"date":40403,"description":291,"excerpt":40404,"extension":317,"location":318,"meta":40416,"navigation":320,"path":40417,"published":320,"seo":40418,"slug":40419,"stem":40420,"tags":40421,"timeToRead":478,"__hash__":40422},"posts\u002Fposts\u002FProgrammation\u002F2010-12-22-qt-concatenation-de-chaine-de-caracteres.md","C++\u002FQt - Concaténation de chaînes de caractères",{"type":9,"value":39215,"toc":40396},[39216,39218,39221,39224,39227,39230,39234,39240,39296,39305,39308,39312,39319,39331,39337,39399,39408,39417,39479,39481,39490,39492,39500,40350,40352,40355,40377,40380,40383,40387,40393],[1901,39217,36099],{"id":36098},[12,39219,39220],{},"Qt est un framework orienté objet écrit en C++ et permettant de faire\ndes interfaces graphiques à l’aide de ces widgets. Ce framework est\nutilisé par le projet KDE depuis ses débuts pour en faire un\nenvironnement très complet.",[12,39222,39223],{},"Qt permet donc de faire des interfaces graphiques mais aussi d’accéder à\ndes bases de données SQL, de faire de la communication réseau, une\ngestion simplifiée des threads, la lecture de fichier XML. Qt intègre\naussi le moteur HTML Webkit.",[12,39225,39226],{},"Qt ajoute une couche supplémentaire au C++ permettant de faire de\nl’introspection de classe un peu plus poussée (comme l’appel d’une\nméthode dont on ne connaît le nom qu’à l’exécution). Qt permet également\nla gestion d’évènement par l’intermédiaire d’un système puissant de\nSIGNALS et de SLOTS.",[12,39228,39229],{},"Dans la suite de cet article nous allons nous concentrer sur une très\npetite partie de Qt mais qui est utilisée dans beaucoup d’applications\nécrites en Qt : les chaînes de caractères, et plus précisément, la\nconcaténation de chaînes de caractères.",[33,39231,39233],{"id":39232},"concaténation-de-chaînes-de-caractères","Concaténation de chaînes de caractères",[12,39235,39236,39237,39239],{},"Comme dans d’autres langages, la concaténation de chaînes de caractères\nse fait à l'aide de l'opérateur ",[344,39238,1310],{},". Prenons un exemple simple :",[352,39241,39243],{"className":635,"code":39242,"language":637,"meta":291,"style":291},"#include \u003CQString>\n\nQString abc = \"abc\", def = \"def\";\nQString result;\nresult = abc + def;\n",[344,39244,39245,39252,39256,39276,39281],{"__ignoreMap":291},[360,39246,39247,39249],{"class":362,"line":363},[360,39248,33204],{"class":574},[360,39250,39251],{"class":397}," \u003CQString>\n",[360,39253,39254],{"class":362,"line":292},[360,39255,372],{"emptyLinePlaceholder":320},[360,39257,39258,39261,39263,39266,39269,39271,39274],{"class":362,"line":375},[360,39259,39260],{"class":366},"QString abc ",[360,39262,583],{"class":574},[360,39264,39265],{"class":397}," \"abc\"",[360,39267,39268],{"class":366},", def ",[360,39270,583],{"class":574},[360,39272,39273],{"class":397}," \"def\"",[360,39275,735],{"class":366},[360,39277,39278],{"class":362,"line":433},[360,39279,39280],{"class":366},"QString result;\n",[360,39282,39283,39286,39288,39291,39293],{"class":362,"line":478},[360,39284,39285],{"class":366},"result ",[360,39287,583],{"class":574},[360,39289,39290],{"class":366}," abc ",[360,39292,1310],{"class":574},[360,39294,39295],{"class":366}," def;\n",[12,39297,39298,39299,39301,39302,39304],{},"L'utilisation de l'opérateur ",[344,39300,1310],{}," facilite l'écriture de la concaténation\ndes chaînes de caractères (tout comme l'opérateur ",[344,39303,2393],{}," permet de\nfacilement comparer des chaînes de caractères de type QString).",[12,39306,39307],{},"Malheureusement cette écriture rend le code peu performant pour diverses\nraisons (que l’on peut retrouver dans la documentation de l’objet\nQString).",[1901,39309,39311],{"id":39310},"concaténation-rapide-de-chaînes-de-caractères","Concaténation rapide de chaînes de caractères",[12,39313,39314,39315,39318],{},"A partir de Qt 4.6, Nokia, a ajouté un ",[344,39316,39317],{},"template"," nommé QStringBuilder\n(cet objet fait beaucoup penser à l'objet StringBuilder de JAVA\npermettant d'accélérer les concaténations de chaînes de caractères).",[12,39320,39321,39322,39325,39326,36772,39328,39330],{},"Ce template ne s’utilise pas directement mais au travers de l'opérateur\n",[344,39323,39324],{},"%",". En remplaçant donc l'opérateur ",[344,39327,1310],{},[344,39329,39324],{}," on gagne en performance\n(dixit la doc de Qt).",[12,39332,39333,39334,34886],{},"Pour pouvoir utiliser l'opérateur, il suffit d'inclure le fichier\n",[344,39335,39336],{},"QStringBuilder",[352,39338,39340],{"className":635,"code":39339,"language":637,"meta":291,"style":291},"#include \u003CQStringBuilder>\n\nQString abc = \"abc\", def = \"def\", ghi = \"ghi\";\nQString result;\nresult = abc % def % ghi;\n",[344,39341,39342,39349,39353,39377,39381],{"__ignoreMap":291},[360,39343,39344,39346],{"class":362,"line":363},[360,39345,33204],{"class":574},[360,39347,39348],{"class":397}," \u003CQStringBuilder>\n",[360,39350,39351],{"class":362,"line":292},[360,39352,372],{"emptyLinePlaceholder":320},[360,39354,39355,39357,39359,39361,39363,39365,39367,39370,39372,39375],{"class":362,"line":375},[360,39356,39260],{"class":366},[360,39358,583],{"class":574},[360,39360,39265],{"class":397},[360,39362,39268],{"class":366},[360,39364,583],{"class":574},[360,39366,39273],{"class":397},[360,39368,39369],{"class":366},", ghi ",[360,39371,583],{"class":574},[360,39373,39374],{"class":397}," \"ghi\"",[360,39376,735],{"class":366},[360,39378,39379],{"class":362,"line":433},[360,39380,39280],{"class":366},[360,39382,39383,39385,39387,39389,39391,39394,39396],{"class":362,"line":478},[360,39384,39285],{"class":366},[360,39386,583],{"class":574},[360,39388,39290],{"class":366},[360,39390,39324],{"class":574},[360,39392,39393],{"class":366}," def ",[360,39395,39324],{"class":574},[360,39397,39398],{"class":366}," ghi;\n",[12,39400,39401,39402,29886,39405,31],{},"Une autre possibilité est de définir (par exemple dans votre fichier\n.pro ou dans un include général de votre application) les définitions\n",[344,39403,39404],{},"QT_USE_FAST_CONCATENATION",[344,39406,39407],{},"QT_USE_FAST_OPERATOR_PLUS",[12,39409,39410,39411,39413,39414,39416],{},"Ces définitions permettent de remplacer l'opérateur ",[344,39412,1310],{}," par l'opérateur\n",[344,39415,39324],{}," dans toute l'application. Par contre cette opération peut demander\nquelques modifications de votre code.",[352,39418,39420],{"className":635,"code":39419,"language":637,"meta":291,"style":291},"#define QT_USE_FAST_CONCATENATION\n#define QT_USE_FAST_OPERATOR_PLUS\n#include \u003CQString>\n\nQString abc = \"abc\", def = \"def\";\nQString result;\nresult = abc + def;\n",[344,39421,39422,39430,39437,39443,39447,39463,39467],{"__ignoreMap":291},[360,39423,39424,39427],{"class":362,"line":363},[360,39425,39426],{"class":574},"#define",[360,39428,39429],{"class":381}," QT_USE_FAST_CONCATENATION\n",[360,39431,39432,39434],{"class":362,"line":292},[360,39433,39426],{"class":574},[360,39435,39436],{"class":381}," QT_USE_FAST_OPERATOR_PLUS\n",[360,39438,39439,39441],{"class":362,"line":375},[360,39440,33204],{"class":574},[360,39442,39251],{"class":397},[360,39444,39445],{"class":362,"line":433},[360,39446,372],{"emptyLinePlaceholder":320},[360,39448,39449,39451,39453,39455,39457,39459,39461],{"class":362,"line":478},[360,39450,39260],{"class":366},[360,39452,583],{"class":574},[360,39454,39265],{"class":397},[360,39456,39268],{"class":366},[360,39458,583],{"class":574},[360,39460,39273],{"class":397},[360,39462,735],{"class":366},[360,39464,39465],{"class":362,"line":483},[360,39466,39280],{"class":366},[360,39468,39469,39471,39473,39475,39477],{"class":362,"line":489},[360,39470,39285],{"class":366},[360,39472,583],{"class":574},[360,39474,39290],{"class":366},[360,39476,1310],{"class":574},[360,39478,39295],{"class":366},[1901,39480,15285],{"id":15284},[12,39482,39483,39484,39486,39487,39489],{},"Nous allons donc dans la suite du document vérifier que l'opérateur ",[344,39485,39324],{},"\nest plus rapide que l'opérateur ",[344,39488,1310],{},". Pour cela nous allons utiliser le\nmodule de benchmark de Qt.",[23034,39491,38345],{"id":38344},[12,39493,39494,39495,39497,39498,31],{},"Voici le petit programme permettant de tester la performance de la\nconcaténation. Notre exemple simple va constituer à la concaténation de\n26 chaînes de caractères créées au début. L'appel se fera une première\nfois en utilisant l'opérateur ",[344,39496,1310],{}," et une seconde fois en utilisant\nl'opérateur ",[344,39499,39324],{},[352,39501,39503],{"className":635,"code":39502,"language":637,"meta":291,"style":291},"#include \u003CQtCore\u002FQString>\n#include \u003CQtTest\u002FQtTest>\n#include \u003CQStringBuilder>\n\nclass TestPerf : public QObject\n{\n    Q_OBJECT\npublic:\n    TestPerf();\nprivate Q_SLOTS:\n    void concat();\n    void concat_data();\n};\n\nTestPerf::TestPerf()\n{\n} \n\nvoid TestPerf::concat()\n{\n    QFETCH(bool, useStringBuilder);\n    QString result;\n    QString a(\"a\"), b(\"b\"), c(\"c\"), d(\"d\"), e(\"e\"), f(\"f\"), g(\"g\"),\n    h(\"h\"), i(\"i\"), j(\"j\"), k(\"k\"), l(\"l\"), m(\"m\"), n(\"n\"), o(\"o\"),\n    p(\"p\"), q(\"q\"), r(\"r\"), s(\"s\"), t(\"t\"), u(\"u\"), v(\"v\"), w(\"w\"),\n    x(\"x\"), y(\"y\"), z(\"z\"); \n\n    if (useStringBuilder)\n    {\n        QBENCHMARK {\n            \u002F\u002F Concaténation en utilisant QStringBuilder\n            \u002F\u002F Dans ce cas la concaténation devrait être plus rapide\n            result = a % b % c % d % e % f % g % h % i % j % k % l %\n            m % n % o % p % q % r % s % t % u % v % w % x % y % z;\n        }\n    }\n    else\n    {\n        QBENCHMARK\n        {\n            \u002F\u002F Concaténation en n'utilisant pas QStringBuilder. On\n            \u002F\u002F utilise alors la concaténation normal de chaînes de\n            \u002F\u002F caractères en utilisant QString\n            result = a + b + c + d + e + f + g + h + i + j + k + l +\n            m + n + o + p + q + r + s + t + u + v + w + x + y + z;\n        }\n    }\n}\n\nvoid TestPerf::concat_data()\n{\n    QTest::addColumn\u003Cbool>(\"useStringBuilder\");\n    QTest::newRow(\"Don't use QStringBuilder\") \u003C\u003C false;\n    QTest::newRow(\"Use QStringBuilder\") \u003C\u003C true;\n}\n\nQTEST_APPLESS_MAIN(TestPerf);\n\n#include \"tst_testperf.moc\"\n",[344,39504,39505,39512,39519,39525,39529,39544,39548,39553,39557,39564,39569,39578,39587,39591,39595,39606,39610,39615,39619,39632,39636,39648,39653,39722,39802,39883,39915,39919,39926,39930,39935,39940,39945,40012,40081,40085,40089,40093,40097,40102,40106,40111,40116,40121,40176,40232,40236,40240,40244,40248,40261,40265,40284,40304,40323,40327,40331,40339,40343],{"__ignoreMap":291},[360,39506,39507,39509],{"class":362,"line":363},[360,39508,33204],{"class":574},[360,39510,39511],{"class":397}," \u003CQtCore\u002FQString>\n",[360,39513,39514,39516],{"class":362,"line":292},[360,39515,33204],{"class":574},[360,39517,39518],{"class":397}," \u003CQtTest\u002FQtTest>\n",[360,39520,39521,39523],{"class":362,"line":375},[360,39522,33204],{"class":574},[360,39524,39348],{"class":397},[360,39526,39527],{"class":362,"line":433},[360,39528,372],{"emptyLinePlaceholder":320},[360,39530,39531,39533,39536,39539,39541],{"class":362,"line":478},[360,39532,18818],{"class":574},[360,39534,39535],{"class":662}," TestPerf",[360,39537,39538],{"class":366}," : ",[360,39540,30609],{"class":574},[360,39542,39543],{"class":662}," QObject\n",[360,39545,39546],{"class":362,"line":483},[360,39547,16340],{"class":366},[360,39549,39550],{"class":362,"line":489},[360,39551,39552],{"class":366},"    Q_OBJECT\n",[360,39554,39555],{"class":362,"line":494},[360,39556,36988],{"class":574},[360,39558,39559,39562],{"class":362,"line":712},[360,39560,39561],{"class":381},"    TestPerf",[360,39563,2204],{"class":366},[360,39565,39566],{"class":362,"line":331},[360,39567,39568],{"class":366},"private Q_SLOTS:\n",[360,39570,39571,39573,39576],{"class":362,"line":762},[360,39572,37456],{"class":574},[360,39574,39575],{"class":381}," concat",[360,39577,2204],{"class":366},[360,39579,39580,39582,39585],{"class":362,"line":781},[360,39581,37456],{"class":574},[360,39583,39584],{"class":381}," concat_data",[360,39586,2204],{"class":366},[360,39588,39589],{"class":362,"line":804},[360,39590,1036],{"class":366},[360,39592,39593],{"class":362,"line":817},[360,39594,372],{"emptyLinePlaceholder":320},[360,39596,39597,39600,39602,39604],{"class":362,"line":823},[360,39598,39599],{"class":662},"TestPerf",[360,39601,666],{"class":366},[360,39603,39599],{"class":381},[360,39605,5008],{"class":366},[360,39607,39608],{"class":362,"line":844},[360,39609,16340],{"class":366},[360,39611,39612],{"class":362,"line":1441},[360,39613,39614],{"class":366},"} \n",[360,39616,39617],{"class":362,"line":1462},[360,39618,372],{"emptyLinePlaceholder":320},[360,39620,39621,39623,39625,39627,39630],{"class":362,"line":1485},[360,39622,36417],{"class":574},[360,39624,39535],{"class":662},[360,39626,666],{"class":366},[360,39628,39629],{"class":381},"concat",[360,39631,5008],{"class":366},[360,39633,39634],{"class":362,"line":1497},[360,39635,16340],{"class":366},[360,39637,39638,39641,39643,39645],{"class":362,"line":3161},[360,39639,39640],{"class":381},"    QFETCH",[360,39642,671],{"class":366},[360,39644,2978],{"class":574},[360,39646,39647],{"class":366},", useStringBuilder);\n",[360,39649,39650],{"class":362,"line":3167},[360,39651,39652],{"class":366},"    QString result;\n",[360,39654,39655,39658,39660,39662,39665,39667,39669,39671,39674,39676,39678,39680,39683,39685,39687,39689,39692,39694,39696,39698,39701,39703,39705,39707,39710,39712,39715,39717,39720],{"class":362,"line":3194},[360,39656,39657],{"class":366},"    QString ",[360,39659,47],{"class":381},[360,39661,671],{"class":366},[360,39663,39664],{"class":397},"\"a\"",[360,39666,6775],{"class":366},[360,39668,2252],{"class":381},[360,39670,671],{"class":366},[360,39672,39673],{"class":397},"\"b\"",[360,39675,6775],{"class":366},[360,39677,2358],{"class":381},[360,39679,671],{"class":366},[360,39681,39682],{"class":397},"\"c\"",[360,39684,6775],{"class":366},[360,39686,25435],{"class":381},[360,39688,671],{"class":366},[360,39690,39691],{"class":397},"\"d\"",[360,39693,6775],{"class":366},[360,39695,3864],{"class":381},[360,39697,671],{"class":366},[360,39699,39700],{"class":397},"\"e\"",[360,39702,6775],{"class":366},[360,39704,2226],{"class":381},[360,39706,671],{"class":366},[360,39708,39709],{"class":397},"\"f\"",[360,39711,6775],{"class":366},[360,39713,39714],{"class":381},"g",[360,39716,671],{"class":366},[360,39718,39719],{"class":397},"\"g\"",[360,39721,5405],{"class":366},[360,39723,39724,39727,39729,39732,39734,39736,39738,39741,39743,39746,39748,39751,39753,39756,39758,39761,39763,39766,39768,39771,39773,39776,39778,39781,39783,39785,39787,39790,39792,39795,39797,39800],{"class":362,"line":3224},[360,39725,39726],{"class":381},"    h",[360,39728,671],{"class":366},[360,39730,39731],{"class":397},"\"h\"",[360,39733,6775],{"class":366},[360,39735,6187],{"class":381},[360,39737,671],{"class":366},[360,39739,39740],{"class":397},"\"i\"",[360,39742,6775],{"class":366},[360,39744,39745],{"class":381},"j",[360,39747,671],{"class":366},[360,39749,39750],{"class":397},"\"j\"",[360,39752,6775],{"class":366},[360,39754,39755],{"class":381},"k",[360,39757,671],{"class":366},[360,39759,39760],{"class":397},"\"k\"",[360,39762,6775],{"class":366},[360,39764,39765],{"class":381},"l",[360,39767,671],{"class":366},[360,39769,39770],{"class":397},"\"l\"",[360,39772,6775],{"class":366},[360,39774,39775],{"class":381},"m",[360,39777,671],{"class":366},[360,39779,39780],{"class":397},"\"m\"",[360,39782,6775],{"class":366},[360,39784,7702],{"class":381},[360,39786,671],{"class":366},[360,39788,39789],{"class":397},"\"n\"",[360,39791,6775],{"class":366},[360,39793,39794],{"class":381},"o",[360,39796,671],{"class":366},[360,39798,39799],{"class":397},"\"o\"",[360,39801,5405],{"class":366},[360,39803,39804,39807,39809,39812,39814,39817,39819,39822,39824,39827,39829,39832,39834,39837,39839,39842,39844,39847,39849,39852,39854,39856,39858,39861,39863,39866,39868,39871,39873,39876,39878,39881],{"class":362,"line":3239},[360,39805,39806],{"class":381},"    p",[360,39808,671],{"class":366},[360,39810,39811],{"class":397},"\"p\"",[360,39813,6775],{"class":366},[360,39815,39816],{"class":381},"q",[360,39818,671],{"class":366},[360,39820,39821],{"class":397},"\"q\"",[360,39823,6775],{"class":366},[360,39825,39826],{"class":381},"r",[360,39828,671],{"class":366},[360,39830,39831],{"class":397},"\"r\"",[360,39833,6775],{"class":366},[360,39835,39836],{"class":381},"s",[360,39838,671],{"class":366},[360,39840,39841],{"class":397},"\"s\"",[360,39843,6775],{"class":366},[360,39845,39846],{"class":381},"t",[360,39848,671],{"class":366},[360,39850,39851],{"class":397},"\"t\"",[360,39853,6775],{"class":366},[360,39855,798],{"class":381},[360,39857,671],{"class":366},[360,39859,39860],{"class":397},"\"u\"",[360,39862,6775],{"class":366},[360,39864,39865],{"class":381},"v",[360,39867,671],{"class":366},[360,39869,39870],{"class":397},"\"v\"",[360,39872,6775],{"class":366},[360,39874,39875],{"class":381},"w",[360,39877,671],{"class":366},[360,39879,39880],{"class":397},"\"w\"",[360,39882,5405],{"class":366},[360,39884,39885,39888,39890,39893,39895,39898,39900,39903,39905,39908,39910,39912],{"class":362,"line":3256},[360,39886,39887],{"class":381},"    x",[360,39889,671],{"class":366},[360,39891,39892],{"class":397},"\"x\"",[360,39894,6775],{"class":366},[360,39896,39897],{"class":381},"y",[360,39899,671],{"class":366},[360,39901,39902],{"class":397},"\"y\"",[360,39904,6775],{"class":366},[360,39906,39907],{"class":381},"z",[360,39909,671],{"class":366},[360,39911,29549],{"class":397},[360,39913,39914],{"class":366},"); \n",[360,39916,39917],{"class":362,"line":3276},[360,39918,372],{"emptyLinePlaceholder":320},[360,39920,39921,39923],{"class":362,"line":3281},[360,39922,5657],{"class":574},[360,39924,39925],{"class":366}," (useStringBuilder)\n",[360,39927,39928],{"class":362,"line":3305},[360,39929,16504],{"class":366},[360,39931,39932],{"class":362,"line":3320},[360,39933,39934],{"class":366},"        QBENCHMARK {\n",[360,39936,39937],{"class":362,"line":3325},[360,39938,39939],{"class":644},"            \u002F\u002F Concaténation en utilisant QStringBuilder\n",[360,39941,39942],{"class":362,"line":3361},[360,39943,39944],{"class":644},"            \u002F\u002F Dans ce cas la concaténation devrait être plus rapide\n",[360,39946,39947,39950,39952,39955,39957,39960,39962,39965,39967,39970,39972,39975,39977,39980,39982,39985,39987,39990,39992,39995,39997,40000,40002,40005,40007,40009],{"class":362,"line":3380},[360,39948,39949],{"class":366},"            result ",[360,39951,583],{"class":574},[360,39953,39954],{"class":366}," a ",[360,39956,39324],{"class":574},[360,39958,39959],{"class":366}," b ",[360,39961,39324],{"class":574},[360,39963,39964],{"class":366}," c ",[360,39966,39324],{"class":574},[360,39968,39969],{"class":366}," d ",[360,39971,39324],{"class":574},[360,39973,39974],{"class":366}," e ",[360,39976,39324],{"class":574},[360,39978,39979],{"class":366}," f ",[360,39981,39324],{"class":574},[360,39983,39984],{"class":366}," g ",[360,39986,39324],{"class":574},[360,39988,39989],{"class":366}," h ",[360,39991,39324],{"class":574},[360,39993,39994],{"class":366}," i ",[360,39996,39324],{"class":574},[360,39998,39999],{"class":366}," j ",[360,40001,39324],{"class":574},[360,40003,40004],{"class":366}," k ",[360,40006,39324],{"class":574},[360,40008,25133],{"class":366},[360,40010,40011],{"class":574},"%\n",[360,40013,40014,40017,40019,40021,40023,40026,40028,40031,40033,40036,40038,40041,40043,40046,40048,40051,40053,40056,40058,40061,40063,40066,40068,40071,40073,40076,40078],{"class":362,"line":3405},[360,40015,40016],{"class":366},"            m ",[360,40018,39324],{"class":574},[360,40020,28527],{"class":366},[360,40022,39324],{"class":574},[360,40024,40025],{"class":366}," o ",[360,40027,39324],{"class":574},[360,40029,40030],{"class":366}," p ",[360,40032,39324],{"class":574},[360,40034,40035],{"class":366}," q ",[360,40037,39324],{"class":574},[360,40039,40040],{"class":366}," r ",[360,40042,39324],{"class":574},[360,40044,40045],{"class":366}," s ",[360,40047,39324],{"class":574},[360,40049,40050],{"class":366}," t ",[360,40052,39324],{"class":574},[360,40054,40055],{"class":366}," u ",[360,40057,39324],{"class":574},[360,40059,40060],{"class":366}," v ",[360,40062,39324],{"class":574},[360,40064,40065],{"class":366}," w ",[360,40067,39324],{"class":574},[360,40069,40070],{"class":366}," x ",[360,40072,39324],{"class":574},[360,40074,40075],{"class":366}," y ",[360,40077,39324],{"class":574},[360,40079,40080],{"class":366}," z;\n",[360,40082,40083],{"class":362,"line":3411},[360,40084,2840],{"class":366},[360,40086,40087],{"class":362,"line":3426},[360,40088,2927],{"class":366},[360,40090,40091],{"class":362,"line":3432},[360,40092,5702],{"class":574},[360,40094,40095],{"class":362,"line":3438},[360,40096,16504],{"class":366},[360,40098,40099],{"class":362,"line":3443},[360,40100,40101],{"class":366},"        QBENCHMARK\n",[360,40103,40104],{"class":362,"line":3462},[360,40105,31002],{"class":366},[360,40107,40108],{"class":362,"line":3467},[360,40109,40110],{"class":644},"            \u002F\u002F Concaténation en n'utilisant pas QStringBuilder. On\n",[360,40112,40113],{"class":362,"line":3472},[360,40114,40115],{"class":644},"            \u002F\u002F utilise alors la concaténation normal de chaînes de\n",[360,40117,40118],{"class":362,"line":3495},[360,40119,40120],{"class":644},"            \u002F\u002F caractères en utilisant QString\n",[360,40122,40123,40125,40127,40129,40131,40133,40135,40137,40139,40141,40143,40145,40147,40149,40151,40153,40155,40157,40159,40161,40163,40165,40167,40169,40171,40173],{"class":362,"line":3500},[360,40124,39949],{"class":366},[360,40126,583],{"class":574},[360,40128,39954],{"class":366},[360,40130,1310],{"class":574},[360,40132,39959],{"class":366},[360,40134,1310],{"class":574},[360,40136,39964],{"class":366},[360,40138,1310],{"class":574},[360,40140,39969],{"class":366},[360,40142,1310],{"class":574},[360,40144,39974],{"class":366},[360,40146,1310],{"class":574},[360,40148,39979],{"class":366},[360,40150,1310],{"class":574},[360,40152,39984],{"class":366},[360,40154,1310],{"class":574},[360,40156,39989],{"class":366},[360,40158,1310],{"class":574},[360,40160,39994],{"class":366},[360,40162,1310],{"class":574},[360,40164,39999],{"class":366},[360,40166,1310],{"class":574},[360,40168,40004],{"class":366},[360,40170,1310],{"class":574},[360,40172,25133],{"class":366},[360,40174,40175],{"class":574},"+\n",[360,40177,40178,40180,40182,40184,40186,40188,40190,40192,40194,40196,40198,40200,40202,40204,40206,40208,40210,40212,40214,40216,40218,40220,40222,40224,40226,40228,40230],{"class":362,"line":3505},[360,40179,40016],{"class":366},[360,40181,1310],{"class":574},[360,40183,28527],{"class":366},[360,40185,1310],{"class":574},[360,40187,40025],{"class":366},[360,40189,1310],{"class":574},[360,40191,40030],{"class":366},[360,40193,1310],{"class":574},[360,40195,40035],{"class":366},[360,40197,1310],{"class":574},[360,40199,40040],{"class":366},[360,40201,1310],{"class":574},[360,40203,40045],{"class":366},[360,40205,1310],{"class":574},[360,40207,40050],{"class":366},[360,40209,1310],{"class":574},[360,40211,40055],{"class":366},[360,40213,1310],{"class":574},[360,40215,40060],{"class":366},[360,40217,1310],{"class":574},[360,40219,40065],{"class":366},[360,40221,1310],{"class":574},[360,40223,40070],{"class":366},[360,40225,1310],{"class":574},[360,40227,40075],{"class":366},[360,40229,1310],{"class":574},[360,40231,40080],{"class":366},[360,40233,40234],{"class":362,"line":3530},[360,40235,2840],{"class":366},[360,40237,40238],{"class":362,"line":3545},[360,40239,2927],{"class":366},[360,40241,40242],{"class":362,"line":3558},[360,40243,847],{"class":366},[360,40245,40246],{"class":362,"line":3573},[360,40247,372],{"emptyLinePlaceholder":320},[360,40249,40250,40252,40254,40256,40259],{"class":362,"line":3578},[360,40251,36417],{"class":574},[360,40253,39535],{"class":662},[360,40255,666],{"class":366},[360,40257,40258],{"class":381},"concat_data",[360,40260,5008],{"class":366},[360,40262,40263],{"class":362,"line":3583},[360,40264,16340],{"class":366},[360,40266,40267,40270,40273,40275,40277,40279,40282],{"class":362,"line":6893},[360,40268,40269],{"class":366},"    QTest::",[360,40271,40272],{"class":381},"addColumn",[360,40274,1358],{"class":366},[360,40276,2978],{"class":574},[360,40278,17571],{"class":366},[360,40280,40281],{"class":397},"\"useStringBuilder\"",[360,40283,801],{"class":366},[360,40285,40286,40288,40291,40293,40296,40298,40300,40302],{"class":362,"line":6899},[360,40287,40269],{"class":366},[360,40289,40290],{"class":381},"newRow",[360,40292,671],{"class":366},[360,40294,40295],{"class":397},"\"Don't use QStringBuilder\"",[360,40297,3972],{"class":366},[360,40299,7696],{"class":574},[360,40301,3315],{"class":414},[360,40303,735],{"class":366},[360,40305,40306,40308,40310,40312,40315,40317,40319,40321],{"class":362,"line":6905},[360,40307,40269],{"class":366},[360,40309,40290],{"class":381},[360,40311,671],{"class":366},[360,40313,40314],{"class":397},"\"Use QStringBuilder\"",[360,40316,3972],{"class":366},[360,40318,7696],{"class":574},[360,40320,3134],{"class":414},[360,40322,735],{"class":366},[360,40324,40325],{"class":362,"line":6920},[360,40326,847],{"class":366},[360,40328,40329],{"class":362,"line":6942},[360,40330,372],{"emptyLinePlaceholder":320},[360,40332,40333,40336],{"class":362,"line":6974},[360,40334,40335],{"class":381},"QTEST_APPLESS_MAIN",[360,40337,40338],{"class":366},"(TestPerf);\n",[360,40340,40341],{"class":362,"line":6992},[360,40342,372],{"emptyLinePlaceholder":320},[360,40344,40345,40347],{"class":362,"line":6997},[360,40346,33204],{"class":574},[360,40348,40349],{"class":397}," \"tst_testperf.moc\"\n",[23034,40351,38849],{"id":38848},[12,40353,40354],{},"Le test a été fait en utilisant la version 4.6.3 de Qt. Le résultat est\nsensiblement le même avec la version 4.7.0",[1545,40356,40357,40367],{},[1548,40358,40359],{},[1551,40360,40361,40364],{},[1554,40362,40363],{},"Sans QStringBuilder",[1554,40365,40366],{},"Avec QStringBuilder",[1567,40368,40369],{},[1551,40370,40371,40374],{},[1572,40372,40373],{},"0.00367 msec",[1572,40375,40376],{},"0.00046 msec",[12,40378,40379],{},"On voit dans ce test que la version en utilisant QStringBuilder est 8\nfois plus rapide que sans. Bien sûr vu le temps que prend la\nconcaténation de chaînes de caractères, ce test commence à avoir de\nl'intérêt uniquement à partir du moment où on fait beaucoup de\nconcaténation dans la seconde, ou si les temps de réponses sont\ncritiques.",[12,40381,40382],{},"Sur ce, je vous souhaite à tous un Joyeux noël et une bonne année.",[23034,40384,40386],{"id":40385},"le-programme","Le programme",[12,40388,40389,40390,31],{},"Vous pouvez trouver le programme ",[47,40391,34697],{"href":40392},"\u002FProgrammation\u002Fqt-concatenation-de-chaine-de-caracteres\u002Ftest-perfconcat.7z",[1613,40394,40395],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}",{"title":291,"searchDepth":292,"depth":292,"links":40397},[40398,40399],{"id":36098,"depth":375,"text":36099},{"id":39232,"depth":292,"text":39233,"children":40400},[40401,40402],{"id":39310,"depth":375,"text":39311},{"id":15284,"depth":375,"text":15285},"2010-12-22",{"type":9,"value":40405},[40406,40408,40410,40412,40414],[1901,40407,36099],{"id":36098},[12,40409,39220],{},[12,40411,39223],{},[12,40413,39226],{},[12,40415,39229],{},{},"\u002Fpost\u002Fqt-concatenation-de-chaine-de-caracteres",{"title":39213,"description":291},"qt-concatenation-de-chaine-de-caracteres","posts\u002FProgrammation\u002F2010-12-22-qt-concatenation-de-chaine-de-caracteres",[39209,32924],"tnYQV8OJKsLZvtUPPbMHph26Eitmdp4-hd-STXhGP2A",{"id":40424,"title":40425,"author":7,"body":40426,"category":300,"categorySlug":301,"date":42055,"description":291,"excerpt":42056,"extension":317,"location":318,"meta":42091,"navigation":320,"path":42092,"published":320,"seo":42093,"slug":42094,"stem":42095,"tags":42096,"timeToRead":489,"__hash__":42097},"posts\u002Fposts\u002FProgrammation\u002F2010-06-06-calcul-de-la-distance.md","Calcul de la distance entre deux fichiers",{"type":9,"value":40427,"toc":42049},[40428,40430,40438,40444,40452,40472,40474,40477,40480,40483,40486,40489,40492,40505,40516,40519,40534,40537,40553,40557,40571,40574,41058,41061,41165,42015,42018,42021,42028,42046],[1901,40429,36099],{"id":36098},[12,40431,34773,40432,40437],{},[47,40433,40436],{"href":40434,"rel":40435},"http:\u002F\u002Flinuxfr.org\u002Fforums\u002F20\u002F28366.html",[51],"billet sur LinuxFR",", où je demandais comment calculer la\ndistance (ou le pourcentage de similitude entre deux logiciels), j'ai\nobtenu la formule suivante :",[352,40439,40442],{"className":40440,"code":40441,"language":32201},[32199],"distance = 1 - ( C(A) + C(B) - C(AB) ) \u002F Max(C(A), C(B))\n",[344,40443,40441],{"__ignoreMap":291},[12,40445,40446,40447,31],{},"où C(X) est la taille du fichier X compressé",[15680,40448,40449],{},[47,40450,1944],{"href":15684,"ariaDescribedBy":40451,"dataFootnoteRef":291,"id":15687},[15686],[12,40453,40454,40455,2311,40458,854,40461,40464,40465,40467,40468,40471],{},"Après avoir testé les formats ",[344,40456,40457],{},"gzip",[344,40459,40460],{},"bzip2",[344,40462,40463],{},"lzma",", j'ai conclu que\nle format de compression le plus performant pour le calcul, est le\nformat ",[344,40466,40463],{},", car le dictionnaire avec ",[105,40469,40470],{},"la mise en commun"," était le\nplus gros, et donc le calcul de distance est plus efficace.",[1901,40473,40386],{"id":40385},[12,40475,40476],{},"J'ai donc décidé d'écrire un programme parcourant un dossier (avec\nplusieurs milliers de fichiers) et de calculer pour toutes les\ncombinaisons des fichiers la distance entre chaque fichier. Ce programme\nconsommant énormément de mémoire, il se peut que pour un grand nombre de\nfichier, le programme se plante avec une erreur d'allocation de mémoire.",[12,40478,40479],{},"Ce programme permet de pouvoir faire une cartographie de ces fichiers et\nainsi de pouvoir les classer. Testé sur des fichiers textes (sources de\nlogiciels), le programme est assez efficace.",[12,40481,40482],{},"Testé sur des images, ou des vidéos, les fichiers sont considérés comme\ntous éloignés les uns des autres, même s'ils sont identiques à\ncompression différente près, ou s'ils sont identiques à un mouvement\nprès sur la photo (du genre une photo où une même personne se tient dans\nune position différente).",[12,40484,40485],{},"Si vous avez une idée sur comment calculer la distance entre deux\nfichiers déjà compressés (avec perte qui plus est), ca m'intéresse. :)",[12,40487,40488],{},"Comme l'exécution est très lente (compression lzma niveau 9), le\nprogramme peut être arrêté et redémarré.",[12,40490,40491],{},"Pour démarrer le programme, il faut exécuter la commande :",[352,40493,40495],{"className":565,"code":40494,"language":567,"meta":291,"style":291},".\u002Fcalcul_distance \u002Fmon\u002Fdossier\n",[344,40496,40497],{"__ignoreMap":291},[360,40498,40499,40502],{"class":362,"line":363},[360,40500,40501],{"class":381},".\u002Fcalcul_distance",[360,40503,40504],{"class":397}," \u002Fmon\u002Fdossier\n",[12,40506,40507,40508,40511,40512,40515],{},"Le programme va alors créer un fichier\n",[344,40509,40510],{},"{5ac1fd3c-504f-4110-9f7e-d6fc89e57bdb}.db"," où\n",[344,40513,40514],{},"{5ac1fd3c-504f-4110-9f7e-d6fc89e57bdb}"," est différent à chaque nouveau\nlancement.",[12,40517,40518],{},"Pour reprendre le traitement où il était, il suffit alors de lancer :",[352,40520,40522],{"className":565,"code":40521,"language":567,"meta":291,"style":291},".\u002Fcalcul_distance --uuid {5ac1fd3c-504f-4110-9f7e-d6fc89e57bdb}\n",[344,40523,40524],{"__ignoreMap":291},[360,40525,40526,40528,40531],{"class":362,"line":363},[360,40527,40501],{"class":381},[360,40529,40530],{"class":414}," --uuid",[360,40532,40533],{"class":397}," {5ac1fd3c-504f-4110-9f7e-d6fc89e57bdb}\n",[12,40535,40536],{},"Si on veut ajouter un dossier au traitement après coup :",[352,40538,40540],{"className":565,"code":40539,"language":567,"meta":291,"style":291},".\u002Fcalcul_distance \u002Fnouveau\u002Fdossier --uuid {5ac1fd3c-504f-4110-9f7e-d6fc89e57bdb}\n",[344,40541,40542],{"__ignoreMap":291},[360,40543,40544,40546,40549,40551],{"class":362,"line":363},[360,40545,40501],{"class":381},[360,40547,40548],{"class":397}," \u002Fnouveau\u002Fdossier",[360,40550,40530],{"class":414},[360,40552,40533],{"class":397},[1901,40554,40556],{"id":40555},"exemple","Exemple",[12,40558,40559,40560,40563,40564,40566,40567,40570],{},"Par exemple soit les différentes versions d'un logiciel, mis dans des\narchives ",[344,40561,40562],{},"tar",". Pour ne prendre que le code source des versions, on va\nsupprimer tous les fichiers suivants de l'archive ",[344,40565,40562],{}," :\n",[344,40568,40569],{},"*.jpg, *.png, *.ico, *.qm, *.db",", ... les sources externes à\nl'application. On ne garde donc que les fichiers textes dont nous avons\nla possession.",[12,40572,40573],{},"Après le nettoyage des dossiers :",[352,40575,40577],{"className":565,"code":40576,"language":567,"meta":291,"style":291},"$ for i in `ls` ; do\n> tar -c $i\u002F*\n> $i.tar\n> done\n$ ls -l\n-rw-r--r-- 1 phoenix phoenix 2,5M  6 juin  13:24 v0.6.10.tar\n-rw-r--r-- 1 phoenix phoenix 440K  6 juin  13:24 v0.6.4.tar\n-rw-r--r-- 1 phoenix phoenix 530K  6 juin  13:24 v0.6.5.tar\n-rw-r--r-- 1 phoenix phoenix 610K  6 juin  13:24 v0.6.6.tar\n-rw-r--r-- 1 phoenix phoenix 690K  6 juin  13:24 v0.6.7.tar\n-rw-r--r-- 1 phoenix phoenix 1,2M  6 juin  13:24 v0.6.8.tar\n-rw-r--r-- 1 phoenix phoenix 1,3M  6 juin  13:24 v0.6.9.tar\n-rw-r--r-- 1 phoenix phoenix 2,9M  6 juin  13:24 v0.7.0.tar\n-rw-r--r-- 1 phoenix phoenix 2,2M  6 juin  13:24 v0.7.1.tar\n-rw-r--r-- 1 phoenix phoenix 3,3M  6 juin  13:24 v0.7.2.tar\n-rw-r--r-- 1 phoenix phoenix 3,3M  6 juin  13:24 v0.8.0.tar\n-rw-r--r-- 1 phoenix phoenix 3,1M  6 juin  13:24 v0.8.1_services.tar\n-rw-r--r-- 1 phoenix phoenix 3,1M  6 juin  13:24 v0.8.1.tar\n-rw-r--r-- 1 phoenix phoenix 3,8M  6 juin  13:24 v0.9.0.tar\n$ cd ..\n$ calcul_distance .\u002Fxinx\u002F\nStep 0 : Create database\nStep 1 : Create file list\nStep 2 : Compress single file\nStep 3 : Compress pair file\n$ ls\n{051b93a0-d9a9-4778-ac73-81ee01a3905d}.db\nxinx\n$ sqlite3 {051b93a0-d9a9-4778-ac73-81ee01a3905d}.db\n",[344,40578,40579,40602,40613,40622,40628,40638,40665,40687,40709,40731,40753,40775,40797,40819,40841,40863,40884,40906,40927,40949,40959,40969,40984,40999,41016,41031,41038,41043,41048],{"__ignoreMap":291},[360,40580,40581,40584,40586,40588,40590,40592,40595,40597,40600],{"class":362,"line":363},[360,40582,40583],{"class":381},"$",[360,40585,2702],{"class":397},[360,40587,6178],{"class":397},[360,40589,8336],{"class":397},[360,40591,16093],{"class":397},[360,40593,40594],{"class":381},"ls",[360,40596,18707],{"class":397},[360,40598,40599],{"class":366}," ; ",[360,40601,5647],{"class":574},[360,40603,40604,40607,40610],{"class":362,"line":292},[360,40605,40606],{"class":366},"> tar -c ",[360,40608,40609],{"class":578},"$i",[360,40611,40612],{"class":366},"\u002F*\n",[360,40614,40615,40617,40619],{"class":362,"line":375},[360,40616,2697],{"class":366},[360,40618,40609],{"class":578},[360,40620,40621],{"class":366},".tar\n",[360,40623,40624,40626],{"class":362,"line":433},[360,40625,2697],{"class":366},[360,40627,5737],{"class":574},[360,40629,40630,40632,40635],{"class":362,"line":478},[360,40631,40583],{"class":381},[360,40633,40634],{"class":397}," ls",[360,40636,40637],{"class":414}," -l\n",[360,40639,40640,40643,40645,40648,40650,40653,40656,40659,40662],{"class":362,"line":483},[360,40641,40642],{"class":381},"-rw-r--r--",[360,40644,1099],{"class":414},[360,40646,40647],{"class":397}," phoenix",[360,40649,40647],{"class":397},[360,40651,40652],{"class":397}," 2,5M",[360,40654,40655],{"class":414},"  6",[360,40657,40658],{"class":397}," juin",[360,40660,40661],{"class":397},"  13:24",[360,40663,40664],{"class":397}," v0.6.10.tar\n",[360,40666,40667,40669,40671,40673,40675,40678,40680,40682,40684],{"class":362,"line":489},[360,40668,40642],{"class":381},[360,40670,1099],{"class":414},[360,40672,40647],{"class":397},[360,40674,40647],{"class":397},[360,40676,40677],{"class":397}," 440K",[360,40679,40655],{"class":414},[360,40681,40658],{"class":397},[360,40683,40661],{"class":397},[360,40685,40686],{"class":397}," v0.6.4.tar\n",[360,40688,40689,40691,40693,40695,40697,40700,40702,40704,40706],{"class":362,"line":494},[360,40690,40642],{"class":381},[360,40692,1099],{"class":414},[360,40694,40647],{"class":397},[360,40696,40647],{"class":397},[360,40698,40699],{"class":397}," 530K",[360,40701,40655],{"class":414},[360,40703,40658],{"class":397},[360,40705,40661],{"class":397},[360,40707,40708],{"class":397}," v0.6.5.tar\n",[360,40710,40711,40713,40715,40717,40719,40722,40724,40726,40728],{"class":362,"line":712},[360,40712,40642],{"class":381},[360,40714,1099],{"class":414},[360,40716,40647],{"class":397},[360,40718,40647],{"class":397},[360,40720,40721],{"class":397}," 610K",[360,40723,40655],{"class":414},[360,40725,40658],{"class":397},[360,40727,40661],{"class":397},[360,40729,40730],{"class":397}," v0.6.6.tar\n",[360,40732,40733,40735,40737,40739,40741,40744,40746,40748,40750],{"class":362,"line":331},[360,40734,40642],{"class":381},[360,40736,1099],{"class":414},[360,40738,40647],{"class":397},[360,40740,40647],{"class":397},[360,40742,40743],{"class":397}," 690K",[360,40745,40655],{"class":414},[360,40747,40658],{"class":397},[360,40749,40661],{"class":397},[360,40751,40752],{"class":397}," v0.6.7.tar\n",[360,40754,40755,40757,40759,40761,40763,40766,40768,40770,40772],{"class":362,"line":762},[360,40756,40642],{"class":381},[360,40758,1099],{"class":414},[360,40760,40647],{"class":397},[360,40762,40647],{"class":397},[360,40764,40765],{"class":397}," 1,2M",[360,40767,40655],{"class":414},[360,40769,40658],{"class":397},[360,40771,40661],{"class":397},[360,40773,40774],{"class":397}," v0.6.8.tar\n",[360,40776,40777,40779,40781,40783,40785,40788,40790,40792,40794],{"class":362,"line":781},[360,40778,40642],{"class":381},[360,40780,1099],{"class":414},[360,40782,40647],{"class":397},[360,40784,40647],{"class":397},[360,40786,40787],{"class":397}," 1,3M",[360,40789,40655],{"class":414},[360,40791,40658],{"class":397},[360,40793,40661],{"class":397},[360,40795,40796],{"class":397}," v0.6.9.tar\n",[360,40798,40799,40801,40803,40805,40807,40810,40812,40814,40816],{"class":362,"line":804},[360,40800,40642],{"class":381},[360,40802,1099],{"class":414},[360,40804,40647],{"class":397},[360,40806,40647],{"class":397},[360,40808,40809],{"class":397}," 2,9M",[360,40811,40655],{"class":414},[360,40813,40658],{"class":397},[360,40815,40661],{"class":397},[360,40817,40818],{"class":397}," v0.7.0.tar\n",[360,40820,40821,40823,40825,40827,40829,40832,40834,40836,40838],{"class":362,"line":817},[360,40822,40642],{"class":381},[360,40824,1099],{"class":414},[360,40826,40647],{"class":397},[360,40828,40647],{"class":397},[360,40830,40831],{"class":397}," 2,2M",[360,40833,40655],{"class":414},[360,40835,40658],{"class":397},[360,40837,40661],{"class":397},[360,40839,40840],{"class":397}," v0.7.1.tar\n",[360,40842,40843,40845,40847,40849,40851,40854,40856,40858,40860],{"class":362,"line":823},[360,40844,40642],{"class":381},[360,40846,1099],{"class":414},[360,40848,40647],{"class":397},[360,40850,40647],{"class":397},[360,40852,40853],{"class":397}," 3,3M",[360,40855,40655],{"class":414},[360,40857,40658],{"class":397},[360,40859,40661],{"class":397},[360,40861,40862],{"class":397}," v0.7.2.tar\n",[360,40864,40865,40867,40869,40871,40873,40875,40877,40879,40881],{"class":362,"line":844},[360,40866,40642],{"class":381},[360,40868,1099],{"class":414},[360,40870,40647],{"class":397},[360,40872,40647],{"class":397},[360,40874,40853],{"class":397},[360,40876,40655],{"class":414},[360,40878,40658],{"class":397},[360,40880,40661],{"class":397},[360,40882,40883],{"class":397}," v0.8.0.tar\n",[360,40885,40886,40888,40890,40892,40894,40897,40899,40901,40903],{"class":362,"line":1441},[360,40887,40642],{"class":381},[360,40889,1099],{"class":414},[360,40891,40647],{"class":397},[360,40893,40647],{"class":397},[360,40895,40896],{"class":397}," 3,1M",[360,40898,40655],{"class":414},[360,40900,40658],{"class":397},[360,40902,40661],{"class":397},[360,40904,40905],{"class":397}," v0.8.1_services.tar\n",[360,40907,40908,40910,40912,40914,40916,40918,40920,40922,40924],{"class":362,"line":1462},[360,40909,40642],{"class":381},[360,40911,1099],{"class":414},[360,40913,40647],{"class":397},[360,40915,40647],{"class":397},[360,40917,40896],{"class":397},[360,40919,40655],{"class":414},[360,40921,40658],{"class":397},[360,40923,40661],{"class":397},[360,40925,40926],{"class":397}," v0.8.1.tar\n",[360,40928,40929,40931,40933,40935,40937,40940,40942,40944,40946],{"class":362,"line":1485},[360,40930,40642],{"class":381},[360,40932,1099],{"class":414},[360,40934,40647],{"class":397},[360,40936,40647],{"class":397},[360,40938,40939],{"class":397}," 3,8M",[360,40941,40655],{"class":414},[360,40943,40658],{"class":397},[360,40945,40661],{"class":397},[360,40947,40948],{"class":397}," v0.9.0.tar\n",[360,40950,40951,40953,40956],{"class":362,"line":1497},[360,40952,40583],{"class":381},[360,40954,40955],{"class":397}," cd",[360,40957,40958],{"class":397}," ..\n",[360,40960,40961,40963,40966],{"class":362,"line":3161},[360,40962,40583],{"class":381},[360,40964,40965],{"class":397}," calcul_distance",[360,40967,40968],{"class":397}," .\u002Fxinx\u002F\n",[360,40970,40971,40974,40976,40978,40981],{"class":362,"line":3167},[360,40972,40973],{"class":381},"Step",[360,40975,1457],{"class":414},[360,40977,632],{"class":397},[360,40979,40980],{"class":397}," Create",[360,40982,40983],{"class":397}," database\n",[360,40985,40986,40988,40990,40992,40994,40996],{"class":362,"line":3194},[360,40987,40973],{"class":381},[360,40989,1099],{"class":414},[360,40991,632],{"class":397},[360,40993,40980],{"class":397},[360,40995,5642],{"class":397},[360,40997,40998],{"class":397}," list\n",[360,41000,41001,41003,41005,41007,41010,41013],{"class":362,"line":3224},[360,41002,40973],{"class":381},[360,41004,732],{"class":414},[360,41006,632],{"class":397},[360,41008,41009],{"class":397}," Compress",[360,41011,41012],{"class":397}," single",[360,41014,41015],{"class":397}," file\n",[360,41017,41018,41020,41022,41024,41026,41029],{"class":362,"line":3239},[360,41019,40973],{"class":381},[360,41021,14384],{"class":414},[360,41023,632],{"class":397},[360,41025,41009],{"class":397},[360,41027,41028],{"class":397}," pair",[360,41030,41015],{"class":397},[360,41032,41033,41035],{"class":362,"line":3256},[360,41034,40583],{"class":381},[360,41036,41037],{"class":397}," ls\n",[360,41039,41040],{"class":362,"line":3276},[360,41041,41042],{"class":366},"{051b93a0-d9a9-4778-ac73-81ee01a3905d}.db\n",[360,41044,41045],{"class":362,"line":3281},[360,41046,41047],{"class":381},"xinx\n",[360,41049,41050,41052,41055],{"class":362,"line":3305},[360,41051,40583],{"class":381},[360,41053,41054],{"class":397}," sqlite3",[360,41056,41057],{"class":397}," {051b93a0-d9a9-4778-ac73-81ee01a3905d}.db\n",[12,41059,41060],{},"Nous allons maintenant faire une requête dans la base de données sqlite :",[352,41062,41066],{"className":41063,"code":41064,"language":41065,"meta":291,"style":291},"language-sql shiki shiki-themes one-dark-pro","$ .TABLES\ndistances  files\n$ SELECT files1.path, files2.path, distances.distance FROM distances, files files1, files files2 WHERE distances.id1=files1.id AND distances.id2=files2.id ORDER BY distance ASC;\n","sql",[344,41067,41068,41073,41078],{"__ignoreMap":291},[360,41069,41070],{"class":362,"line":363},[360,41071,41072],{"class":366},"$ .TABLES\n",[360,41074,41075],{"class":362,"line":292},[360,41076,41077],{"class":366},"distances  files\n",[360,41079,41080,41083,41086,41089,41091,41093,41095,41098,41100,41102,41104,41107,41109,41111,41114,41117,41120,41123,41125,41128,41130,41133,41135,41137,41140,41142,41144,41147,41149,41151,41153,41155,41158,41160,41163],{"class":362,"line":375},[360,41081,41082],{"class":366},"$ ",[360,41084,41085],{"class":574},"SELECT",[360,41087,41088],{"class":414}," files1",[360,41090,31],{"class":366},[360,41092,4817],{"class":414},[360,41094,2311],{"class":366},[360,41096,41097],{"class":414},"files2",[360,41099,31],{"class":366},[360,41101,4817],{"class":414},[360,41103,2311],{"class":366},[360,41105,41106],{"class":414},"distances",[360,41108,31],{"class":366},[360,41110,26177],{"class":414},[360,41112,41113],{"class":574}," FROM",[360,41115,41116],{"class":366}," distances, files files1, files files2 ",[360,41118,41119],{"class":574},"WHERE",[360,41121,41122],{"class":414}," distances",[360,41124,31],{"class":366},[360,41126,41127],{"class":414},"id1",[360,41129,583],{"class":582},[360,41131,41132],{"class":414},"files1",[360,41134,31],{"class":366},[360,41136,18908],{"class":414},[360,41138,41139],{"class":574}," AND",[360,41141,41122],{"class":414},[360,41143,31],{"class":366},[360,41145,41146],{"class":414},"id2",[360,41148,583],{"class":582},[360,41150,41097],{"class":414},[360,41152,31],{"class":366},[360,41154,18908],{"class":414},[360,41156,41157],{"class":574}," ORDER BY",[360,41159,25886],{"class":366},[360,41161,41162],{"class":574},"ASC",[360,41164,735],{"class":366},[1545,41166,41167,41180],{},[1548,41168,41169],{},[1551,41170,41171,41174,41177],{},[1554,41172,41173],{},"Version 1",[1554,41175,41176],{},"Version 2",[1554,41178,41179],{},"Distance",[1567,41181,41182,41193,41204,41214,41223,41234,41244,41254,41265,41275,41284,41293,41302,41311,41321,41330,41339,41349,41358,41367,41376,41385,41394,41403,41412,41421,41430,41439,41448,41457,41466,41475,41484,41493,41502,41511,41520,41529,41538,41547,41556,41565,41574,41583,41592,41601,41610,41619,41628,41637,41646,41655,41664,41673,41682,41691,41700,41709,41718,41727,41736,41745,41754,41763,41772,41781,41790,41799,41808,41817,41826,41835,41844,41853,41862,41871,41880,41889,41898,41907,41916,41925,41934,41943,41952,41961,41970,41979,41988,41997,42006],{},[1551,41183,41184,41187,41190],{},[1572,41185,41186],{},"v0.8.1",[1572,41188,41189],{},"v0.8.1_services",[1572,41191,41192],{},"0.0350740694634633",[1551,41194,41195,41198,41201],{},[1572,41196,41197],{},"v0.6.8",[1572,41199,41200],{},"v0.6.9",[1572,41202,41203],{},"0.132275346477201",[1551,41205,41206,41209,41211],{},[1572,41207,41208],{},"v0.8.0",[1572,41210,41186],{},[1572,41212,41213],{},"0.142321125298336",[1551,41215,41216,41218,41220],{},[1572,41217,41208],{},[1572,41219,41189],{},[1572,41221,41222],{},"0.161719318637048",[1551,41224,41225,41228,41231],{},[1572,41226,41227],{},"v0.6.5",[1572,41229,41230],{},"v0.6.6",[1572,41232,41233],{},"0.196933113059686",[1551,41235,41236,41239,41241],{},[1572,41237,41238],{},"v0.6.4",[1572,41240,41227],{},[1572,41242,41243],{},"0.231812199675573",[1551,41245,41246,41248,41251],{},[1572,41247,41230],{},[1572,41249,41250],{},"v0.6.7",[1572,41252,41253],{},"0.266593999923953",[1551,41255,41256,41259,41262],{},[1572,41257,41258],{},"v0.6.10",[1572,41260,41261],{},"v0.7.0",[1572,41263,41264],{},"0.27412838729727",[1551,41266,41267,41270,41272],{},[1572,41268,41269],{},"v0.7.2",[1572,41271,41208],{},[1572,41273,41274],{},"0.312111739912996",[1551,41276,41277,41279,41281],{},[1572,41278,41227],{},[1572,41280,41250],{},[1572,41282,41283],{},"0.351347925829225",[1551,41285,41286,41288,41290],{},[1572,41287,41238],{},[1572,41289,41230],{},[1572,41291,41292],{},"0.364115163581424",[1551,41294,41295,41297,41299],{},[1572,41296,41269],{},[1572,41298,41186],{},[1572,41300,41301],{},"0.386971922637303",[1551,41303,41304,41306,41308],{},[1572,41305,41269],{},[1572,41307,41189],{},[1572,41309,41310],{},"0.401055941017259",[1551,41312,41313,41316,41318],{},[1572,41314,41315],{},"v0.7.1",[1572,41317,41269],{},[1572,41319,41320],{},"0.436705836223058",[1551,41322,41323,41325,41327],{},[1572,41324,41261],{},[1572,41326,41315],{},[1572,41328,41329],{},"0.465121645779551",[1551,41331,41332,41334,41336],{},[1572,41333,41238],{},[1572,41335,41250],{},[1572,41337,41338],{},"0.468472350726879",[1551,41340,41341,41343,41346],{},[1572,41342,41189],{},[1572,41344,41345],{},"v0.9.0",[1572,41347,41348],{},"0.516795574578859",[1551,41350,41351,41353,41355],{},[1572,41352,41186],{},[1572,41354,41345],{},[1572,41356,41357],{},"0.51733623689019",[1551,41359,41360,41362,41364],{},[1572,41361,41208],{},[1572,41363,41345],{},[1572,41365,41366],{},"0.544376861655528",[1551,41368,41369,41371,41373],{},[1572,41370,41250],{},[1572,41372,41197],{},[1572,41374,41375],{},"0.558824765667689",[1551,41377,41378,41380,41382],{},[1572,41379,41315],{},[1572,41381,41208],{},[1572,41383,41384],{},"0.560609480175814",[1551,41386,41387,41389,41391],{},[1572,41388,41258],{},[1572,41390,41200],{},[1572,41392,41393],{},"0.594036969567445",[1551,41395,41396,41398,41400],{},[1572,41397,41315],{},[1572,41399,41186],{},[1572,41401,41402],{},"0.604226316444666",[1551,41404,41405,41407,41409],{},[1572,41406,41315],{},[1572,41408,41189],{},[1572,41410,41411],{},"0.613613062086946",[1551,41413,41414,41416,41418],{},[1572,41415,41250],{},[1572,41417,41200],{},[1572,41419,41420],{},"0.622950487834501",[1551,41422,41423,41425,41427],{},[1572,41424,41261],{},[1572,41426,41269],{},[1572,41428,41429],{},"0.631060763867616",[1551,41431,41432,41434,41436],{},[1572,41433,41258],{},[1572,41435,41315],{},[1572,41437,41438],{},"0.632444883185258",[1551,41440,41441,41443,41445],{},[1572,41442,41258],{},[1572,41444,41197],{},[1572,41446,41447],{},"0.637234847328374",[1551,41449,41450,41452,41454],{},[1572,41451,41230],{},[1572,41453,41197],{},[1572,41455,41456],{},"0.6494052372746",[1551,41458,41459,41461,41463],{},[1572,41460,41200],{},[1572,41462,41315],{},[1572,41464,41465],{},"0.666200571812458",[1551,41467,41468,41470,41472],{},[1572,41469,41269],{},[1572,41471,41345],{},[1572,41473,41474],{},"0.678423568871868",[1551,41476,41477,41479,41481],{},[1572,41478,41227],{},[1572,41480,41197],{},[1572,41482,41483],{},"0.692250570944195",[1551,41485,41486,41488,41490],{},[1572,41487,41197],{},[1572,41489,41315],{},[1572,41491,41492],{},"0.701063946130892",[1551,41494,41495,41497,41499],{},[1572,41496,41230],{},[1572,41498,41200],{},[1572,41500,41501],{},"0.701698986545754",[1551,41503,41504,41506,41508],{},[1572,41505,41200],{},[1572,41507,41261],{},[1572,41509,41510],{},"0.717262408423359",[1551,41512,41513,41515,41517],{},[1572,41514,41261],{},[1572,41516,41208],{},[1572,41518,41519],{},"0.720311680104721",[1551,41521,41522,41524,41526],{},[1572,41523,41227],{},[1572,41525,41200],{},[1572,41527,41528],{},"0.738013305804084",[1551,41530,41531,41533,41535],{},[1572,41532,41238],{},[1572,41534,41197],{},[1572,41536,41537],{},"0.747495551539097",[1551,41539,41540,41542,41544],{},[1572,41541,41258],{},[1572,41543,41269],{},[1572,41545,41546],{},"0.747929200720491",[1551,41548,41549,41551,41553],{},[1572,41550,41197],{},[1572,41552,41261],{},[1572,41554,41555],{},"0.748031544518325",[1551,41557,41558,41560,41562],{},[1572,41559,41261],{},[1572,41561,41186],{},[1572,41563,41564],{},"0.758510349354368",[1551,41566,41567,41569,41571],{},[1572,41568,41261],{},[1572,41570,41189],{},[1572,41572,41573],{},"0.767204482779187",[1551,41575,41576,41578,41580],{},[1572,41577,41238],{},[1572,41579,41200],{},[1572,41581,41582],{},"0.772451857549627",[1551,41584,41585,41587,41589],{},[1572,41586,41258],{},[1572,41588,41208],{},[1572,41590,41591],{},"0.796649043913944",[1551,41593,41594,41596,41598],{},[1572,41595,41315],{},[1572,41597,41345],{},[1572,41599,41600],{},"0.801221496333008",[1551,41602,41603,41605,41607],{},[1572,41604,41200],{},[1572,41606,41269],{},[1572,41608,41609],{},"0.804765901655414",[1551,41611,41612,41614,41616],{},[1572,41613,41197],{},[1572,41615,41269],{},[1572,41617,41618],{},"0.819917045496318",[1551,41620,41621,41623,41625],{},[1572,41622,41258],{},[1572,41624,41186],{},[1572,41626,41627],{},"0.823540395867048",[1551,41629,41630,41632,41634],{},[1572,41631,41258],{},[1572,41633,41189],{},[1572,41635,41636],{},"0.831055117394626",[1551,41638,41639,41641,41643],{},[1572,41640,41258],{},[1572,41642,41250],{},[1572,41644,41645],{},"0.838850951377793",[1551,41647,41648,41650,41652],{},[1572,41649,41200],{},[1572,41651,41208],{},[1572,41653,41654],{},"0.849001032539087",[1551,41656,41657,41659,41661],{},[1572,41658,41250],{},[1572,41660,41315],{},[1572,41662,41663],{},"0.853848016623182",[1551,41665,41666,41668,41670],{},[1572,41667,41261],{},[1572,41669,41345],{},[1572,41671,41672],{},"0.860291356912217",[1551,41674,41675,41677,41679],{},[1572,41676,41197],{},[1572,41678,41208],{},[1572,41680,41681],{},"0.86075956509228",[1551,41683,41684,41686,41688],{},[1572,41685,41258],{},[1572,41687,41230],{},[1572,41689,41690],{},"0.863340151908353",[1551,41692,41693,41695,41697],{},[1572,41694,41200],{},[1572,41696,41186],{},[1572,41698,41699],{},"0.872265541006983",[1551,41701,41702,41704,41706],{},[1572,41703,41230],{},[1572,41705,41315],{},[1572,41707,41708],{},"0.873275579233521",[1551,41710,41711,41713,41715],{},[1572,41712,41258],{},[1572,41714,41227],{},[1572,41716,41717],{},"0.875332023895544",[1551,41719,41720,41722,41724],{},[1572,41721,41200],{},[1572,41723,41189],{},[1572,41725,41726],{},"0.87987037883801",[1551,41728,41729,41731,41733],{},[1572,41730,41250],{},[1572,41732,41261],{},[1572,41734,41735],{},"0.879941907871053",[1551,41737,41738,41740,41742],{},[1572,41739,41197],{},[1572,41741,41186],{},[1572,41743,41744],{},"0.881174812987336",[1551,41746,41747,41749,41751],{},[1572,41748,41227],{},[1572,41750,41315],{},[1572,41752,41753],{},"0.886172606121206",[1551,41755,41756,41758,41760],{},[1572,41757,41197],{},[1572,41759,41189],{},[1572,41761,41762],{},"0.889515283880001",[1551,41764,41765,41767,41769],{},[1572,41766,41258],{},[1572,41768,41238],{},[1572,41770,41771],{},"0.892364892140999",[1551,41773,41774,41776,41778],{},[1572,41775,41230],{},[1572,41777,41261],{},[1572,41779,41780],{},"0.894375709613201",[1551,41782,41783,41785,41787],{},[1572,41784,41258],{},[1572,41786,41345],{},[1572,41788,41789],{},"0.895694726039398",[1551,41791,41792,41794,41796],{},[1572,41793,41250],{},[1572,41795,41269],{},[1572,41797,41798],{},"0.898582911617307",[1551,41800,41801,41803,41805],{},[1572,41802,41238],{},[1572,41804,41315],{},[1572,41806,41807],{},"0.902038058337369",[1551,41809,41810,41812,41814],{},[1572,41811,41227],{},[1572,41813,41261],{},[1572,41815,41816],{},"0.904821831317442",[1551,41818,41819,41821,41823],{},[1572,41820,41230],{},[1572,41822,41269],{},[1572,41824,41825],{},"0.910637046476578",[1551,41827,41828,41830,41832],{},[1572,41829,41238],{},[1572,41831,41261],{},[1572,41833,41834],{},"0.918347943544789",[1551,41836,41837,41839,41841],{},[1572,41838,41227],{},[1572,41840,41269],{},[1572,41842,41843],{},"0.919716704855963",[1551,41845,41846,41848,41850],{},[1572,41847,41200],{},[1572,41849,41345],{},[1572,41851,41852],{},"0.921714099772221",[1551,41854,41855,41857,41859],{},[1572,41856,41250],{},[1572,41858,41208],{},[1572,41860,41861],{},"0.924717744438112",[1551,41863,41864,41866,41868],{},[1572,41865,41197],{},[1572,41867,41345],{},[1572,41869,41870],{},"0.925849165227404",[1551,41872,41873,41875,41877],{},[1572,41874,41238],{},[1572,41876,41269],{},[1572,41878,41879],{},"0.928888262611658",[1551,41881,41882,41884,41886],{},[1572,41883,41250],{},[1572,41885,41186],{},[1572,41887,41888],{},"0.933685479216414",[1551,41890,41891,41893,41895],{},[1572,41892,41230],{},[1572,41894,41208],{},[1572,41896,41897],{},"0.933940067594635",[1551,41899,41900,41902,41904],{},[1572,41901,41250],{},[1572,41903,41189],{},[1572,41905,41906],{},"0.939898268404416",[1551,41908,41909,41911,41913],{},[1572,41910,41227],{},[1572,41912,41208],{},[1572,41914,41915],{},"0.940789807767177",[1551,41917,41918,41920,41922],{},[1572,41919,41230],{},[1572,41921,41186],{},[1572,41923,41924],{},"0.94210246370087",[1551,41926,41927,41929,41931],{},[1572,41928,41230],{},[1572,41930,41189],{},[1572,41932,41933],{},"0.946464528845253",[1551,41935,41936,41938,41940],{},[1572,41937,41238],{},[1572,41939,41208],{},[1572,41941,41942],{},"0.948830071149278",[1551,41944,41945,41947,41949],{},[1572,41946,41227],{},[1572,41948,41186],{},[1572,41950,41951],{},"0.94922082772201",[1551,41953,41954,41956,41958],{},[1572,41955,41227],{},[1572,41957,41189],{},[1572,41959,41960],{},"0.951278461132112",[1551,41962,41963,41965,41967],{},[1572,41964,41238],{},[1572,41966,41186],{},[1572,41968,41969],{},"0.955572468114482",[1551,41971,41972,41974,41976],{},[1572,41973,41238],{},[1572,41975,41189],{},[1572,41977,41978],{},"0.95567206186826",[1551,41980,41981,41983,41985],{},[1572,41982,41250],{},[1572,41984,41345],{},[1572,41986,41987],{},"0.96084453455483",[1551,41989,41990,41992,41994],{},[1572,41991,41230],{},[1572,41993,41345],{},[1572,41995,41996],{},"0.964619158469125",[1551,41998,41999,42001,42003],{},[1572,42000,41227],{},[1572,42002,41345],{},[1572,42004,42005],{},"0.965955795849916",[1551,42007,42008,42010,42012],{},[1572,42009,41238],{},[1572,42011,41345],{},[1572,42013,42014],{},"0.968866861905835",[12,42016,42017],{},"On peut ainsi voir d'après ce tableau, les versions ayant peu de\ndifférences et celles qui ont fait des plus gros bonds en avant.",[12,42019,42020],{},"On voit ainsi qu'il y a plus de différences entre la version 0.8.0 et la\n0.9.0, qu'il y en a eu entre la version 0.6.8 et la 0.6.9. On peut\négalement voir que les versions 0.6.4 et 0.9.0 n'ont plus rien à voir\nentre elles.",[12,42022,42023,42024,31],{},"Vous pouvez télécharger le programme attaché à ",[47,42025,42027],{"href":42026},"\u002FProgrammation\u002Fcalcul-de-la-distance\u002Fcalcul_distance.7z","ce lien",[21499,42029,42031,42034],{"className":42030,"dataFootnotes":291},[21502],[33,42032,21507],{"className":42033,"id":15686},[21506],[13835,42035,42036],{},[143,42037,42038,42039,36012,42043],{"id":21512},"On peut retrouver l'explication de cette formule ",[47,42040,34697],{"href":42041,"rel":42042},"http:\u002F\u002Finterstices.info\u002Fjcms\u002Fc_21828\u002Fclasser-musiques-langues-images-textes-et-genomes",[51],[47,42044,21520],{"href":21516,"ariaLabel":21517,"className":42045,"dataFootnoteBackref":291},[21519],[1613,42047,42048],{},"html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}",{"title":291,"searchDepth":292,"depth":292,"links":42050},[42051,42052,42053,42054],{"id":36098,"depth":375,"text":36099},{"id":40385,"depth":375,"text":40386},{"id":40555,"depth":375,"text":40556},{"id":15686,"depth":292,"text":21507},"2010-06-06",{"type":9,"value":42057},[42058,42060,42065,42070,42077,42089],[1901,42059,36099],{"id":36098},[12,42061,34773,42062,40437],{},[47,42063,40436],{"href":40434,"rel":42064},[51],[352,42066,42068],{"className":42067,"code":40441,"language":32201},[32199],[344,42069,40441],{"__ignoreMap":291},[12,42071,40446,42072,31],{},[15680,42073,42074],{},[47,42075,1944],{"href":15684,"ariaDescribedBy":42076,"dataFootnoteRef":291,"id":15687},[15686],[12,42078,40454,42079,2311,42081,854,42083,40464,42085,40467,42087,40471],{},[344,42080,40457],{},[344,42082,40460],{},[344,42084,40463],{},[344,42086,40463],{},[105,42088,40470],{},[1613,42090,42048],{},{},"\u002Fpost\u002Fcalcul-de-la-distance",{"title":40425,"description":291},"calcul-de-la-distance","posts\u002FProgrammation\u002F2010-06-06-calcul-de-la-distance",[32924,39209],"f5dJI_rOrb9a2Kflve8ejZKhwpF_zkBfNrrcWae0dOg",{"id":42099,"title":42100,"author":7,"body":42101,"category":300,"categorySlug":301,"date":44574,"description":42105,"excerpt":44575,"extension":317,"location":318,"meta":44589,"navigation":320,"path":44590,"published":320,"seo":44591,"slug":44592,"stem":44593,"tags":44594,"timeToRead":804,"__hash__":44595},"posts\u002Fposts\u002FProgrammation\u002F2009-09-21-qt-transformation-d-une-vue-tableau-en-une-vue-hierarchique.md","Qt - Transformation d'une vue tableau en une vue hiérarchique",{"type":9,"value":42102,"toc":44567},[42103,42106,42112,42115,42121,42124,42130,42133,42141,42145,42148,42154,42157,42173,42188,42195,42199,42203,42214,42220,42223,42227,42230,42420,42427,42443,42463,42473,42477,42481,42484,42572,42579,42596,42599,42603,42606,42613,42616,42652,42659,42936,42944,42947,42950,43154,43157,43164,43167,43170,43173,43176,43248,43251,43311,43326,43411,43417,43489,43498,43504,43524,43527,43530,43536,43607,43610,43644,43647,43695,43698,43733,43739,43757,43772,43775,43790,43827,43830,43914,43924,43981,43984,44003,44012,44015,44018,44077,44087,44170,44176,44188,44191,44197,44228,44231,44294,44297,44410,44417,44425,44428,44431,44444,44448,44451,44485,44489,44492,44526,44530,44533,44547,44550,44564],[12,42104,42105],{},"Pour visualiser des données internes à l'écran, Nokia\u002FQt nous propose\nl'architecture MVC à l'aide des classes QAbstractItemModel et de ses\nsous classes (QAbstractListModel, QAbstractTableModel, ...). Le but de\nl'architecture MVC est de séparer la représentation mémoire des données,\nde l'affichage qu'elles auront.",[12,42107,42108],{},[69,42109],{"alt":42110,"src":42111},"mvc1","\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Fmvc1.png",[12,42113,42114],{},"Si les données sont par exemple issue d'une requête SQL, le modèle\nQSqlQueryModel permet de représenter la sélection SQL, à l'écran dans un\ncomposant QTableView. Ces données sont alors représentées sous forme\nd'un tableau deux dimensions.",[12,42116,42117],{},[69,42118],{"alt":42119,"src":42120},"tableau","\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Ftableau.png",[12,42122,42123],{},"Si l'on veut représenter les dossiers de l'ordinateur, le modèle\nQDirView permet d'afficher les données de façon hiérarchique.",[12,42125,42126],{},[69,42127],{"alt":42128,"src":42129},"qdirview","\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Fqdirview.png",[12,42131,42132],{},"Il est également possible d'écrire nos propres modèles pour représenter\nnos propres données.",[12,42134,42135,42136,31],{},"Le but de cet article est de présenter l'écriture d'un modèle,\ntransformant une vue plane (tableau deux dimensions) en vue\nhiérarchique. Pour cela nous allons prendre l'exemple de l'affichage\nd'une liste de catégorie",[15680,42137,42138],{},[47,42139,1944],{"href":15684,"ariaDescribedBy":42140,"dataFootnoteRef":291,"id":15687},[15686],[1901,42142,42144],{"id":42143},"présentation-de-lexemple","Présentation de l'exemple",[12,42146,42147],{},"Nous allons voir ci-dessous comment transformer une vue plane en une vue\nhiérarchique. Pour cela nous allons prendre l'exemple d'une liste de\ncatégorie. Ces catégories seront stockées dans une base de données\nSqlite. Ceci n'a pas d'importance mais permet d'expliquer pourquoi les\ndonnées en mémoire ne sont pas déjà sous forme hiérarchique.",[12,42149,42150],{},[69,42151],{"alt":42152,"src":42153},"proxymodel","\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Fproxymodel.png",[12,42155,42156],{},"La description d'une catégorie passe donc par :",[13835,42158,42159,42164,42167],{},[143,42160,42161,42162],{},"un identifiant unique appelé ",[105,42163,18908],{},[143,42165,42166],{},"un nom de catégorie",[143,42168,42169,42170],{},"un lien vers la catégorie parente appelé ",[105,42171,42172],{},"parent_id",[12,42174,42175,42176,42178,42179,42182,42183,42185,42186,31],{},"C'est le champ ",[105,42177,42172],{}," qui permettra de déterminer dans quelle\ncatégorie notre sous-catégorie se trouve. Dans notre cas, ",[105,42180,42181],{},"test3"," a\ncomme ",[105,42184,42172],{}," l'identifiant 11 qui est la catégorie ",[105,42187,33288],{},[12,42189,42190,42191,42194],{},"Dans notre exemple, nous allons nous conditionner à un modèle en lecture\nseul. Il est également possible de faire un modèle en lecture\u002Fécriture\nmais nous n'en parlerons pas dans cet article. Nous nous cantonnerons\ndonc à un modèle lecture seul sur un modèle source de type\n",[105,42192,42193],{},"QSqlTableView",". (Un modèle en lecture\u002Fécriture peut nécessiter de\nmettre à jour notre structure, ce qui peut être assez compliqué, par\nexemple en cas de changement de la catégorie parente).",[1901,42196,42198],{"id":42197},"déclaration-dun-modèle","Déclaration d'un modèle",[23034,42200,42202],{"id":42201},"quest-quun-proxy","Qu'est qu'un proxy ?",[12,42204,42205,42206,42209,42210,42213],{},"Notre interface se basera sur la classe ",[105,42207,42208],{},"QAbstractProxyModel",". Le but de\ncette classe est de permettre de faire une transposition entre un\npremier modèle et une vue. Elle peut par exemple (à l'aide de\n",[105,42211,42212],{},"QSortFilterProxyModel",") permettre de filtrer ou trier les données d'une\nvue.",[12,42215,42216],{},[69,42217],{"alt":42218,"src":42219},"mvc","\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Fmvc.png",[12,42221,42222],{},"Cette vue nous permettra de faire la transposition entre un modèle\ntableau et une vue arborescente.",[23034,42224,42226],{"id":42225},"interface-du-proxy","Interface du proxy",[12,42228,42229],{},"Les méthodes à ré-implémenter pour faire fonctionner une proxy, sont les\nsuivantes :",[352,42231,42233],{"className":635,"code":42232,"language":637,"meta":291,"style":291},"virtual QModelIndex index( int row, int column, const QModelIndex & parent ) const;\nvirtual QModelIndex parent( const QModelIndex & index ) const;\n\nvirtual int rowCount( const QModelIndex & parent = QModelIndex() ) const;\nvirtual int columnCount( const QModelIndex & parent = QModelIndex() ) const;\n\nvirtual QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const;\nvirtual QModelIndex mapToSource ( const QModelIndex & proxyIndex ) const;\n",[344,42234,42235,42277,42301,42305,42335,42364,42368,42394],{"__ignoreMap":291},[360,42236,42237,42240,42243,42246,42248,42250,42253,42255,42257,42260,42262,42264,42266,42268,42270,42273,42275],{"class":362,"line":363},[360,42238,42239],{"class":574},"virtual",[360,42241,42242],{"class":662}," QModelIndex",[360,42244,42245],{"class":381}," index",[360,42247,25124],{"class":366},[360,42249,26486],{"class":574},[360,42251,42252],{"class":677}," row",[360,42254,2311],{"class":366},[360,42256,26486],{"class":574},[360,42258,42259],{"class":677}," column",[360,42261,2311],{"class":366},[360,42263,6053],{"class":574},[360,42265,42242],{"class":662},[360,42267,4195],{"class":574},[360,42269,22788],{"class":677},[360,42271,42272],{"class":366}," ) ",[360,42274,6053],{"class":574},[360,42276,735],{"class":366},[360,42278,42279,42281,42283,42285,42287,42289,42291,42293,42295,42297,42299],{"class":362,"line":292},[360,42280,42239],{"class":574},[360,42282,42242],{"class":662},[360,42284,22788],{"class":381},[360,42286,25124],{"class":366},[360,42288,6053],{"class":574},[360,42290,42242],{"class":662},[360,42292,4195],{"class":574},[360,42294,42245],{"class":677},[360,42296,42272],{"class":366},[360,42298,6053],{"class":574},[360,42300,735],{"class":366},[360,42302,42303],{"class":362,"line":375},[360,42304,372],{"emptyLinePlaceholder":320},[360,42306,42307,42309,42311,42314,42316,42318,42320,42322,42324,42326,42328,42331,42333],{"class":362,"line":433},[360,42308,42239],{"class":574},[360,42310,1091],{"class":574},[360,42312,42313],{"class":381}," rowCount",[360,42315,25124],{"class":366},[360,42317,6053],{"class":574},[360,42319,42242],{"class":662},[360,42321,4195],{"class":574},[360,42323,22788],{"class":677},[360,42325,401],{"class":574},[360,42327,42242],{"class":381},[360,42329,42330],{"class":366},"() ) ",[360,42332,6053],{"class":574},[360,42334,735],{"class":366},[360,42336,42337,42339,42341,42344,42346,42348,42350,42352,42354,42356,42358,42360,42362],{"class":362,"line":478},[360,42338,42239],{"class":574},[360,42340,1091],{"class":574},[360,42342,42343],{"class":381}," columnCount",[360,42345,25124],{"class":366},[360,42347,6053],{"class":574},[360,42349,42242],{"class":662},[360,42351,4195],{"class":574},[360,42353,22788],{"class":677},[360,42355,401],{"class":574},[360,42357,42242],{"class":381},[360,42359,42330],{"class":366},[360,42361,6053],{"class":574},[360,42363,735],{"class":366},[360,42365,42366],{"class":362,"line":483},[360,42367,372],{"emptyLinePlaceholder":320},[360,42369,42370,42372,42374,42377,42379,42381,42383,42385,42388,42390,42392],{"class":362,"line":489},[360,42371,42239],{"class":574},[360,42373,42242],{"class":662},[360,42375,42376],{"class":381}," mapFromSource",[360,42378,35489],{"class":366},[360,42380,6053],{"class":574},[360,42382,42242],{"class":662},[360,42384,4195],{"class":574},[360,42386,42387],{"class":677}," sourceIndex",[360,42389,42272],{"class":366},[360,42391,6053],{"class":574},[360,42393,735],{"class":366},[360,42395,42396,42398,42400,42403,42405,42407,42409,42411,42414,42416,42418],{"class":362,"line":494},[360,42397,42239],{"class":574},[360,42399,42242],{"class":662},[360,42401,42402],{"class":381}," mapToSource",[360,42404,35489],{"class":366},[360,42406,6053],{"class":574},[360,42408,42242],{"class":662},[360,42410,4195],{"class":574},[360,42412,42413],{"class":677}," proxyIndex",[360,42415,42272],{"class":366},[360,42417,6053],{"class":574},[360,42419,735],{"class":366},[12,42421,42422,42423,42426],{},"Les quatre premières méthodes appartiennent à l'objet\n",[105,42424,42425],{},"QAbstractItemModel"," et seront questionnées par la vue (liste, arbre, …)\npour connaître la représentation à l'écran.",[12,42428,29638,42429,29886,42432,42435,42436,42438,42439,42442],{},[105,42430,42431],{},"mapFromSource()",[105,42433,42434],{},"mapToSource()"," sont à implémenter\npour l'objet ",[105,42437,42208],{},". Elles permettent de faire la liaison\nentre les indexes (",[105,42440,42441],{},"QModelIndex",") du modèle d'origine et les indexes du\nnouveau modèle.",[12,42444,29638,42445,2311,42448,2311,42451,42454,42455,42457,42458,854,42460,42462],{},[105,42446,42447],{},"data()",[105,42449,42450],{},"headerData()",[105,42452,42453],{},"flags()"," sont réimplémentées par\nl'objet ",[105,42456,42208],{}," et utilisent les méthodes\n",[105,42459,42431],{},[105,42461,42434],{}," pour, lors de l'appel d'une de ces\nméthodes, récupérer les informations stockées sur le modèle d'origine.",[12,42464,42465,42466,854,42469,42472],{},"Des méthodes ",[105,42467,42468],{},"sourceModel()",[105,42470,42471],{},"setSourceModel()"," permettent de\nspécifier le modèle d'origine.",[1901,42474,42476],{"id":42475},"implémentation-de-notre-modèle","Implémentation de notre modèle",[23034,42478,42480],{"id":42479},"structure-interne","Structure interne",[12,42482,42483],{},"Nous allons, dans cette partie, parler de la structure interne utilisée\npar notre objet.",[352,42485,42487],{"className":635,"code":42486,"language":637,"meta":291,"style":291},"struct Mapping {\n    int id, parrentId;\n    int index, parentIndex;\n    QVector\u003Cint> source_rows;\n};\ntypedef QMap\u003Cint,Mapping*> IndexMap;\n\nIndexMap m_sourcesIndexMapping;\nQHash\u003Cint,int> m_categoryIdMapping;\n",[344,42488,42489,42498,42506,42513,42524,42528,42548,42552,42557],{"__ignoreMap":291},[360,42490,42491,42493,42496],{"class":362,"line":363},[360,42492,890],{"class":574},[360,42494,42495],{"class":662}," Mapping",[360,42497,896],{"class":366},[360,42499,42500,42503],{"class":362,"line":292},[360,42501,42502],{"class":574},"    int",[360,42504,42505],{"class":366}," id, parrentId;\n",[360,42507,42508,42510],{"class":362,"line":375},[360,42509,42502],{"class":574},[360,42511,42512],{"class":366}," index, parentIndex;\n",[360,42514,42515,42518,42521],{"class":362,"line":433},[360,42516,42517],{"class":366},"    QVector",[360,42519,42520],{"class":574},"\u003Cint>",[360,42522,42523],{"class":366}," source_rows;\n",[360,42525,42526],{"class":362,"line":478},[360,42527,1036],{"class":366},[360,42529,42530,42533,42536,42539,42542,42545],{"class":362,"line":483},[360,42531,42532],{"class":574},"typedef",[360,42534,42535],{"class":366}," QMap",[360,42537,42538],{"class":574},"\u003Cint",[360,42540,42541],{"class":366},",Mapping",[360,42543,42544],{"class":574},"*>",[360,42546,42547],{"class":366}," IndexMap;\n",[360,42549,42550],{"class":362,"line":489},[360,42551,372],{"emptyLinePlaceholder":320},[360,42553,42554],{"class":362,"line":494},[360,42555,42556],{"class":366},"IndexMap m_sourcesIndexMapping;\n",[360,42558,42559,42562,42564,42566,42569],{"class":362,"line":712},[360,42560,42561],{"class":366},"QHash",[360,42563,42538],{"class":574},[360,42565,22488],{"class":366},[360,42567,42568],{"class":574},"int>",[360,42570,42571],{"class":366}," m_categoryIdMapping;\n",[12,42573,42574,42575,42578],{},"Nous allons créer une structure ",[105,42576,42577],{},"Mapping"," qui associera pour une ligne\ndans le modèle source, les informations concernant :",[13835,42580,42581,42584,42587,42590,42593],{},[143,42582,42583],{},"l'identifiant de la ligne.",[143,42585,42586],{},"l'identifiant de la ligne parente.",[143,42588,42589],{},"l'index dans le modèle source.",[143,42591,42592],{},"l'index du parent dans le modèle source.",[143,42594,42595],{},"la liste des indexes dans le modèle source des enfants dans notre\nmodèle.",[12,42597,42598],{},"Une table de hashage permettra de retrouver à partir d'un identifiant\n(id), la ligne dans le modèle source correspondante. On ne gardera que\nla seconde colonne (le nom de la catégorie), on ne fera donc\nl'association qu'entre le nom de la colonne de notre modèle et le modèle\nsource en dure dans le programme.",[23034,42600,42602],{"id":42601},"createmapping","createMapping()",[12,42604,42605],{},"Le but de cette méthode est de générer l'arborescence qui sera ensuite\nutilisée dans la suite des méthodes. Cette arborescence étant générée\nune fois pour toute (ou à chaque fois que le modèle source sera\nréinitialisé), il faudra parcourir l'ensemble des lignes du modèle\nsource pour construire notre arbre. Parcourir l'ensemble des lignes du\nmodèle source peut prendre du temps si ce dernier contient beaucoup de\nligne.",[12,42607,42608,42609,42612],{},"Nous allons considérer dans la suite, que l'identifiant de ligne 1 (id)\ncorrespond à la catégorie de plus haut niveau (ci-dessus du nom de\n",[105,42610,42611],{},"Categories","). Nous allons créer une catégorie fictive 0 qui\ncorrespondra à la racine de notre modèle. Cette catégorie sera donc la\ncatégorie parente de celle à l'identifiant 1.Dans notre modèle source,\nla catégorie 0 n'a pas d'équivalence parmi les lignes du modèle source.\nNous allons donc lui associer la ligne -1 dans le modèle source.",[12,42614,42615],{},"Maintenant voyons la génération de la structure interne.",[352,42617,42619],{"className":635,"code":42618,"language":637,"meta":291,"style":291},"qDeleteAll( m_sourcesIndexMapping );\nm_sourcesIndexMapping.clear();\nm_categoryIdMapping.clear();\n",[344,42620,42621,42629,42641],{"__ignoreMap":291},[360,42622,42623,42626],{"class":362,"line":363},[360,42624,42625],{"class":381},"qDeleteAll",[360,42627,42628],{"class":366},"( m_sourcesIndexMapping );\n",[360,42630,42631,42634,42636,42639],{"class":362,"line":292},[360,42632,42633],{"class":662},"m_sourcesIndexMapping",[360,42635,31],{"class":366},[360,42637,42638],{"class":381},"clear",[360,42640,2204],{"class":366},[360,42642,42643,42646,42648,42650],{"class":362,"line":375},[360,42644,42645],{"class":662},"m_categoryIdMapping",[360,42647,31],{"class":366},[360,42649,42638],{"class":381},[360,42651,2204],{"class":366},[12,42653,42654,42655,42658],{},"Nous commençons ci-dessous par nettoyer les différentes structures afin\nde les régénérer. Il faudra à la suite de la création du mapping appeler\nla méthode ",[105,42656,42657],{},"reset()"," afin de prévenir la vue que l'ensemble des indexes\ndu modèle sont obsolètes.",[352,42660,42662],{"className":635,"code":42661,"language":637,"meta":291,"style":291},"int source_rows = m_sourceModel->rowCount();\nfor( int i = -1; i \u003C source_rows; ++i ) {\n    Mapping * m = new Mapping;\n    IndexMap::const_iterator it = IndexMap::const_iterator( m_sourcesIndexMapping.insert( i, m ) );\n    m->index = i;\n    m->parrentId = 0;\n    m->parentIndex = 0;\n\n    if( i >= 0 ) {\n        QSqlRecord record = m_sourceModel->record( i );\n        m_categoryIdMapping[ record.value( list_id ).toInt() ] = i;\n        m->id = record.value( list_id ).toInt();\n    } else { \u002F\u002F Create the root Item\n        m->id = 0;\n        m_categoryIdMapping[ 0 ] = -1;\n    }\n}\n",[344,42663,42664,42683,42712,42729,42754,42769,42784,42799,42803,42816,42833,42860,42884,42895,42909,42928,42932],{"__ignoreMap":291},[360,42665,42666,42668,42671,42673,42676,42678,42681],{"class":362,"line":363},[360,42667,26486],{"class":574},[360,42669,42670],{"class":366}," source_rows ",[360,42672,583],{"class":574},[360,42674,42675],{"class":662}," m_sourceModel",[360,42677,2376],{"class":366},[360,42679,42680],{"class":381},"rowCount",[360,42682,2204],{"class":366},[360,42684,42685,42687,42689,42691,42693,42695,42697,42699,42702,42704,42707,42709],{"class":362,"line":292},[360,42686,6945],{"class":574},[360,42688,25124],{"class":366},[360,42690,26486],{"class":574},[360,42692,39994],{"class":366},[360,42694,583],{"class":574},[360,42696,518],{"class":574},[360,42698,1944],{"class":414},[360,42700,42701],{"class":366},"; i ",[360,42703,1358],{"class":574},[360,42705,42706],{"class":366}," source_rows; ",[360,42708,6199],{"class":574},[360,42710,42711],{"class":366},"i ) {\n",[360,42713,42714,42717,42719,42722,42724,42726],{"class":362,"line":375},[360,42715,42716],{"class":366},"    Mapping ",[360,42718,925],{"class":574},[360,42720,42721],{"class":366}," m ",[360,42723,583],{"class":574},[360,42725,3040],{"class":574},[360,42727,42728],{"class":366}," Mapping;\n",[360,42730,42731,42734,42736,42739,42742,42744,42746,42748,42751],{"class":362,"line":433},[360,42732,42733],{"class":366},"    IndexMap::const_iterator it ",[360,42735,583],{"class":574},[360,42737,42738],{"class":366}," IndexMap::",[360,42740,42741],{"class":381},"const_iterator",[360,42743,25124],{"class":366},[360,42745,42633],{"class":662},[360,42747,31],{"class":366},[360,42749,42750],{"class":381},"insert",[360,42752,42753],{"class":366},"( i, m ) );\n",[360,42755,42756,42759,42761,42764,42766],{"class":362,"line":478},[360,42757,42758],{"class":662},"    m",[360,42760,2376],{"class":366},[360,42762,42763],{"class":578},"index",[360,42765,401],{"class":574},[360,42767,42768],{"class":366}," i;\n",[360,42770,42771,42773,42775,42778,42780,42782],{"class":362,"line":483},[360,42772,42758],{"class":662},[360,42774,2376],{"class":366},[360,42776,42777],{"class":578},"parrentId",[360,42779,401],{"class":574},[360,42781,1457],{"class":414},[360,42783,735],{"class":366},[360,42785,42786,42788,42790,42793,42795,42797],{"class":362,"line":489},[360,42787,42758],{"class":662},[360,42789,2376],{"class":366},[360,42791,42792],{"class":578},"parentIndex",[360,42794,401],{"class":574},[360,42796,1457],{"class":414},[360,42798,735],{"class":366},[360,42800,42801],{"class":362,"line":494},[360,42802,372],{"emptyLinePlaceholder":320},[360,42804,42805,42807,42810,42812,42814],{"class":362,"line":712},[360,42806,5657],{"class":574},[360,42808,42809],{"class":366},"( i ",[360,42811,729],{"class":574},[360,42813,1457],{"class":414},[360,42815,2426],{"class":366},[360,42817,42818,42821,42823,42825,42827,42830],{"class":362,"line":331},[360,42819,42820],{"class":366},"        QSqlRecord record ",[360,42822,583],{"class":574},[360,42824,42675],{"class":662},[360,42826,2376],{"class":366},[360,42828,42829],{"class":381},"record",[360,42831,42832],{"class":366},"( i );\n",[360,42834,42835,42838,42841,42843,42845,42847,42850,42853,42856,42858],{"class":362,"line":762},[360,42836,42837],{"class":662},"        m_categoryIdMapping",[360,42839,42840],{"class":366},"[ ",[360,42842,42829],{"class":662},[360,42844,31],{"class":366},[360,42846,19758],{"class":381},[360,42848,42849],{"class":366},"( list_id ).",[360,42851,42852],{"class":381},"toInt",[360,42854,42855],{"class":366},"() ] ",[360,42857,583],{"class":574},[360,42859,42768],{"class":366},[360,42861,42862,42865,42867,42869,42871,42874,42876,42878,42880,42882],{"class":362,"line":781},[360,42863,42864],{"class":662},"        m",[360,42866,2376],{"class":366},[360,42868,18908],{"class":578},[360,42870,401],{"class":574},[360,42872,42873],{"class":662}," record",[360,42875,31],{"class":366},[360,42877,19758],{"class":381},[360,42879,42849],{"class":366},[360,42881,42852],{"class":381},[360,42883,2204],{"class":366},[360,42885,42886,42888,42890,42892],{"class":362,"line":804},[360,42887,18951],{"class":366},[360,42889,2488],{"class":574},[360,42891,32239],{"class":366},[360,42893,42894],{"class":644}," \u002F\u002F Create the root Item\n",[360,42896,42897,42899,42901,42903,42905,42907],{"class":362,"line":817},[360,42898,42864],{"class":662},[360,42900,2376],{"class":366},[360,42902,18908],{"class":578},[360,42904,401],{"class":574},[360,42906,1457],{"class":414},[360,42908,735],{"class":366},[360,42910,42911,42913,42915,42917,42920,42922,42924,42926],{"class":362,"line":823},[360,42912,42837],{"class":662},[360,42914,42840],{"class":366},[360,42916,1344],{"class":414},[360,42918,42919],{"class":366}," ] ",[360,42921,583],{"class":574},[360,42923,518],{"class":574},[360,42925,1944],{"class":414},[360,42927,735],{"class":366},[360,42929,42930],{"class":362,"line":844},[360,42931,2927],{"class":366},[360,42933,42934],{"class":362,"line":1441},[360,42935,847],{"class":366},[12,42937,42938,42939,42941,42942,31],{},"Nous récupérons le nombre de ligne dans le modèle source et commençons à\ninitialiser notre structure. Le but de cette boucle est surtout\nd'initialiser dans notre correspondance identifiant\u002Findex\n(",[105,42940,42645],{},"), l'emplacement des identifiants dans notre\ntableau. Ainsi dans la suite lorsque l'on essaiera d'associer une ligne\nà son parent, nous pourrons savoir à quel emplacement retrouver notre id\ndans la structure ",[105,42943,42633],{},[12,42945,42946],{},"Nous profitons également de cette boucle pour initialiser les différents\nchamps de notre structure comme l'index (qui correspond à la ligne dans\nle modèle source), et l'id qui correspond à un identifiant unique dans\nnotre liste.",[12,42948,42949],{},"Nous n'oublions pas notre cas particulier que représente notre racine\n(ligne source -1 inexistante).",[352,42951,42953],{"className":635,"code":42952,"language":637,"meta":291,"style":291},"for( int i = 0; i \u003C source_rows; ++i ) {\n    QSqlRecord record = m_sourceModel->record( i );\n\n    int parentCategoryId = record.value( list_parentid ).toInt();\n    int parentCategoryIndex = m_categoryIdMapping.value( parentCategoryId, -2 );\n    Q_ASSERT( parentCategoryIndex > -2 );\n    Mapping * mapping = m_sourcesIndexMapping.value( i );\n    mapping->parentIndex = parentCategoryIndex;\n    mapping->parrentId   = parentCategoryId;\n\n    Mapping * categoryMapping = m_sourcesIndexMapping.value( parentCategoryIndex );\n    categoryMapping->source_rows.append( i );\n}\n",[344,42954,42955,42979,42994,42998,43020,43046,43062,43082,43096,43110,43114,43134,43150],{"__ignoreMap":291},[360,42956,42957,42959,42961,42963,42965,42967,42969,42971,42973,42975,42977],{"class":362,"line":363},[360,42958,6945],{"class":574},[360,42960,25124],{"class":366},[360,42962,26486],{"class":574},[360,42964,39994],{"class":366},[360,42966,583],{"class":574},[360,42968,1457],{"class":414},[360,42970,42701],{"class":366},[360,42972,1358],{"class":574},[360,42974,42706],{"class":366},[360,42976,6199],{"class":574},[360,42978,42711],{"class":366},[360,42980,42981,42984,42986,42988,42990,42992],{"class":362,"line":292},[360,42982,42983],{"class":366},"    QSqlRecord record ",[360,42985,583],{"class":574},[360,42987,42675],{"class":662},[360,42989,2376],{"class":366},[360,42991,42829],{"class":381},[360,42993,42832],{"class":366},[360,42995,42996],{"class":362,"line":375},[360,42997,372],{"emptyLinePlaceholder":320},[360,42999,43000,43002,43005,43007,43009,43011,43013,43016,43018],{"class":362,"line":433},[360,43001,42502],{"class":574},[360,43003,43004],{"class":366}," parentCategoryId ",[360,43006,583],{"class":574},[360,43008,42873],{"class":662},[360,43010,31],{"class":366},[360,43012,19758],{"class":381},[360,43014,43015],{"class":366},"( list_parentid ).",[360,43017,42852],{"class":381},[360,43019,2204],{"class":366},[360,43021,43022,43024,43027,43029,43032,43034,43036,43039,43041,43043],{"class":362,"line":478},[360,43023,42502],{"class":574},[360,43025,43026],{"class":366}," parentCategoryIndex ",[360,43028,583],{"class":574},[360,43030,43031],{"class":662}," m_categoryIdMapping",[360,43033,31],{"class":366},[360,43035,19758],{"class":381},[360,43037,43038],{"class":366},"( parentCategoryId, ",[360,43040,1491],{"class":574},[360,43042,795],{"class":414},[360,43044,43045],{"class":366}," );\n",[360,43047,43048,43051,43054,43056,43058,43060],{"class":362,"line":483},[360,43049,43050],{"class":381},"    Q_ASSERT",[360,43052,43053],{"class":366},"( parentCategoryIndex ",[360,43055,24917],{"class":574},[360,43057,518],{"class":574},[360,43059,795],{"class":414},[360,43061,43045],{"class":366},[360,43063,43064,43066,43068,43071,43073,43076,43078,43080],{"class":362,"line":489},[360,43065,42716],{"class":366},[360,43067,925],{"class":574},[360,43069,43070],{"class":366}," mapping ",[360,43072,583],{"class":574},[360,43074,43075],{"class":662}," m_sourcesIndexMapping",[360,43077,31],{"class":366},[360,43079,19758],{"class":381},[360,43081,42832],{"class":366},[360,43083,43084,43087,43089,43091,43093],{"class":362,"line":494},[360,43085,43086],{"class":662},"    mapping",[360,43088,2376],{"class":366},[360,43090,42792],{"class":578},[360,43092,401],{"class":574},[360,43094,43095],{"class":366}," parentCategoryIndex;\n",[360,43097,43098,43100,43102,43104,43107],{"class":362,"line":712},[360,43099,43086],{"class":662},[360,43101,2376],{"class":366},[360,43103,42777],{"class":578},[360,43105,43106],{"class":574},"   =",[360,43108,43109],{"class":366}," parentCategoryId;\n",[360,43111,43112],{"class":362,"line":331},[360,43113,372],{"emptyLinePlaceholder":320},[360,43115,43116,43118,43120,43123,43125,43127,43129,43131],{"class":362,"line":762},[360,43117,42716],{"class":366},[360,43119,925],{"class":574},[360,43121,43122],{"class":366}," categoryMapping ",[360,43124,583],{"class":574},[360,43126,43075],{"class":662},[360,43128,31],{"class":366},[360,43130,19758],{"class":381},[360,43132,43133],{"class":366},"( parentCategoryIndex );\n",[360,43135,43136,43139,43141,43144,43146,43148],{"class":362,"line":781},[360,43137,43138],{"class":662},"    categoryMapping",[360,43140,2376],{"class":366},[360,43142,43143],{"class":662},"source_rows",[360,43145,31],{"class":366},[360,43147,37657],{"class":381},[360,43149,42832],{"class":366},[360,43151,43152],{"class":362,"line":804},[360,43153,847],{"class":366},[12,43155,43156],{},"Enfin pour chaque enregistrement de notre modèle source, nous récupérons\nl'identifiant du parent et recherchons dans la structure que nous venons\nde créer l'index dans le modèle source de la catégorie parente.",[12,43158,43159,43160,43163],{},"Ces valeurs sont alors renseignées dans le modèle. Nos ajoutons\négalement dans la structure de ",[105,43161,43162],{},"mapping"," de la catégorie parent, notre\nligne dans la liste des enfants.",[12,43165,43166],{},"Notre structure est ainsi complètement initialisé. Un identifiant\nconnaît donc son parent, et la liste de ses enfants. C'est sur cette\nstructure que se basera le reste des méthodes de notre modèle.",[23034,43168,42431],{"id":43169},"mapfromsource",[12,43171,43172],{},"Le but de cette méthode est de convertir notre index venant du modèle\nsource vers un index de notre modèle à nous.",[12,43174,43175],{},"L'index du modèle source nous donne l'emplacement de la donnée dans le\nmodèle source sous forme (ligne, colonne) alors que l'index de notre\nmodèle doit donner l'emplacement dans notre modèle sous la forme (ligne,\ncolonne, pointeur indiquant le parent).",[352,43177,43179],{"className":635,"code":43178,"language":637,"meta":291,"style":291},"if( ! sourceIndex.isValid() ) return QModelIndex();\nif( sourceIndex.model() != m_sourceModel ) {\n    qWarning( \"CategoryItemModel: index from wrong model passed to mapFromSource\" );\n    return QModelIndex();\n}\n",[344,43180,43181,43204,43224,43236,43244],{"__ignoreMap":291},[360,43182,43183,43185,43187,43189,43191,43193,43196,43198,43200,43202],{"class":362,"line":363},[360,43184,2370],{"class":574},[360,43186,25124],{"class":366},[360,43188,1448],{"class":582},[360,43190,42387],{"class":662},[360,43192,31],{"class":366},[360,43194,43195],{"class":381},"isValid",[360,43197,42330],{"class":366},[360,43199,1454],{"class":574},[360,43201,42242],{"class":381},[360,43203,2204],{"class":366},[360,43205,43206,43208,43210,43213,43215,43217,43219,43221],{"class":362,"line":292},[360,43207,2370],{"class":574},[360,43209,25124],{"class":366},[360,43211,43212],{"class":662},"sourceIndex",[360,43214,31],{"class":366},[360,43216,21668],{"class":381},[360,43218,2805],{"class":366},[360,43220,27471],{"class":574},[360,43222,43223],{"class":366}," m_sourceModel ) {\n",[360,43225,43226,43229,43231,43234],{"class":362,"line":375},[360,43227,43228],{"class":381},"    qWarning",[360,43230,25124],{"class":366},[360,43232,43233],{"class":397},"\"CategoryItemModel: index from wrong model passed to mapFromSource\"",[360,43235,43045],{"class":366},[360,43237,43238,43240,43242],{"class":362,"line":433},[360,43239,1386],{"class":574},[360,43241,42242],{"class":381},[360,43243,2204],{"class":366},[360,43245,43246],{"class":362,"line":478},[360,43247,847],{"class":366},[12,43249,43250],{},"Il faut donc d'abord vérifier que l'index du modèle source est valide.\nS'il n'est pas valide, alors il ne sera pas valide non plus dans notre\nmodèle à nous.",[352,43252,43254],{"className":635,"code":43253,"language":637,"meta":291,"style":291},"int row = sourceIndex.row();\nIndexMap::const_iterator it = m_sourcesIndexMapping.constFind( row );\nQ_ASSERT( it != m_sourcesIndexMapping.constEnd() );\n",[344,43255,43256,43274,43291],{"__ignoreMap":291},[360,43257,43258,43260,43263,43265,43267,43269,43272],{"class":362,"line":363},[360,43259,26486],{"class":574},[360,43261,43262],{"class":366}," row ",[360,43264,583],{"class":574},[360,43266,42387],{"class":662},[360,43268,31],{"class":366},[360,43270,43271],{"class":381},"row",[360,43273,2204],{"class":366},[360,43275,43276,43279,43281,43283,43285,43288],{"class":362,"line":292},[360,43277,43278],{"class":366},"IndexMap::const_iterator it ",[360,43280,583],{"class":574},[360,43282,43075],{"class":662},[360,43284,31],{"class":366},[360,43286,43287],{"class":381},"constFind",[360,43289,43290],{"class":366},"( row );\n",[360,43292,43293,43296,43299,43301,43303,43305,43308],{"class":362,"line":375},[360,43294,43295],{"class":381},"Q_ASSERT",[360,43297,43298],{"class":366},"( it ",[360,43300,27471],{"class":574},[360,43302,43075],{"class":662},[360,43304,31],{"class":366},[360,43306,43307],{"class":381},"constEnd",[360,43309,43310],{"class":366},"() );\n",[12,43312,43313,43314,43316,43317,43319,43320,43322,43323,43325],{},"Nous récupérons l'index dans le modèle source, et à l'aide de notre\ntableau d'index source, nous allons retrouver l'objet ",[105,43315,42577],{},"\ncorrespondant. Cette objet ",[105,43318,42577],{}," correspondra à celui de notre index\nsource. Ce dont nous avons besoin pour notre modèle est l'objet\n",[105,43321,42577],{}," de l'objet parent (En effet, notre index est construit sous la\nforme : ligne, colonne, pointeur sur la structure ",[105,43324,42577],{}," du parent de\nnotre index). Nous récupérons donc l'index de la ligne source dans\nl'objet parent.",[352,43327,43329],{"className":635,"code":43328,"language":637,"meta":291,"style":291},"int parentRow = it.value()->parentIndex;\nIndexMap::const_iterator parentIt = m_sourcesIndexMapping.constFind( parentRow );\nQ_ASSERT( parentIt != m_sourcesIndexMapping.constEnd() );\n\nMapping * m = parentIt.value();\n",[344,43330,43331,43354,43370,43387,43391],{"__ignoreMap":291},[360,43332,43333,43335,43338,43340,43343,43345,43347,43350,43352],{"class":362,"line":363},[360,43334,26486],{"class":574},[360,43336,43337],{"class":366}," parentRow ",[360,43339,583],{"class":574},[360,43341,43342],{"class":662}," it",[360,43344,31],{"class":366},[360,43346,19758],{"class":381},[360,43348,43349],{"class":366},"()->",[360,43351,42792],{"class":578},[360,43353,735],{"class":366},[360,43355,43356,43359,43361,43363,43365,43367],{"class":362,"line":292},[360,43357,43358],{"class":366},"IndexMap::const_iterator parentIt ",[360,43360,583],{"class":574},[360,43362,43075],{"class":662},[360,43364,31],{"class":366},[360,43366,43287],{"class":381},[360,43368,43369],{"class":366},"( parentRow );\n",[360,43371,43372,43374,43377,43379,43381,43383,43385],{"class":362,"line":375},[360,43373,43295],{"class":381},[360,43375,43376],{"class":366},"( parentIt ",[360,43378,27471],{"class":574},[360,43380,43075],{"class":662},[360,43382,31],{"class":366},[360,43384,43307],{"class":381},[360,43386,43310],{"class":366},[360,43388,43389],{"class":362,"line":433},[360,43390,372],{"emptyLinePlaceholder":320},[360,43392,43393,43396,43398,43400,43402,43405,43407,43409],{"class":362,"line":478},[360,43394,43395],{"class":366},"Mapping ",[360,43397,925],{"class":574},[360,43399,42721],{"class":366},[360,43401,583],{"class":574},[360,43403,43404],{"class":662}," parentIt",[360,43406,31],{"class":366},[360,43408,19758],{"class":381},[360,43410,2204],{"class":366},[12,43412,43413,43414,43416],{},"Cela nous permet de récupérer l'objet ",[105,43415,42577],{}," de l'index parent.",[352,43418,43420],{"className":635,"code":43419,"language":637,"meta":291,"style":291},"int proxyRow    = m->source_rows.indexOf( row );\nint proxyColumn = sourceColumnToProxy( sourceIndex.column() );\nif( proxyColumn == -1 ) return QModelIndex();\n",[344,43421,43422,43445,43468],{"__ignoreMap":291},[360,43423,43424,43426,43429,43431,43434,43436,43438,43440,43443],{"class":362,"line":363},[360,43425,26486],{"class":574},[360,43427,43428],{"class":366}," proxyRow    ",[360,43430,583],{"class":574},[360,43432,43433],{"class":662}," m",[360,43435,2376],{"class":366},[360,43437,43143],{"class":662},[360,43439,31],{"class":366},[360,43441,43442],{"class":381},"indexOf",[360,43444,43290],{"class":366},[360,43446,43447,43449,43452,43454,43457,43459,43461,43463,43466],{"class":362,"line":292},[360,43448,26486],{"class":574},[360,43450,43451],{"class":366}," proxyColumn ",[360,43453,583],{"class":574},[360,43455,43456],{"class":381}," sourceColumnToProxy",[360,43458,25124],{"class":366},[360,43460,43212],{"class":662},[360,43462,31],{"class":366},[360,43464,43465],{"class":381},"column",[360,43467,43310],{"class":366},[360,43469,43470,43472,43475,43477,43479,43481,43483,43485,43487],{"class":362,"line":375},[360,43471,2370],{"class":574},[360,43473,43474],{"class":366},"( proxyColumn ",[360,43476,2393],{"class":574},[360,43478,518],{"class":574},[360,43480,1944],{"class":414},[360,43482,42272],{"class":366},[360,43484,1454],{"class":574},[360,43486,42242],{"class":381},[360,43488,2204],{"class":366},[12,43490,29024,43491,43494,43495,31],{},[105,43492,43493],{},"sourceColumnToProxy()"," permet de transformer une colonne de\nl'objet source en une colonne de l'objet courant. Cela signifie que la\ncolonne 2 sera convertie en colonne 1, et que les colonnes 1 et 3 ne\nseront pas converties (et cachées). Dans ce dernier cas, nous retournons\n",[105,43496,43497],{},"QModelIndex()",[12,43499,43500,43501,43503],{},"L'index de la ligne dans notre modèle sera donné par la position dans la\nliste ",[105,43502,43143],{}," dans notre structure de conversion.",[352,43505,43507],{"className":635,"code":43506,"language":637,"meta":291,"style":291},"return createIndex( proxyRow, proxyColumn, *parentIt );\n",[344,43508,43509],{"__ignoreMap":291},[360,43510,43511,43513,43516,43519,43521],{"class":362,"line":363},[360,43512,1454],{"class":574},[360,43514,43515],{"class":381}," createIndex",[360,43517,43518],{"class":366},"( proxyRow, proxyColumn, ",[360,43520,925],{"class":574},[360,43522,43523],{"class":366},"parentIt );\n",[12,43525,43526],{},"Nous pouvons alors créer notre index.",[23034,43528,42434],{"id":43529},"maptosource",[12,43531,43532,43533,43535],{},"De la manière inverse à la méthode ",[105,43534,42431],{},", cette méthode\npermet de convertir un index de notre objet en un index du modèle\nsource.",[352,43537,43539],{"className":635,"code":43538,"language":637,"meta":291,"style":291},"if( ! proxyIndex.isValid() ) return QModelIndex();\nif( proxyIndex.model() != this ) {\n    qWarning( \"CategoryItemModel: index from wrong model passed to mapToSource\" );\n    return QModelIndex();\n}\n",[344,43540,43541,43563,43584,43595,43603],{"__ignoreMap":291},[360,43542,43543,43545,43547,43549,43551,43553,43555,43557,43559,43561],{"class":362,"line":363},[360,43544,2370],{"class":574},[360,43546,25124],{"class":366},[360,43548,1448],{"class":582},[360,43550,42413],{"class":662},[360,43552,31],{"class":366},[360,43554,43195],{"class":381},[360,43556,42330],{"class":366},[360,43558,1454],{"class":574},[360,43560,42242],{"class":381},[360,43562,2204],{"class":366},[360,43564,43565,43567,43569,43572,43574,43576,43578,43580,43582],{"class":362,"line":292},[360,43566,2370],{"class":574},[360,43568,25124],{"class":366},[360,43570,43571],{"class":662},"proxyIndex",[360,43573,31],{"class":366},[360,43575,21668],{"class":381},[360,43577,2805],{"class":366},[360,43579,27471],{"class":574},[360,43581,14110],{"class":662},[360,43583,2426],{"class":366},[360,43585,43586,43588,43590,43593],{"class":362,"line":375},[360,43587,43228],{"class":381},[360,43589,25124],{"class":366},[360,43591,43592],{"class":397},"\"CategoryItemModel: index from wrong model passed to mapToSource\"",[360,43594,43045],{"class":366},[360,43596,43597,43599,43601],{"class":362,"line":433},[360,43598,1386],{"class":574},[360,43600,42242],{"class":381},[360,43602,2204],{"class":366},[360,43604,43605],{"class":362,"line":478},[360,43606,847],{"class":366},[12,43608,43609],{},"Si le modèle est invalide dans notre modèle, il l'est aussi dans le\nmodèle source. Il n'y a pas d'équivalent dans le modèle source de\nl'index racine.",[352,43611,43613],{"className":635,"code":43612,"language":637,"meta":291,"style":291},"Mapping * m = static_cast\u003CMapping*>( proxyIndex.internalPointer() );\n",[344,43614,43615],{"__ignoreMap":291},[360,43616,43617,43619,43621,43623,43625,43627,43629,43631,43633,43635,43637,43639,43642],{"class":362,"line":363},[360,43618,43395],{"class":366},[360,43620,925],{"class":574},[360,43622,42721],{"class":366},[360,43624,583],{"class":574},[360,43626,1389],{"class":366},[360,43628,1358],{"class":574},[360,43630,42577],{"class":366},[360,43632,42544],{"class":574},[360,43634,25124],{"class":366},[360,43636,43571],{"class":662},[360,43638,31],{"class":366},[360,43640,43641],{"class":381},"internalPointer",[360,43643,43310],{"class":366},[12,43645,43646],{},"Nous récupérons la structure dans le pointeur interne de notre index.",[352,43648,43650],{"className":635,"code":43649,"language":637,"meta":291,"style":291},"int sourceColumn = proxyColumnToSource( proxyIndex.column() );\nif( sourceColumn == -1 ) return QModelIndex();\n",[344,43651,43652,43674],{"__ignoreMap":291},[360,43653,43654,43656,43659,43661,43664,43666,43668,43670,43672],{"class":362,"line":363},[360,43655,26486],{"class":574},[360,43657,43658],{"class":366}," sourceColumn ",[360,43660,583],{"class":574},[360,43662,43663],{"class":381}," proxyColumnToSource",[360,43665,25124],{"class":366},[360,43667,43571],{"class":662},[360,43669,31],{"class":366},[360,43671,43465],{"class":381},[360,43673,43310],{"class":366},[360,43675,43676,43678,43681,43683,43685,43687,43689,43691,43693],{"class":362,"line":292},[360,43677,2370],{"class":574},[360,43679,43680],{"class":366},"( sourceColumn ",[360,43682,2393],{"class":574},[360,43684,518],{"class":574},[360,43686,1944],{"class":414},[360,43688,42272],{"class":366},[360,43690,1454],{"class":574},[360,43692,42242],{"class":381},[360,43694,2204],{"class":366},[12,43696,43697],{},"Nous récupérons également les informations sur notre colonne (Soit,\nconversion de la colonne 0 dans notre modèle, en la colonne 1 dans le\nmodèle source).",[352,43699,43701],{"className":635,"code":43700,"language":637,"meta":291,"style":291},"int sourceRow = m->source_rows.at( proxyIndex.row() );\n",[344,43702,43703],{"__ignoreMap":291},[360,43704,43705,43707,43710,43712,43714,43716,43718,43720,43723,43725,43727,43729,43731],{"class":362,"line":363},[360,43706,26486],{"class":574},[360,43708,43709],{"class":366}," sourceRow ",[360,43711,583],{"class":574},[360,43713,43433],{"class":662},[360,43715,2376],{"class":366},[360,43717,43143],{"class":662},[360,43719,31],{"class":366},[360,43721,43722],{"class":381},"at",[360,43724,25124],{"class":366},[360,43726,43571],{"class":662},[360,43728,31],{"class":366},[360,43730,43271],{"class":381},[360,43732,43310],{"class":366},[12,43734,43735,43736,43738],{},"Nous recherchons dans notre liste ",[105,43737,43143],{}," la ligne dans le modèle\nsource qui correspond à la ligne (relative au père) indiqué par notre\nindex et nous construisons un index de type (ligne, colonne)\ncorrespondant au modèle source.",[352,43740,43742],{"className":635,"code":43741,"language":637,"meta":291,"style":291},"return m_sourceModel->index( sourceRow, sourceColumn );\n",[344,43743,43744],{"__ignoreMap":291},[360,43745,43746,43748,43750,43752,43754],{"class":362,"line":363},[360,43747,1454],{"class":574},[360,43749,42675],{"class":662},[360,43751,2376],{"class":366},[360,43753,42763],{"class":381},[360,43755,43756],{"class":366},"( sourceRow, sourceColumn );\n",[12,43758,43759,43760,854,43762,43764,43765,2311,43767,29886,43769,43771],{},"L'implémentation des méthodes ",[105,43761,42431],{},[105,43763,42434],{},"\npermettent de faire fonctionner les implémentations des méthodes\n",[105,43766,42447],{},[105,43768,42450],{},[105,43770,42453],{},". Il n'y aura donc aucun intérêt à\nré-implémenter ces méthodes à moins de vouloir traiter les données de\nces fonctions. Nous ne les décrirons donc pas ici, mais vous pourrez\nvoir dans le fichier attaché à la fin du billet, un exemple d'utilisation.",[23034,43773,43774],{"id":42763},"index()",[12,43776,43777,43778,2968,43781,2311,43783,2311,43786,2311,43788,31],{},"Le principe de cette méthode est de générer un index pour notre modèle.\nL'index doit être valide et réutilisable dans les méthodes ",[105,43779,43780],{},"rowCount()",[105,43782,42453],{},[105,43784,43785],{},"columnCount()",[105,43787,42447],{},[105,43789,42434],{},[352,43791,43793],{"className":635,"code":43792,"language":637,"meta":291,"style":291},"if( ( row \u003C 0 ) || ( column \u003C 0 ) ) return QModelIndex();\n",[344,43794,43795],{"__ignoreMap":291},[360,43796,43797,43799,43802,43804,43806,43808,43811,43814,43816,43818,43821,43823,43825],{"class":362,"line":363},[360,43798,2370],{"class":574},[360,43800,43801],{"class":366},"( ( row ",[360,43803,1358],{"class":574},[360,43805,1457],{"class":414},[360,43807,42272],{"class":366},[360,43809,43810],{"class":582},"||",[360,43812,43813],{"class":366}," ( column ",[360,43815,1358],{"class":574},[360,43817,1457],{"class":414},[360,43819,43820],{"class":366}," ) ) ",[360,43822,1454],{"class":574},[360,43824,42242],{"class":381},[360,43826,2204],{"class":366},[12,43828,43829],{},"Si la ligne ou la colonne est inférieure à 0, l'index n'est pas valide.",[352,43831,43833],{"className":635,"code":43832,"language":637,"meta":291,"style":291},"IndexMap::const_iterator it = m_sourcesIndexMapping.constFind( -1 );\n\nQModelIndex sourceParent = mapToSource( parent );\nif( sourceParent.isValid() ) {\n    it = m_sourcesIndexMapping.constFind( sourceParent.row() );\n}\n",[344,43834,43835,43855,43859,43871,43887,43910],{"__ignoreMap":291},[360,43836,43837,43839,43841,43843,43845,43847,43849,43851,43853],{"class":362,"line":363},[360,43838,43278],{"class":366},[360,43840,583],{"class":574},[360,43842,43075],{"class":662},[360,43844,31],{"class":366},[360,43846,43287],{"class":381},[360,43848,25124],{"class":366},[360,43850,1491],{"class":574},[360,43852,1944],{"class":414},[360,43854,43045],{"class":366},[360,43856,43857],{"class":362,"line":292},[360,43858,372],{"emptyLinePlaceholder":320},[360,43860,43861,43864,43866,43868],{"class":362,"line":375},[360,43862,43863],{"class":366},"QModelIndex sourceParent ",[360,43865,583],{"class":574},[360,43867,42402],{"class":381},[360,43869,43870],{"class":366},"( parent );\n",[360,43872,43873,43875,43877,43880,43882,43884],{"class":362,"line":433},[360,43874,2370],{"class":574},[360,43876,25124],{"class":366},[360,43878,43879],{"class":662},"sourceParent",[360,43881,31],{"class":366},[360,43883,43195],{"class":381},[360,43885,43886],{"class":366},"() ) {\n",[360,43888,43889,43892,43894,43896,43898,43900,43902,43904,43906,43908],{"class":362,"line":478},[360,43890,43891],{"class":366},"    it ",[360,43893,583],{"class":574},[360,43895,43075],{"class":662},[360,43897,31],{"class":366},[360,43899,43287],{"class":381},[360,43901,25124],{"class":366},[360,43903,43879],{"class":662},[360,43905,31],{"class":366},[360,43907,43271],{"class":381},[360,43909,43310],{"class":366},[360,43911,43912],{"class":362,"line":483},[360,43913,847],{"class":366},[12,43915,43916,43917,43919,43920,43923],{},"A partir de l'index ",[105,43918,22767],{}," nous retrouvons l'index qui correspond dans\nle modèle source (",[105,43921,43922],{},"sourceParent'). Si l'on ne trouve pas d'index dans le\nmodèle source, nous considérons être sur l'élément racine de notre\narbre. Sinon nous recherchons dans la table de","Mapping'' la structure\nqui correspond.",[352,43925,43927],{"className":635,"code":43926,"language":637,"meta":291,"style":291},"Q_ASSERT( it != m_sourcesIndexMapping.constEnd() );\nif( it.value()->source_rows.count() \u003C= row )\n    return QModelIndex();\n",[344,43928,43929,43945,43973],{"__ignoreMap":291},[360,43930,43931,43933,43935,43937,43939,43941,43943],{"class":362,"line":363},[360,43932,43295],{"class":381},[360,43934,43298],{"class":366},[360,43936,27471],{"class":574},[360,43938,43075],{"class":662},[360,43940,31],{"class":366},[360,43942,43307],{"class":381},[360,43944,43310],{"class":366},[360,43946,43947,43949,43951,43954,43956,43958,43960,43962,43964,43966,43968,43970],{"class":362,"line":292},[360,43948,2370],{"class":574},[360,43950,25124],{"class":366},[360,43952,43953],{"class":662},"it",[360,43955,31],{"class":366},[360,43957,19758],{"class":381},[360,43959,43349],{"class":366},[360,43961,43143],{"class":662},[360,43963,31],{"class":366},[360,43965,3842],{"class":381},[360,43967,2805],{"class":366},[360,43969,31890],{"class":574},[360,43971,43972],{"class":366}," row )\n",[360,43974,43975,43977,43979],{"class":362,"line":375},[360,43976,1386],{"class":574},[360,43978,42242],{"class":381},[360,43980,2204],{"class":366},[12,43982,43983],{},"Nous vérifions le nombre d'élément dans la structure et nous retournons\nun index non valide si l'index demandé va au delà de la taille du\ntableau.",[352,43985,43987],{"className":635,"code":43986,"language":637,"meta":291,"style":291},"return createIndex( row, column, *it );\n",[344,43988,43989],{"__ignoreMap":291},[360,43990,43991,43993,43995,43998,44000],{"class":362,"line":363},[360,43992,1454],{"class":574},[360,43994,43515],{"class":381},[360,43996,43997],{"class":366},"( row, column, ",[360,43999,925],{"class":574},[360,44001,44002],{"class":366},"it );\n",[12,44004,44005,44006,44008,44009,31],{},"Finalement nous retournons l'index créé avec le pointeur vers la\nstructure ",[105,44007,42577],{}," du père en ",[105,44010,44011],{},"internalData",[23034,44013,44014],{"id":22767},"parent()",[12,44016,44017],{},"Cette méthode permet de retourner pour l'index donné du proxy, l'index\ndu parent. Un index invalide n'a pas de parent.",[352,44019,44021],{"className":635,"code":44020,"language":637,"meta":291,"style":291},"if( ! index.isValid() ) return QModelIndex();\n\nMapping * m = static_cast\u003CMapping*>( index.internalPointer() );\n",[344,44022,44023,44045,44049],{"__ignoreMap":291},[360,44024,44025,44027,44029,44031,44033,44035,44037,44039,44041,44043],{"class":362,"line":363},[360,44026,2370],{"class":574},[360,44028,25124],{"class":366},[360,44030,1448],{"class":582},[360,44032,42245],{"class":662},[360,44034,31],{"class":366},[360,44036,43195],{"class":381},[360,44038,42330],{"class":366},[360,44040,1454],{"class":574},[360,44042,42242],{"class":381},[360,44044,2204],{"class":366},[360,44046,44047],{"class":362,"line":292},[360,44048,372],{"emptyLinePlaceholder":320},[360,44050,44051,44053,44055,44057,44059,44061,44063,44065,44067,44069,44071,44073,44075],{"class":362,"line":375},[360,44052,43395],{"class":366},[360,44054,925],{"class":574},[360,44056,42721],{"class":366},[360,44058,583],{"class":574},[360,44060,1389],{"class":366},[360,44062,1358],{"class":574},[360,44064,42577],{"class":366},[360,44066,42544],{"class":574},[360,44068,25124],{"class":366},[360,44070,42763],{"class":662},[360,44072,31],{"class":366},[360,44074,43641],{"class":381},[360,44076,43310],{"class":366},[12,44078,44079,44080,44083,44084,44086],{},"On récupère la structure de correspondance stockée dans le pointeur\ninterne de l'objet. Cette structure nous donne les informations du\nparent (en effet dans ",[105,44081,44082],{},"internalPointer()",", on stock la structure\n",[105,44085,42577],{}," du parent), et donc l'index dans le modèle source.",[352,44088,44090],{"className":635,"code":44089,"language":637,"meta":291,"style":291},"int sourceRow = m->index;\nif( sourceRow == -1 ) return QModelIndex();\n\nQModelIndex sourceParent = m_sourceModel->index( sourceRow, proxyColumnToSource( 0 ) );\nQModelIndex proxyParent = mapFromSource( sourceParent )\n",[344,44091,44092,44108,44129,44133,44158],{"__ignoreMap":291},[360,44093,44094,44096,44098,44100,44102,44104,44106],{"class":362,"line":363},[360,44095,26486],{"class":574},[360,44097,43709],{"class":366},[360,44099,583],{"class":574},[360,44101,43433],{"class":662},[360,44103,2376],{"class":366},[360,44105,42763],{"class":578},[360,44107,735],{"class":366},[360,44109,44110,44112,44115,44117,44119,44121,44123,44125,44127],{"class":362,"line":292},[360,44111,2370],{"class":574},[360,44113,44114],{"class":366},"( sourceRow ",[360,44116,2393],{"class":574},[360,44118,518],{"class":574},[360,44120,1944],{"class":414},[360,44122,42272],{"class":366},[360,44124,1454],{"class":574},[360,44126,42242],{"class":381},[360,44128,2204],{"class":366},[360,44130,44131],{"class":362,"line":375},[360,44132,372],{"emptyLinePlaceholder":320},[360,44134,44135,44137,44139,44141,44143,44145,44148,44151,44153,44155],{"class":362,"line":433},[360,44136,43863],{"class":366},[360,44138,583],{"class":574},[360,44140,42675],{"class":662},[360,44142,2376],{"class":366},[360,44144,42763],{"class":381},[360,44146,44147],{"class":366},"( sourceRow, ",[360,44149,44150],{"class":381},"proxyColumnToSource",[360,44152,25124],{"class":366},[360,44154,1344],{"class":414},[360,44156,44157],{"class":366}," ) );\n",[360,44159,44160,44163,44165,44167],{"class":362,"line":478},[360,44161,44162],{"class":366},"QModelIndex proxyParent ",[360,44164,583],{"class":574},[360,44166,42376],{"class":381},[360,44168,44169],{"class":366},"( sourceParent )\n",[12,44171,44172,44173,44175],{},"On utilise alors notre méthode ",[105,44174,42431],{}," pour retrouver l'index\ndu parent dans le référentiel du proxy.",[352,44177,44179],{"className":635,"code":44178,"language":637,"meta":291,"style":291},"return proxyParent;\n",[344,44180,44181],{"__ignoreMap":291},[360,44182,44183,44185],{"class":362,"line":363},[360,44184,1454],{"class":574},[360,44186,44187],{"class":366}," proxyParent;\n",[23034,44189,43780],{"id":44190},"rowcount",[12,44192,44193,44194,44196],{},"Le but de cette méthode est de retourner le nombre de ligne enfant pour\nun index. Dans le modèle source les indexes n'ont pas d'enfant.Lorsque\nl'index vaut ",[105,44195,43497],{},", cela signifie qu'il faut retourner le\nnombre de ligne pour notre racine.",[352,44198,44200],{"className":635,"code":44199,"language":637,"meta":291,"style":291},"if( index.column() > 0 ) return 0;\n",[344,44201,44202],{"__ignoreMap":291},[360,44203,44204,44206,44208,44210,44212,44214,44216,44218,44220,44222,44224,44226],{"class":362,"line":363},[360,44205,2370],{"class":574},[360,44207,25124],{"class":366},[360,44209,42763],{"class":662},[360,44211,31],{"class":366},[360,44213,43465],{"class":381},[360,44215,2805],{"class":366},[360,44217,24917],{"class":574},[360,44219,1457],{"class":414},[360,44221,42272],{"class":366},[360,44223,1454],{"class":574},[360,44225,1457],{"class":414},[360,44227,735],{"class":366},[12,44229,44230],{},"Seul la première colonne a des enfants.",[352,44232,44234],{"className":635,"code":44233,"language":637,"meta":291,"style":291},"if( ! index.isValid() ) {\n    Mapping * rootMapping = m_sourcesIndexMapping.value( -1 );\n    return rootMapping->source_rows.count();\n",[344,44235,44236,44252,44277],{"__ignoreMap":291},[360,44237,44238,44240,44242,44244,44246,44248,44250],{"class":362,"line":363},[360,44239,2370],{"class":574},[360,44241,25124],{"class":366},[360,44243,1448],{"class":582},[360,44245,42245],{"class":662},[360,44247,31],{"class":366},[360,44249,43195],{"class":381},[360,44251,43886],{"class":366},[360,44253,44254,44256,44258,44261,44263,44265,44267,44269,44271,44273,44275],{"class":362,"line":292},[360,44255,42716],{"class":366},[360,44257,925],{"class":574},[360,44259,44260],{"class":366}," rootMapping ",[360,44262,583],{"class":574},[360,44264,43075],{"class":662},[360,44266,31],{"class":366},[360,44268,19758],{"class":381},[360,44270,25124],{"class":366},[360,44272,1491],{"class":574},[360,44274,1944],{"class":414},[360,44276,43045],{"class":366},[360,44278,44279,44281,44284,44286,44288,44290,44292],{"class":362,"line":375},[360,44280,1386],{"class":574},[360,44282,44283],{"class":662}," rootMapping",[360,44285,2376],{"class":366},[360,44287,43143],{"class":662},[360,44289,31],{"class":366},[360,44291,3842],{"class":381},[360,44293,2204],{"class":366},[12,44295,44296],{},"Pour l'index racine, on récupère le nombre de ligne à la ligne -1 du\nmodèle source.",[352,44298,44300],{"className":635,"code":44299,"language":637,"meta":291,"style":291},"} else {\n    Mapping * parrentMapping = static_cast\u003CMapping*>( index.internalPointer() );\n    int sourceRowIndex = parrentMapping->source_rows.at( index.row() );\n    Mapping * rowMapping = m_sourcesIndexMapping.value( sourceRowIndex );\n\n    return rowMapping->source_rows.count();\n",[344,44301,44302,44310,44339,44369,44389,44393],{"__ignoreMap":291},[360,44303,44304,44306,44308],{"class":362,"line":363},[360,44305,2485],{"class":366},[360,44307,2488],{"class":574},[360,44309,896],{"class":366},[360,44311,44312,44314,44316,44319,44321,44323,44325,44327,44329,44331,44333,44335,44337],{"class":362,"line":292},[360,44313,42716],{"class":366},[360,44315,925],{"class":574},[360,44317,44318],{"class":366}," parrentMapping ",[360,44320,583],{"class":574},[360,44322,1389],{"class":366},[360,44324,1358],{"class":574},[360,44326,42577],{"class":366},[360,44328,42544],{"class":574},[360,44330,25124],{"class":366},[360,44332,42763],{"class":662},[360,44334,31],{"class":366},[360,44336,43641],{"class":381},[360,44338,43310],{"class":366},[360,44340,44341,44343,44346,44348,44351,44353,44355,44357,44359,44361,44363,44365,44367],{"class":362,"line":375},[360,44342,42502],{"class":574},[360,44344,44345],{"class":366}," sourceRowIndex ",[360,44347,583],{"class":574},[360,44349,44350],{"class":662}," parrentMapping",[360,44352,2376],{"class":366},[360,44354,43143],{"class":662},[360,44356,31],{"class":366},[360,44358,43722],{"class":381},[360,44360,25124],{"class":366},[360,44362,42763],{"class":662},[360,44364,31],{"class":366},[360,44366,43271],{"class":381},[360,44368,43310],{"class":366},[360,44370,44371,44373,44375,44378,44380,44382,44384,44386],{"class":362,"line":433},[360,44372,42716],{"class":366},[360,44374,925],{"class":574},[360,44376,44377],{"class":366}," rowMapping ",[360,44379,583],{"class":574},[360,44381,43075],{"class":662},[360,44383,31],{"class":366},[360,44385,19758],{"class":381},[360,44387,44388],{"class":366},"( sourceRowIndex );\n",[360,44390,44391],{"class":362,"line":478},[360,44392,372],{"emptyLinePlaceholder":320},[360,44394,44395,44397,44400,44402,44404,44406,44408],{"class":362,"line":483},[360,44396,1386],{"class":574},[360,44398,44399],{"class":662}," rowMapping",[360,44401,2376],{"class":366},[360,44403,43143],{"class":662},[360,44405,31],{"class":366},[360,44407,3842],{"class":381},[360,44409,2204],{"class":366},[12,44411,44412,44413,44416],{},"Sinon on récupère la structure stockée dans le pointeur interne. Cette\nstructure est celle du parent de notre objet. On récupère à l'aide de la\nméthode ",[105,44414,44415],{},"row()"," de l'index l'emplacement de la ligne source. Cette ligne\nsource nous permet de récupérer la structure de correspondance de notre\nindex, et ainsi le nombre de ligne de notre index.",[352,44418,44419],{"className":635,"code":847,"language":637,"meta":291,"style":291},[344,44420,44421],{"__ignoreMap":291},[360,44422,44423],{"class":362,"line":363},[360,44424,847],{"class":366},[23034,44426,43785],{"id":44427},"columncount",[12,44429,44430],{},"Notre modèle ne possède qu'une seule colonne.",[352,44432,44434],{"className":635,"code":44433,"language":637,"meta":291,"style":291},"return 1;\n",[344,44435,44436],{"__ignoreMap":291},[360,44437,44438,44440,44442],{"class":362,"line":363},[360,44439,1454],{"class":574},[360,44441,1099],{"class":414},[360,44443,735],{"class":366},[23034,44445,44447],{"id":44446},"proxycolumntosource","proxyColumnToSource()",[12,44449,44450],{},"Si la colonne du proxy vaut 0, alors on retourne la colonne 1, sinon on\nretourne la colonne -1 : la colonne n'est pas convertible, elle n'existe\npas dans notre proxy.",[352,44452,44454],{"className":635,"code":44453,"language":637,"meta":291,"style":291},"if( proxyColumn == 0 )\n    return list_name;\nreturn -1;\n",[344,44455,44456,44468,44475],{"__ignoreMap":291},[360,44457,44458,44460,44462,44464,44466],{"class":362,"line":363},[360,44459,2370],{"class":574},[360,44461,43474],{"class":366},[360,44463,2393],{"class":574},[360,44465,1457],{"class":414},[360,44467,35498],{"class":366},[360,44469,44470,44472],{"class":362,"line":292},[360,44471,1386],{"class":574},[360,44473,44474],{"class":366}," list_name;\n",[360,44476,44477,44479,44481,44483],{"class":362,"line":375},[360,44478,1454],{"class":574},[360,44480,518],{"class":574},[360,44482,1944],{"class":414},[360,44484,735],{"class":366},[23034,44486,44488],{"id":44487},"sourcecolumtoproxy","sourceColumToProxy()",[12,44490,44491],{},"Si la colonne source est 1, alors nous convertissons celle-ci en la\ncolonne 0. Sinon la colonne n'existe pas dans notre proxy.",[352,44493,44495],{"className":635,"code":44494,"language":637,"meta":291,"style":291},"if( sourceColumn == list_name )\n    return 0;\nreturn -1;\n",[344,44496,44497,44508,44516],{"__ignoreMap":291},[360,44498,44499,44501,44503,44505],{"class":362,"line":363},[360,44500,2370],{"class":574},[360,44502,43680],{"class":366},[360,44504,2393],{"class":574},[360,44506,44507],{"class":366}," list_name )\n",[360,44509,44510,44512,44514],{"class":362,"line":292},[360,44511,1386],{"class":574},[360,44513,1457],{"class":414},[360,44515,735],{"class":366},[360,44517,44518,44520,44522,44524],{"class":362,"line":375},[360,44519,1454],{"class":574},[360,44521,518],{"class":574},[360,44523,1944],{"class":414},[360,44525,735],{"class":366},[1901,44527,44529],{"id":44528},"les-sources","Les sources",[12,44531,44532],{},"Vous pouvez trouver les sources suivants décrivants ce que l'on trouve\nci-dessus :",[140,44534,44535,44541],{},[143,44536,44537],{},[47,44538,44540],{"href":44539},"\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Fcategoryitemmodel.h","categoryitemmodel.h",[143,44542,44543],{},[47,44544,44546],{"href":44545},"\u002FProgrammation\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique\u002Fcategoryitemmodel.cpp","categoryitemmodel.cpp",[12,44548,44549],{},"l'objet QSortFilterProxyModel de Nokia.",[21499,44551,44553,44556],{"className":44552,"dataFootnotes":291},[21502],[33,44554,21507],{"className":44555,"id":15686},[21506],[13835,44557,44558],{},[143,44559,44560,44561],{"id":21512},"La construction de notre objet s'est basé sur l'analyse de ",[47,44562,21520],{"href":21516,"ariaLabel":21517,"className":44563,"dataFootnoteBackref":291},[21519],[1613,44565,44566],{},"html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}",{"title":291,"searchDepth":292,"depth":292,"links":44568},[44569,44570,44571,44572,44573],{"id":42143,"depth":375,"text":42144},{"id":42197,"depth":375,"text":42198},{"id":42475,"depth":375,"text":42476},{"id":44528,"depth":375,"text":44529},{"id":15686,"depth":292,"text":21507},"2009-09-21",{"type":9,"value":44576},[44577,44579,44583,44585],[12,44578,42105],{},[12,44580,44581],{},[69,44582],{"alt":42110,"src":42111},[12,44584,42114],{},[12,44586,44587],{},[69,44588],{"alt":42119,"src":42120},{},"\u002Fpost\u002Fqt-transformation-d-une-vue-tableau-en-une-vue-hierarchique",{"title":42100,"description":42105},"qt-transformation-d-une-vue-tableau-en-une-vue-hierarchique","posts\u002FProgrammation\u002F2009-09-21-qt-transformation-d-une-vue-tableau-en-une-vue-hierarchique",[32924],"9hW60XZGhuixfVazFGe6eySQJPcsFBX02vlKbBhDNJs",{"id":44597,"title":44598,"author":7,"body":44599,"category":300,"categorySlug":301,"date":45761,"description":44603,"excerpt":45762,"extension":317,"location":318,"meta":45770,"navigation":320,"path":45771,"published":320,"seo":45772,"slug":45773,"stem":45774,"tags":45775,"timeToRead":489,"__hash__":45777},"posts\u002Fposts\u002FProgrammation\u002F2009-05-31-parseur-xml.md","Parseur XML",{"type":9,"value":44600,"toc":45755},[44601,44604,44611,44614,44618,44621,44624,44627,44630,44634,44637,44640,44684,44693,44837,44840,44843,44846,44852,44856,44859,44873,44876,44880,44892,44895,44901,44904,44910,44913,44917,44920,44923,45572,45586,45589,45595,45598,45732,45752],[12,44602,44603],{},"Bonjours à tous,",[12,44605,44606,44607,44610],{},"L'utilisation des fichiers XML est, à ce jour, un fait dans la plupart\ndes logiciels et est fortement à la mode. Une entreprise qui ne fait pas\nun peu de XML est souvent ",[105,44608,44609],{},"has-been",". On utilise alors le XML à bon ou\nmauvais escient.",[1613,44612,44613],{},"\nth {background-color: #E4E4E4;weigh: bold;}\n .veryslow {background-color: #FF0000;}\n .slow {background-color: #FF8686;}\n .good {background-color: #C3FFC7;}\n .ignored {background-color: #E4E4E4;}\n",[1901,44615,44617],{"id":44616},"avantages-inconvénients","Avantages \u002F Inconvénients",[12,44619,44620],{},"Pourquoi utiliser les fichiers XML ? Les fichiers XML sont, pour\ncommencer, des fichiers textes, il seront donc toujours lisibles, ce qui\ngarantit une meilleur pérennité de l'information. Les fichiers XML sont\nstructurés hiérarchiquement et suivent une syntaxe stricte. Ainsi le XML\nest lisible informatiquement par les différents langages de\nprogrammation existant, pour organiser vos données, en utilisant\ndifférents niveaux. Les fichiers XML peuvent être commenté ce qui peut\naméliorer la lisibilité pour un humain.",[12,44622,44623],{},"Le gros inconvénient du XML est sa verbosité. Pour chaque noeud dans la\nhiérarchie, il y a une balise de début, et une balise de fin contenant\nle nom de la balise. Le fichier est moins compact que s'il avait été\nécrit en binaire. Cela peut poser des problèmes comme alourdir les\ncommunications réseaux (ex: pour les webservices). Le fichier est aussi\nplus long à lire qu'un fichier binaire et peut contenir des erreurs.",[12,44625,44626],{},"Si le fichier n'a pas besoin d'être hiérarchique, il est possible\nd'utiliser une structure de fichier INI pour ses données.",[12,44628,44629],{},"Nous nous arrêterons là pour les avantages\u002Finconvénients. L'utilisation\nou non d'un fichier XML est ensuite une question (besoin, éthique, ...)\nà se poser pour ses données et la nécessité de pouvoir les lire\nautrement que par le programme lui-même.",[1901,44631,44633],{"id":44632},"performance-des-parseurs","Performance des parseurs.",[12,44635,44636],{},"Je me suis amusé à effectuer le test de lecture de différents fichiers\nde donnée au format XML de taille différentes par une variété de parseur\nXML en construisant si possible un arbre DOM. Le but est donc de créer\nun objet par noeud\u002Fattribut du fichier XML et de reconstituer la\nhiérarchie.",[12,44638,44639],{},"Les parseurs choisis pour ce test sont :",[140,44641,44642,44648,44654,44660,44666,44672,44678],{},[143,44643,44644,44647],{},[28,44645,44646],{},"QtXml"," : Le module XML de la librairie Qt (de la société Nokia)",[143,44649,44650,44653],{},[28,44651,44652],{},"LibXml2"," : Une librairie C permettant de faire du parsing XML en\nutilisant DOM ou SAX",[143,44655,44656,44659],{},[28,44657,44658],{},"LibExpat"," : Un parseur orienté flux (plus proche de la méthode\nSAX que du DOM)",[143,44661,44662,44665],{},[28,44663,44664],{},"SCEW"," : Un parseur basé sur Expat générant un arbre DOM (donc un\npeu plus comparable aux autre parseur).",[143,44667,44668,44671],{},[28,44669,44670],{},"TinyXML"," : Encore un autre parseur XML",[143,44673,44674,44677],{},[28,44675,44676],{},"Xerces-C++"," : Le parseur XML d’Apache",[143,44679,44680,44683],{},[28,44681,44682],{},"Oracle XML Parser"," : Le parseur d’Oracle propriétaire utiliser\ndans le serveur d’application.",[12,44685,44686,44687,44692],{},"Pour faire cette suite de benchmark",[15680,44688,44689],{},[47,44690,1944],{"href":15684,"ariaDescribedBy":44691,"dataFootnoteRef":291,"id":15687},[15686],", j’ai utilisé la librairie\nQTestLib de Nokia\u002FQt. Je vous offre donc en avant première le résultat\nde ce test :",[1545,44694,44696,44700],{"style":44695},"width:100%",[44697,44698,44699],"caption",{},"Temps de lecture d'un fichier XML en ms",[1567,44701,44702,44718,44736,44755,44774,44789,44805,44823],{},[1551,44703,44704,44707,44710,44711,44714,44715,44710],{},[1572,44705,44706],{},"               ",[1554,44708,44709],{},"250k","                     ",[1554,44712,44713],{},"9300k","                      ",[1554,44716,44717],{},"11300k",[1551,44719,44720,44723,44728,44732],{},[1554,44721,44722],{},"Qt DOM         ",[1572,44724,44727],{"className":44725},[44726],"veryslow","41,42 ms",[1572,44729,44731],{"className":44730},[44726],"2184,34 ms",[1572,44733,44735],{"className":44734},[44726],"2648,71 ms",[1551,44737,44738,44741,44744,44745,44750,44751,44750],{},[1554,44739,44740],{},"LibXML2        ",[1572,44742,44743],{},"16,55 ms","                 ",[1572,44746,44749],{"className":44747},[44748],"good","710,09 ms","     ",[1572,44752,44754],{"className":44753},[44748],"874,42 ms",[1551,44756,44757,44760,44765,44766,44765,44770,44765],{},[1554,44758,44759],{},"Expat (SAX)    ",[1572,44761,44764],{"className":44762},[44763],"ignored","5,95 ms","  ",[1572,44767,44769],{"className":44768},[44763],"312,02 ms",[1572,44771,44773],{"className":44772},[44763],"393,58 ms",[1551,44775,44776,44779,44744,44782,44785,44786,44744],{},[1554,44777,44778],{},"Oracle         ",[1572,44780,44781],{},"23,24 ms",[1572,44783,44784],{},"928,93 ms","                  ",[1572,44787,44788],{},"1135,86 ms",[1551,44790,44791,44794,44798,44799,44785,44802,44744],{},[1554,44792,44793],{},"Scew           ",[1572,44795,44797],{"className":44796},[44748],"12,05 ms","    ",[1572,44800,44801],{},"944,37 ms",[1572,44803,44804],{},"1184,46 ms",[1551,44806,44807,44810,44798,44815,44750,44819,44750],{},[1554,44808,44809],{},"Tiny XML       ",[1572,44811,44814],{"className":44812},[44813],"slow","28,91 ms",[1572,44816,44818],{"className":44817},[44813],"1101,8 ms",[1572,44820,44822],{"className":44821},[44813],"1369,8 ms",[1551,44824,44825,44828,44744,44831,44785,44834,44785],{},[1554,44826,44827],{},"Xerces (Apache)",[1572,44829,44830],{},"25,03 ms",[1572,44832,44833],{},"742,22 ms",[1572,44835,44836],{},"904,62 ms",[12,44838,44839],{},"La conclusion de ce résultat signifie que le parseur inclu dans Qt (pour\nla construction d'un arbre DOM) est très lent ;). Mais pour une\nutilisation dans une interface graphique, sur de petits fichiers, ne\ndevrait pas poser de problème.",[12,44841,44842],{},"Enfin le parseur le plus rapide (pour les gros fichiers) est Libxml2. Le\nparseur C d'oracle, bien que propriétaire n'a rien d'exceptionnel (si on\ncompte avec les problèmes présenté également ci-dessous). Peut-être que\nla version Java est elle plus performante.",[12,44844,44845],{},"Vous pouvez retrouver quelques graphiques ci-dessous :",[12,44847,44848],{},[69,44849],{"alt":44850,"src":44851},"TestXMLPerf","\u002FProgrammation\u002Fparseur-xml\u002FTestXMLPerf.png",[1901,44853,44855],{"id":44854},"le-source-du-benchmark","Le source du benchmark",[12,44857,44858],{},"Voici de suite :",[140,44860,44861,44867],{},[143,44862,44863],{},[47,44864,44866],{"href":44865},"\u002FProgrammation\u002Fparseur-xml\u002Fxmlparser-bench.7z","les sources de l'application",[143,44868,44869,31],{},[47,44870,44872],{"href":44871},"\u002FProgrammation\u002Fparseur-xml\u002Fbenchmark_100iterations.ods","le résultat du bench",[12,44874,44875],{},"Pour la partie utilisation du Parseur Oracle, il a fallut contourner\nplusieurs petits problèmes. Ceci est la joie des librairies propriétaires\nbien documentées.",[23034,44877,44879],{"id":44878},"compilation-avec-le-xdk-9","Compilation avec le XDK 9",[12,44881,44882,44883,44886,44887,44889,44890,31],{},"Lors de la compilation avec le XDK 9, l'application ne dépasse pas le\nstade du ",[105,44884,44885],{},"linkage",". Les méthodes sont pourtant bien dans les ",[105,44888,21307],{},".\nDe plus les librairies sont bien précisées pour le ",[105,44891,44885],{},[12,44893,44894],{},"La définition faite dans le projet est :",[352,44896,44899],{"className":44897,"code":44898,"language":32201},[32199],"XDKPATH = xdk9\nXDK_LIB = -lxmlg9 -lxml9 -lxsd9\nORA_LIB = -lcore9 -lnls9 -lunls9 -lcore9 -lnls9 -lcore9\nNET_LIB = -lnsl\nLIBS += -L$$XDKPATH\u002Flib $$XDK_LIB $$ORA_LIB $$NET_LIB -lpthread\nINCLUDEPATH += $$XDKPATH\u002Fxdk\u002Finclude\n",[344,44900,44898],{"__ignoreMap":291},[12,44902,44903],{},"A la suite de ça, lors de la phase de compilation, on se retrouve avec\nles messages d'erreurs suivants :",[352,44905,44908],{"className":44906,"code":44907,"language":32201},[32199],"g++ -Wl,-O1 -o xmlparserbenchmark libxml2parser.o expatparser.o xercescppparser.o oracleparser.o qtparser.o scewparser.o tinyparser.o tinyxml.o tinystr.o tinyxmlerror.o tinyxmlparser.o xmlparserbenchmark.o moc_xmlparserbenchmark.o -L\u002Fusr\u002Flib -lxml2 -lexpat -lxerces-c -Lxdk9\u002Flib -lxmlg9 -lxml9 -lxsd9 -lcore9 -lnls9 -lunls9 -lcore9 -lnls9 -lcore9 -lnsl -lpthread -Lscew\u002Fscew -lscew -lQtTest -lQtXml -lQtGui -lQtCore -lpthread\noracleparser.o: In function `parseWithOracleParser(QString const&)':\noracleparser.cpp:(.text+0x82): undefined reference to `XMLParser::xmlinit(unsigned char*, void (*)(void*, unsigned char const*, unsigned int), void*, xmlsaxcb*, void*, unsigned char*)'\noracleparser.cpp:(.text+0xa8): undefined reference to `XMLParser::xmlparse(unsigned char*, unsigned char*, unsigned int)'\noracleparser.cpp:(.text+0x2b4): undefined reference to `XMLParser::getDocumentElement()'\noracleparser.cpp:(.text+0x2ca): undefined reference to `XMLParser::xmlterm()'\n",[344,44909,44907],{"__ignoreMap":291},[12,44911,44912],{},"J'ai alors essayé de recompiler les exemples de démonstrations mais là,\nmême problème ...",[23034,44914,44916],{"id":44915},"compilation-avec-le-xdk-10","Compilation avec le XDK 10",[12,44918,44919],{},"Avec cette version du XDK, nous avons le droit à deux problèmes. Le\npremier est une grosse fuite mémoire (si on écrit le programme tel que\ndécrit dans la démo), et à un problème d'initialisation du parseur.",[12,44921,44922],{},"Le code permettant de parser le fichier XML et de générer l'arbre DOM\nressemble à ceci :",[352,44924,44926],{"className":635,"code":44925,"language":637,"meta":291,"style":291},"CXmlCtx * ctxp = 0;\ntry {\n    ctxp = new CXmlCtx();\n} catch( XmlException & e ) {\n    unsigned ecode = e.getCode();\n    QFAIL( qPrintable( QString(\"Failed to initialize XML context, error %1\").arg( ecode ) ) );\n}\n\nFactory\u003CCXmlCtx,xmlnode> * fp = 0;\ntry {\n    fp = new Factory\u003CCXmlCtx,xmlnode>( ctxp );\n} catch( FactoryException & fe ) {\n    unsigned ecode = fe.getCode();\n    QFAIL( qPrintable( QString(\"Failed to create create parser, error %1\").arg( ecode ) ) );\n}\n\nDOMParser\u003CCXmlCtx,xmlnode> * parserp = 0;\ntry {\n    parserp = fp->createDOMParser( DOMParCXml, NULL );\n} catch( FactoryException & fe ) {\n    delete fp;\n    unsigned ecode = fe.getCode();\n    QFAIL( qPrintable( QString(\"Failed to create parser, error %1\").arg( ecode ) ) );\n}\n\nconst char * fname = filename;\nFileSource * isrcp = new FileSource( (oratext*) fname );\ntry {\n    DocumentRef\u003Cxmlnode> * docrefp = parserp->parse( isrcp, FALSE );\n    if( docrefp == NULL ) {\n        QFAIL( qPrintable( QString(\"NULL document\") ) );\n        return;\n    }\n    xmlnode * np = docrefp->getDocumentElement();\n    if( np == NULL ) {\n        QFAIL( qPrintable( QString(\"Empty document\") ) );\n        return;\n    }\n    docrefp->markToDelete();\n    delete docrefp;\n} catch( ParserException & pe ) {\n    delete parserp;\n    delete isrcp;\n    delete fp;\n\n    unsigned ecode = pe.getCode();\n    QFAIL( qPrintable( QString( \"Failed to parse the document, error %1\").arg( ecode ) ) );\n}\n\u002F\u002F    delete parserp;\n\u002F\u002F    delete isrcp;\n\u002F\u002F    delete fp;\n\u002F\u002F    delete ctxp;\n",[344,44927,44928,44944,44950,44964,44978,44997,45024,45028,45032,45055,45061,45086,45100,45117,45140,45144,45148,45170,45176,45199,45211,45219,45235,45258,45262,45266,45283,45308,45314,45342,45356,45377,45383,45387,45409,45422,45441,45447,45451,45463,45470,45484,45491,45498,45504,45508,45525,45548,45552,45557,45562,45567],{"__ignoreMap":291},[360,44929,44930,44933,44935,44938,44940,44942],{"class":362,"line":363},[360,44931,44932],{"class":366},"CXmlCtx ",[360,44934,925],{"class":574},[360,44936,44937],{"class":366}," ctxp ",[360,44939,583],{"class":574},[360,44941,1457],{"class":414},[360,44943,735],{"class":366},[360,44945,44946,44948],{"class":362,"line":292},[360,44947,7214],{"class":574},[360,44949,896],{"class":366},[360,44951,44952,44955,44957,44959,44962],{"class":362,"line":375},[360,44953,44954],{"class":366},"    ctxp ",[360,44956,583],{"class":574},[360,44958,3040],{"class":574},[360,44960,44961],{"class":381}," CXmlCtx",[360,44963,2204],{"class":366},[360,44965,44966,44968,44970,44973,44975],{"class":362,"line":433},[360,44967,2485],{"class":366},[360,44969,7242],{"class":574},[360,44971,44972],{"class":366},"( XmlException ",[360,44974,31664],{"class":582},[360,44976,44977],{"class":366}," e ) {\n",[360,44979,44980,44983,44986,44988,44990,44992,44995],{"class":362,"line":478},[360,44981,44982],{"class":574},"    unsigned",[360,44984,44985],{"class":366}," ecode ",[360,44987,583],{"class":574},[360,44989,26887],{"class":662},[360,44991,31],{"class":366},[360,44993,44994],{"class":381},"getCode",[360,44996,2204],{"class":366},[360,44998,44999,45002,45004,45007,45009,45011,45013,45016,45018,45021],{"class":362,"line":483},[360,45000,45001],{"class":381},"    QFAIL",[360,45003,25124],{"class":366},[360,45005,45006],{"class":381},"qPrintable",[360,45008,25124],{"class":366},[360,45010,36156],{"class":381},[360,45012,671],{"class":366},[360,45014,45015],{"class":397},"\"Failed to initialize XML context, error %1\"",[360,45017,2198],{"class":366},[360,45019,45020],{"class":381},"arg",[360,45022,45023],{"class":366},"( ecode ) ) );\n",[360,45025,45026],{"class":362,"line":489},[360,45027,847],{"class":366},[360,45029,45030],{"class":362,"line":494},[360,45031,372],{"emptyLinePlaceholder":320},[360,45033,45034,45037,45039,45042,45044,45046,45049,45051,45053],{"class":362,"line":712},[360,45035,45036],{"class":366},"Factory",[360,45038,1358],{"class":574},[360,45040,45041],{"class":366},"CXmlCtx,xmlnode",[360,45043,24917],{"class":574},[360,45045,920],{"class":574},[360,45047,45048],{"class":366}," fp ",[360,45050,583],{"class":574},[360,45052,1457],{"class":414},[360,45054,735],{"class":366},[360,45056,45057,45059],{"class":362,"line":331},[360,45058,7214],{"class":574},[360,45060,896],{"class":366},[360,45062,45063,45066,45068,45070,45073,45075,45078,45080,45083],{"class":362,"line":762},[360,45064,45065],{"class":366},"    fp ",[360,45067,583],{"class":574},[360,45069,3040],{"class":574},[360,45071,45072],{"class":381}," Factory",[360,45074,1358],{"class":366},[360,45076,45077],{"class":662},"CXmlCtx",[360,45079,22488],{"class":366},[360,45081,45082],{"class":662},"xmlnode",[360,45084,45085],{"class":366},">( ctxp );\n",[360,45087,45088,45090,45092,45095,45097],{"class":362,"line":781},[360,45089,2485],{"class":366},[360,45091,7242],{"class":574},[360,45093,45094],{"class":366},"( FactoryException ",[360,45096,31664],{"class":582},[360,45098,45099],{"class":366}," fe ) {\n",[360,45101,45102,45104,45106,45108,45111,45113,45115],{"class":362,"line":804},[360,45103,44982],{"class":574},[360,45105,44985],{"class":366},[360,45107,583],{"class":574},[360,45109,45110],{"class":662}," fe",[360,45112,31],{"class":366},[360,45114,44994],{"class":381},[360,45116,2204],{"class":366},[360,45118,45119,45121,45123,45125,45127,45129,45131,45134,45136,45138],{"class":362,"line":817},[360,45120,45001],{"class":381},[360,45122,25124],{"class":366},[360,45124,45006],{"class":381},[360,45126,25124],{"class":366},[360,45128,36156],{"class":381},[360,45130,671],{"class":366},[360,45132,45133],{"class":397},"\"Failed to create create parser, error %1\"",[360,45135,2198],{"class":366},[360,45137,45020],{"class":381},[360,45139,45023],{"class":366},[360,45141,45142],{"class":362,"line":823},[360,45143,847],{"class":366},[360,45145,45146],{"class":362,"line":844},[360,45147,372],{"emptyLinePlaceholder":320},[360,45149,45150,45153,45155,45157,45159,45161,45164,45166,45168],{"class":362,"line":1441},[360,45151,45152],{"class":366},"DOMParser",[360,45154,1358],{"class":574},[360,45156,45041],{"class":366},[360,45158,24917],{"class":574},[360,45160,920],{"class":574},[360,45162,45163],{"class":366}," parserp ",[360,45165,583],{"class":574},[360,45167,1457],{"class":414},[360,45169,735],{"class":366},[360,45171,45172,45174],{"class":362,"line":1462},[360,45173,7214],{"class":574},[360,45175,896],{"class":366},[360,45177,45178,45181,45183,45186,45188,45191,45194,45197],{"class":362,"line":1485},[360,45179,45180],{"class":366},"    parserp ",[360,45182,583],{"class":574},[360,45184,45185],{"class":662}," fp",[360,45187,2376],{"class":366},[360,45189,45190],{"class":381},"createDOMParser",[360,45192,45193],{"class":366},"( DOMParCXml, ",[360,45195,45196],{"class":414},"NULL",[360,45198,43045],{"class":366},[360,45200,45201,45203,45205,45207,45209],{"class":362,"line":1497},[360,45202,2485],{"class":366},[360,45204,7242],{"class":574},[360,45206,45094],{"class":366},[360,45208,31664],{"class":582},[360,45210,45099],{"class":366},[360,45212,45213,45216],{"class":362,"line":3161},[360,45214,45215],{"class":574},"    delete",[360,45217,45218],{"class":366}," fp;\n",[360,45220,45221,45223,45225,45227,45229,45231,45233],{"class":362,"line":3167},[360,45222,44982],{"class":574},[360,45224,44985],{"class":366},[360,45226,583],{"class":574},[360,45228,45110],{"class":662},[360,45230,31],{"class":366},[360,45232,44994],{"class":381},[360,45234,2204],{"class":366},[360,45236,45237,45239,45241,45243,45245,45247,45249,45252,45254,45256],{"class":362,"line":3194},[360,45238,45001],{"class":381},[360,45240,25124],{"class":366},[360,45242,45006],{"class":381},[360,45244,25124],{"class":366},[360,45246,36156],{"class":381},[360,45248,671],{"class":366},[360,45250,45251],{"class":397},"\"Failed to create parser, error %1\"",[360,45253,2198],{"class":366},[360,45255,45020],{"class":381},[360,45257,45023],{"class":366},[360,45259,45260],{"class":362,"line":3224},[360,45261,847],{"class":366},[360,45263,45264],{"class":362,"line":3239},[360,45265,372],{"emptyLinePlaceholder":320},[360,45267,45268,45270,45273,45275,45278,45280],{"class":362,"line":3256},[360,45269,6053],{"class":574},[360,45271,45272],{"class":574}," char",[360,45274,920],{"class":574},[360,45276,45277],{"class":366}," fname ",[360,45279,583],{"class":574},[360,45281,45282],{"class":366}," filename;\n",[360,45284,45285,45288,45290,45293,45295,45297,45300,45303,45305],{"class":362,"line":3276},[360,45286,45287],{"class":366},"FileSource ",[360,45289,925],{"class":574},[360,45291,45292],{"class":366}," isrcp ",[360,45294,583],{"class":574},[360,45296,3040],{"class":574},[360,45298,45299],{"class":381}," FileSource",[360,45301,45302],{"class":366},"( (oratext",[360,45304,925],{"class":574},[360,45306,45307],{"class":366},") fname );\n",[360,45309,45310,45312],{"class":362,"line":3281},[360,45311,7214],{"class":574},[360,45313,896],{"class":366},[360,45315,45316,45319,45321,45323,45325,45327,45330,45332,45335,45337,45339],{"class":362,"line":3305},[360,45317,45318],{"class":366},"    DocumentRef",[360,45320,1358],{"class":574},[360,45322,45082],{"class":366},[360,45324,24917],{"class":574},[360,45326,920],{"class":574},[360,45328,45329],{"class":366}," docrefp ",[360,45331,583],{"class":574},[360,45333,45334],{"class":662}," parserp",[360,45336,2376],{"class":366},[360,45338,5302],{"class":381},[360,45340,45341],{"class":366},"( isrcp, FALSE );\n",[360,45343,45344,45346,45349,45351,45354],{"class":362,"line":3320},[360,45345,5657],{"class":574},[360,45347,45348],{"class":366},"( docrefp ",[360,45350,2393],{"class":574},[360,45352,45353],{"class":414}," NULL",[360,45355,2426],{"class":366},[360,45357,45358,45361,45363,45365,45367,45369,45371,45374],{"class":362,"line":3325},[360,45359,45360],{"class":381},"        QFAIL",[360,45362,25124],{"class":366},[360,45364,45006],{"class":381},[360,45366,25124],{"class":366},[360,45368,36156],{"class":381},[360,45370,671],{"class":366},[360,45372,45373],{"class":397},"\"NULL document\"",[360,45375,45376],{"class":366},") ) );\n",[360,45378,45379,45381],{"class":362,"line":3361},[360,45380,24470],{"class":574},[360,45382,735],{"class":366},[360,45384,45385],{"class":362,"line":3380},[360,45386,2927],{"class":366},[360,45388,45389,45392,45394,45397,45399,45402,45404,45407],{"class":362,"line":3405},[360,45390,45391],{"class":366},"    xmlnode ",[360,45393,925],{"class":574},[360,45395,45396],{"class":366}," np ",[360,45398,583],{"class":574},[360,45400,45401],{"class":662}," docrefp",[360,45403,2376],{"class":366},[360,45405,45406],{"class":381},"getDocumentElement",[360,45408,2204],{"class":366},[360,45410,45411,45413,45416,45418,45420],{"class":362,"line":3411},[360,45412,5657],{"class":574},[360,45414,45415],{"class":366},"( np ",[360,45417,2393],{"class":574},[360,45419,45353],{"class":414},[360,45421,2426],{"class":366},[360,45423,45424,45426,45428,45430,45432,45434,45436,45439],{"class":362,"line":3426},[360,45425,45360],{"class":381},[360,45427,25124],{"class":366},[360,45429,45006],{"class":381},[360,45431,25124],{"class":366},[360,45433,36156],{"class":381},[360,45435,671],{"class":366},[360,45437,45438],{"class":397},"\"Empty document\"",[360,45440,45376],{"class":366},[360,45442,45443,45445],{"class":362,"line":3432},[360,45444,24470],{"class":574},[360,45446,735],{"class":366},[360,45448,45449],{"class":362,"line":3438},[360,45450,2927],{"class":366},[360,45452,45453,45456,45458,45461],{"class":362,"line":3443},[360,45454,45455],{"class":662},"    docrefp",[360,45457,2376],{"class":366},[360,45459,45460],{"class":381},"markToDelete",[360,45462,2204],{"class":366},[360,45464,45465,45467],{"class":362,"line":3462},[360,45466,45215],{"class":574},[360,45468,45469],{"class":366}," docrefp;\n",[360,45471,45472,45474,45476,45479,45481],{"class":362,"line":3467},[360,45473,2485],{"class":366},[360,45475,7242],{"class":574},[360,45477,45478],{"class":366},"( ParserException ",[360,45480,31664],{"class":582},[360,45482,45483],{"class":366}," pe ) {\n",[360,45485,45486,45488],{"class":362,"line":3472},[360,45487,45215],{"class":574},[360,45489,45490],{"class":366}," parserp;\n",[360,45492,45493,45495],{"class":362,"line":3495},[360,45494,45215],{"class":574},[360,45496,45497],{"class":366}," isrcp;\n",[360,45499,45500,45502],{"class":362,"line":3500},[360,45501,45215],{"class":574},[360,45503,45218],{"class":366},[360,45505,45506],{"class":362,"line":3505},[360,45507,372],{"emptyLinePlaceholder":320},[360,45509,45510,45512,45514,45516,45519,45521,45523],{"class":362,"line":3530},[360,45511,44982],{"class":574},[360,45513,44985],{"class":366},[360,45515,583],{"class":574},[360,45517,45518],{"class":662}," pe",[360,45520,31],{"class":366},[360,45522,44994],{"class":381},[360,45524,2204],{"class":366},[360,45526,45527,45529,45531,45533,45535,45537,45539,45542,45544,45546],{"class":362,"line":3545},[360,45528,45001],{"class":381},[360,45530,25124],{"class":366},[360,45532,45006],{"class":381},[360,45534,25124],{"class":366},[360,45536,36156],{"class":381},[360,45538,25124],{"class":366},[360,45540,45541],{"class":397},"\"Failed to parse the document, error %1\"",[360,45543,2198],{"class":366},[360,45545,45020],{"class":381},[360,45547,45023],{"class":366},[360,45549,45550],{"class":362,"line":3558},[360,45551,847],{"class":366},[360,45553,45554],{"class":362,"line":3573},[360,45555,45556],{"class":644},"\u002F\u002F    delete parserp;\n",[360,45558,45559],{"class":362,"line":3578},[360,45560,45561],{"class":644},"\u002F\u002F    delete isrcp;\n",[360,45563,45564],{"class":362,"line":3583},[360,45565,45566],{"class":644},"\u002F\u002F    delete fp;\n",[360,45568,45569],{"class":362,"line":6893},[360,45570,45571],{"class":644},"\u002F\u002F    delete ctxp;\n",[12,45573,45574,45575,45577,45578,45580,45581,31],{},"Le premier problème se situe lors de la suppression du contexte\n(dernière ligne, en commentaire). Si cette ligne est exécutée, alors\nnous avons une grosse erreur de segmentation. J'ai le problème, quels\nque soient les ",[344,45576,29597],{}," que je fais avant.Même en faisant le maximum de\n",[344,45579,29597],{}," (soit parserp, isrcp, fp), le fait de ne pas supprimer le\ncontext (ctxp), fait qu'au bout de plusieurs itérations, nous avons une\nbonne fuite mémoire",[15680,45582,45583],{},[47,45584,795],{"href":16257,"ariaDescribedBy":45585,"dataFootnoteRef":291,"id":16259},[15686],[12,45587,45588],{},"Vient ensuite le second problème, celui des erreurs d'intialisation. Si\nle parseur est lancé plusieurs fois de suite, alors l'application\naffiche les erreurs suivantes à l'écran :",[352,45590,45593],{"className":45591,"code":45592,"language":32201},[32199],"LPX-00202: Message 202 not found; No message file for product=XDK, facility=LPX\nFAIL!  : XmlParserBenchmark::oracleParser(file250k.xml) Failed to parse the document, error 202\n    Loc: [oracleparser.cpp(73)]\n",[344,45594,45592],{"__ignoreMap":291},[12,45596,45597],{},"Aucune explication sur le pourquoi. Parfois ça marche, parfois non...\nPour contourner le problème, j'ai forké le parseur pour l'exécuter isolé\ndu reste.",[352,45599,45601],{"className":2356,"code":45600,"language":2358,"meta":291,"style":291},"pid_t pid = fork();\nif( pid > 0 ) {\n    waitpid( pid, (int*)0, 0 );\n} else if( pid == 0 ) {\n    if( ! filename.isEmpty() )\n        parse( qPrintable( filename ) );\n    exit( 0 );\n} else {\n    QFAIL( \"Cannot fork\" );\n}\n",[344,45602,45603,45618,45631,45652,45668,45686,45698,45709,45717,45728],{"__ignoreMap":291},[360,45604,45605,45608,45611,45613,45616],{"class":362,"line":363},[360,45606,45607],{"class":574},"pid_t",[360,45609,45610],{"class":366}," pid ",[360,45612,583],{"class":574},[360,45614,45615],{"class":381}," fork",[360,45617,2204],{"class":366},[360,45619,45620,45622,45625,45627,45629],{"class":362,"line":292},[360,45621,2370],{"class":574},[360,45623,45624],{"class":366},"( pid ",[360,45626,24917],{"class":574},[360,45628,1457],{"class":414},[360,45630,2426],{"class":366},[360,45632,45633,45636,45639,45642,45644,45646,45648,45650],{"class":362,"line":375},[360,45634,45635],{"class":381},"    waitpid",[360,45637,45638],{"class":366},"( pid, (",[360,45640,45641],{"class":574},"int*",[360,45643,16112],{"class":366},[360,45645,1344],{"class":414},[360,45647,2311],{"class":366},[360,45649,1344],{"class":414},[360,45651,43045],{"class":366},[360,45653,45654,45656,45658,45660,45662,45664,45666],{"class":362,"line":433},[360,45655,2485],{"class":366},[360,45657,2488],{"class":574},[360,45659,2491],{"class":574},[360,45661,45624],{"class":366},[360,45663,2393],{"class":574},[360,45665,1457],{"class":414},[360,45667,2426],{"class":366},[360,45669,45670,45672,45674,45676,45678,45680,45683],{"class":362,"line":478},[360,45671,5657],{"class":574},[360,45673,25124],{"class":366},[360,45675,1448],{"class":582},[360,45677,15068],{"class":662},[360,45679,31],{"class":366},[360,45681,45682],{"class":381},"isEmpty",[360,45684,45685],{"class":366},"() )\n",[360,45687,45688,45691,45693,45695],{"class":362,"line":483},[360,45689,45690],{"class":381},"        parse",[360,45692,25124],{"class":366},[360,45694,45006],{"class":381},[360,45696,45697],{"class":366},"( filename ) );\n",[360,45699,45700,45703,45705,45707],{"class":362,"line":489},[360,45701,45702],{"class":381},"    exit",[360,45704,25124],{"class":366},[360,45706,1344],{"class":414},[360,45708,43045],{"class":366},[360,45710,45711,45713,45715],{"class":362,"line":494},[360,45712,2485],{"class":366},[360,45714,2488],{"class":574},[360,45716,896],{"class":366},[360,45718,45719,45721,45723,45726],{"class":362,"line":712},[360,45720,45001],{"class":381},[360,45722,25124],{"class":366},[360,45724,45725],{"class":397},"\"Cannot fork\"",[360,45727,43045],{"class":366},[360,45729,45730],{"class":362,"line":331},[360,45731,847],{"class":366},[21499,45733,45735,45738],{"className":45734,"dataFootnotes":291},[21502],[33,45736,21507],{"className":45737,"id":15686},[21506],[13835,45739,45740,45746],{},[143,45741,45742,45743],{"id":21512},"Ces tests ont été réalisé dans un chroot 32-bits allant à 2,4GHz. Les temps sont une moyenne sur 100 itérations ",[47,45744,21520],{"href":21516,"ariaLabel":21517,"className":45745,"dataFootnoteBackref":291},[21519],[143,45747,45748,45749],{"id":21523},"Si quelqu'un a déjà utilisé ce parseur, et qu'il sait comment il fonctionne, il peut m'écrire ",[47,45750,21520],{"href":21531,"ariaLabel":21532,"className":45751,"dataFootnoteBackref":291},[21519],[1613,45753,45754],{},"html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":291,"searchDepth":292,"depth":292,"links":45756},[45757,45758,45759,45760],{"id":44616,"depth":375,"text":44617},{"id":44632,"depth":375,"text":44633},{"id":44854,"depth":375,"text":44855},{"id":15686,"depth":292,"text":21507},"2009-05-31",{"type":9,"value":45763},[45764,45766],[12,45765,44603],{},[12,45767,44606,45768,44610],{},[105,45769,44609],{},{},"\u002Fpost\u002Fparseur-xml",{"title":44598,"description":44603},"parseur-xml","posts\u002FProgrammation\u002F2009-05-31-parseur-xml",[39209,32924,45776],"xml","G7dHisiUAKK_MNKBFUElPa66LJWw54bB5Z9U4-7H4Ck",{"id":45779,"title":45780,"author":7,"body":45781,"category":300,"categorySlug":301,"date":46801,"description":46802,"excerpt":46803,"extension":317,"location":318,"meta":46815,"navigation":320,"path":46816,"published":320,"seo":46817,"slug":46818,"stem":46819,"tags":46820,"timeToRead":483,"__hash__":46821},"posts\u002Fposts\u002FProgrammation\u002F2008-09-08-paquet-debian-et-qt.md","Paquet Debian et Qt",{"type":9,"value":45782,"toc":46795},[45783,45793,45799,45803,45812,45837,45841,45845,45854,45860,45863,45966,45972,45985,45989,45998,46034,46037,46074,46077,46109,46113,46116,46123,46129,46139,46149,46244,46259,46263,46275,46281,46287,46301,46581,46584,46588,46592,46597,46610,46615,46627,46630,46643,46646,46650,46653,46659,46663,46666,46672,46691,46695,46702,46708,46712,46718,46722,46725,46762,46792],[12,45784,45785,45786,45789,45790,2198],{},"A titre personnel je fabrique quelques programmes en Qt. Comme j'utilise\nun système ",[105,45787,45788],{},"Gnu\u002FDebian",", j'ai cherché à fabriquer des paquets pour mon\nsystème (plus pour le plaisir qu'autre chose, car la plus grande partie\nde mes utilisateurs sont sous ",[105,45791,45792],{},"MS\u002FWindows",[12,45794,45795,45796,45798],{},"Ce billet explique la création de paquet ",[105,45797,45788],{}," pour des\napplications Qt 4 utilisant QMake",[1901,45800,45802],{"id":45801},"installation-des-paquets","Installation des paquets",[12,45804,45805,45806,45808,45809,31],{},"Pour la création des paquets pour des programmes utilisant ",[344,45807,34162],{},", il\nfaut ",[344,45810,45811],{},"cdbs, dh_make, dpkg-buildpackage",[352,45813,45815],{"className":565,"code":45814,"language":567,"meta":291,"style":291},"aptitude install cdbs dh-make fakeroot devscripts\n",[344,45816,45817],{"__ignoreMap":291},[360,45818,45819,45822,45825,45828,45831,45834],{"class":362,"line":363},[360,45820,45821],{"class":381},"aptitude",[360,45823,45824],{"class":397}," install",[360,45826,45827],{"class":397}," cdbs",[360,45829,45830],{"class":397}," dh-make",[360,45832,45833],{"class":397}," fakeroot",[360,45835,45836],{"class":397}," devscripts\n",[1901,45838,45840],{"id":45839},"création-du-paquet","Création du paquet",[23034,45842,45844],{"id":45843},"préparation","Préparation",[12,45846,45847,45848,45851,45852,31],{},"Vous pouvez donc choisir un de vos programmes que vous voulez\nempaqueter. Pour cela vous allez commencer par nettoyer l'arborescence\nde votre projet pour retirer les fichiers de sauvegarde ainsi que les\nfichiers de construction (",[344,45849,45850],{},"*~ *.o",", ...). Ce petit nettoyage va\npermettre d'avoir un paquet source ",[105,45853,34830],{},[12,45855,45856,45857,31],{},"Il faut que vous placiez les sources dans un dossier du nom de\n",[344,45858,45859],{},"\u003Cprogramme>-\u003Cversion>",[12,45861,45862],{},"Voici un exemple de fichier projet :",[352,45864,45867],{"className":45865,"code":45866,"language":34162,"meta":291,"style":291},"language-qmake shiki shiki-themes one-dark-pro","TARGET = qgenconfig\nTEMPLATE = app\n\nCONFIG += exceptions warn_on qt\nQT += xml\n\nHEADERS += src\u002Floadconfigimpl.h \\\\\n    src\u002Fsetupfile.h \\\\\n    src\u002Fconfigfile.h \\\\\n    src\u002Fp_configfile.h\nSOURCES += src\u002Floadconfigimpl.cpp \\\\\n    src\u002Fsetupfile.cpp \\\\\n    src\u002Fmain.cpp \\\\\n    src\u002Fconfigfile.cpp\nFORMS = ui\u002Floadconfig.ui\n\nDESTDIR = bin\nMOC_DIR = build\nOBJECTS_DIR = build\nUI_DIR = build\n",[344,45868,45869,45874,45879,45883,45888,45893,45897,45902,45907,45912,45917,45922,45927,45932,45937,45942,45946,45951,45956,45961],{"__ignoreMap":291},[360,45870,45871],{"class":362,"line":363},[360,45872,45873],{},"TARGET = qgenconfig\n",[360,45875,45876],{"class":362,"line":292},[360,45877,45878],{},"TEMPLATE = app\n",[360,45880,45881],{"class":362,"line":375},[360,45882,372],{"emptyLinePlaceholder":320},[360,45884,45885],{"class":362,"line":433},[360,45886,45887],{},"CONFIG += exceptions warn_on qt\n",[360,45889,45890],{"class":362,"line":478},[360,45891,45892],{},"QT += xml\n",[360,45894,45895],{"class":362,"line":483},[360,45896,372],{"emptyLinePlaceholder":320},[360,45898,45899],{"class":362,"line":489},[360,45900,45901],{},"HEADERS += src\u002Floadconfigimpl.h \\\\\n",[360,45903,45904],{"class":362,"line":494},[360,45905,45906],{},"    src\u002Fsetupfile.h \\\\\n",[360,45908,45909],{"class":362,"line":712},[360,45910,45911],{},"    src\u002Fconfigfile.h \\\\\n",[360,45913,45914],{"class":362,"line":331},[360,45915,45916],{},"    src\u002Fp_configfile.h\n",[360,45918,45919],{"class":362,"line":762},[360,45920,45921],{},"SOURCES += src\u002Floadconfigimpl.cpp \\\\\n",[360,45923,45924],{"class":362,"line":781},[360,45925,45926],{},"    src\u002Fsetupfile.cpp \\\\\n",[360,45928,45929],{"class":362,"line":804},[360,45930,45931],{},"    src\u002Fmain.cpp \\\\\n",[360,45933,45934],{"class":362,"line":817},[360,45935,45936],{},"    src\u002Fconfigfile.cpp\n",[360,45938,45939],{"class":362,"line":823},[360,45940,45941],{},"FORMS = ui\u002Floadconfig.ui\n",[360,45943,45944],{"class":362,"line":844},[360,45945,372],{"emptyLinePlaceholder":320},[360,45947,45948],{"class":362,"line":1441},[360,45949,45950],{},"DESTDIR = bin\n",[360,45952,45953],{"class":362,"line":1462},[360,45954,45955],{},"MOC_DIR = build\n",[360,45957,45958],{"class":362,"line":1485},[360,45959,45960],{},"OBJECTS_DIR = build\n",[360,45962,45963],{"class":362,"line":1497},[360,45964,45965],{},"UI_DIR = build\n",[12,45967,45968,45969,45971],{},"Pour générer le ",[344,45970,34810],{},", vous pouvez faire comme d'habitude :",[352,45973,45975],{"className":565,"code":45974,"language":567,"meta":291,"style":291},"qmake-qt4 qgenconfig.pro\n",[344,45976,45977],{"__ignoreMap":291},[360,45978,45979,45982],{"class":362,"line":363},[360,45980,45981],{"class":381},"qmake-qt4",[360,45983,45984],{"class":397}," qgenconfig.pro\n",[23034,45986,45988],{"id":45987},"création-des-scripts","Création des scripts",[12,45990,45991,45992,45994,45995,31],{},"Pour créer les paquets, il faut un ensemble de script dans le dossier\n",[344,45993,32927],{},". Pour se faciliter la vie, il est possible de créer les scripts\navec ",[344,45996,45997],{},"dh_make",[352,45999,46001],{"className":565,"code":46000,"language":567,"meta":291,"style":291},"DEBFULLNAME=\"Ulrich Van Den Hekke\"\ndh_make -e ulrich.vdh@shadoware.org -n -s -c gpl\n",[344,46002,46003,46013],{"__ignoreMap":291},[360,46004,46005,46008,46010],{"class":362,"line":363},[360,46006,46007],{"class":578},"DEBFULLNAME",[360,46009,583],{"class":582},[360,46011,46012],{"class":397},"\"Ulrich Van Den Hekke\"\n",[360,46014,46015,46017,46020,46023,46026,46028,46031],{"class":362,"line":292},[360,46016,45997],{"class":381},[360,46018,46019],{"class":414}," -e",[360,46021,46022],{"class":397}," ulrich.vdh@shadoware.org",[360,46024,46025],{"class":414}," -n",[360,46027,31556],{"class":414},[360,46029,46030],{"class":414}," -c",[360,46032,46033],{"class":397}," gpl\n",[12,46035,46036],{},"Voici la description de la liste des paramètres :",[140,46038,46039,46044,46050,46059,46065],{},[143,46040,46041,46043],{},[344,46042,46007],{}," indique le nom du mainteneur.",[143,46045,46046,46049],{},[344,46047,46048],{},"-e"," Permet de préciser l'email (suivis de l'email).",[143,46051,46052,46055,46056,46058],{},[344,46053,46054],{},"-n"," Produit un paquet natif pour ",[105,46057,45788],{}," (quand l'auteur fait\nses paquets lui-même).",[143,46060,46061,46064],{},[344,46062,46063],{},"-s"," Indique que le paquet ne va contenir qu'un simple exécutable\n(si vous voulez faire plusieurs paquets, il suffit de ne pas mettre\ncette option).",[143,46066,46067,46070,46071,2198],{},[344,46068,46069],{},"-c"," Indique la licence d'utilisation (ici ",[344,46072,46073],{},"gpl",[12,46075,46076],{},"Vous pouvez ensuite supprimer les fichiers exemples (mais pas\nnécessairement si vous voulez les étudier).",[352,46078,46080],{"className":565,"code":46079,"language":567,"meta":291,"style":291},"rm debian\u002F*.ex  debian\u002F*.EX  debian\u002Fdocs  debian\u002Fdirs\n",[344,46081,46082],{"__ignoreMap":291},[360,46083,46084,46087,46090,46092,46095,46098,46100,46103,46106],{"class":362,"line":363},[360,46085,46086],{"class":381},"rm",[360,46088,46089],{"class":397}," debian\u002F",[360,46091,925],{"class":662},[360,46093,46094],{"class":397},".ex",[360,46096,46097],{"class":397},"  debian\u002F",[360,46099,925],{"class":662},[360,46101,46102],{"class":397},".EX",[360,46104,46105],{"class":397},"  debian\u002Fdocs",[360,46107,46108],{"class":397},"  debian\u002Fdirs\n",[29701,46110,46112],{"id":46111},"paquet-simple","Paquet simple",[12,46114,46115],{},"Nous allons commencer par créer un paquet simple. Cela signifie qu'il\nn'y aura qu'un seul exécutable dans le paquet (pas de librairie, ...).",[12,46117,46118,46119,46122],{},"Dans le fichier ",[344,46120,46121],{},"control",", il faut que vous renseignez les informations\ndu paquet que vous allez créer.",[352,46124,46127],{"className":46125,"code":46126,"language":32201},[32199],"Source: qgenconfig\nSection: devel\nPriority: extra\nMaintainer: Ulrich Van Den Hekke \u003Culrich.vdh@shadoware.org>\nBuild-Depends: debhelper (>= 7)\nStandards-Version: 3.7.3\nHomepage: http:\u002F\u002Fprojects.shadoware.org\u002Fqgenconfig\n\nPackage: qgenconfig\nArchitecture: any\nDepends: ${shlibs:Depends}, ${misc:Depends}\nDescription: Create a config class in Qt after loading a XML file.\n    Load an XML description file of a settings object and create a class\n    that can be used to load and save information in a QSettings class. To\n    load information structure are used.\n",[344,46128,46126],{"__ignoreMap":291},[12,46130,46131,46132,46135,46136,46138],{},"Dans le paquet ci-dessus, on créait un paquet binaire et un paquet\nsource. Les variables de dépendance (dans ",[344,46133,46134],{},"Depends",") sont remplacées\nautomatiquement à la génération du paquet. La description est celle\nécrite dans ",[344,46137,45821],{},". La première ligne est la description courte, les\nsuivantes (précédées d'un espace) sont la description longue.",[12,46140,46141,46142,46145,46146,34886],{},"Ensuite on va remplacer le fichier ",[344,46143,46144],{},"debian\u002Frules"," en utilisant ",[344,46147,46148],{},"cdbs",[352,46150,46152],{"className":565,"code":46151,"language":567,"meta":291,"style":291},"#!\u002Fusr\u002Fbin\u002Fmake -f\ninclude \u002Fusr\u002Fshare\u002Fcdbs\u002F1\u002Frules\u002Fdebhelper.mk\ninclude \u002Fusr\u002Fshare\u002Fcdbs\u002F1\u002Fclass\u002Fqmake.mk\nQMAKE=qmake-qt4\n\ninstall\u002Fqgenconfig::\n    mkdir $(DEB_DESTDIR)\u002Fusr\u002F\n    mkdir $(DEB_DESTDIR)\u002Fusr\u002Fbin\u002F\n    cp $(CURDIR)\u002Fbin\u002Fqgenconfig $(DEB_DESTDIR)\u002Fusr\u002Fbin\u002F\n",[344,46153,46154,46159,46166,46173,46183,46187,46192,46208,46221],{"__ignoreMap":291},[360,46155,46156],{"class":362,"line":363},[360,46157,46158],{"class":644},"#!\u002Fusr\u002Fbin\u002Fmake -f\n",[360,46160,46161,46163],{"class":362,"line":292},[360,46162,35308],{"class":381},[360,46164,46165],{"class":397}," \u002Fusr\u002Fshare\u002Fcdbs\u002F1\u002Frules\u002Fdebhelper.mk\n",[360,46167,46168,46170],{"class":362,"line":375},[360,46169,35308],{"class":381},[360,46171,46172],{"class":397}," \u002Fusr\u002Fshare\u002Fcdbs\u002F1\u002Fclass\u002Fqmake.mk\n",[360,46174,46175,46178,46180],{"class":362,"line":433},[360,46176,46177],{"class":578},"QMAKE",[360,46179,583],{"class":582},[360,46181,46182],{"class":397},"qmake-qt4\n",[360,46184,46185],{"class":362,"line":478},[360,46186,372],{"emptyLinePlaceholder":320},[360,46188,46189],{"class":362,"line":483},[360,46190,46191],{"class":381},"install\u002Fqgenconfig::\n",[360,46193,46194,46197,46200,46203,46205],{"class":362,"line":489},[360,46195,46196],{"class":381},"    mkdir",[360,46198,46199],{"class":366}," $(",[360,46201,46202],{"class":381},"DEB_DESTDIR",[360,46204,16112],{"class":366},[360,46206,46207],{"class":397},"\u002Fusr\u002F\n",[360,46209,46210,46212,46214,46216,46218],{"class":362,"line":494},[360,46211,46196],{"class":381},[360,46213,46199],{"class":366},[360,46215,46202],{"class":381},[360,46217,16112],{"class":366},[360,46219,46220],{"class":397},"\u002Fusr\u002Fbin\u002F\n",[360,46222,46223,46226,46228,46231,46233,46236,46238,46240,46242],{"class":362,"line":712},[360,46224,46225],{"class":381},"    cp",[360,46227,46199],{"class":366},[360,46229,46230],{"class":381},"CURDIR",[360,46232,16112],{"class":366},[360,46234,46235],{"class":397},"\u002Fbin\u002Fqgenconfig",[360,46237,46199],{"class":366},[360,46239,46202],{"class":381},[360,46241,16112],{"class":366},[360,46243,46220],{"class":397},[12,46245,46246,46247,46250,46255,46256,2198],{},"En premier lieu on définit les variables pour la compilation, puis\nensuite on définit les opérations d'installations dans la cible\n",[344,46248,46249],{},"install\u002Fqgenconfig",[15680,46251,46252],{},[47,46253,1944],{"href":15684,"ariaDescribedBy":46254,"dataFootnoteRef":291,"id":15687},[15686],".Dans les opérations, vous allez copier\nvotre exécutable dans le dossier de génération de debian (dossier\n",[344,46257,46258],{},"debian\u002F\u003Ccible>",[29701,46260,46262],{"id":46261},"paquet-multiple","Paquet multiple",[12,46264,46265,46266,46268,46269,46271,46272,33759],{},"Créer plusieurs paquets à partir d'une même source avec ",[344,46267,46148],{}," est assez\nsimple. Il suffit de rajouter des cibles, correspondantes au fichier\n",[344,46270,46121],{},", dans le fichier ",[344,46273,46274],{},"rules",[12,46276,46277,46278,46280],{},"Dans le fichier de ",[344,46279,46121],{}," on va avoir plusieurs paquets binaires pour\nun seul paquet source.",[352,46282,46285],{"className":46283,"code":46284,"language":32201},[32199],"Source: xinx\nSection: devel\nPriority: extra\nMaintainer: Ulrich Van Den Hekke \u003Cxinx@shadoware.org>\nBuild-Depends: debhelper (>= 7)\nStandards-Version: 3.7.3\nHomepage: http:\u002F\u002Fxinx.shadoware.org\u002F\n\nPackage: xinx\nSection: devel\nArchitecture: any\nDepends: ${shlibs:Depends}, ${misc:Depends}, xinx-scripts (>= 0.7.2.0)\nRecommends: xinx-plugins-services, xinx-plugins-cvs, xinx-plugins-svn\nSuggests: xinx-doc\nDescription: XSL\u002FJS\u002FHTML editor for Generix\n    XINX is an editor of XSL stylesheet, JavaScript, Cascading Style Sheet.\n    This editor is used with egx.\n\nPackage: xinx-doc\nSection: doc\nArchitecture: all\nDepends: xinx (>= 0.7.2.0)\nDescription: Documentation for xinx\n    Technical Documentation of XINX\n",[344,46286,46284],{"__ignoreMap":291},[12,46288,46289,46290,46292,46293,46295,46300],{},"Nous allons définir dans le fichier ",[344,46291,46274],{}," les différentes cibles que\nnous avons dans le fichier ",[344,46294,46121],{},[15680,46296,46297],{},[47,46298,795],{"href":16257,"ariaDescribedBy":46299,"dataFootnoteRef":291,"id":16259},[15686],"^.",[352,46302,46304],{"className":565,"code":46303,"language":567,"meta":291,"style":291},"#!\u002Fusr\u002Fbin\u002Fmake -f\ninclude \u002Fusr\u002Fshare\u002Fcdbs\u002F1\u002Frules\u002Fdebhelper.mk\ninclude \u002Fusr\u002Fshare\u002Fcdbs\u002F1\u002Fclass\u002Fqmake.mk\nQMAKE=qmake-qt4 project.pro\n\ninstall\u002Fxinx::\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002F\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002Fbin\u002F\n    cp $(CURDIR)\u002Fxinx\u002Fxinx $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002Fbin\u002F\n    cp $(CURDIR)\u002Fxinxprojectwizard\u002Fxinxprojectwizard $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002Fbin\u002F\n\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002Flib\u002F\n    cp -a $(CURDIR)\u002Flibxinx\u002Flibsharedxinx* $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002Flib\u002F\n    cp -a $(CURDIR)\u002Fcomponents\u002Flibxinxcmp* $(CURDIR)\u002Fdebian\u002Fxinx\u002Fusr\u002Flib\u002F\n\ninstall\u002Fxinx-doc::\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx-doc\u002Fusr\u002F\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002F\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002F\n    mkdir $(CURDIR)\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002Fxinx-doc\u002F\n    cp -a $(CURDIR)\u002Fdoc\u002F* $(CURDIR)\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002Fxinx-doc\u002F\n    rm -rf $(CURDIR)\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002Fxinx-doc\u002Fhtml\u002F.svn\n",[344,46305,46306,46310,46316,46322,46333,46337,46342,46355,46368,46389,46410,46414,46427,46453,46478,46482,46487,46500,46513,46526,46539,46564],{"__ignoreMap":291},[360,46307,46308],{"class":362,"line":363},[360,46309,46158],{"class":644},[360,46311,46312,46314],{"class":362,"line":292},[360,46313,35308],{"class":381},[360,46315,46165],{"class":397},[360,46317,46318,46320],{"class":362,"line":375},[360,46319,35308],{"class":381},[360,46321,46172],{"class":397},[360,46323,46324,46326,46328,46330],{"class":362,"line":433},[360,46325,46177],{"class":578},[360,46327,583],{"class":582},[360,46329,45981],{"class":397},[360,46331,46332],{"class":381}," project.pro\n",[360,46334,46335],{"class":362,"line":478},[360,46336,372],{"emptyLinePlaceholder":320},[360,46338,46339],{"class":362,"line":483},[360,46340,46341],{"class":381},"install\u002Fxinx::\n",[360,46343,46344,46346,46348,46350,46352],{"class":362,"line":489},[360,46345,46196],{"class":381},[360,46347,46199],{"class":366},[360,46349,46230],{"class":381},[360,46351,16112],{"class":366},[360,46353,46354],{"class":397},"\u002Fdebian\u002Fxinx\u002Fusr\u002F\n",[360,46356,46357,46359,46361,46363,46365],{"class":362,"line":494},[360,46358,46196],{"class":381},[360,46360,46199],{"class":366},[360,46362,46230],{"class":381},[360,46364,16112],{"class":366},[360,46366,46367],{"class":397},"\u002Fdebian\u002Fxinx\u002Fusr\u002Fbin\u002F\n",[360,46369,46370,46372,46374,46376,46378,46381,46383,46385,46387],{"class":362,"line":712},[360,46371,46225],{"class":381},[360,46373,46199],{"class":366},[360,46375,46230],{"class":381},[360,46377,16112],{"class":366},[360,46379,46380],{"class":397},"\u002Fxinx\u002Fxinx",[360,46382,46199],{"class":366},[360,46384,46230],{"class":381},[360,46386,16112],{"class":366},[360,46388,46367],{"class":397},[360,46390,46391,46393,46395,46397,46399,46402,46404,46406,46408],{"class":362,"line":331},[360,46392,46225],{"class":381},[360,46394,46199],{"class":366},[360,46396,46230],{"class":381},[360,46398,16112],{"class":366},[360,46400,46401],{"class":397},"\u002Fxinxprojectwizard\u002Fxinxprojectwizard",[360,46403,46199],{"class":366},[360,46405,46230],{"class":381},[360,46407,16112],{"class":366},[360,46409,46367],{"class":397},[360,46411,46412],{"class":362,"line":762},[360,46413,372],{"emptyLinePlaceholder":320},[360,46415,46416,46418,46420,46422,46424],{"class":362,"line":781},[360,46417,46196],{"class":381},[360,46419,46199],{"class":366},[360,46421,46230],{"class":381},[360,46423,16112],{"class":366},[360,46425,46426],{"class":397},"\u002Fdebian\u002Fxinx\u002Fusr\u002Flib\u002F\n",[360,46428,46429,46431,46434,46436,46438,46440,46443,46445,46447,46449,46451],{"class":362,"line":804},[360,46430,46225],{"class":381},[360,46432,46433],{"class":414}," -a",[360,46435,46199],{"class":366},[360,46437,46230],{"class":381},[360,46439,16112],{"class":366},[360,46441,46442],{"class":397},"\u002Flibxinx\u002Flibsharedxinx",[360,46444,925],{"class":662},[360,46446,46199],{"class":366},[360,46448,46230],{"class":381},[360,46450,16112],{"class":366},[360,46452,46426],{"class":397},[360,46454,46455,46457,46459,46461,46463,46465,46468,46470,46472,46474,46476],{"class":362,"line":817},[360,46456,46225],{"class":381},[360,46458,46433],{"class":414},[360,46460,46199],{"class":366},[360,46462,46230],{"class":381},[360,46464,16112],{"class":366},[360,46466,46467],{"class":397},"\u002Fcomponents\u002Flibxinxcmp",[360,46469,925],{"class":662},[360,46471,46199],{"class":366},[360,46473,46230],{"class":381},[360,46475,16112],{"class":366},[360,46477,46426],{"class":397},[360,46479,46480],{"class":362,"line":823},[360,46481,372],{"emptyLinePlaceholder":320},[360,46483,46484],{"class":362,"line":844},[360,46485,46486],{"class":381},"install\u002Fxinx-doc::\n",[360,46488,46489,46491,46493,46495,46497],{"class":362,"line":1441},[360,46490,46196],{"class":381},[360,46492,46199],{"class":366},[360,46494,46230],{"class":381},[360,46496,16112],{"class":366},[360,46498,46499],{"class":397},"\u002Fdebian\u002Fxinx-doc\u002Fusr\u002F\n",[360,46501,46502,46504,46506,46508,46510],{"class":362,"line":1462},[360,46503,46196],{"class":381},[360,46505,46199],{"class":366},[360,46507,46230],{"class":381},[360,46509,16112],{"class":366},[360,46511,46512],{"class":397},"\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002F\n",[360,46514,46515,46517,46519,46521,46523],{"class":362,"line":1485},[360,46516,46196],{"class":381},[360,46518,46199],{"class":366},[360,46520,46230],{"class":381},[360,46522,16112],{"class":366},[360,46524,46525],{"class":397},"\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002F\n",[360,46527,46528,46530,46532,46534,46536],{"class":362,"line":1497},[360,46529,46196],{"class":381},[360,46531,46199],{"class":366},[360,46533,46230],{"class":381},[360,46535,16112],{"class":366},[360,46537,46538],{"class":397},"\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002Fxinx-doc\u002F\n",[360,46540,46541,46543,46545,46547,46549,46551,46554,46556,46558,46560,46562],{"class":362,"line":3161},[360,46542,46225],{"class":381},[360,46544,46433],{"class":414},[360,46546,46199],{"class":366},[360,46548,46230],{"class":381},[360,46550,16112],{"class":366},[360,46552,46553],{"class":397},"\u002Fdoc\u002F",[360,46555,925],{"class":662},[360,46557,46199],{"class":366},[360,46559,46230],{"class":381},[360,46561,16112],{"class":366},[360,46563,46538],{"class":397},[360,46565,46566,46569,46572,46574,46576,46578],{"class":362,"line":3167},[360,46567,46568],{"class":381},"    rm",[360,46570,46571],{"class":414}," -rf",[360,46573,46199],{"class":366},[360,46575,46230],{"class":381},[360,46577,16112],{"class":366},[360,46579,46580],{"class":397},"\u002Fdebian\u002Fxinx-doc\u002Fusr\u002Fshare\u002Fdoc\u002Fxinx-doc\u002Fhtml\u002F.svn\n",[12,46582,46583],{},"Ici on génère deux paquets, le paquet binaire et la documentation.",[23034,46585,46587],{"id":46586},"génération-du-paquet","Génération du paquet",[29701,46589,46591],{"id":46590},"mise-à-jour-des-informations-du-paquets","Mise à jour des informations du paquets",[140,46593,46594],{},[143,46595,46596],{},"Pour modifier le changelog sur la version courante",[352,46598,46600],{"className":565,"code":46599,"language":567,"meta":291,"style":291},"dch -a\n",[344,46601,46602],{"__ignoreMap":291},[360,46603,46604,46607],{"class":362,"line":363},[360,46605,46606],{"class":381},"dch",[360,46608,46609],{"class":414}," -a\n",[140,46611,46612],{},[143,46613,46614],{},"Pour créer une nouvelle version",[352,46616,46618],{"className":565,"code":46617,"language":567,"meta":291,"style":291},"dch -i\n",[344,46619,46620],{"__ignoreMap":291},[360,46621,46622,46624],{"class":362,"line":363},[360,46623,46606],{"class":381},[360,46625,46626],{"class":414}," -i\n",[29701,46628,45840],{"id":46629},"création-du-paquet-1",[352,46631,46633],{"className":565,"code":46632,"language":567,"meta":291,"style":291},"dpkg-buildpackage -rfakeroot\n",[344,46634,46635],{"__ignoreMap":291},[360,46636,46637,46640],{"class":362,"line":363},[360,46638,46639],{"class":381},"dpkg-buildpackage",[360,46641,46642],{"class":414}," -rfakeroot\n",[12,46644,46645],{},"L'application va signer le paquet s'il trouve la clé assignée à\nl'utilisateur.",[1901,46647,46649],{"id":46648},"création-dun-dépôt","Création d'un dépôt",[12,46651,46652],{},"Après avoir créé des paquets, il peut-être intéressant de créer un dépôt\npour installer ces paquets. voici la marche à suivre pour créer le\ndépôt.",[12,46654,46655,46656,2198],{},"Sur votre serveur internet (nous ne parlerons pas ici de la mise à\ndisposition sur Internet), vous allez devoir créer un dossier contenant\nvotre référentiel (exemple : ",[344,46657,46658],{},"\u002Fwww\u002Fsites\u002Fapt",[23034,46660,46662],{"id":46661},"création-de-larborescence","Création de l'arborescence",[12,46664,46665],{},"Vous allez devoir créer une arborescence comme suite :",[352,46667,46670],{"className":46668,"code":46669,"language":32201},[32199],"dists\n    +- main\n        |- binary-i386\n        |- binary-amd64\n        +- source\n",[344,46671,46669],{"__ignoreMap":291},[12,46673,46674,46675,46678,46679,2311,46682,46685,46686,15272,46689,31],{},"Parmi les fichiers générés vous allez devoir mettre le fichier ",[344,46676,46677],{},".deb","\ndans le dossier binaire, et les fichiers ",[344,46680,46681],{},".changes",[344,46683,46684],{},".dsc",", et\n",[344,46687,46688],{},".tar.gz",[344,46690,34850],{},[23034,46692,46694],{"id":46693},"création-dun-fichier-apt-ftparchiveconf","Création d'un fichier apt-ftparchive.conf",[12,46696,46697,46698,46701],{},"Nous allons commencer par créer un fichier ",[344,46699,46700],{},"apt-ftparchive.conf"," dans\nlequel nous allons définir les fichiers à créer.",[352,46703,46706],{"className":46704,"code":46705,"language":32201},[32199],"Dir {\n    ArchiveDir \".\";\n    CacheDir \".\";\n};\n\nTree \"dists\u002Funstable\" {\n    Sections \"main\";\n    Architectures \"amd64 source\";\n};\n\nBinDirectory \"dists\u002Funstable\u002Fmain\u002Fbinary-amd64\" {\n    Packages \"dists\u002Funstable\u002Fmain\u002Fbinary-amd64\u002FPackages\";\n    Contents \"dists\u002Funstable\u002FContents-amd64\";\n    SrcPackages \"dists\u002Funstable\u002Fmain\u002Fsource\u002FSources\";\n};\n",[344,46707,46705],{"__ignoreMap":291},[23034,46709,46711],{"id":46710},"création-du-fichier-apt-unstable-releaseconf","Création du fichier apt-unstable-release.conf",[352,46713,46716],{"className":46714,"code":46715,"language":32201},[32199],"APT::FTPArchive::Release::Origin    \"shadoware.org\";\nAPT::FTPArchive::Release::Label     \"shadoware.org\";\nAPT::FTPArchive::Release::Suite     \"unstable\";\nAPT::FTPArchive::Release::Codename   \"unstable\";\nAPT::FTPArchive::Release::Architectures  \"amd64 source\";\nAPT::FTPArchive::Release::Components \"main\";\nAPT::FTPArchive::Release::Description    \"Paquets du site Shadoware.Org\";\n",[344,46717,46715],{"__ignoreMap":291},[23034,46719,46721],{"id":46720},"création-du-fichier-update-archivesh","Création du fichier update-archive.sh",[12,46723,46724],{},"Ce fichier est celui que l'on doit exécuter pour la génération du\ncontenu de l'arborescence :",[352,46726,46728],{"className":565,"code":46727,"language":567,"meta":291,"style":291},"apt-ftparchive generate apt-ftparchive.conf\napt-ftparchive -c apt-unstable-release.conf release dists\u002Funstable > dists\u002Funstable\u002FRelease\n",[344,46729,46730,46741],{"__ignoreMap":291},[360,46731,46732,46735,46738],{"class":362,"line":363},[360,46733,46734],{"class":381},"apt-ftparchive",[360,46736,46737],{"class":397}," generate",[360,46739,46740],{"class":397}," apt-ftparchive.conf\n",[360,46742,46743,46745,46747,46750,46753,46756,46759],{"class":362,"line":292},[360,46744,46734],{"class":381},[360,46746,46030],{"class":414},[360,46748,46749],{"class":397}," apt-unstable-release.conf",[360,46751,46752],{"class":397}," release",[360,46754,46755],{"class":397}," dists\u002Funstable",[360,46757,46758],{"class":366}," > ",[360,46760,46761],{"class":397},"dists\u002Funstable\u002FRelease\n",[21499,46763,46765,46768],{"className":46764,"dataFootnotes":291},[21502],[33,46766,21507],{"className":46767,"id":15686},[21506],[13835,46769,46770,46779],{},[143,46771,46772,46773,46775,46776],{"id":21512},"D'autres cibles sont disponibles (cf la doc de ",[344,46774,46148],{},"). ",[47,46777,21520],{"href":21516,"ariaLabel":21517,"className":46778,"dataFootnoteBackref":291},[21519],[143,46780,46781,46782,46785,46786,34698,46789],{"id":21523},"A cause d'un bogue, ou d'une mauvaise utilisation, la variable ",[344,46783,46784],{},"$(DEB_DESTDIR)"," ne me ramenait pas la bonne valeur, je l'ai donc remplacée par ",[344,46787,46788],{},"$(CURDIR)\u002Fdebian",[47,46790,21520],{"href":21531,"ariaLabel":21532,"className":46791,"dataFootnoteBackref":291},[21519],[1613,46793,46794],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}",{"title":291,"searchDepth":292,"depth":292,"links":46796},[46797,46798,46799,46800],{"id":45801,"depth":375,"text":45802},{"id":45839,"depth":375,"text":45840},{"id":46648,"depth":375,"text":46649},{"id":15686,"depth":292,"text":21507},"2008-09-08","A titre personnel je fabrique quelques programmes en Qt. Comme j'utilise\nun système Gnu\u002FDebian, j'ai cherché à fabriquer des paquets pour mon\nsystème (plus pour le plaisir qu'autre chose, car la plus grande partie\nde mes utilisateurs sont sous MS\u002FWindows).",{"type":9,"value":46804},[46805,46811],[12,46806,45785,46807,45789,46809,2198],{},[105,46808,45788],{},[105,46810,45792],{},[12,46812,45795,46813,45798],{},[105,46814,45788],{},{},"\u002Fpost\u002Fpaquet-debian-et-qt",{"title":45780,"description":46802},"paquet-debian-et-qt","posts\u002FProgrammation\u002F2008-09-08-paquet-debian-et-qt",[32927,32924],"UfskBB2vEveCnHyHdgHEScfMRoTQzydi1tuF-O_x8Ik",{"id":46823,"title":46824,"author":7,"body":46825,"category":300,"categorySlug":301,"date":46900,"description":46901,"excerpt":46902,"extension":317,"location":318,"meta":46923,"navigation":320,"path":46924,"published":320,"seo":46925,"slug":46926,"stem":46927,"tags":46928,"timeToRead":363,"__hash__":46929},"posts\u002Fposts\u002FProgrammation\u002F2008-01-21-memo-qt.md","Mémo Qt",{"type":9,"value":46826,"toc":46896},[46827,46835,46838,46856,46860,46862,46867,46869,46872,46878,46880,46886,46890],[12,46828,46829,46830,31],{},"Ceci est un petit mémo pour me permettre de ne pas oublier quelques\nastuces lors de la programmation avec Qt. En parlant de cela, je me suis\ncommandé le livre suivant : ",[47,46831,46834],{"href":46832,"rel":46833},"http:\u002F\u002Fwww.amazon.fr\u002FGUI-Programming-Qt4-Jasmin-Blanchette\u002Fdp\u002F0132354160\u002Fref=sr_11_1?ie=UTF8&qid=1199972515&sr=11-1",[51],"C++ GUI Programming with Qt4",[1901,46836,42425],{"id":46837},"qabstractitemmodel",[140,46839,46840,46843],{},[143,46841,46842],{},"Lors de l'insertion (avec beginInsertRows()), les éléments insérés\nne doivent pas contenir de sous éléments (rowCount() == 0) sous\npeine de causer des plantages.",[143,46844,46845,46846,854,46851],{},"Un model de donnée interne, pouvant être utilisé avec\nQAbstractItemModel pour afficher une arborescence et étant capable\nde se rafraîchir à la lecture d'un fichier, se trouve dans les\nfichiers ",[47,46847,46850],{"href":46848,"rel":46849},"http:\u002F\u002Fhg.shadoware.org\u002FSoftware\u002FXINX\u002Fxinx\u002Ffiles\u002F53bd629daf731398437a8c2f328e7b4015a013ca\u002Flibxinx\u002Ffilecontentstructure.cpp",[51],"filecontentstructure.cpp",[47,46852,46855],{"href":46853,"rel":46854},"http:\u002F\u002Fhg.shadoware.org\u002FSoftware\u002FXINX\u002Fxinx\u002Ffiles\u002F53bd629daf731398437a8c2f328e7b4015a013ca\u002Flibxinx\u002Ffilecontentstructure.h",[51],"filecontentstructure.h",[1901,46857,46859],{"id":46858},"cmake-et-qt","CMake et Qt",[23034,46861,35894],{"id":35893},[352,46863,46865],{"className":46864,"code":35897,"language":32201},[32199],[344,46866,35897],{"__ignoreMap":291},[23034,46868,35712],{"id":35711},[29701,46870,46871],{"id":46871},"dynamique",[352,46873,46876],{"className":46874,"code":46875,"language":32201},[32199],"add_definitions(${QT_DEFINITIONS})\nadd_definitions(-DQT_PLUGIN)\nadd_definitions(-DQT_NO_DEBUG)\nadd_definitions(-DQT_SHARED)\nadd_library(webplugin SHARED ${webplugin_SRCS} ${webplugin_MOC_SRCS})\n",[344,46877,46875],{"__ignoreMap":291},[29701,46879,5931],{"id":5931},[352,46881,46884],{"className":46882,"code":46883,"language":32201},[32199],"?\n",[344,46885,46883],{"__ignoreMap":291},[23034,46887,46889],{"id":46888},"compilation-de-fichier-rc-pour-windows","Compilation de fichier RC pour Windows",[352,46891,46894],{"className":46892,"code":46893,"language":32201},[32199],"if(WIN32)\n    add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}\u002Fxinx_ico.obj\n           COMMAND windres.exe -I${CMAKE_CURRENT_SOURCE_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}\u002Fxinx_ico.obj -i${CMAKE_CURRENT_SOURCE_DIR}\u002F${xinx_RCS}\n    )\n    set(xinx_RESS ${CMAKE_CURRENT_BINARY_DIR}\u002Fxinx_ico.obj)\nendif(WIN32)\n",[344,46895,46893],{"__ignoreMap":291},{"title":291,"searchDepth":292,"depth":292,"links":46897},[46898,46899],{"id":46837,"depth":375,"text":42425},{"id":46858,"depth":375,"text":46859},"2008-01-21","Ceci est un petit mémo pour me permettre de ne pas oublier quelques\nastuces lors de la programmation avec Qt. En parlant de cela, je me suis\ncommandé le livre suivant : C++ GUI Programming with Qt4.",{"type":9,"value":46903},[46904,46909,46911],[12,46905,46829,46906,31],{},[47,46907,46834],{"href":46832,"rel":46908},[51],[1901,46910,42425],{"id":46837},[140,46912,46913,46915],{},[143,46914,46842],{},[143,46916,46845,46917,854,46920],{},[47,46918,46850],{"href":46848,"rel":46919},[51],[47,46921,46855],{"href":46853,"rel":46922},[51],{},"\u002Fpost\u002Fmemo-qt",{"title":46824,"description":46901},"memo-qt","posts\u002FProgrammation\u002F2008-01-21-memo-qt",[32924],"LurBRat5GKyW_n9EoVty1Vi5WkYd8uVKKIfb9AwdIE4",1777849582748]