You are on page 1of 84
NyLrgee Ta 2021 Cer eS Eee Poetry CE Om Tat) Comers MAGAZINE / FRANCE yma eS el LL Le = CRYPTOMONNAIES : DECOUVREZ LES NFT! GENEREZ DES IMAGES ET CREEZ VOS TOKEN ERC-721 rs "Node js | SGBD MAITRISEZ LES TECHNIQUES SQL cbc =| AVANCEES EN JAVASCRIPT DECOUVREZ STREAMLIT AVEC LE MOTEUR ALASQL POUR LA CREATION RAPIDE aie D’INTERFACES EN PYTHON rx) Celera ass} ea DU CODE EN LATEX po WIKIMEDIA FRANCE Grace a votre contribution, les projets Wikimédia existent en toute indépendance, des contenus sont libérés, de jeunes publics sont sensi és au numérique et la connaissance est un peu plus accessible 4 tous chaque jour Ld Le saviez-vous ? Votre don est déductible des impéts. Un regu fiscal vous sera adressé par courrier a réception de votre don edi Cee e me CG) GNU/Linux Magazine France fe 6d par Ls tens Dimond {2 Place Captain Dri 88000 Col France ‘Tau c367 100020 ax: 0967 100024 nal: acteurs cc ‘Service commercial: arond@abomarque com Stas waning com Directour de pubiteation :Amaus Matter ‘ligation graphique : Thomas Pichon ‘Series abonnement: (GAU Line Magasine Abomaraue ‘Suse do Laur 31240 Union -Franes ‘Tél: 0967 1000 20-darendiBabomerae com Impression : pra. Drockund Medien -lersistungen {Grob Landaa, ilemagne Distrbution France: uniques pour les dipostares de prose) MLE Résssort: tae for de Sie. Bashtemy An Teu-aaat 2753 12 Paterme de Sai Qbantn- Fata, Tal =06 748269 04 IMPRIME on Alemagne- PRINTED in Germany pdt égal: A parton, NISSN 1251-7034 W'CPPAP: K7AS70 inde verte: 90€ = deni) esr erne aan Lararae ens, pots ese srs & NU Magaae snr ett tinny i ‘inert sans aan nie tsa merase a ania er Gps pra poate eect aso ‘epoomie trek mopiote pepe yer ote https://www.gnulinuxmag.com RETROUVEZ-NOUS SUR co Pee ENCART CONNECT ENCARTE DANS LA COUVERTURE @D Codes sources sur: rd EDITO Regulidrement, je magace dans ces lignes des aber- rations constatées surdes sites web ou des applications, allant du « simple » probleme ergonomique jusquaux erreurs non traitées. Je pense avoir encore de trés nom breux exemples & soulever, la source n’étant pas prés de se tarir ! En effet, je constate dans mes activités drenseignement universitaire que, de plus en plus souvent, on cherche & «« protéger » les étudiants, a leur prémacher le travail. On conserve donc des étudiants codte que coGte en revoyant constamment les exigences & la baisse, en nivelant par le bas. Venseigne par exemple le langage Python (comme par hasard !) en LI Informatique. Je souhaite proposer & mes étudiants d'installer Python et Jupyter sur leur ordinateur (en leur fournissant bien entendu un cours dé- 1aillé contenant des explications & la fois pour Linux et pour Windows) Or, mes collégues miont indiqué que je me montrais particuligrement exi- geant : « C'est un peu compliqué pour des étudiants qui ne connaissent pas la programmation », Pourtant, je ne me trouve pas élitiste en deman- dant a des étudiants en informatique de savoir installer un programme, int: AE 0 <= code <= 255: saturn code eles raise Exception('Color code must be an int between 0 and 255") def get (self, color_nane: str) -> int: Af color name == ‘red’ return self._r elif color_name == ‘green’: return eelf._g elif color_nane == ‘blue! : return self._b elif color_nane == ‘alpha’: return self._a raise Exception('Unknown channel") def _iter_(self): Yield self._r yield self."g yield self." if self._a is not None: return self. NOTE Pour convertir un code couleur hexadécimal en triplet” dentiers, vous pouvez utiliser simplement le Shell in- teractif de Python avec int(, ). Par exemple >>> int ("37", 16) 55 >>> ant ("73", 16) 115 >>> ant (1A5', 16) 165 F dont le code RGB est parfaitement connu, Fig. 4: Image comportant des zones colorées uniformes Cette classe permet de stocker les valeurs red (atribut self._r), green (seUf._r), blue (seLf._b) et alpha (trans- parence avec Fattribut seUf._a). Les valeurs données lors de la création d'une instance sont vérifiges de manigre & © tre valides (entre © et 255) grice & la méthode de classe valid’) Pour obtenir la quantité d'une couleur, il faut utiliser la | méthode get() & laguelle on passe en paramatre le nom ddu canal sous forme de chaine de caractéres. Enfin, la méthode spéciale __ ite ) permet uti © liser les fonctions de conversion List() et tuple() pour récupérer les données sous forme de liste ou de tuple (en © fait, on peut méme itérer sur une instance de la classe | pour obtenir dans lordre les canaux red, green, blue et alpha). Voici un exemple d'utilisation de la classe dans un Shell Python >>> from Color import Color >>> orange = Color (245, 152, 41) >>> tuple (orange) (245, 152, 41) >>> blue = Color (55, 115, 265) ‘Traceback (most recent call last): raise Exception('Color code must be an int between 0 and 255") waww.ed-diamond.com ACTUS & HUMEUR PYTHON Exception: Color code mist be an int between 0 and 255 >>> blue = Color (55, 115, 165, 50) >>> List (blue) 155, 115, 165) Nous pouvons passer au script de changement de cou- leur proprement dit dans change_color.py : from PIL import Image amport numpy from Color import Color mage = Image. open('image_color.png') data = numpy.array (image) data_r, data g, datab, data_a = data.T orange = Color (245, 152, 41) blue = Color (55, 115, 165) blue_area = (data_r == blue.get(‘red")) & (data_g == blue.get("green')) & (data_b == Blue. get ("blue')} data[..., :-1][blue_area.t] = tuple(orange) result = Image. fromarray (data) result.save('final.png") On charge bien entendu l'image dans image et on r&- ccupere les données dans un array Numpy. Chaque canal est ensuite stocké séparéiment en prenant le tableau trans- posé de data et en identifiant les colonnes, Les couleurs sont ensuite définies en créant des instances de Color : orange sera la couleur de remplacement et blue la couleur a remplacer. La définition de la zone a remplacer| se fait dans blue_area en créant un masque : les True cor respondent aux pixels bleus (on teste les iférents canaux des pixels et on effectue un et binaite) et les False aux autres. Ensuite, on remplace dans data les pixels du masque ‘blue_area (qu'il faut & nouveau transposer) par des pixels ranges (il faut donne les trois canaux sous forme de tuple) Pour finir, on récupire Pimage depuis les données de data et on la sauvegarde dans final.png. Crest un peu plus compliqué que la fusion de calques, ce mest pas du tout utilisé dans les Weird Whales, mais «ala va nous permettre de générer encore plus dimages, différentes, et ce, sans effort | 4, LE GENERATEUR DE PINGOUINS Pour notre générateur de pingouins, nous allons uti- liser les traits suivants (les layers associés seront stockés dans des répertoires de méme nom, préfixés parle numé= ro dfordre pour la fusion), ordonnés par ordre de fusion + Background © sélection de la couleur de fond de Vimage (ce qui donnera le répertoire 1_Background) ; + Base : sélection de la forme de base du pingouin + ye Accessory : sélection du type d'yeux (répertoire EyeAccessory_3); + Beak : le type de bec + Headgear : sélection du type de chapeau ; + Shoes : sélection du type de chaussures. ‘Chacun de ces répertoires contiendra des images dont la rareté sera indiquée par un prétixe + C_ pour common (commune) avec 70 % de chance apparition ; + U_pour unusual (inhabituelle) avec 24 % de chance appar + R_pour rare avec 5 % de chance «apparition ; + X_pour extra rare avec 1 % de chance dapparition. Le nom des images sera simplement une numérota- tion : 2 pour la premigre image d'un répertoire, puis 2, etc, Cela permettra d’établir un identifiant unique pour le nom de limage générée et dautoriser plusieurs images pour chaque type de rareté. On pourra par exemple avoir €_2.png, €_2.png, etc. ATTENTION ! Le fait d'autoriser plusieurs images par type de rareté ‘modifiefes pourcentages de chance «apparition, Ai Rous prenons deux images x_1.png et X_2.png, comme Xa I % de chance «apparition, chaque image ide X aura alors 0,5 % de chance «apparition De plus, les pixels des images feront nécessairement partie des couleurs de base suivantes : 40 © GNU/Linux Magazine France N°253 ‘ww ve gnulinuxmag.com Génération automatique de NFT + noir (8, 9, 0) et blanc (255, 255, 255) qui se- ront des pixels « stables » dont la couleur ne peu tre modifige + rouge (255, 9, 0), vert (8, 255, 6), bleu (0, 6, 255), rose (255, 0, 255), jaune (255, 255, 0) et bleu clair (@, 255, 255) qui seront des pixels modifiables. - Yai retenu 9 couleurs qui auront elles aussi un niveau de rareté exprimé par le méme préfixe que pour les layers et auront le méme pourcentage d'apparition (70 % pour les communes, 24 % pour les inhabituelles, 5 % pour les rares et 1 9% pour les extra rares) + €_1 (beige) pour (222, 197, 167) ; + € 2 (sable) pour (250, 244, 212) ; + C3 (vert) pour (223, 235, 157) ; + ¢_4 (mauve) pour (296, 167, 222) ; + U_5 (bleu clair) pour (157, 181, 255) ; + U_6 (orange) pour (255, 280, 128) ; + U_7 (tose vif) pour (254, 60, 122) + R_8 (bleu turquoise) pour (102, 98, 208) ; + X_9 (rose) pour (250, 68, 106). NOTE Les couleurs sélectionnées sont des couleurs « Kaw. puisque visiblement, cst ce qui plait. En japonais, « Kawail » signfie « mignon », nous fai~ sons de donc de « mignons dessins de pingouins en pixel art ».. quelle horreur ! Puisque nous avons posé toutes nos contraintes et que nous avons défriché les points techniques qui auraient pu étre bloquants, nous pouvons nous lancer dans la program ‘mation du générateur ! Nous ne pourrons malheureusement pas conserver la classe Color, car nous allons devoir effectuer non seule- ‘ment une modification des pixels de image, mais aussi une recherche des pixels colorés des layers (ce qui permettra de savoir quelles sont les couleurs qui ont été réellement em- ployées pour générer une image). Du coup, nous allons par- Ccouri les layers pixel par pixel, ce qui sera nécessairement plus long. Une autre solution aurait été de consigner dans tun fichier, pour chaque layer, les couleurs employées qui | seront ensuite remplacées. Comme nous ne sommes pas particuligrement pressés pour générer nos pingouins, choisi la méthode en brute-force avec un parcours de tous les pixels des images, Voici le code de PartyingPenguins.py que je com- mentera au fil des lignes import os, os.path import random from PIL import Imago import numpy import sys from collections import OrderedDict from typing import Dict, Tuple from PIL.PngImagePlugin import PngInageFile [Nous allons utiliser de nombreux modules. Naturelle- ment, nous retrouvons PIL et numpy pour le traitement des images, et random pour le tirage aléatoire des layers et des couleurs. Le module os et son sous-module os.path permettront de naviguer dans le systéme de fichiers. Le module sys sera utilisé pour récupérer les para- metres transmis par Futilsateur en ligne de commande. [Nous utliserons des dictionnaires ordonnés (OrderedDi.ct) © qui permettent d'assurer un ordre des clés. Enfin, Dict, TupLeet PngtnageFiLe seront utilisés pour + typer les signatures des méthodes a Taide dannotations. class PartyingPenguins: COLORS : Dict{str, Tuple[int, int, int, ant] = ( Yor: ((1A", (222, 197, 167, 255), (Bt, (250, 244, 212, 255)), (e', (13, 215, 157, 255)), (*p", (196, 167, 211, 255)), (1B, (252, 188, 109, 255), CF", (203, 226, 144, 255)), (@", (254, 185, 177, 255))), ‘o' (CH, (257, 181, 255, 255), CI", (255, 200, 120, 255)), (a', (254, 60, 112, 255)), 219, 166, 255), (ur, (210, 211, 204, 255))), CR, (169, wwweed-diamond.com ‘GNU/Linux Magazine France N°253 ACTUS & HUMEUR PYTHON "R's (('M', (102, 99, 208, 255), (wr, (211, 202, 249, 255))), "x's (('0", (250, 60, 106, 255), CP, (104, 4 255, 184, 255))) COLORS est un attribut de classe (auquel on accéde- ra donc par PartyingPenguins.cOLORS) qui recense les ‘couleurs par rareté (‘¢* pour commune, *U* pour inhabi- tuelle, etc), Chaque couleur est enregistrée dans un tuple contenant une lettre d'identification et un tuple de quatre valeurs (les canaux red, green, blue et alpha). NOTE ‘Comme nous ne jouons pas sur la transparence, les ca- naux alpha auront toujours la valeur maximale de 255. RARITY : Dict{str, int] = { ‘cr: 70, nur: 24, UR: 5, xd Un deuxieme attribut de classe est défini avec RARITY ‘Qui est un dictionnaire permettant de specifier le pourcen- tage d'apparition des raretés. Ici, jai fixé 70 % pour com- mune, 24 % pour inhabituell, etc. def raz(self): self._selected_colors = None Lf ."layer_colors = [] La méthode raz() permet dinitialiser deux attributs : _selected_colors, la liste des couleurs tiées au sort dans la méthode _randonize_colors() définie plus loin, et _Layer_cotors, laliste des couleurs utilisées dans les layers sélectionnés (cette lst est peuple dans_change_colors()) NOTE Les couleurs des layers sont les couleurs de « base », le rouge (255, 9, 0, 255), bleu (0, 0, 255, 255), etc. qui seront remplacés par des couleurs de PartyingPenguins.coLoRS. def _init (self): £. Tayers = [None] * 10 rarity = () for dixpath, o8.walk("." filenames in if dizpath = '.' or dirpath == '/Mmages' or dirpath = './_pycache_' continue index, category = dirpath(2:) split('_') self,_layers int (index) - 1] = catagory selE._rarityloategory] = ( ie a a i” for filenane in filenanes: z, _= filenane.split('_") self._rarity[category] [F] += 1 Le constructeur définit es attributs Layers, _rarity et ceux de la méthode raz(). En parcourant les répertoires présents dans le répertoire courant avec os.walk(), on ob~ tient leur nom dans dirpath. Avec la structure imposée sur les noms de répertoires, nous savons que nous pou- vons couper leur nom suivant le caractére _(split(*_)) pour obtenir d'une part « index » ou la position du layer et dautre part la « catégorie » (Background, Base, etc). Ici, il faudra faire attention a deux choses + les noms de répertoires ne devront bien sir com- porter qu'un seul _ (L_Base par exemple, mais pas 4_kye Accessory); + il faut utiliser dirpath{2:] pour supprimer les deux premiers caractéres qui indiquent le répertoire courant (par exemple pour Images dans le répertoire courant dirpath contient ./Tmages). def display_report(self) -> None: print('* Layers :') for category in self. layers: Af category is Noni continue print(£" - (category) :') peint(#! = Common: {self._rarityleategory] ["C"]}') peint(f' - Unusual {sel£._carity[category] ["0"]}') print(#!- Rare {self._rarity[category] ["R"]}') GNU/Linux Magazine France N°253 ‘ww wegnulinuxmag.com = ) MAGAZINE’ eiianee) pune sa ee 7 te ho (self,_rarity[category] ["X"]}") print ("* Colors :') for rarity in (‘Comon', 'Causual', ‘pare’, ‘Xtra rare'): print(f' - {rarity:<9): ') for color in PartyingPenguins ‘coLoRsrarity(0]]: peint(f" —- (color(1]}") print() permet un affichage de controle du nombre de layers par rareté et par catégorie, ainsi que des couleurs de remplacement qui pourront étre employées. Toutes ces informations sont contenues dans les attributs et NOTE Dans la fstring le formatage signifie que fon souhaitealigner les caracteres sur fa gauche et sur9 caractéres. Ceci permet de conserver tun alignement des données, quelle que soit la taille de la chaine contenue dans (tant que cette chaine contient moins de 10 caractéres bien entendu). def change colors(self, image : PogtnageFile) -> PaginageFile + Toujours disponible sur ones seer eceae) www.ed-diamond.com for x in range (data. shape(0]) for y in range (data.shapo[1]) ‘wuple data = tuple (datalx, yl) Af tuple data in self, selected colors: Af tuple data not in self. layer_colors: self. _layer_colors. append (tuple_data) datalx, 7! colors{tuple data} [1] Lf, _selected_ return Inage, fromarray (data) La méthode parcourt une image passée en paramatre dans pixel par pixel aprés conversion en tableau par Silacou- leur du pixel fait partie des couleurs & changer, alors on liste cette couleur dans les couleurs de base modifiées cette couleur est pas déja présente dans ) wwweed-diamond.com ACTUS & HUMEUR PYTHON et on rodifie la couleur du pixel avec la couleur associée & la couleur de base de celu-ci et contenue dans tuple_data (Conversion sous forme de tuple du tableau datalx, y] contenant les données (red, green, blue, alpha)). image modifge est ensuite obtenue depuis le tableau et elle est renvoyée. @staticmethod def _random rarity() -> str: F = randon.randint (0, 100) if r <= PartyingPenguins .RARITY['C']: return 'C! elif r <= PartyingPenguins RARITY['C'] + PartyingPenguins.RARITY['0"] return ‘J’ elif r <= PartyingPenguins. RARITY['C'] + PartyingPenguins.RARITY['U'] + PartyingPenguins.RARITY['R'] return 'R! else: return _random_rarity() est une méthode statique (appe- lee sans instance de PartyingPenguins) qui tire un en- tier au hasard entre @ et 100 (random.randint(0, 100) et détermine une rareté qui sera retournée sous la forme un caractére (avec toujours le méme codage, *C* pour commune, etc). = le) random. choices (PartyingPenguins. couors[PartyingPenguins._ random rarity()}) [0] green = random. choices (PartyingPenguins Couors [Partyingzenguins._random_rarity() }) [0] blue = random. choices (PartyingPenguins COLORS [PartyingPenguins._random_rarity() 1) [0] pink = random. choices (PartyingPonguin: cotors|PartyingPenguins, yellow = random choices (PartyingPenguins. coLors [PartyingPenguins. random rarity() ) [0] ight_blue = random. choices (PartyingPenguins couons [PartyingPenguins._random_rarity() ) [0] self. _selected_colors = OrderedDict ([ _xandom_rarity ()]) [0] ((255, 0, 0, 255), red), (( 0, 255, 0, 255), green), (( 0, 0, 255, 255), blue) , ((255, 0, 255, 255), pink), ((255, 255, 0, 255), yellow) , (0, 255, 255, 255), light blue) , » La méthode _randomize_colors() sélectionne au ha sard six couleurs qui seront utilisées pour remplacer les cou- leurs de base des Layers. Pour chacune des couleurs, une rareté est trée au sort par PartyingPenguins._random_ rarity(), Cette rareté permet de cibler une liste de cou- leurs dans PartyingPenguins.coLoRs, puis d'en choisir une au hasard par random.choices() NOTE random.choices() retournant une liste d'un élément, Trutilisation de [0] permet de ne conserver que la donnée extraite de la liste dans les variables red, green, etc. def _randomize layer(self, layer : str) > str: rarity = PartyingPenguins._random_ rarity() index = randon.randint (1, self._ rarity[layer] [zarity]) if rarity =U": index 4= self._rarity[layer]('C'] elif rarity = 'R'7 index 4= self. rarity{layer]('C'] rarity[layer] (‘0'] ‘elif rarity != 'c': index 4= self._rarity[layer] ['c'] + self. carity[layer]['U"] + self._ rarity [layer|T'R'] retum £! (rarity) (index) png’ _randomize ayer() permet de sélectionner aléatoi- rementun layer de la catégorie Layer passé en paramatre. Pour cela dans rarity, on sélectionne une rareté de ma- nigre aléatoie & Vaide de PartyingPenguins._randon_ rarity(), puis un numéro de layer pour cette rareté (se. rarity(layer! [rarity] contient le nombre de layers pour ayer de rareté rarity : on tire donc au sort un entier compris entre 2 et self._rarityLlayer]IrarityD. Comme la numérotation des fichiers commence avec les layers de rareté ¢, puis U, R et X. il faut penser & ajou- ter a chaque groupe de rareté de layers le nombre de layers des groupes précédents, 14 GNU/Linux Magazine France N°253 ‘ww wegnulinuxmag.com Génération automatique de NFT Enfin, on retourne le nom du fichier de la forme rarity_index.png (par exemple C_2.png). def create _penguin(self) -> None filename = self. _randonize_colors() used golors = ‘7 for i, layer in enumerate ( Lf layer is None: ‘continue LE. layers): layer_nane = self. randonize layer (layer) filename += layer fane. split(’_') [1] [0] if i= 0: image = self._change_colors (Image.open(£" {i + 1)_(layer}/{layer_name}")) ‘mage = self._change_colors (image) else new_image = self. change colors (Inage ‘open(£'{ + 1)_{Jayar} /(layer_nane}')) Amage,paste(new_image, (0, 0), new image) for color in sel: if color in [01 used_colors filename = £7Images/(filename}_{used_colors}.png’ ath. isfile(filenane) : Print ('Partying Penguin allready exists... retrying generation’) f.create_penguin() nage. save (filenana) yenguiin() est la méthode principale, Le nom du fi- chier dans lequel sera sauvegardiée l'image sera créé au fur et & mesure dans filenane. On commence par titer aléatoirement les couleurs de remplacement a Taide de _randomize_colors() et on initialise une variable used_colors pour y stocker les codes des couleurs utilisées (ceci permettra de créer des noms de fichiers uniques et de ne pas générer plusieurs pingouins identiques). if _nane ‘main: “Print('Welcome in the Partying Penguins generator !') p = PartyingPenguins() p.display_report() LE len(sys.argy) == 2: for i in range (int(sys.argv(1])) : print (f'Generating Penguin (i + 1)/{sys.argv{2]}") p.create penguin() p.raz() elif len(sys.argv) p.create_penguin() else: print ("PartyingPenguins.py [number] ') print(" — [munber] Number of penguins images to generate’) exit (1) Nous arrivons enfin au programme principal : aprés affichage d'un mes- sage de bienvenue, nous créons une instance de PartyingPenguins et nous affichons les informations col- lectées: les différents types de layers et leur rareté ainsi que les couleurs ‘qui seront employées pour la géné- ration des images, accompagnées la aussi de leur rareté. Si l'utilisateur fransmet un parametre lors du lance= ment du script, cest quil doit sagir du nombre de pingouins a générer et nous effectuons une boucle d'appels de la méthode create_penguin() (en pensant a réinitialiser les variables avec raz()). Si aucun paramétre n'est donné, cest que l'utilisateur souhaite ‘générer un seul pingouin et sinon, si plusieurs paramétres sont transmis, est quiil Sagit d'une erreur NOTE Jai un peu tatonné au niveau des layers avant d obtenir des layers permettant une _g6nération vraiment unique. Par exemple, ‘quand un fond comporte plusieurs couleurs, Siln'ya pas de séparation avec une couleur stable entre les différentes couleurs, si le _générateuraléatoire sélectionne plusieurs fois la méme couleur, une image rate sera identique a une image commune dont le fond ne comporte qu‘une seule couleur. Des détails dont il faut tenir compte pour la eréaibilité d'une collection, wwweed-diamond.com GNU/Linux Magazine France N°253 ACTUS & HUMEUR Magic Ae tig Ay OED tin HN tein Oka lenin re Fig. 5: Quelques Partying Penguins obtenus par génération automatique, Jai lancé ce script pour générer mes pingouins, La figure 5 montre un échan- tillon des images obtenues et la figure 6 un des Partying Penguins. 5. DES IMAGES AUX NFT Maintenant que nous avons des images, il faut les inscrire dans la blockchain Ethereum. Si Yon utilise OpenSea, cela se fait ts simplement depuis une in- terface web. NOTE Pour pouvoir se connecter a OpenSea, il faut disposer d'un portefeuille de ‘cryptomonnaies tel que Metamask [5] Fig. 6 Un Partying Pengouin assez Une fois connecté, une icdne ronde et colorée apparalra en haut et a droite de la fenétre. En passant la souris dessus, un menu contextuel apparaitra dans lequel vous pourrez sélectionner My Collections (figure 7) avant de cliquer sur le bouton Create. collection. Des champs vous permetiront de configurer votre collection igure 8). Vous pourrez notamment choisir un logo et une bannigre, donner un nom a la col lection, ajouter une description du projet, le nom d'URL souhaité ete, Lorsque ‘vous aurez complété tous les champs désirés, il n'y aura plus qu’a soumettre Fy. 7. Accts aun collections dans le formulaire a Faide du bouton en bas de page. Opensea 16 GNU/Linux Magazine France N°253 ‘www.gnulinuxmag.com Génération automatique de NFT Dans mon cas, FURL de la collection esthi(ps:opensea.io! collection/partying»penguins. Crest en se rendant sur cette page et en liquant sur le bouton Additem que fon peut créer un nouveau NFT. Choisissez une image, donnez-lui un nom (pour ‘une collection, on peut garder le nom de la collection suivi dun ‘nombre: Partying Penguins 1, etc), Le bouton + droite de Properties permet cjouter des propriété (les layerset les cou- leurs employés, ce qui déter- rminera la rareté). La figure 9 monire une saisie en cours. Edit your collection gst Le bouton Greate permet de lancer la création du NFT proprement dite. Fig. 8: Configuration d'une nowvelle collection Tous les NFT saisis de cette rmaniére sont alors visibles sur la page de la collection ¢figure 10, ‘a Properties x page suivante). Si fon clique sur un NFT, dans le menu de gauche de la page at- tachée d ce NFT, on peut voir dans fonglet Properties les caracté- om ~e ristiques du NET et dans Yonglet Details Tadresse du smart contract |. ne an (avec un lien vers Etherscan), dentifiant du token, etc. (figure 11, page suivante), x ome nt ‘Tout est gratuit jusque 1a, mais si vous voulez vendre un NFT,il |) conn — faudra cliquer sur le bouton Sell sur sa page et les frais de gas duu smart contract résultant seront a votre charge. x me ore x ge tone Nous avons généré une magnifique collection d'images et nous {en avons transformé quelques-unes en NFT. 3 | eae 4 Pour que cela se transforme en une industie, il faudrait effectuer x coin “ un changement échelle : salsir quelques images a fa main sur un site web est tout a fait réalisable, mais si Yon génére des centaines. putnase iB images (le principe d'une collection avec génération aléatoire), i est impensable «utiliser cette méthode. II faudra donc envisager zk ‘écriture d'un script générant les smart contracts (OpenSea dispose d'une API) ou de passer par une automatisation des taches sur site Fig. 9: Saisie des propriétés d'un NFT waww.ed-diamond.com ‘GNU/Linux Magazine France N°253 ACTUS & HUMEUR Hiaeiox Q ore i : & & a Fig. 10 : Quelques images converties en NFT dans OpenSea, ayer? tayo Lever EH About Partying Penguins . B oetais - contract Address 95.7050 Token nes759000080067. Token standard Rc 85 ockchain «thereum Metodata stable Fig. 1! : Informations détaillées d'un NFT. Le changement d'échelle ne serait pas la seule condi- tion ! En effet, il faudrait également disposer de la somme correspondant au gas relat exécution de tous les smart contracts. Les petits Partying Penguins resteront donc dans l'ano- nnymat des NFT, mais nous aurons au moins eu le plaisir de les générer... i REFERENCES [i] Collection de NFT Weird Whales : btips:/lopensea.io/collection/weirdwhales [2] Plateforme d'achat (marketplace) de NET ‘OpenSea : htips://opensea.iol [5] Standard ERC-721 : hiips:(fethereum.orgien! developersidocs/standards/tokens/ere-721 [4] Weird Whales 2691 hips:/fopensea io/assets/0x96ed81c714406e! 1359e27bf16325de3c92042bd/2691 [5] Portefeuille de cryptomonnaies Metamask huips:ifmetamask.io/ 48 © GNU/Linux Magazine France N°253 ‘www.gnulinuxmag.com Nov. /DEC. 2021 Statis:une solution de gestion de SS Ghements & prendre en compte pour ian SRockage moderne etavancée P.20 serreparer aun controle dela CNIE P78 | CREEZ VOJIRE CLOUD (vis EN 4 OpenNebula i Were oe A Suk Découvrez comment optimise votre Personnaliser une instance distribution Debian P.'° | pache Tomcat avec Ansible 5 ‘AUTOMATISAT! Cy pale ES de peered aaa Chez votre marchand de journaux ° . sur www.ed-diamond.com IA, ROBOTIQUE & SCIENCE aan VOYAGE INITIATIQUE VERS AN Tet ae ALBAN MANCHERON: [Enseignant-chercheur en bioinformatique a Université de Montpelier, inuxien depuis 1997 (convaineu depuis 1998}] MOTS-CLES ; EMBOSS, BIOINFORMATIQUE, ANALYSE, GENOMIQUE CINE U Ua MSL AMOUR ere) en étions-nous ? Ah oui, je me souviens. ‘Nous avions récupéré quelques sé- ‘quences de SARS-CoV-2, donitla séquence de référence du virus (NC_845512.2). ‘Nous avions également installé et pris ‘en main la suite EMBOSS [2,3], ce qui ‘nous avait permis de commencer 'ana~ lyse des séquences récupérées. Nous: avions notamment mis en évidence des régions de la séquence de réfé- rence, appelées ORF (Open Reading Frames — cadres ouverts de lecture), qui correspondent a de potentielles protéines que le virus ferait produire Par organisme héte (celui qu'il squatte ‘sans vergogne) et qui lui permettent . cs . de se reproduire. Ah oui, favais ou- Dans un précédent article [1], nous avions découvert la. Si ewes peseatse sous suite EMBOSS et mii nce desrégionsd’intérétde un angle assez image et peut patois laséquence nucléique deréférence du virus SARS-CoV-2. _ piquer les yeux des puristes (done, si Nous allons done continuer le chemin en exploitant de ‘us sve dans votre entourage des , at a biologistes, n’essayez pas de frimer nouveaux outils, certains issus de la bioinformatique et | en eprenant mes propos, cela pour autres issus de Ia communauté linuxienne. rat tourer 3 votre désavantage). Par en 20 GNU/Linux Magazine France N°253 ‘www gnulinuxmag.com Voyage initiatique vers la bioinformatique : en route pour Taventure exemple, vous pouvez tout a falt vous représenter un vi rus comme une bombe fork. Son seul objectif est de se reproduire et ga finit par faire planter le systéme, si celui Cine parvient pas a le détecter et Véradiquer (en occur- rence, dans le cas du SARS-CoV-2, cet plutot le systéme qui « exabuse » ~ du verbe exabuser ~ la contre-attaque). Vous aviez tout bien fait la demigre fois, mais vous ne savez plus oit sont les résultats que vous aviez obtenus ! ‘Ne vous inquiétez pas, nul besoin de tout refaire (ct. note). NOTE Les données récupérées, les résultats obtenus et les scripts développés dans le cadre de cette série d'ar- ticles sont disponibles sur la forge logicielle GitLab hébergée par Framasoft : htips://{ramagil org/dacey/ SARS-CoV-2-bioinfo-analysis 1, REGIONS D'INTERET DE LA SEQUENCE DE REFERENCE Nous avions récupéré les ORF valides dans le fichier results/nc_045512.2_ORF.fasta partiellement repro: duit ci-apres : >NC_045512.2 1 [468 - 530] Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, complete genome MCSSNVRMLELELMVMLHLSW >UC_045512.2_192 [29866 - 29901] Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, complete genome MEEKKKEEKKEK Pour chaque ORF, nous disposons d'un nom de séquence qui est le nom drorigine de la séquence suffixé d'un iden- tiiant (compteur commencant & 2) ; de ses positions dans la séquence (information entre crochets); du descriptf as- socié & la séquence drorigine et de la séquence dacides aminés correspondant & sa traduction. Nous avions éga- ement mentionné que le denier ORF contenant un co- don start (une Méthionine), le programme getorf avait renvoyé la traduction de la fin de la séquence a partir de la position 29866 ; cependant, cet ORF n'est pas valide en réalité, est juste qu'il va jusqu’a la fin de la séquence ‘Avant toute chose, commengons par récupérer les coot- données des régions codantes potentielles, Pour cel, isu fitde récupérer les lignes d fichier qui commencent par > {avec grep), puis &capturerVidenttiant, la positon de dé but et la position de fin de 'ORF (avec sed), tout conser- ver sauf la demniére (avec head) et enfin rdiriger dans le fichier tout en Faffichant sur la sortie standard (avec tee) Te kee PC Rr eee CAC RY CARAS mi) Poetry Tee Me ad tren Peis yy SULT Ey FETE A partir de maintenant, les choses sérieuses peuvent 1.1 Visualisation des ORF La bioinformatique admet de trés nombreuses définitions (et je nentrerai pas dans le débat, méme si jai un avis as- sez tranché sur la question), cependant il faut comprendre que lusager des outils développés reste pour une grande majorité un biologiste. Donc, son expertise passera & un moment ou & un autre par une représentation graphique. Notre objectif est d'annoter des portions de séquences, mais également de permettre de visualiser le produit de nos annotations. Il existe plusieurs formats pour représenter les annotations, parmi eux le format GFF (voir encadré) qui, cute son format assez facile & exploiter sous GNU/Linux, iablit un lien direct entre Yannotation et la Sequence Ontology [4] donnant ains la fois un formalisme rigou- reux et une véritable sémantique aux annotations Nous allons donc écrire un script awk permettant de transformer notre fichier CSV en GFF. Pour cela, nous al- lons représenter les ORF sous forme de tableaux & trois clés Gd, deb et fin), Outre une fonction permettant de renvoyer Ia taille d'un ORF (lignes 17 3 19), comme je ne sais pas définir une fonction qui renvoie un tableau en awk {Ge ne suis pas certain que cela soit possible, par ailleurs) je contourne la difficulté en passant par un procédé de sérialisation/dé-s6rialisation (lignes 24 a 26 et 33 A 37) wwweed-diamond.com ‘GNU/Linux Magazine France N°253. IA, ROBOTIQUE & SCIENCE 02: #!/usx/bin/awk --exec 02: 03: # Assigne simplement 1e nom du programme a la variable PROGRAM NAME. 04: function setProgramVane() { 05: PROGRAM NAME = gensub (/*(.*\7)2(1°\/]#)\.[°\.148/, "2", %g", ENVIRON["_"]) 06:' if (TPROGRAM NAME) { 07: PROGRAM _NAME = gensub(/*(.*\/) (W140 8/, "\\2", "a", PROGRAM NAME = gensub(/*(.*\/)?({*\/1#) (\.amk) $/, "\Y2") "gy ENVIRON["_"}) 10: if (1PROGRAM NAME) { PROGRAM NAHE = "£iltre ORF" 15: # Calcule 1a taille d’un ORF (tableau dont les clés "deb" et "fin" 16: # définissent les positions de début et de fin de 1'0RF) . 21: # Renvoie une chaine descriptive de 1'ORF (tableau dont les clés "id’ 22: # "deb" et "fin" définissent respectivement 1'identifiant ainsi que 23: # les positions de début et de fin d 1'0Re) . 24: £unction or£2stringlorf) { 25: return orf["id"] "\t" orf{"deb"] "\t" orf ["fin"] 28: # Remplit le paranétre orf (deuxiéne ‘argunent) a partir de la chaine 29: # str (premier argunent) descriptive de L'ORF. Le tableau résultant 30: # disposera des clés "id" définissant respectivenent 31: # 1!identifiant ainsi que les positions début et de fin de 1'oRF. function string2orf(str, orf, tmp) { split(str, tmp) orf["id"] = tmp[1] orf["deb"] = tmp(2] ) cretion) = tmp(3] deb" et "fin" ‘Au début du programme, il ne se passe pas grand-chose (lignes 41 43), mais & chaque début de fichier passé en ligne de commande (lignes 47 8 7), nous remettons le BIOINFO compteur d'ORF a 6 (variable nb), nous initialisons la va- riable name au nom du fichier sans Vextension (ce sera notamment le champ 2 du GFF produit) et nous réinitia- lisons la position maximale de la séquence pour le fichier en cours 2 2 (variable max_pos). 40: # Initialisation effectuée au démarrage du script name = gensub(/*.*\/({*\/]*)__ ORF\.[*\.1#8/, "\\1", “g", FILENAME) 50: if (!name) { name = gensub(/*.*\/([*\/]*)\. <1*8/, 'N\L", "gi", FELENAME) , if (‘name) { ‘name = FILENAME d max_pos = 1 Pour chaque ligne du fchieren cours de lecture (lignes 60 2 68), il suffit d'associer a ORF en cours les valeurs de ‘chaque champ a chaque clé (notons que nous ajoutons 3 8 la borne de fin, car les positions renvoyées par getort ‘uent pas le cocion stop). Nous en profitons pour mettre 8 jour la valeur de la plus grande position, 59: # Traitement a effectuer pour une Ligne du fichier en cours. 60: ¢ 61: ORF{nb] ["id"] = $1 62: ORF[nb] ["deb"] = $2 63: ORF[nb] ["£in"] = $3 + 3 64: Hnb 65: if ($3 > max_pos) { 66: max pos er: a 68: ) ‘Arrivés la fin de a lecture du fichier en cours (lignes 71 278), nous afichons les métadonnées associes au fichier GFF (la position maximale est une estimation), puis pour ‘chaque ORF. nous produisons une annotation de type ORF (champ 3), Nous utilisons la taille de ORF en guise de score (champ 6). Nous en profitons pour calculer la phase de lecture (champ 8 de annotation), GNU/Linux Magazine France N°253 ‘ww w.gnulinuxmag.com Voyage initiatique vers la bioinformatique : en route pour Taventure LE FORMAT GFF Le « Generic Feature Format » permet d'annoter tout ou parties des sé-séparés par des j. Il est recom- Cee a ee Re Ce ae Pe er he nate ad ae ate ee cee Ee Cte oS een tivea la syntaxe des URI (Uniform Dee gad Cee ee eer eum at ee ee ee Cest-a-dire d’utiliser le symbole Identifiant de la source de annotation (nom |) PSU en eto du programme, de la base de données, du |) fee consortium... code ASCII du caractére échappé ee ‘Type de Vékément annots qui doit corres- pose taearneere nner pondre a un des termes de la Sequence Poe eg cree ond Ontology 4) eed ee tare Position de début de Fannotation sur la sé- | oe mia ucts fi raenolation cate BD ed eee ges Position (incluse) de fin de lannotation sur | settee la séquence (la numérotation commence aD. Reda ee ee Fiabitité de Fannotation (lorsque celle-ci est | fs) penpegu rent sm tl prédite par un outil, elle est souvent assortie | yay) seas 0 Weer d'une métrique représentative de la fiabilté |) MM) os de la prédiction). Labsence de score est dé- foto par ini Pr tee rd re eet eed Indication du brin codant de Félément sere eae eo (oir {t). Ce champ admet trois valeurs pos- | ret rie SARIN yr sibles : + pour le sens de lecture « normal », | _ ssalll yesh onfeni pins = pour le sens de lecture inverse et. lorsque | Payer etrEnE Melts information est indéerminge, Bree sire iia eee Phase du cadre de lecture applicable aux brhonaliarchnnlnsonbenasel annotations de type CDS (voir{f). Celle-ci | Sue Rah phase peut prendre 4 valeurs : 0, 1 ou 2 sile type J Unuecpins Ube oo de Tannotation est cS et . dans les autres | ipuiuesnnskie noah ‘as, ee Peete attributs Autres informations relatives & Tannotation. | PP pa path eft Sprays tadonnées commencent par #! et Pee et ee eet ee ee end ‘veut. Il est généralement composé d'une suite de couples clé=valeur commentaires. ‘Nom (identifiant) de la séquence porteuse de annotation. séquence wwwed-diamond.com GNU/Linux Magazine France N°253 BIOINFO IA, ROBOTIQUE & SCIENCE 70: # Traitement & effectuer a la fin du fichier en cours 71: ENDEILE { 72: print '##gff-version 73: print "##sequence-region 74: OF: _ 75: for (o in ORF) { 76: print name, PROGRAM NAME, "ORF", ORF{e] [deb], ORF[e] ["fin"], ORF[e] ["Ein"] = ORF[e] ["deb"] +1, "4", ((ORF[e) ("deb") - 2) $3), "ID=" name "_* ORE[e]["id"] "snane-ORF_" ORF[e] ("14") "name " 1" max pos En appliquant ce script (apres Vavoir rendu exécutable) au fichier CSV, nous ‘obtenons eee eonaat ree ee LC rd oer our rss cree) eee Cee T Ty PS per reo Ceti) PTC were ae eee PORES rm ere) Eee een ees Comme la position de fin de la séquence est une estimation, nous allons ccorriger cela rapidement eon kore cr mes ernst’ Pe Ew Sr Etre s Serer Perot reer tt ay Pertn Ct Re ard ree Peer ote Reet Trace) Cees Ese ee Il existe un outil permettant de vi- sualiser les fichiers GFF. 1! s'agit du programme annotation sketch ce la suite GenoméTools [6] qu'il est possible installer localement (par exemple, sous Debian/Ubuntu) ee genometools (On peut Futiliser en ligne de com- mande (commande gt. sketch), mais ilest également possible duiliser Youti cen ligne & adresse hitp:igenometools, cxelegbinlannotatonsketch_dero gi (ee que jai fit pour cet article en rense- gant, pour plus de confort vsuel, une largeur de 1600 pixels au lieu des 800 pixels proposés par défaut; cf: figue 1. 24 © GNU/Linux Magazine France N°253 wwwrgnulinuxmag.com Voyage initiatique vers la bioinformatique : en route pour Taventure Visuellement, nous nous apercevons aisément que tous les ORF ne semblent pas présenter le méme intérét. Sans entrer dans les détails de la biologie, tune protéine est généralement compo- sée en moyenne de 300 & 400 acides amines, et trés rarement moins de 100 cides amings, Nous allons donc tenter de déterminer des critéres permettant de filter les ORF a étudier. 1.2 Sélection des ORF candidats Mame s'il parait que ce n'est pas la taille qui compte, intéressons-nous de plus prés 2 la distribution des lon- ‘gueurs des ORF. Pour cela, nous pouvons écrire un petit script gnuplot assez simpliste #! usr /bin/anoplot reset # See http://www. gnuplotting.org/calculating- binval (x) = binwidtht (floor ((x-binstart) / binwidth) +0.5)+binstart set xrange [binstart:*] set boxwidth 0.9 * binwidth set style fill solid 0.5 set title "Distribution des longueurs des ORF" set xlabel "Longueur" set ylabel "Wonbre* f ar défaut es graphiques sont affichés fn change le terminal pour produire des images au format PNG. sot terminal png notransparent interlace truecolor enhanced nocrop font "Arial,18" size 4600,1200 set output *resulte/ne_045512.2_ORP_ distribution. png" plot "results/ne_045512.2 ORF.csv" using (binval ($3-$241)): (1.0) sooth frequency with boxes notitle WORF de la séque ition du nom © NC_045512.2 en fonction Il reste a le rendre exécutable et ale lancer pour obte- nir Phistogramme présenté en figure 2 Cerne eee terrr en | Pree at re) Pee tty Mayor ee eect Cee) Pe eee ICRU eerste ese) Cet histogramme fait clairement apparaitre 5 grands (voire tés grands) ORF candidat. Il est done trés raison- nable de ne pas considérer les petits ORF qui seraient in- clus dans des plus grands. Un ORF de 150 nucléotides code pour 49 acides aminés plus 1 codon stop, ce qui est vraiment trés petit et donc est un critére de filtrage tres satisfaisant. Copions le script précédent dans un nouveau script appelé filtre_ORF.awk et ajoutons donc une var Fiable permettant de détinir le seuil en dessous duquel nous considérerons un ORF comme petit. 15: # Initialise les paramétres par défaut du programne. 16: function setDefaultParameters() 17; SBUIL_TATLEE = 150 18: } t Cette fonction dinitialisation devra étre appelée au dé- marrage du script wwweed-diamond.com ‘GNU/Linux Magazine France N°253.

You might also like