L'exécution de code Javascript

Chaque navigateur possède son propre moteur Javascript :

Les moteurs Javascript

Ceux-ci vérifient les normes ECMAScript (ES7 = ES2016) et la plupart sont compatibles avec WebAssembly.

Leur principe de fonctionnement est décrit dans l’image ci-dessous. Le navigateur transmet le code Javascript au moteur, qui le compile afin d’obtenir du code machine qui est exécuté sur le processeur de votre machine.

Principe de fonctionnement de Javascript

Depuis 2009, on peut réaliser ces opérations hors d’un navigateur grâce à Node.

Afin de demander au navigateur d’exécuter du code Javascript, il suffit d’insérer dans le code HTML des balises <script></script>.

javascript1.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>intro à javascript</title>
</head>
<body>
<h1>contenu de la page web</h1>

<!-- insertion d'un code javascript -->
<script>
    console.log('toto');
</script>
</body>
</html>
javascript2.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>intro à javascript</title>
</head>
<body>
<h1>contenu de la page web</h1>

<!-- insertion d'un code javascript -->
<script src="page1.js"></script>
</body>
</html>

Exercice 1 : Installation de Node   

Pour installer Node, si vous travaillez sous Windows ou MacOS, allez sur l’URL suivante :

https://nodejs.org/en/download

Si vous travaillez sous Linux, vous pouvez également suivre les instruction de l’URL ci-dessus ou bien installer nodejs via apt, yum, pacman, snap ou n’importe quel autre système de package. Mais attention : il faut une version récente de Node (au moins une version 22). Ce sera nécessaire par la suite pour pouvoir utiliser Angular.

Une fois Node installé, vous devez pouvoir utiliser la commande npm. Dans une console, tapez la commande npm list ou npm.cmd list si vous êtes sous Windows. Cela devrait fonctionner (vous ne devriez pas voir de message d’erreur, juste au pire quelques warnings).

IMPORTANT : Déclarations de variables en Javascript

La figure ci-dessous vous présente sur l’échelle du « beurk » les différentes manières de déclarer des variables en Javascript. Important : lisez bien ce qui suit pour déclarer correctement vos variables.

Les déclarations de variables

Lorsque vous utilisez la syntaxe Python nom_variable = valeur, vous créez des variables globales, ce qui est franchement à proscrire dans tout programme qui se respecte. À la rigueur, si vous souhaitez réellement créer une variable globale, utilisez global.nom_variable ou window.nom_variable, ce sera au moins explicite. Utiliser le mot-clef var n’est pas mieux car la portée des variables définies ainsi est une portée de fonction, pas de bloc, ce qui est franchement générateur de bug. Je ne veux donc pas voir cela dans vos programmes.

Règle

Les deux manières correctes pour créer des variables sont d’utiliser les mots-clefs const et let, avec une préférence pour const. Ces deux mots-clefs vous permettront de créer des variables locales à l’intérieur des blocs ou, si elles sont déclarés en dehors de blocs, elles auront une portée limitée au fichier dans lequel elles sont déclarées.

Le mot-clef const vous interdira de réaffecter une nouvelle valeur à la variable. Si vous avez absolument besoin de faire des réaffectations, utilisez let.

Nom des variables :

Les noms de variables autorisés suivent les mêmes règles qu’en Java ou C. En principe, on utilise la notation Camel (par exemple, firstName). Attention : Javascript est sensible à la casse (firstName est différent de FirstName). Comme d’habitude, éviter de créer des variables O (O majuscule) et l (L minuscule) parce que cela ressemble trop aux chiffres 0 et 1.

Les types des variables

Javascript est une version « light » de Java. À ce titre, le langage reprend les caractéristiques des types de Java. Notamment, on retrouve les types dits primitifs (string, number, boolean, undefined, null), qui sont copiés par valeur, et les types référence (Object, Array, Function) qui sont copiés par référence.

Les fonctions, objets, tableaux et strings

Les fonctions  

Il existe deux manières pour déclarer des fonctions. La première consiste à utiliser le mot-clef function :

function.js
// les fonctions : function nom_fonc (arguments) { code }, comme en php
function f(arg1, arg2) {
    arg1++;
    console.log(arg1, arg2);
}

// passage de paramètres :
// par référence pour les types référence, copie par valeur pour les types primitifs
let x = 3;
f(x,x); console.log(x);
f(x);   console.log(x);

Les fonctions sont des valeurs comme les autres et peuvent donc être affectées à des variables. Dans ce cas, on utilise souvent une autre manière de les créer, que l’on appelle arrow functions. L’idée consiste à ne pas écrire le mot-clef function ni le nom de la fonction et, plutôt de rajouter un flèche => avant l’accolade ouvrante :

function2.js
const f = (arg1, arg2) => {
    arg1++;
    console.log(arg1, arg2);
}

let x = 3;
f(x,x); console.log(x);
f(x);   console.log(x);

Cette notation vous sera particulièrement utile pour déclarer des callbacks dans Angular.

Notez que vous pouvez tester les codes ci-dessus en utilisant Node, qui permet d’exécuter sur un desktop du code Javascript :

node function2.js
4 3
3
4 undefined
3

Les objets  

Le code suivant vous montre comment créer des objets en Javascript :

objects.js
// objets = {}
// création d'un objet :
let guy = {
    prenom : 'guy', // couples clef-valeur
    nom : 'nipigue' // séparation des propriétés
                    // par des ','
};

console.log(guy);

// accès aux propriétés : 2 possibilités :
// notation '.' ou '[]'
console.log(guy.nom);
console.log(guy['prenom']);
let field = 'prenom';
console.log(guy[field]);

Après la création d’un objet, on peut rajouter/supprimer dynamiquement des champs/propriétés.

Notez qu’une propriété peut être une fonction. On dira alors que c’est une méthode :

methodes.js
// création d'un objet avec une méthode :
let obj = {
    propriete1 : 3,
    propriete2 : 5,
    // définition d'une méthode avant ES6
    display1 : function () {
        console.log(this.propriete1);
    },

    // définition possible (et préférable) depuis ES6
    display2 () {
        console.log(this.propriete2);
    }
};

obj.display1();
obj.display2();

Notez que, quand on veut accéder à la valeur d’une propriété à l’intérieur d’une méthode, on utilise le mot-clef this, comme en Java.

Depuis ES6, on peut également créer des objets en utilisant les mots-clefs class et new, mais cela vous sera moins utile que ce que l’on a vu précédemment (à ceci près qu’Angular créera ses composants en exploitant le mot-clef class) :

obj_class.js
// création d'un objet par classe : depuis ES6
class MonObjet {
    // on définit explicitement une méthode constructor.
    // on ne peut définir qu'un seul constructeur
    constructor (val1, val2) {
        // déclaration, initialisation des propriétés
        this.propriete1 = val1;
        this.propriete2 = val2;
    }

    // pas besoin de mot clef "function" pour les
    // méthodes
    display () {
        console.log(this.propriete1, this.propriete2);
    }
}

let obj = new MonObjet(3,4);
obj.display ();

Attention : les objets sont des types référence, comme le montre le code suivant :

value_vs_ref.js
// copie de types primitifs : x != y
let x = 4;
let y = x;
y++;
console.log (x,y);

// copie de types référence : x = y
let a = { val : 4 };
let b = a;
b.val = 5;
console.log (a,b);
4 5
{ val: 5 } { val: 5 }

Les tableaux  

Les tableaux se déclarent comme en Python ou en PHP (versions > 5.4) :

arrays.js
// array = []
// les éléments sont indexés à partir de 0, comme en C, accès avec l'opérateur []
const x = [1, 3, 4];
console.log (x);

x[4] = 5;        // avec const, x = ... est interdit, mais pas x[...] = ...
console.log(x);  // C'est en fait la référence qui est constante, pas ce qui
                 // est référencé

// on peut mettre des éléments de types différents dans un même array :
x[5] = 'toto';
console.log(x);
[ 1, 3, 4 ]
[ 1, 3, 4, <1 empty item>, 5 ]
[ 1, 3, 4, <1 empty item>, 5, 'toto' ]

On peut voir ici qu’il peut y avoir des « trous » dans les tableaux. Comme en Python ou en PHP, un tableau peut contenir des éléments de différents types.

À noter que les tableaux sont des objets, ce qui vous permettra d’utiliser leurs méthodes et propriétés comme push, pop, unshift, length, filter, forEach, etc. :

Les tableaux sont des objets

Les strings et template literals  

Comme en Python, on peut créer des strings en les encadrant à l’intérieur de quotes ('toto') ou de guillemets ("toto"). Mais il existe une autre manière de créer des chaînes de caractères en Javascript, que l’on appelle des string literals. Ceux-ci sont encadrés par des back quotes (`toto`). L’intérêt de ces string literals, c’est :

  1. que l’on peut les définir sur plusieurs lignes ;

  2. que l’on peut y insérer (entre accolades) des variables ou expressions Javascript, qui sont alors évaluées et dont le résultat fait partie de la chaîne.

template_literals.js
// concaténation de strings : +
let x = 4;
let y = 'x vaut : ' + x + '\n\'3 fois\' moins que ' + (3 * x);
console.log(y);

// template literals (backquotes : ``) : depuis ES6
let z = `x vaut : ${x}
'3 fois' moins que ${3 * x}`;  // fin du template literal
console.log(z);
x vaut : 4
'3 fois' moins que 12
x vaut : 4
'3 fois' moins que 12

Notez qu’à l’intérieur d’un template literal, tout retour à la ligne fait partie de la chaîne de caractère.

Les itérateurs en Javascript

Javascript propose des itérateurs pour parcourir les éléments d’un tableau et les propriétés des objets.

Règle

Pour itérer sur un tableau, utilisez le for (let/const x of …).

Pour itérer sur un objet, utilisez le for (let/const cle in …).

La boucle for … of vous sera particulièrement utile en Angular. Mais je spoile, je spoile…

Voici deux exemples d’illustration :

iterOf.js
const tab = [5, 4, 3];

// parcours avec un itérateur
for (const elt of tab) {
    console.log(elt);
}

// parcours avec une boucle for à la C
for (let i = 0; i < tab.length; i++) {
    console.log(tab[i]);
}
iterIn.js
class MonObjet {
    constructor (val1, val2) {
        this.propriete1 = val1;
        this.propriete2 = val2;
    }

    // affichage des propriétés de l'objet
    display () {
        // for .. in : parcours des clefs de
        // l'objet ou des index pour un tableau
        for (let key in this)
            console.log(key, this[key]);
    }
}

let obj = new MonObjet(3,4);
obj.display ();

console.log('==========================');

const obj2 = {
    prop1: 5,
    prop2: 6,
    prop3: "toto"
};

for (const key in obj2) {
    console.log(key, obj2[key]);
}
propriete1 3
propriete2 4
==========================
prop1 5
prop2 6
prop3 toto

Angular

Angular est un framework pour construire des applications clientes, autrement dit pour réaliser des front-ends. Il est conçu pour en simplifier la programmation, la maintenance et le débuggage. Pour cela, il va vous imposer de structurer correctement votre application. Notamment, il sépare ce qui concerne la gestion des données (business logic) des affichages. En outre, mais nous ne le verrons pas par manque de temps, il permet une mise en place de tests assez simple.

Angular s’appuie sur :

Structure d’une application Angular  

Une page web est souvent structurée. Par exemple, l’image ci-dessous représente une page constituée d’une barre de navigation, d’un menu et d’une partie dévolue au contenu que l’on souhaite afficher dans cette page. L’idée clef d’Angular est que chaque partie (chaque rectangle) correspond à un composant spécifique. La partie bleue montre que, lorsqu’un composant (le composant principal bleu) est complexe ou lorsqu’il constitué d’une répétition de parties similaires, on peut le décomposer en petits morceaux (des sous-composants) et inclure ceux-ci dans le composant principal en bleu. Outre le fait de simplifier la programmation et le débuggage, cette stratégie de scinder les composants offre l’avantage qu’un même composant peut être réutilisé plusieurs fois.

Structure d'une page web

La structure ci-dessus correspond à l’arbre de composants ci-dessous. Celui-ci est précisément ce qui est rajouté au DOM par Angular pour afficher votre page.

Une arborescence de composants

Contenu d’un composant Angular  

Un composant Angular est, en gros, constitué de 3 fichiers :

  1. un fichier TypeScript contenant une classe avec :

    • les données du composant,

    • la logique/le comportement du composant (des méthodes).

  2. un fichier HTML :

    • contenant le code HTML affiché par le navigateur,

    • des instructions pour interagir avec le code TypeScript.

  3. un fichier CSS/SCSS/Sass contenant le style propre au composant.

Dans les projets Angular, le répertoire src/app contient les composants.

Il est à noter qu’Angular crée un composant principal, la racine de l’arborescence de composants, appelé app ou root.

Exercice 2 : Installation d'Angular   

Pour installer Angular. Pour cela, tapez la commande ci-dessous :

sudo npm install -g @angular/cli

Les projets Angular

Création d'un projet Angular  

Pour créer un nouveau projet Angular, il faut taper la commande ci-dessous et indiquer les caractéristiques de votre projet. Je vous suggère de choisir SCSS pour vos fichiers de style (c’est une extension plus pratique à utiliser que CSS). De plus, dans ce module, on n’utilisera pas de Server-Side Rendering.

ng new nom_de_mon_projet

Anatomie d'un projet Angular  

Cette commande va créer un nouveau répertoire nom_de_mon_projet et le remplir avec un squelette d’application et elle va également télécharger des librairies via npm. Le contenu du répertoire devrait être similaire à celui ci-dessous :

Structure des fichiers d'un projet Angular

Le répertoire src/app contient tous les composants. À l’initialisation, il n’en contient qu’un seul, le composant racine app. Chaque composant est spécifié par un répertoire du même nom contenant :

  • le fichier TypeScript du composant (sa classe) .component.ts,

  • le fichier HTML .component.html,

  • le fichier de style du composant, ici .component.scss,

  • un fichier .component.spec.ts qui permet de réaliser des tests automatiques du composant.

Le composant app est spécial en ce sens qu’il est racine de votre application et, à ce titre, il contient deux fichiers supplémentaires :

  • le fichier app.config.ts, qui contient des instructions de configuration de l’application. Notamment, la section providers charge des librairies nécessaires à l’application :

    app.config.ts
    import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
    import { provideRouter } from '@angular/router';
    
    import { routes } from './app.routes';
    
    export const appConfig: ApplicationConfig = {
      providers: [
        provideZoneChangeDetection({ eventCoalescing: true }),
        provideRouter(routes)
      ]
    };
    

    Vous serez amenés à rajouter des providers dans ce fichier, notamment pour pouvoir transférer des informations entre le client et le serveur.

  • le fichier app.routes.ts, qui contient les « routes » de l’application :

    app.routes.ts
    import { Routes } from '@angular/router';
    
    export const routes: Routes = [];
    

    Pour l’instant, votre application n’est pas configurée pour avoir plusieurs « pages » (routes), mais l’idée sera de générer une route par page. Par exemple, dans votre forum, vous aurez une route pour la page de login, une pour afficher les cours, une pour les topics, etc.

Le répertoire src  

Dans le répertoire src, vous pouvez voir un fichier index.html. C’est le point d’entrée (le main) de votre application. Ce fichier est simple et instructif. En gros, il ne contient qu’une balise <app-root></app-root>. Dit autrement, le DOM ne contient qu’un nœud <app-root>. Cette balise n’existe pas en HTML et c’est là qu’Angular intervient : Angular sait que celle-ci correspond au composant app. Dans le DOM, il va donc insérer à la place du <app-root></app-root> tout le code/tous les nœuds spécifiés dans le composant app. C’est ce qui va remplir toute la page web. En principe, vous n’aurez jamais à éditer le fichier index.html.

index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Frontend</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

Le 2ème fichier intéressant dans le répertoire src est le fichier styles.scss. J’ai dit précédemment que chaque composant possède un fichier de style. Le fichier styles.scss a pour but de définir le style « global » de l’application, autrement dit les propriétés CSS/SCSS communes à tous les composants. Les fichiers .component.scss, quant à eux, permettent de spécifier des styles propres à chaque composant.

Le répertoire racine du projet  

Le répertoire racine contient lui-même des fichiers intéressants. Les fichiers package.json et package-lock.json sont utilisés par npm afin d’installer les packages dont vous avez besoin.

Plus intéressant pour les développeurs, le fichier angular.json permet de spécifier comment compiler votre application, quelles options utiliser, etc. Comme tout fichier json, il encode un objet Javascript. Il contient par exemple une propriété styles qui définit les fichiers de styles à inclure dans le fichier index.html. Si vous souhaitez exploiter bootstrap, il suffit de rajouter à cette propriété les styles de bootstrap.

Visualisation de l'application  

Lorsque vous programmez, vous avez besoin de voir ce que fait votre application dans votre navigateur. Pour cela, Angular permet de « servir » votre application via la commande ci-dessous. Celle-ci va compiler votre programme et démarrer un serveur sur lequel votre navigateur pourra aller pour exécuter l’application.

ng serve

Cette commande vous produira un affichage similaire à celui ci-dessous :

Node.js version v23.3.0 detected.
Odd numbered Node.js versions will not enter LTS status and should not be
used for production. For more information, please see
https://nodejs.org/en/about/previous-releases/.
Initial chunk files | Names         |  Raw size
polyfills.js        | polyfills     |  90.20 kB |
main.js             | main          |  18.19 kB |
styles.css          | styles        |  96 bytes |

                    | Initial total | 108.49 kB

Application bundle generation complete. [1.584 seconds]

Watch mode enabled. Watching for file changes...
NOTE: Raw file sizes do not reflect development server per-request transformations.
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show help

L’avant dernière ligne indique l’url à utiliser dans votre navigateur pour exécuter votre application. Autrement dit, il faut contacter le serveur se trouvant sur le port 4200 de votre machine (localhost).

Localhost représente votre machine mais cette adresse internet va vous poser des problèmes avec des navigateurs tels que Chrome. En effet, votre application frontend sera servie par un serveur sur le port 4200 de votre machine mais les données qu’elle manipulera proviendront d’un serveur Apache auquel vous accéderez en http, pas en https (autrement dit avec une liaison non sécurisée, non chiffrée). Certains navigateurs, dont Chrome, vous interdiront de transmettre des données dans ces conditions, sauf si celles-ci sont échangées entre deux serveurs de votre machine. Mais comment s’assurer que c’est bien le cas? Utiliser Localhost n’est pas fiable car on peut affecter à ce nom n’importe quelle adresse routable sur internet (cf. le fichier /etc/hosts sous Linux). Aussi, la règle adoptée par ces navigateurs est la suivante :

Règle

Un serveur est considéré comme local si on communique avec lui via l’adresse IP 127.0.0.1, qui est l’adresse du loopback, une adresse non routable d’internet qui représente votre machine. Les alias de noms de machines ne sont pas pris en compte.

Il faudrait donc qu’Angular serve l’adresse http://127.0.0.1:4200 plutôt que http://localhost:4200. Le fichier angular.json décrit précédemment permet de le faire facilement. Dans ce fichier, recherchez la propriété « serve », qui spécifie les options du ng serve et rajoutez à la fin de cet objet une nouvelle propriété options :

angular.json
{
  .......
        "serve": {
          .............
          "defaultConfiguration": "development",
          "options": {
            "host": "127.0.0.1"
          }
        },
  ........
}

Maintenant, si vous faites un ng serve, votre application sera servie sur la machine 127.0.0.1 et cela vous évitera bien des problèmes.

Exercice 3 : Forum - Création du frontend   

Créez un projet frontend qui contiendra le frontend Angular de votre forum.

Faites en sorte que votre application soit servie via le port 4200 de la machine d’adresse 127.0.0.1.

Servez votre application et regardez ce qu’elle donne sur un navigateur. Mon conseil sur le choix de ce dernier : utilisez autant que possible Chrome. Évitez firefox car il est vraiment trop permissif et il laissera passer certaines erreurs sans que vous vous en aperceviez.

Exercice 4 : Forum - Réinitialisation   

Dans le fichier src/app/app.component.html, supprimez toutes les lignes excepté la dernière (<router-outlet />) qui vous sera utile par la suite. Ajoutez au dessus une balise <h1></h1> avec un titre et testez votre application. Voilà, elle est maintenant prête pour accueillir votre forum.

Les composants dans Angular

Création d'un composant  

Pour créer un nouveau composant mon-comp, il faut utiliser la commande :

ng generate component mon-comp

ou, en abrégé :

ng g c mon-comp

Cela produira un répertoire mon-comp contenant les fichiers :

  • mon-comp.component.html

  • mon-comp.component.scss

  • mon-comp.component.ts

  • mon-comp.component.spec.ts

Anatomie du composant  

Il n’y a pas grand chose à dire pour l’instant sur les fichiers scss et html. Concentrons-nous sur le TypeScript :

mon-comp.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-mon-comp',
  imports: [],
  templateUrl: './mon-comp.component.html',
  styleUrl: './mon-comp.component.scss'
})
export class MonCompComponent {

}

On voit tout en bas que l’on a défini une classe. C’est celle-ci qui contiendra la logique « business » du composant, c’est-à-dire ses données ainsi que des méthodes permettant de les manipuler.

Au dessus de la classe, on a une annotation @Component qui indique à Angular que la classe qui suit concerne un composant. Dans cette annotation, la propriété selector indique quelle balise utiliser dans la partie HTML pour insérer une instance du composant (c’est plus général que ce que je vous dis ici, mais ce sera suffisant pour faire les TPs. Si vous souhaitez approfondir vos connaissances en Angular, il faudra vous reporter à la documentation d’Angular, qui est très bien faite). Ici, si je souhaite insérer deux instances du composant dans ma page principale, je vais modifier le fichier app.component.html de la manière suivante :

app.component.html
<h1>première instance :</h1>
<app-mon-comp />
<h1>deuxième instance :</h1>
<app-mon-comp />

<router-outlet />

La deuxième propriété des @Component concerne les imports. Ici, vous devez importer tous les composants, services, etc. que vous utilisez. C’est vraiment l’équivalent de l'import de Java ou du #include du C. Par conséquent, pour que app puisse utiliser mon-comp, il va falloir rajouter ce dernier dans les imports de app :

app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import {MonCompComponent} from './mon-comp/mon-comp.component';

@Component({
  selector: 'app-root',
  imports: [
    RouterOutlet,
    MonCompComponent
  ],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  title = 'frontend';
}

Les IDE sont en principe assez intelligents et vont vous proposer de rajouter automatiquement MonCompComponent aux imports de app. En tous cas, c’est ce que fait l’IDE webstorm de JetBrains et c’est bien pratique.

La troisième propriété de @Component indique quel code HTML le composant va utiliser. Ici, en général, on indique le nom du fichier HTML du composant, ce que l’on appelle le template HTML.

Enfin, la dernière propriété indique le fichier de style spécifique que le composant va utiliser.

Exercice 5 : Forum - Page de Login   

Créez un composant login qui permettra de se connecter à votre forum. Pour l’instant, contentez-vous de créer le composant et de le visualiser. Vous mettrez les balises <input>, les boutons, etc., plus tard.

Exercice 6 : Forum - Style   

bootstrap est une librairie très populaire, accessible sur l’URL :

https://getbootstrap.com.

Installez-la dans votre frontend via la commande :

npm install bootstrap

La librairie contient notamment des fichiers de style SCSS qui vous simplifieront la vie. La documentation de bootstrap (https://getbootstrap.com/docs/5.3/) vous sera utile pour déterminer les classes bootstrap à utiliser pour obtenir le rendu que vous souhaitez de vos pages.

Comme vu plus haut, dans Angular, si des fichiers de style concernent toute l’application, on les inclut dans le fichier angular.json à la racine du frontend. Dans ce fichier, propriété build, rajoutez les styles de bootstrap. Vous devez obtenir quelque chose comme :

angular.json
.....
"styles": [
  "src/styles.scss",
  "node_modules/bootstrap/scss/bootstrap.scss"
]
......

Vérifiez bien à chaque étape de développement que ng serve compile et ne crée pas d’erreurs.

 
© C.G. 2007 - 2025