Fractales de Koch et Mandelbrot - Ensiwiki - Ensimag
Fractales de Koch et Mandelbrot - Ensiwiki - Ensimag
Fractales de Koch et Mandelbrot - Ensiwiki - Ensimag
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
<strong>Fractales</strong> <strong>de</strong> <strong>Koch</strong> <strong>et</strong> Man<strong>de</strong>lbrot<br />
<strong>Ensimag</strong> 1A - Préparation au Proj<strong>et</strong> C<br />
Année scolaire 2011 – 2012<br />
Présentation<br />
Le but <strong>de</strong> c<strong>et</strong> exercice est <strong>de</strong> se familiariser avec quelques points <strong>de</strong> base du langage C, à travers la mise en œuvre<br />
<strong>de</strong> fractales.<br />
Les objectifs <strong>de</strong> ce suj<strong>et</strong>, du point <strong>de</strong> vue du langage C, sont les suivants :<br />
• Programmation modulaire<br />
• Allocation dynamique, listes chainées<br />
• Utilisation <strong>de</strong>s arguments argc <strong>et</strong> argv <strong>de</strong> la fonction main<br />
• Utilisation du préprocesseur C<br />
• Ecriture dans un fichier<br />
• Utilisation <strong>de</strong>s types C99<br />
• Manipulation <strong>de</strong>s opérateurs binaires , |, &<br />
• Utilisation <strong>de</strong> l’assertion pour la gestion <strong>de</strong>s erreurs<br />
• Utilisation <strong>de</strong>s fonctions <strong>de</strong> la librairie string (strcmp, …)<br />
• Utilisation du <strong>de</strong>bugger ddd <strong>et</strong> <strong>de</strong> valgrind<br />
L’appel aux programmes s'effectuera <strong>de</strong> plusieurs façons :<br />
• Programme koch sans arguments : la saisie <strong>de</strong> tous les paramètres sera <strong>de</strong>mandée par le programme à<br />
l'utilisateur.<br />
• Programme koch avec arguments : les paramètres sont initialisés avec les arguments indiqués.<br />
• Programme man<strong>de</strong>lbrot : les paramètres sont lus dans un fichier <strong>de</strong> configuration.<br />
Nous vous <strong>de</strong>mandons <strong>de</strong> n’utiliser que <strong>de</strong>s types C99 pour vos variables : uint32_t, uint16_t, int32_t, int16_t,<br />
bool, <strong>et</strong>c…<br />
Les exercices à traiter obligatoirement pour le livrable 1 sont les parties 1, 2 <strong>et</strong> 3.<br />
Les extensions supplémentaires proposées en partie 4 donneront potentiellement <strong>de</strong>s points <strong>de</strong> bonus.<br />
Le <strong>de</strong>bugger ddd sera utilisé pour tracer les erreurs du programme. Valgrind sera aussi utilisé pour vérifier<br />
l’allocation correcte <strong>de</strong>s données dynamiques du programme.<br />
Le rendu du proj<strong>et</strong> contiendra tous les fichiers constituant les programmes Test, <strong>Koch</strong> <strong>et</strong> Man<strong>de</strong>lbrot (fichiers .c, .h)<br />
ainsi que <strong>de</strong>s fichiers images résultats au format .ppm. Un makefile perm<strong>et</strong>tant <strong>de</strong> régénérer les 3 programmes sera<br />
également fourni.<br />
Le résultat <strong>de</strong> l’exécution <strong>de</strong>s programmes via valgrind sera également fourni.<br />
1/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
1) Préambule : Création d'une image ppm<br />
Une même fonction perm<strong>et</strong>tra <strong>de</strong> créer les fichiers .ppm pour les 2 programmes <strong>Koch</strong> <strong>et</strong> Man<strong>de</strong>lbrot.<br />
Les fonctions fopen, fwrite <strong>et</strong> fclose <strong>de</strong>vront être utilisées pour la création du fichier <strong>de</strong> sortie.<br />
1.1 Représentation interne <strong>de</strong> l'image<br />
Il est <strong>de</strong>mandé pour <strong>de</strong>s raisons pédagogiques d’utiliser une variable <strong>de</strong> type uint32_t * pour la représentation<br />
interne <strong>de</strong> l’image dans les programmes.<br />
Chaque élément <strong>de</strong> ce tableau est composé <strong>de</strong> 4 oct<strong>et</strong>s, dont 3 serviront à stocker la valeur d’une composante (R, V<br />
ou B) d’un pixel. Le <strong>de</strong>rnier oct<strong>et</strong> sera inutilisé.<br />
En supposant qu’une variable <strong>de</strong> type uint32_t contienne dans ses trois oct<strong>et</strong>s <strong>de</strong> poids faible trois valeurs<br />
représentant <strong>de</strong>s intensités <strong>de</strong> couleurs dans l’ordre R, G, B (du poids le plus fort vers le poids le plus faible), on<br />
pourra extraire les composantes R, G <strong>et</strong> B à l'ai<strong>de</strong> <strong>de</strong>s opérateurs binaires.<br />
Exemple :<br />
uint32_t * picture;<br />
...<br />
/* Exemple d'un élément/pixel du tableau picture initialisé avec une couleur codée en hexadécimal */<br />
picture[...] = 0xF788AA;<br />
/* Composante Rouge <strong>de</strong> la couleur du pixel : 0xF7 soit 247 en décimal */<br />
/* Composante Verte <strong>de</strong> la couleur du pixel : 0x88 soit 136 en décimal */<br />
/* Composante Bleue <strong>de</strong> la couleur du pixel : 0xAA soit 170 en décimal */<br />
...<br />
1.2 Création du fichier ppm<br />
De manière à pouvoir visualiser le résultat, on se propose d’utiliser le format d’image ppm (Portable Pixel Map).<br />
Ce format très simple consiste en un en-tête spécifiant le type d’image (ex : couleur ou noir <strong>et</strong> blanc) <strong>et</strong> ses<br />
dimensions, puis la suite <strong>de</strong>s pixels <strong>de</strong> l’image ligne par ligne, chaque pixel étant codé sur 3 oct<strong>et</strong>s : un pour le<br />
rouge (R), un pour le vert (V) <strong>et</strong> un pour le bleu (B).<br />
Il est possible d’aller voir à l’adresse http://n<strong>et</strong>pbm.sourceforge.n<strong>et</strong>/doc/ppm.html ou simplement le « man ppm »<br />
pour plus <strong>de</strong> détails sur ce format. Néanmoins, dans le cadre du travail <strong>de</strong>mandé, le fichier <strong>de</strong>vra commencer par<br />
l’en-tête suivant :<br />
P6<br />
LARGEUR HAUTEUR<br />
255<br />
où LARGEUR <strong>et</strong> HAUTEUR sont la largeur <strong>et</strong> la hauteur <strong>de</strong> l’image au format texte <strong>et</strong> 255 la valeur maximale<br />
<strong>de</strong> chaque couleur (rouge, vert ou bleu)<br />
Implémenter une fonction create_image ayant comme paramètres la variable image uint32_t *picture, la largeur<br />
<strong>et</strong> la hauteur <strong>de</strong> l'image codées en int32_t <strong>et</strong> le nom du fichier <strong>de</strong> sortie codé sous forme <strong>de</strong> chaîne <strong>de</strong> caractères.<br />
1.3 Test <strong>et</strong> visualisation du fichier ppm<br />
Le format d’images ppm est visualisable par beaucoup <strong>de</strong> visionneurs, comme par exemple eog (eye of gnome)<br />
sous linux/Unix.<br />
Si vous souhaitez convertir vos fichiers ppm en images jpg, vous pouvez utiliser la comman<strong>de</strong> ppmtojpg, avec<br />
l’option - -smooth=30 pour lisser le résultat.<br />
Un fichier obj<strong>et</strong> test_create_image.o est fourni. Couplé avec votre module create_image.o, il <strong>de</strong>vrait générer un<br />
programme « test » perm<strong>et</strong>tant l'obtention <strong>de</strong> l'image suivante :<br />
2/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
2 Programme : Fractale géométrique Flocon <strong>de</strong> <strong>Koch</strong><br />
2.2 Principe<br />
Il s'agit <strong>de</strong> la première fractale inventée en 1904 par le mathématicien suédois Helge von <strong>Koch</strong> (1870 – 1924).<br />
Pour tracer c<strong>et</strong>te courbe, il faut:<br />
• Tracez un triangle équilatéral<br />
• Remplacer le tiers central <strong>de</strong> chaque côté par une pointe dont la longueur <strong>de</strong> chaque côté égale aussi au<br />
tiers du côté<br />
• Recommencer c<strong>et</strong>te construction sur chaque côté <strong>de</strong>s triangles ainsi formés.<br />
Schéma <strong>de</strong>s étapes successives :<br />
Pour chaque segment [a,e], on peut calculer les coordonnées <strong>de</strong>s points intermédiaires b,c <strong>et</strong> d <strong>de</strong> la façon suivante :<br />
xb = xa + (xe-xa)/3<br />
yb = ya + (ye-ya)/3<br />
xd = xa + 2 * (xe-xa)/3<br />
yd = ya + 2 * (ye-ya)/3<br />
xc = (xb+xd) * cos(60°) - (yd-yb) * sin(60°)<br />
yc = (yb+yd) * cos(60°) + (xd-xb) * sin(60°)<br />
A l'itération suivante, on recommence sur les nouveaux segments créés.<br />
3/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
2.2 Objectifs<br />
Le programme Flocon <strong>de</strong> <strong>Koch</strong> <strong>de</strong>vra perm<strong>et</strong>tre <strong>de</strong> paramétrer les données suivantes :<br />
• La longueur (en pixels) d'un segment du triangle initial.<br />
• La taille en pixels (hauteur = largeur) du carré <strong>de</strong> l'image finale sera calculée automatiquement à partir <strong>de</strong><br />
la longueur <strong>de</strong> segment précé<strong>de</strong>nte.<br />
• Le nombre d'itérations à effectuer<br />
• La couleur <strong>de</strong> tracé (qui pourra être codée sous la forme hexadécimale 0xRRVVBB, RR : rouge, VV : vert,<br />
BB : bleu)<br />
• La couleur <strong>de</strong> fond (qui pourra être aussi codée sous la forme 0xRRVVBB)<br />
• Le nom du fichier .ppm <strong>de</strong> <strong>de</strong>stination<br />
• Une <strong>de</strong>rnière option « all » indiquant qu'on veut tous les fichiers image intermédiaires entre le triangle <strong>de</strong><br />
départ <strong>et</strong> le flocon <strong>de</strong> koch final. Si elle est omise, seul le fichier image final est généré.<br />
Ces paramètres principaux <strong>de</strong> la fractale seront stockés dans une seule structure <strong>de</strong> données.<br />
Les paramètres pourront être donnés en arguments <strong>de</strong> l’appel du programme en ligne <strong>de</strong> comman<strong>de</strong>s :<br />
• Exemple <strong>de</strong> ligne <strong>de</strong> comman<strong>de</strong> : koch 270 4 0xFF0000 0xFFFFFF koch.ppm all<br />
• C<strong>et</strong> exemple lancera le programme en définissant la taille d'un segment du triangle initial à 270 pixels, le<br />
nombre d'itérations <strong>de</strong> calcul à 4, 5 fichiers <strong>de</strong> sortie .ppm (00_koch.ppm, 01_koch.ppm, 02_koch.ppm,<br />
03_koch.ppm, 04_koch.ppm,), les images seront rendues avec un tracé rouge sur fond blanc<br />
Si aucun paramètre n’est passé en arguments <strong>de</strong> la ligne <strong>de</strong> comman<strong>de</strong> ou si le nombre d’arguments attendus est<br />
incompl<strong>et</strong>, le programme <strong>Koch</strong> <strong>de</strong>man<strong>de</strong>ra à l’utilisateur <strong>de</strong> saisir les paramètres.<br />
2.3 Directives <strong>de</strong> programmation<br />
2.3.1 Programmation modulaire<br />
Le programme <strong>Koch</strong> comportera au minimum 3 modules<br />
• Module principal (programme principal)<br />
• Module fonctions (les fonctions liées au traitement <strong>de</strong>s données du programme : calcul, rendu,...)<br />
• Module ihm (l’interface homme machine contenant les fonctions liées à l’affichage <strong>et</strong> la saisie <strong>de</strong>s<br />
données)<br />
Chaque module sera découpé en fonctions élémentaires perm<strong>et</strong>tant une programmation simple, structurée <strong>et</strong> très<br />
lisible du programme.<br />
2.3.2 Structure <strong>de</strong> données<br />
Une liste chainée est imposée pour stocker tous les points calculés du flocon <strong>de</strong> <strong>Koch</strong>. Chaque élément <strong>de</strong> la liste<br />
contiendra les coordonnées X <strong>et</strong> Y d'un point du flocon <strong>de</strong> <strong>Koch</strong> <strong>et</strong> un lien vers le point suivant.<br />
Les coordonnées seront typées en entiers non signés uint16_t.<br />
2.3.3 Etapes <strong>de</strong> résolution<br />
Il est <strong>de</strong>mandé <strong>de</strong> procé<strong>de</strong>r <strong>de</strong> la façon suivante :<br />
• Définition <strong>de</strong> la liste chaînée initiale <strong>de</strong>s points définissant le triangle <strong>de</strong> départ.<br />
• Génération <strong>et</strong> calcul <strong>de</strong>s points du flocon <strong>de</strong> <strong>Koch</strong>. Les nouveaux points seront insérés dynamiquement à la<br />
liste chainée initiale.<br />
• Rendu image par la métho<strong>de</strong> Bresenhem (détaillée ci-<strong>de</strong>ssous). C<strong>et</strong>te métho<strong>de</strong> perm<strong>et</strong>tra <strong>de</strong> tracer <strong>de</strong>s traits<br />
entre les points calculés du flocon <strong>de</strong> <strong>Koch</strong>. Comme expliqué au paragraphe 1), l'image générée sera<br />
stockée dans un tableau <strong>de</strong> type uint32_t * alloué dynamiquement en mémoire.<br />
• Ecriture <strong>de</strong> l'image mémoire uint32_t * dans le fichier .ppm <strong>de</strong> <strong>de</strong>stination.<br />
4/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
2.3.4 Métho<strong>de</strong> <strong>de</strong> tracé <strong>de</strong> ligne Bresehem<br />
Documentation sur la métho<strong>de</strong> : http://en.wikipedia.org/wiki/Bresenham's_line_algorithm<br />
On propose <strong>de</strong> m<strong>et</strong>tre en œuvre la métho<strong>de</strong> générale simplifiée en se basant sur le pseudo co<strong>de</strong> suivant :<br />
/* Tracé <strong>de</strong> ligne entre 2 points <strong>de</strong> coordonnées (x0,y0) <strong>et</strong> (x1,y1) */<br />
function line(x0, y0, x1, y1)<br />
dx := abs(x1-x0)<br />
dy := abs(y1-y0)<br />
if x0 < x1 then sx := 1 else sx := -1<br />
if y0 < y1 then sy := 1 else sy := -1<br />
err := dx-dy<br />
loop<br />
s<strong>et</strong>Pixel(x0,y0)<br />
if x0 = x1 and y0 = y1 exit loop<br />
e2 := 2 * err<br />
if e2 > -dy then<br />
err :=err – dy<br />
x0 := x0 + sx<br />
end if<br />
if e2 < dx then<br />
err := err + dx<br />
y0 := y0 +sy<br />
end if<br />
end loop<br />
5/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
3 Programme : <strong>Fractales</strong> <strong>de</strong> Man<strong>de</strong>lbrot<br />
3.1 Principe général<br />
Le fonctionnement <strong>de</strong> calcul pour ce type <strong>de</strong> fractale est le suivant :<br />
• On définit un plan complexe associant à chaque point (i, j) <strong>de</strong> l’image un nombre complexe z 0 .<br />
• On définit une fonction complexe f(z) ainsi que la suite associée z n+1 = f(z n )<br />
• Pour chaque point (i, j) <strong>de</strong> l’image, on prend le z 0 associé dans le plan (ex : pour le point (0,1), la valeur<br />
complexe 0 + 1i)<br />
• On calcule ensuite les termes z n <strong>de</strong> la suite jusqu’à ce que |z n | atteigne une valeur <strong>de</strong> sortie choisie, ou que n<br />
atteigne une certaine profon<strong>de</strong>ur donnée<br />
• Si la profon<strong>de</strong>ur est atteinte, la suite converge ; tandis que si la valeur du module <strong>de</strong> sortie est atteinte, la<br />
suite diverge<br />
• Pour colorier l’image, on affiche pour chaque point divergeant une couleur associée à la profon<strong>de</strong>ur atteinte<br />
3.2 Fractale <strong>de</strong> base <strong>de</strong> Man<strong>de</strong>lbrot<br />
On se propose tout d'abord <strong>de</strong> tracer une image représentant une partie <strong>de</strong> l’ensemble <strong>de</strong> Man<strong>de</strong>lbrot avec la<br />
fonction f(z) = z 2 + z 0<br />
Autrement dit, c<strong>et</strong> ensemble <strong>de</strong> Man<strong>de</strong>lbrot est l’ensemble <strong>de</strong>s points c du plan complexe tels que la suite : z n+1 =<br />
z n<br />
2 + c <strong>et</strong> z 0 = 0 converge vers un point <strong>de</strong> C.<br />
Dans c<strong>et</strong>te partie, on <strong>de</strong>man<strong>de</strong> <strong>de</strong> produire une image en noir <strong>et</strong> blanc <strong>de</strong> l’ensemble : un point est colorié en noir<br />
s’il appartient à l’ensemble, <strong>et</strong> en blanc sinon. Les intervalles à utiliser sont [−2.2; 0.8] pour les abscisses, <strong>et</strong> [−1.5;<br />
1.5] pour les ordonnées. L’image fournie <strong>de</strong>vra être aux dimensions 300*300 pixels.<br />
Pour déterminer si un point diverge ou converge, il est possible <strong>de</strong> s’arrêter après 1000 itérations.<br />
Enfin, on pourra remarquer que si R(z) 2 + I(z) 2 ≥ 4, alors la suite diverge.<br />
3.3 Tracé d’autres fractales <strong>de</strong> Man<strong>de</strong>lbrot<br />
On souhaite désormais pouvoir spécifier d’autres valeurs pour le sous-ensemble à visualiser, ainsi que pouvoir<br />
fournir <strong>de</strong>s tailles d’images différentes. Comme on souhaite ne pas avoir <strong>de</strong> déformation dans l’image, les<br />
paramètres sont les suivants :<br />
• Résolution horizontale (RESOL_X) <strong>et</strong> résolution verticale (RESOL_Y) <strong>de</strong> l’image<br />
• Coordonnées X <strong>et</strong> Y du centre du sous-ensemble (centre = CENTRE_X + i CENTRE_Y )<br />
• Intervalle horizontal du sous-ensemble (SPAN_X)<br />
• Nombre d’itérations maximal (NB_ITER_MAX)<br />
Le nombre d’itérations maximal ne peut pas être connu à l’avance, mais est dépendant soit du zoom sur le sousensemble,<br />
soit <strong>de</strong> l’intervalle horizontal représenté. Quelques exemples d’images sont donnés <strong>de</strong>ssous (Tab. 1). Si<br />
vous voulez en faire d’autres, à vous <strong>de</strong> trouver une valeur suffisamment gran<strong>de</strong>, mais pas trop pour ne pas alourdir<br />
inutilement le calcul.<br />
Modifier votre co<strong>de</strong> précé<strong>de</strong>nt pour prendre en compte ces paramètres. L’utilisation du programme s'effectuera<br />
sous la forme : ./man<strong>de</strong>lbrot <br />
On lira les paramètres dans le fichier <strong>de</strong> configuration config_file. Le fichier outfile est le nom du fichier contenant<br />
l’image à créer.<br />
Plusieurs fichiers <strong>de</strong> configurations sont fournis dans le répertoire « configs ». Les fichiers intitulés<br />
« config_fractale_1_nx.txt » correspon<strong>de</strong>nt aux fractales <strong>de</strong> Man<strong>de</strong>lbrot étudiées dans c<strong>et</strong>te partie.<br />
6/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
Le format <strong>de</strong> ces fichiers est le suivant :<br />
<br />
<br />
<br />
<br />
<br />
# Utilisé uniquement dans la partie 4.2<br />
<br />
ou ... # Utilisé uniquement dans la partie 3.4<br />
*<br />
<br />
Nota bene : les 3 <strong>de</strong>rnières lignes <strong>de</strong>s fichiers serviront ultérieurement pour la mise en couleur <strong>de</strong>s fractales.<br />
3.4 Utilisation <strong>de</strong> couleurs pour le tracé <strong>de</strong> la fractale<br />
De manière à rendre les <strong>de</strong>ssins plus jolis, on souhaite dans c<strong>et</strong>te section utiliser <strong>de</strong>s couleurs pour le tracé <strong>de</strong> la<br />
fractale. L’approche est la suivante : on définit un p<strong>et</strong>it nombre P <strong>de</strong> couleurs (par exemple jaune (#FFFF00), vert<br />
(#00FF00), bleu (#0000FF) <strong>et</strong> rouge (#FF0000)), appelées paliers, <strong>et</strong> une valeur N correspondant au nombre <strong>de</strong><br />
couleurs entre <strong>de</strong>ux paliers, <strong>de</strong> manière à obtenir une transition entre ces <strong>de</strong>ux paliers. À partir <strong>de</strong> ces informations,<br />
il faut générer toutes les couleurs correspondantes (au nombre <strong>de</strong> (P − 1) ∗ N ). Entre autres, il faut bien faire<br />
attention à diviser les paliers selon les 3 composantes R, V <strong>et</strong> B.<br />
Une fois toutes les couleurs obtenues, il suffit <strong>de</strong> colorier un point divergeant avec la couleur ayant pour indice le<br />
numéro <strong>de</strong> l’itération ayant fait diverger la suite (modulo le nombre <strong>de</strong> couleurs total).<br />
Implémenter c<strong>et</strong>te fonctionnalité.<br />
7/8
<strong>Ensimag</strong> 1A – Proj<strong>et</strong> C - Préparation 2012 - Exercice <strong>Fractales</strong><br />
4 Extensions possibles<br />
4.1 Extensions <strong>Koch</strong> :<br />
• Figure <strong>de</strong> départ différente d'un triangle (figure à n segments : carré, hexagone, <strong>et</strong>c...).<br />
• Variantes <strong>de</strong>s courbes <strong>de</strong> <strong>Koch</strong> (http://fr.wikipedia.org/wiki/Flocon_<strong>de</strong>_<strong>Koch</strong>) :<br />
• <strong>Fractales</strong> Cesàro<br />
• Courbes <strong>de</strong> <strong>Koch</strong> quadratiques<br />
4.2 Extensions Man<strong>de</strong>lbrot :<br />
• Autres fonctions <strong>de</strong> génération f(z).<br />
• Fonctions f(z n ) à implémenter :<br />
• f(z) = sin(z) x z 0 (fonction Man<strong>de</strong>lbrot numérotée 2 dans les fichiers <strong>de</strong> configurations)<br />
• f(z) = z 2 + h, avec h = - 0.39492 + 0.59568i (fonction Julia numérotée 3 dans les fichiers <strong>de</strong><br />
configurations)<br />
• f(z) = cos(z) x h, avec h = 4.72675 + 0.001456i (fonction Julia numérotée 4 dans les fichiers <strong>de</strong><br />
configurations)<br />
• 3 fichiers <strong>de</strong> configurations sont fournis dans le répertoire « configs » pour tester ces fonctions :<br />
• config_fractale_2_n1.txt<br />
• config_fractale_3_n1.txt<br />
• config_fractale_4_n1.txt<br />
NOTA BENE : On pourra utiliser la librairie C99 complex pour les calculs sur les nombres complexes liés à ces<br />
autres fonctions.<br />
8/8