Skip to content
Snippets Groups Projects
Commit 0c6d767b authored by mschiess's avatar mschiess
Browse files

Ajout d'un exercice au nb recursivite2

parent 20af64be
No related branches found
No related tags found
No related merge requests found
recursivite/images/carresemboites.png

2.48 KiB

recursivite/images/flocon-iteration.png

21.3 KiB

recursivite/images/koch_snowflake.png

35.4 KiB

%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1 class="alert alert-success">Complément sur la récursivité en programmation</h2> <h1 class="alert alert-success">Complément sur la récursivité en programmation</h2>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## <h2 class="alert alert-info"> 1. Introduction à la récursivité</h2> ## <h2 class="alert alert-info"> 1. Introduction à la récursivité</h2>
Un algorithme récursif est un algorithme qui résout un problème en calculant des solutions d'instances plus petites du même problème. Un algorithme récursif est un algorithme qui résout un problème en calculant des solutions d'instances plus petites du même problème.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h2 class="alert alert-success"> Rappel : Algorithme pour implémenter une fonction récursive</h2> <h2 class="alert alert-success"> Rappel : Algorithme pour implémenter une fonction récursive</h2>
- Etape 1 - Définir le cas de base : Identifier le cas le plus simple pour lequel une solution est connue. - Etape 1 - Définir le cas de base : Identifier le cas le plus simple pour lequel une solution est connue.
- Etape 2 - Définir la récursion : Définir le problème en termes de plus petits sous-problèmes et appeler la fonction pour les résoudre. - Etape 2 - Définir la récursion : Définir le problème en termes de plus petits sous-problèmes et appeler la fonction pour les résoudre.
- Etape 3 - Définir la fin : S'assurer que la récursion va bien arriver au cas de base pour éviter d'avoir une boucle infinie. - Etape 3 - Définir la fin : S'assurer que la récursion va bien arriver au cas de base pour éviter d'avoir une boucle infinie.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h2 class = "alert alert-success"> Structure d'un code récursif en python :</h2> <h2 class = "alert alert-success"> Structure d'un code récursif en python :</h2>
%% Cell type:raw id: tags: %% Cell type:raw id: tags:
def fonction(n, ...): def fonction(n, ...):
if n==0 : if n==0 :
# code pour le cas de base # code pour le cas de base
else : else :
# votre code où apparaîtra fonction(n-1,...) # votre code où apparaîtra fonction(n-1,...)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### <h2 class="alert alert-info">2. Fractales : courbe de Koch Correction</h2> ### <h2 class="alert alert-info">2. Fractales : courbe de Koch Correction</h2>
La courbe de Koch est une fractale reposant sur la construction récursive suviante : La courbe de Koch est une fractale reposant sur la construction récursive suviante :
1. Étape 1 : Tracer un segment de longueur a. 1. Étape 1 : Tracer un segment de longueur a.
![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_0.png) ![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_0.png)
2. Étape 2 : Diviser le segment en 3 parties de même longueur. Construire un triangle équilatéral ayant pour base le segment médian de la première étape, et en supprimer la base. 2. Étape 2 : Diviser le segment en 3 parties de même longueur. Construire un triangle équilatéral ayant pour base le segment médian de la première étape, et en supprimer la base.
![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_1.png) ![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_1.png)
3. Étape 3 : Reprendre l'étape 2 sur chacun des segments créés. 3. Étape 3 : Reprendre l'étape 2 sur chacun des segments créés.
![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_2.png) ![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_2.png)
4. Et ainsi de suite... 4. Et ainsi de suite...
![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_3.png) ![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_3.png)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
On peut construire récursivement cette courbe. On peut construire récursivement cette courbe.
La fonction de tracer prend deux paramètres en entrée : La fonction de tracer prend deux paramètres en entrée :
* la longeur $a$ du segment. * la longeur $a$ du segment.
* l'étape $n$ de "profondeur" de récursivité. * l'étape $n$ de "profondeur" de récursivité.
Par exemple, à la profondeur $n=0$, on trace un simple segment : ceci constituera le cas de base et la condition d'arrêt des appels récursifs. À la profondeur $n=1$, le tracé donne la figure de l'étape 2. Par exemple, à la profondeur $n=0$, on trace un simple segment : ceci constituera le cas de base et la condition d'arrêt des appels récursifs. À la profondeur $n=1$, le tracé donne la figure de l'étape 2.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h2 class="alert alert-warning">Courbe de Koch : fonction récursive.</h2> <h2 class="alert alert-warning">Courbe de Koch : fonction récursive.</h2>
En vous inspirant de la logique du code de la fonction précédente (en la "rendant récursive"), écrire une fonction koch(a, n) récursive qui : En vous inspirant de la logique du code de la fonction précédente (en la "rendant récursive"), écrire une fonction koch(a, n) récursive qui :
- prend comme paramètres un nombre entier a représentant la longueur du segment et un entier n égal au nombre de récursions souhaité. - prend comme paramètres un nombre entier a représentant la longueur du segment et un entier n égal au nombre de récursions souhaité.
- construit la courbe de Koch en divisant récursivement chacun des segments - construit la courbe de Koch en divisant récursivement chacun des segments
*Rappel* : si n=0, le tracé est un simplement segment de longueur a. *Rappel* : si n=0, le tracé est un simplement segment de longueur a.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<div class = "alert alert-block alert-success"> <div class = "alert alert-block alert-success">
### Solution ### Solution
</div> </div>
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
import turtle as tt # import du module turtle import turtle as tt # import du module turtle
tt.speed(10) tt.speed(10)
tt.penup() tt.penup()
tt.setposition(-300, 0) tt.setposition(-300, 0)
tt.pendown() tt.pendown()
def koch(a, n): def koch(a, n):
if n == 0: if n == 0:
tt.forward(a) tt.forward(a)
else: else:
koch(a/3, n-1) koch(a/3, n-1)
tt.left(60) tt.left(60)
koch(a/3, n-1) koch(a/3, n-1)
tt.right(120) tt.right(120)
koch(a/3, n-1) koch(a/3, n-1)
tt.left(60) tt.left(60)
koch(a/3, n-1) koch(a/3, n-1)
koch(360, 3) koch(360, 3)
tt.done() tt.done()
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h2 class="alert alert-warning">Flocon de Koch : fonction récursive</h2> <h2 class="alert alert-warning">Flocon de Koch : fonction récursive</h2>
Pour obtenir le flocon de Koch: Pour obtenir le flocon de Koch:
<figure> <figure>
<img title='Koch snowflake' <img title='Koch snowflake'
src="https://isquared.digital/assets/images/koch_snowflake.png" src="https://isquared.digital/assets/images/koch_snowflake.png"
width='600px' > width='600px' >
<figcaption>Etapes 0, 1, 2, 3 et 4</figcaption> <figcaption>Etapes 0, 1, 2, 3 et 4</figcaption>
</figure> </figure>
Il suffit d'écrire une fonction `floconkoch(a,n)` qui va itérer `koch(a,n)` avec la bonne rotation. Il suffit d'écrire une fonction `floconkoch(a,n)` qui va itérer `koch(a,n)` avec la bonne rotation.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
a = 180 a = 180
tt.speed(10) tt.speed(10)
tt.penup() tt.penup()
tt.setposition(-a/2, a/3) tt.setposition(-a/2, a/3)
tt.pendown() tt.pendown()
def floconkoch(a, n): def floconkoch(a, n):
for i in range(3): for i in range(3):
koch(a, n) koch(a, n)
tt.right(120) tt.right(120)
# test pour afficher l'étape 3 # test pour afficher l'étape 3
flocon(a, 3) flocon(a, 3)
tt.penup() tt.penup()
tt.home() tt.home()
tt.done() tt.done()
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### <h2 class="alert alert-info">2. Fractales de Koch et perimètres </h2> ### <h2 class="alert alert-info">2. Fractales de Koch et perimètres </h2>
1. Complétez ce code récursif pour donner le perimètre du Flocon de Koch à l'étape n. 1. Complétez ce code récursif pour donner le perimètre du Flocon de Koch à l'étape n.
*Aidez vous de la figure ci-dessous pour comprendre l'évolution de l'aire entre deux itérations* *Aidez vous de la figure ci-dessous pour comprendre l'évolution de l'aire entre deux itérations*
![Image du triangle de sierpinski](http://img.over-blog-kiwi.com/1/93/65/56/20160116/ob_804ca5_flcon-iteration.png) ![Image du triangle de sierpinski](http://img.over-blog-kiwi.com/1/93/65/56/20160116/ob_804ca5_flcon-iteration.png)
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def perimetreKoch(a,n): def perimetreKoch(a,n):
if n==0 : if n==0 :
# code pour le cas de base # code pour le cas de base
else : else :
# votre code où apparaîtra fonction(n-1,...) # votre code où apparaîtra fonction(n-1,...)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# test pour a=50, n=3 # test pour a=50, n=3
perimetreKoch(50,3) perimetreKoch(50,3)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# test pour a=50, n=100 # test pour a=50, n=100
perimetreKoch(50,100) perimetreKoch(50,100)
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**Question:** Que peut-on déduire du périmètre du Flocon de Koch (lorsque n tend vers l'infini) ? **Question:** Que peut-on déduire du périmètre du Flocon de Koch (lorsque n tend vers l'infini) ?
**Réponse:** **Réponse:**
%% Cell type:raw id: tags: %% Cell type:raw id: tags:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Pour calculer l'aire il est plus facile d'utiliser une boucle avec des variables qui comptes le nombres de triangles qu'on rajoute à chaque étape et la largeur de leur base. Pour calculer l'aire il est plus facile d'utiliser une boucle avec des variables qui comptes le nombres de triangles qu'on rajoute à chaque étape et la largeur de leur base.
2. Complétez le code de la fonction pour donner l'aire du Flocon de Koch à l'étape n. 2. Complétez le code de la fonction pour donner l'aire du Flocon de Koch à l'étape n.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def aireKoch(a,n): def aireKoch(a,n):
A = ... A = ...
l = ... l = ...
c = ... # le nombre de carré c = ... # le nombre de carré
for i in range(n): for i in range(n):
A = ... A = ...
l = ... l = ...
c = ... c = ...
return A return A
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# test pour a=50, n=3 # test pour a=50, n=3
aireKoch(50,3) aireKoch(50,3)
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# test pour a=50, n=100 # test pour a=50, n=100
aireKoch(50,100) aireKoch(50,100)
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**Question:** Que peut-on déduire de l'aire du Flocon de Koch (lorsque n tend vers l'infini) ? **Question:** Que peut-on déduire de l'aire du Flocon de Koch (lorsque n tend vers l'infini) ?
**Réponse:** **Réponse:**
%% Cell type:raw id: tags: %% Cell type:raw id: tags:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### <h2 class="alert alert-info">3. une autre images fractale: le triangle de Sierpinski</h2> ### <h2 class="alert alert-info">3. une autre images fractale: le triangle de Sierpinski</h2>
La courbe de Koch est une fractale reposant sur la construction récursive suviante : La courbe de Koch est une fractale reposant sur la construction récursive suviante :
![Image du triangle de sierpinski](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/images/triangle_de_sierpinski.png) ![Image du triangle de sierpinski](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/images/triangle_de_sierpinski.png)
1. Écrire une fonction `triangle(a)` qui permet de dessiner un triangle de longeur `a`, puis une fonction `etape2(a)` qui permet de dessiner (pas de récursivité ici) la figure correspondant à l'étape 2 en utilisant la fonction `triangle(a)`. 1. Écrire une fonction `triangle(a)` qui permet de dessiner un triangle de longeur `a`, puis une fonction `etape2(a)` qui permet de dessiner (pas de récursivité ici) la figure correspondant à l'étape 2 en utilisant la fonction `triangle(a)`.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
import turtle as tt import turtle as tt
def triangle(a): def triangle(a):
... ...
def etape2(a) : def etape2(a) :
... ...
etape2(200) etape2(200)
tt.done() tt.done()
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
2. En vous inspirant de la logique du code de la fonction précédente (en la "rendant récursive"), écrire une fonction `triangle_sierpinski(a, n)` récursive qui : 2. En vous inspirant de la logique du code de la fonction précédente (en la "rendant récursive"), écrire une fonction `triangle_sierpinski(a, n)` récursive qui :
- remplace les appels à triangle par des appels récursifs pour n>=1 - remplace les appels à triangle par des appels récursifs pour n>=1
- trace un simple triangle lorsque n=0 - trace un simple triangle lorsque n=0
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
import turtle as tt import turtle as tt
def triangle_sierpinski(a, n) : def triangle_sierpinski(a, n) :
... ...
tt.hideturtle() # on cache la tortue tt.hideturtle() # on cache la tortue
tt.speed(0) # tortue rapide tt.speed(0) # tortue rapide
triangle_sierpinski( 200 , 7) triangle_sierpinski( 200 , 7)
tt.done() tt.done()
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### <h2 class="alert alert-info">3. une autre images fractale: les carrés imbriqués</h2>
Écrire une fonction python récursive produisant le type de figures suivantes :
![Image du triangle de sierpinski](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/images/carresemboites.png)
%% Cell type:code id: tags:
``` python
```
%% Cell type:markdown id: tags:
### <h2 class="alert alert-info">4. Décomposition d'un entier positif en somme d'au plus quatre carrés</h2> ### <h2 class="alert alert-info">4. Décomposition d'un entier positif en somme d'au plus quatre carrés</h2>
Le théorème des quatre carrés de Lagrange affirme que tout nombre entier positif `n` peut s'écrire comme la somme d'au plus quatre carrés. Le théorème des quatre carrés de Lagrange affirme que tout nombre entier positif `n` peut s'écrire comme la somme d'au plus quatre carrés.
Par exemple, $1871 = 1 + 25 + 81 + 1764 = 1^2 + 5^2 + 9^2 + 42^2$. Par exemple, $1871 = 1 + 25 + 81 + 1764 = 1^2 + 5^2 + 9^2 + 42^2$.
Pour afficher une possibilité on peut donner l'algorithme suivant qui permet de décomposer un entier positif `n` en une somme d'au plus quatre carrés. Pour afficher une possibilité on peut donner l'algorithme suivant qui permet de décomposer un entier positif `n` en une somme d'au plus quatre carrés.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<div style='background-color: #f7bd83; <div style='background-color: #f7bd83;
border-radius: 0.5em; border-radius: 0.5em;
padding: 1em; padding: 1em;
margin: 0em 2em 0em 2em'> margin: 0em 2em 0em 2em'>
<p><b>Algorithme de décomposition de l'entier positif <code>n</code> en une somme d'au plus quatre carrés</b></p> <p><b>Algorithme de décomposition de l'entier positif <code>n</code> en une somme d'au plus quatre carrés</b></p>
<p><b>Début</b></p> <p><b>Début</b></p>
<p STYLE="padding:0 0 0 40px;">Si <code>n</code> est le carré d'un entier alors</p> <p STYLE="padding:0 0 0 40px;">Si <code>n</code> est le carré d'un entier alors</p>
<p STYLE="padding:0 0 0 80px;">Retourner un tableau contenant uniquement l'élément <code>n</code></p> <p STYLE="padding:0 0 0 80px;">Retourner un tableau contenant uniquement l'élément <code>n</code></p>
<p STYLE="padding:0 0 0 40px;">Sinon</p> <p STYLE="padding:0 0 0 40px;">Sinon</p>
<p STYLE="padding:0 0 0 80px;"><code>liste_carres</code> tableau contenant la liste décroissante des nombres compris entre 1 et <code>n</code> qui sont des carrés d'entiers</p> <p STYLE="padding:0 0 0 80px;"><code>liste_carres</code> tableau contenant la liste décroissante des nombres compris entre 1 et <code>n</code> qui sont des carrés d'entiers</p>
<p STYLE="padding:0 0 0 80px;">Pour chaque élément <code>carre</code> de <code>liste_carres</code> faire</p> <p STYLE="padding:0 0 0 80px;">Pour chaque élément <code>carre</code> de <code>liste_carres</code> faire</p>
<p STYLE="padding:0 0 0 120px;"><code>decompo</code> ← liste renvoyé par <code>decomposition_carres(n - carre)</code> auquel on ajoute l'élément <code>carre</code> à la fin</p> <p STYLE="padding:0 0 0 120px;"><code>decompo</code> ← liste renvoyé par <code>decomposition_carres(n - carre)</code> auquel on ajoute l'élément <code>carre</code> à la fin</p>
<p STYLE="padding:0 0 0 120px;">Si longueur(<code>decompo</code>) $\leq$ 4 alors</p> <p STYLE="padding:0 0 0 120px;">Si longueur(<code>decompo</code>) $\leq$ 4 alors</p>
<p STYLE="padding:0 0 0 160px;">Retourner <code>decompo</code></p> <p STYLE="padding:0 0 0 160px;">Retourner <code>decompo</code></p>
<p><b>Fin</b></p> <p><b>Fin</b></p>
</div> </div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**(1)** 💻 Définir une fonction `est_carre` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie `True` si `n` est le carré d'un entier et `False` sinon. **(1)** 💻 Définir une fonction `est_carre` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie `True` si `n` est le carré d'un entier et `False` sinon.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def est_carre(n): def est_carre(n):
if ...: if ...:
return ... return ...
else: else:
return ... return ...
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# Test # Test
nb = 9 nb = 9
print(nb, "est-il un carre ? ", est_carre(nb)) print(nb, "est-il un carre ? ", est_carre(nb))
nb = 10 nb = 10
print(nb, "est-il un carre ? ", est_carre(nb)) print(nb, "est-il un carre ? ", est_carre(nb))
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**(2)** 💻 Définir une fonction `liste_carres_entiers` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie la liste décroissante des entiers compris entre 1 et `n` et qui sont des carrés d'entiers. **(2)** 💻 Définir une fonction `liste_carres_entiers` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie la liste décroissante des entiers compris entre 1 et `n` et qui sont des carrés d'entiers.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def liste_carres_entiers(n): def liste_carres_entiers(n):
L = ... L = ...
for k in reversed(...): for k in reversed(...):
if ...: if ...:
... ...
return L return L
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# Test # Test
listes_carres = liste_carres_entiers(100) listes_carres = liste_carres_entiers(100)
print(listes_carres) # doit afficher [100, 81, 64, 49, 36, 25, 16, 9, 4, 1] print(listes_carres) # doit afficher [100, 81, 64, 49, 36, 25, 16, 9, 4, 1]
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**(3)** 💻 Implémenter la fonction `decomposition_carres` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie, sous forme de tableau de longueur inférieure ou égale à 4, une décomposition de `n` en somme de carrés d'entiers. **(3)** 💻 Implémenter la fonction `decomposition_carres` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie, sous forme de tableau de longueur inférieure ou égale à 4, une décomposition de `n` en somme de carrés d'entiers.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def decomposition_carres(n): def decomposition_carres(n):
... ...
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# Test # Test
nb = 1871 nb = 1871
print("La décomposition de ",nb, "est : ", decomposition_carres(nb)) print("La décomposition de ",nb, "est : ", decomposition_carres(nb))
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**(4)** ✏️ Donner une décomposition en somme d'au plus quatre carrés pour les entiers $300$, $1789$, $2021$ et $12345$. **(4)** ✏️ Donner une décomposition en somme d'au plus quatre carrés pour les entiers $300$, $1789$, $2021$ et $12345$.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**(5)** ✏️ Proposer une fonction non récursive `decomposition_carres2(n)` qui permet de calculer la décomposition et tester la fonction **(5)** ✏️ Proposer une fonction non récursive `decomposition_carres2(n)` qui permet de calculer la décomposition et tester la fonction
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def decomposition_carres2(n): def decomposition_carres2(n):
listes_carres = ... listes_carres = ...
for ...: for ...:
for ...: for ...:
for ...: for ...:
for ...: for ...:
if ... : if ... :
return ... return ...
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
# Test # Test
nb = 1871 nb = 1871
print("La décomposition de ",nb, "est : ", decomposition_carres2(nb)) print("La décomposition de ",nb, "est : ", decomposition_carres2(nb))
``` ```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment