Skip to content

niveau 2 analyse complexe

hprzeta edited this page Sep 12, 2026 · 3 revisions

🌀 Niveau 2 — Analyse complexe : holomorphie, Cauchy et prolongement de ζ(s)

Session 3 — Fonctions holomorphes, théorème de Cauchy et prolongement analytique Méthode : théorie → formule → exemple à la main → code Python


🎬 Animation interactive

Animation Ce qu'elle montre
▶ Plan complexe Heatmap $\lvert\zeta(\sigma+it)\rvert$ — pôle en $s=1$ — bande critique — zéros non-triviaux

🎯 Objectif de cette session

Comprendre pourquoi $\zeta(s) = \sum_{n=1}^{\infty} \frac{1}{n^s}$ ne converge que pour $\text{Re}(s) > 1$, et comment l'analyse complexe permet de définir $\zeta(s)$ sur tout $\mathbb{C} \setminus {1}$.

C'est la brique entre la définition élémentaire de $\zeta$ et ses propriétés profondes :

  • Les zéros non triviaux de $\zeta(s)$ vivent dans la bande $0 < \text{Re}(s) < 1$
  • Pour y accéder, il faut sortir du domaine de convergence de la série
  • Le prolongement analytique est l'outil qui rend cela rigoureux

📖 PARTIE 1 — Fonctions holomorphes et conditions de Cauchy-Riemann

1.1 Rappel théorique

Une fonction $f : \mathbb{C} \to \mathbb{C}$ est holomorphe en $z_0$ si elle est dérivable au sens complexe :

$$f'(z_0) = \lim_{h \to 0} \frac{f(z_0 + h) - f(z_0)}{h} \quad h \in \mathbb{C}$$

La différence avec la dérivée réelle : $h$ peut s'approcher de $0$ depuis n'importe quelle direction dans $\mathbb{C}$. C'est une condition bien plus forte que la dérivabilité réelle.

1.2 Conditions de Cauchy-Riemann

On écrit $f(x + iy) = u(x,y) + iv(x,y)$ avec $u, v$ fonctions réelles.

$f$ est holomorphe si et seulement si :

$$\frac{\partial u}{\partial x} = \frac{\partial v}{\partial y} \qquad \text{et} \qquad \frac{\partial u}{\partial y} = -\frac{\partial v}{\partial x}$$

Intuition : ces deux équations forcent la dérivée à être la même quelle que soit la direction d'approche.

1.3 Exemple à la main

Vérifions que $f(z) = z^2$ est holomorphe.

On écrit $z = x + iy$, donc : $$f(z) = (x+iy)^2 = (x^2 - y^2) + i(2xy)$$

Ainsi $u = x^2 - y^2$ et $v = 2xy$. On vérifie :

$$\frac{\partial u}{\partial x} = 2x = \frac{\partial v}{\partial y} \quad \checkmark \qquad \frac{\partial u}{\partial y} = -2y = -\frac{\partial v}{\partial x} \quad \checkmark$$

Les conditions de Cauchy-Riemann sont satisfaites — $f(z) = z^2$ est bien holomorphe sur $\mathbb{C}$.

1.4 Connexion avec $\zeta(s)$

Pour $s = \sigma + it$ avec $\sigma > 1$, la série $\zeta(s) = \sum_{n=1}^{\infty} \frac{1}{n^s}$ converge et définit une fonction holomorphe. Cela signifie que $\zeta(s)$ est "infiniment lisse" sur ce demi-plan — une propriété que le prolongement analytique va pouvoir exploiter.

1.5 Code Python — vérification des conditions de Cauchy-Riemann

from mpmath import mp, mpc, re, im, diff
import numpy as np
import matplotlib.pyplot as plt

mp.dps = 15

def f(z):
    return z**2

# Vérification numérique des conditions C-R en z = 1 + 2i
z0 = mpc(1, 2)
h = 1e-7

# Dérivées partielles de u = Re(f) et v = Im(f)
du_dx = float(re(f(z0 + h) - f(z0)) / h)
du_dy = float(re(f(z0 + mpc(0,h)) - f(z0)) / h)
dv_dx = float(im(f(z0 + h) - f(z0)) / h)
dv_dy = float(im(f(z0 + mpc(0,h)) - f(z0)) / h)

print("Conditions de Cauchy-Riemann pour f(z) = z² en z = 1+2i")
print(f"  du/dx = {du_dx:.6f}   dv/dy = {dv_dy:.6f}   → égaux : {abs(du_dx - dv_dy) < 1e-5}")
print(f"  du/dy = {du_dy:.6f}  -dv/dx = {-dv_dx:.6f}   → égaux : {abs(du_dy + dv_dx) < 1e-5}")

# Visualisation du module |f(z)| sur C
x = np.linspace(-2, 2, 300)
y = np.linspace(-2, 2, 300)
X, Y = np.meshgrid(x, y)
Z = (X + 1j*Y)**2
module = np.abs(Z)

plt.figure(figsize=(7, 6))
plt.contourf(X, Y, module, levels=30, cmap='plasma')
plt.colorbar(label='|f(z)| = |z²|')
plt.xlabel('Re(z)')
plt.ylabel('Im(z)')
plt.title('Module de f(z) = z² — fonction holomorphe\n(les lignes de niveau sont des cercles)')
plt.tight_layout()
plt.savefig("niveau2_holomorphie.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau2_holomorphie.png")

📖 PARTIE 2 — Théorème de Cauchy et formule intégrale

2.1 Rappel théorique

Théorème de Cauchy : Si $f$ est holomorphe à l'intérieur et sur un contour fermé $\gamma$, alors :

$$\oint_{\gamma} f(z) dz = 0$$

Intuition : une fonction holomorphe n'a "aucune information cachée" à l'intérieur — la valeur sur le bord détermine tout.

2.2 Formule intégrale de Cauchy

Conséquence directe : si $f$ est holomorphe et $z_0$ est à l'intérieur de $\gamma$, alors :

$$f(z_0) = \frac{1}{2\pi i} \oint_{\gamma} \frac{f(z)}{z - z_0} dz$$

Ce que cela signifie : la valeur de $f$ en un seul point est déterminée par ses valeurs sur n'importe quel contour qui l'entoure.

2.3 Conséquence fondamentale — développement en série entière

Toute fonction holomorphe est développable en série de Taylor :

$$f(z) = \sum_{n=0}^{\infty} \frac{f^{(n)}(z_0)}{n!}(z - z_0)^n$$

Ce développement converge dans tout disque ne contenant pas de singularité.

2.4 Exemple à la main — intégrale sur un cercle

Calculons $\displaystyle\oint_{|z|=1} \frac{1}{z} dz$.

On paramétrise $z = e^{i\theta}$, $dz = ie^{i\theta} d\theta$, $\theta \in [0, 2\pi]$ :

$$\oint_{|z|=1} \frac{1}{z} dz = \int_0^{2\pi} \frac{1}{e^{i\theta}} \cdot ie^{i\theta} d\theta = \int_0^{2\pi} i d\theta = 2\pi i$$

La fonction $1/z$ n'est pas holomorphe en $z = 0$ — le théorème de Cauchy ne s'applique pas, et l'intégrale vaut $2\pi i \neq 0$.

2.5 Code Python — intégration numérique sur un contour

from mpmath import mp, mpc, exp, pi, quad, log, re, im
import numpy as np
import matplotlib.pyplot as plt

mp.dps = 15

def integrer_contour(f, centre, rayon, n_points=1000):
    """Intégrale numérique de f sur un cercle de centre et rayon donnés."""
    thetas = np.linspace(0, 2*np.pi, n_points, endpoint=False)
    dtheta = 2*np.pi / n_points
    resultat = mpc(0)
    for theta in thetas:
        z = centre + rayon * exp(mpc(0, theta))
        dz = mpc(0, 1) * rayon * exp(mpc(0, theta)) * dtheta
        resultat += f(z) * dz
    return resultat

# Test 1 : f(z) = 1/z  →  devrait donner 2πi
f1 = lambda z: 1/z
I1 = integrer_contour(f1, mpc(0,0), 1.0)
print(f"∮ 1/z dz  sur |z|=1 :")
print(f"  Résultat numérique : {float(re(I1)):.6f} + {float(im(I1)):.6f}i")
print(f"  Valeur exacte      : 0 + {float(2*pi):.6f}i  (= 2πi)")

# Test 2 : f(z) = z²  →  devrait donner 0 (f holomorphe)
f2 = lambda z: z**2
I2 = integrer_contour(f2, mpc(0,0), 1.0)
print(f"\n∮ z² dz  sur |z|=1 :")
print(f"  Résultat numérique : {float(re(I2)):.2e} + {float(im(I2)):.2e}i")
print(f"  Valeur exacte      : 0 (théorème de Cauchy)")

# Test 3 : formule intégrale — récupérer f(z0) = z0² = (0.5+0.3i)²
z0 = mpc(0.5, 0.3)
f3 = lambda z: z**2 / (z - z0)
I3 = integrer_contour(f3, mpc(0,0), 1.0)
f_reconstitue = I3 / (2 * pi * mpc(0,1))
f_exact = z0**2
print(f"\nFormule intégrale de Cauchy pour f(z)=z², z0={z0}:")
print(f"  f(z0) reconstruit  : {float(re(f_reconstitue)):.6f} + {float(im(f_reconstitue)):.6f}i")
print(f"  f(z0) exact        : {float(re(f_exact)):.6f} + {float(im(f_exact)):.6f}i")

📖 PARTIE 3 — Principe du prolongement analytique

3.1 Rappel théorique

Principe du prolongement analytique : si deux fonctions holomorphes $f$ et $g$ coïncident sur un sous-ensemble ayant un point d'accumulation (par exemple un segment ou un disque), alors $f = g$ partout où elles sont toutes deux définies.

Conséquence : si une fonction holomorphe est connue sur un domaine $D$, son extension à un domaine plus grand $D' \supset D$ est unique.

3.2 Procédé concret — disques de convergence enchaînés

On part d'une série $\sum a_n (z-z_0)^n$ convergente dans un disque $|z - z_0| &lt; R$. En un point $z_1$ à l'intérieur de ce disque, on développe en une nouvelle série :

$$f(z) = \sum_{n=0}^{\infty} b_n (z - z_1)^n$$

convergente dans un disque centré en $z_1$, qui peut déborder du disque initial. On a ainsi étendu $f$ à un nouveau domaine.

   Disque initial          Nouveau disque
   centré en z0            centré en z1
   ___________             ___________
  /           \           /           \
 /    z0       \    z1   /             \
|       •      |---•----|      •       |
 \             /         \             /
  \___________|_____       \___________|
              |   prolongement
              |   vers un nouveau domaine

3.3 Identité de réflexion de Schwarz

Un cas particulier important : si $f$ est holomorphe sur le demi-plan supérieur et réelle sur l'axe réel, alors elle se prolonge au demi-plan inférieur par :

$$f(\bar{z}) = \overline{f(z)}$$

C'est exactement la propriété qu'on utilise pour ζ : puisque $\zeta(s)$ est réelle pour $s$ réel, son prolongement vérifie $\zeta(\bar{s}) = \overline{\zeta(s)}$.

3.4 Exemple à la main — prolongement de $\sum z^n$

La série géométrique converge pour $|z| &lt; 1$ :

$$\sum_{n=0}^{\infty} z^n = \frac{1}{1-z} \qquad \text{si } |z| < 1$$

La fonction $\dfrac{1}{1-z}$ est, elle, holomorphe sur $\mathbb{C} \setminus {1}$ — donc sur un domaine bien plus grand que le disque unité. C'est le prolongement analytique de la série.

La série diverge pour $|z| \geq 1$, mais sa valeur "naturelle" reste $\frac{1}{1-z}$ — par exemple :

$$\sum_{n=0}^{\infty} (-1)^n \stackrel{\text{prolongement}}{=} \frac{1}{1-(-1)} = \frac{1}{2}$$

3.5 Code Python — visualisation du prolongement

from mpmath import mp, mpc, fabs
import numpy as np
import matplotlib.pyplot as plt

mp.dps = 15

# Comparaison : somme partielle vs fonction prolongée 1/(1-z)
def serie_geometrique(z, N=50):
    s = mpc(0)
    zn = mpc(1)
    for n in range(N):
        s += zn
        zn *= z
        if fabs(zn) > 1e10:  # divergence
            return None
    return s

x = np.linspace(-2, 2, 400)
y = np.linspace(-2, 2, 400)
X, Y = np.meshgrid(x, y)
Z_exact = 1.0 / (1.0 - (X + 1j*Y))
module_exact = np.abs(Z_exact)
module_exact = np.clip(module_exact, 0, 10)

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# Prolongement analytique 1/(1-z)
ax1 = axes[0]
cf1 = ax1.contourf(X, Y, module_exact, levels=30, cmap='viridis')
plt.colorbar(cf1, ax=ax1, label='|1/(1-z)|')
circle = plt.Circle((0,0), 1, color='red', fill=False, linewidth=2, label='|z|=1 (bord de convergence)')
ax1.add_patch(circle)
ax1.plot(1, 0, 'r*', markersize=15, label='Pôle en z=1')
ax1.set_xlim(-2, 2)
ax1.set_ylim(-2, 2)
ax1.set_aspect('equal')
ax1.set_title('Prolongement analytique de Σzⁿ\nFonction 1/(1−z) sur C\\{1}')
ax1.set_xlabel('Re(z)')
ax1.set_ylabel('Im(z)')
ax1.legend(fontsize=8)
ax1.grid(True, alpha=0.2)

# Domaine de convergence de la série
ax2 = axes[1]
module_serie = np.where(X**2 + Y**2 < 1, module_exact, np.nan)
cf2 = ax2.contourf(X, Y, module_serie, levels=30, cmap='viridis')
plt.colorbar(cf2, ax=ax2, label='|Σzⁿ| (série tronquée)')
circle2 = plt.Circle((0,0), 1, color='red', fill=False, linewidth=2)
ax2.add_patch(circle2)
ax2.set_xlim(-2, 2)
ax2.set_ylim(-2, 2)
ax2.set_aspect('equal')
ax2.set_title('Série Σzⁿ — converge seulement\npour |z| < 1 (disque rouge)')
ax2.set_xlabel('Re(z)')
ax2.set_ylabel('Im(z)')
ax2.grid(True, alpha=0.2)

plt.tight_layout()
plt.savefig("niveau2_prolongement.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau2_prolongement.png")

📖 PARTIE 4 — Prolongement analytique de $\zeta(s)$ au-delà de $\text{Re}(s) &gt; 1$

4.1 Le problème : la série diverge pour $\text{Re}(s) \leq 1$

La définition par série :

$$\zeta(s) = \sum_{n=1}^{\infty} \frac{1}{n^s} \qquad \text{converge si et seulement si } \text{Re}(s) > 1$$

Pour $s = 1$ : série harmonique $\sum 1/n = +\infty$ — pôle. Pour $\text{Re}(s) \leq 1$, $s \neq 1$ : la série diverge, mais $\zeta(s)$ a quand même une valeur au sens du prolongement analytique.

4.2 Première extension — formule d'Euler-Maclaurin

Une première façon d'étendre $\zeta(s)$ à $\text{Re}(s) &gt; 0$, $s \neq 1$ :

$$\zeta(s) = \frac{s}{s-1} - s \int_1^{\infty} \frac{{x}}{x^{s+1}} dx$$

où ${x} = x - \lfloor x \rfloor$ est la partie fractionnaire de $x$. Cette formule converge pour $\text{Re}(s) &gt; 0$ et coïncide avec la série pour $\text{Re}(s) &gt; 1$.

4.3 Équation fonctionnelle de Riemann ⭐

Le prolongement à tout $\mathbb{C} \setminus {1}$ est donné par l'équation fonctionnelle :

$$\zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s)$$

Ce que cela signifie : connaître $\zeta(s)$ pour $\text{Re}(s) &gt; 1$ suffit à déterminer $\zeta(s)$ pour $\text{Re}(s) &lt; 0$ via cette symétrie.

La droite critique $\text{Re}(s) = \tfrac{1}{2}$ est le centre de symétrie de cette équation — c'est précisément là que l'hypothèse de Riemann place tous les zéros non triviaux.

4.4 Structure de $\zeta(s)$ sur $\mathbb{C}$

Région Comportement de $\zeta(s)$
$\text{Re}(s) &gt; 1$ Série convergente $\sum 1/n^s$
$s = 1$ Pôle simple, résidu $= 1$
$0 &lt; \text{Re}(s) &lt; 1$ Zone critique — zéros non triviaux
$\text{Re}(s) = \tfrac{1}{2}$ Droite critique — HR : tous les zéros y sont
$s = -2, -4, -6, \ldots$ Zéros triviaux
$\text{Re}(s) &lt; 0$ Défini par l'équation fonctionnelle

4.5 Valeurs remarquables du prolongement

Les valeurs de $\zeta(s)$ pour $s \leq 0$ obtenues par prolongement :

$$\zeta(0) = -\frac{1}{2} \qquad \zeta(-1) = -\frac{1}{12} \qquad \zeta(-2) = 0 \qquad \zeta(-3) = \frac{1}{120}$$

La valeur $\zeta(-1) = -\tfrac{1}{12}$ est la signification rigoureuse de la "somme" $1 + 2 + 3 + \cdots$ au sens du prolongement analytique — non pas une somme ordinaire.

4.6 Code Python — visualisation de $\zeta(s)$ sur tout $\mathbb{C}$

from mpmath import mp, mpc, zeta, re, im, fabs, log, pi
import numpy as np
import matplotlib.pyplot as plt
import warnings

mp.dps = 15

# Valeurs remarquables du prolongement
print("Valeurs de ζ(s) par prolongement analytique :")
print(f"{'s':<12} | {'Re(ζ(s))':>14} | {'Im(ζ(s))':>14} | Note")
print("-" * 65)
points = [
    (mpc(2,   0),   "ζ(2) = π²/6"),
    (mpc(0,   0),   "ζ(0) = -1/2"),
    (mpc(-1,  0),   "ζ(-1) = -1/12"),
    (mpc(-2,  0),   "ζ(-2) = 0 (zéro trivial)"),
    (mpc(-3,  0),   "ζ(-3) = 1/120"),
    (mpc(0.5, 14.1347), "premier zéro non trivial"),
]
for s, note in points:
    try:
        val = zeta(s)
        print(f"s={s!r:<10} | {float(re(val)):>+14.6f} | {float(im(val)):>+14.6f} | {note}")
    except Exception:
        print(f"s={s!r:<10} | {'(pôle)':>14} | {'':>14} | {note}")

# Carte du module |ζ(s)| dans la bande critique
sigma = np.linspace(-1, 3, 400)
t     = np.linspace(0.5, 40, 400)
S, T  = np.meshgrid(sigma, t)

module = np.zeros_like(S)
for i in range(len(t)):
    for j in range(len(sigma)):
        try:
            val = zeta(mpc(S[i,j], T[i,j]))
            module[i,j] = min(float(fabs(val)), 5)
        except Exception:
            module[i,j] = 5

fig, ax = plt.subplots(figsize=(10, 7))
cf = ax.contourf(S, T, module, levels=40, cmap='hot_r')
plt.colorbar(cf, ax=ax, label='|ζ(s)| (écrêté à 5)')

# Droite critique
ax.axvline(0.5, color='cyan', linewidth=2, linestyle='--', label='Droite critique Re(s)=1/2')
# Bord de convergence de la série
ax.axvline(1.0, color='lime', linewidth=2, linestyle='--', label='Re(s)=1 (bord série)')

# Zéros connus
zeros_t = [14.1347, 21.0220, 25.0109, 30.4249, 32.9351]
for t_zero in zeros_t:
    ax.plot(0.5, t_zero, 'b*', markersize=12)
ax.plot([], [], 'b*', markersize=12, label='Zéros non triviaux')

ax.set_xlabel('Re(s) = σ', fontsize=12)
ax.set_ylabel('Im(s) = t', fontsize=12)
ax.set_title('Module |ζ(s)| dans la bande 0 < Re(s) < 1\nProlongement analytique au-delà de Re(s) > 1', fontsize=11)
ax.legend(loc='upper right', fontsize=9)
ax.grid(True, alpha=0.2)

plt.tight_layout()
plt.savefig("niveau2_zeta_bande_critique.png", dpi=150)
plt.show()
print("Graphique sauvegardé : niveau2_zeta_bande_critique.png")

✏️ Exercices de cette session

Exercice 1 — Conditions de Cauchy-Riemann

Vérifiez à la main que $f(z) = e^z$ satisfait les conditions de Cauchy-Riemann.

Indication : $e^{x+iy} = e^x \cos y + i e^x \sin y$, donc $u = e^x \cos y$, $v = e^x \sin y$.

Exercice 2 — Intégrale de contour

Calculez numériquement $\displaystyle\oint_{|z|=2} \frac{1}{z^2 - 1} dz$.

Indication : la fonction a des pôles en $z = \pm 1$, tous deux à l'intérieur du cercle $|z|=2$. Utilisez la fonction integrer_contour du code de la Partie 2 et comparez au résultat théorique.

Exercice 3 — Prolongement de la série

Calculez $\zeta(-1)$ par l'équation fonctionnelle :

$$\zeta(-1) = 2^{-1} \pi^{-2} \sin\left(\frac{-\pi}{2}\right) \Gamma(2) \zeta(2)$$

et vérifiez que vous obtenez $-\tfrac{1}{12}$.

from mpmath import mp, zeta, pi, gamma, sin
mp.dps = 15
s = -1
val = 2**s * pi**(s-1) * sin(pi*s/2) * gamma(1-s) * zeta(1-s)
print(f"ζ(-1) via équation fonctionnelle = {float(val):.8f}")
print(f"ζ(-1) via mpmath directement     = {float(zeta(-1)):.8f}")

Exercice 4 — Connexion ζ

Vérifiez numériquement que $\zeta\left(\tfrac{1}{2} + 14{,}1347i\right) \approx 0$ (premier zéro non trivial), et que la série $\sum 1/n^s$ diverge pour ce même $s$.

from mpmath import mp, mpc, zeta
mp.dps = 20
s = mpc(0.5, 14.134725141734693)
print(f"|ζ(1/2 + 14.13...i)| = {abs(zeta(s)):.2e}")

🗺️ Carte mentale de cette session

graph TD
    A["Fonction holomorphe\nf'(z) existe pour tout z"] --> B["Conditions Cauchy-Riemann\n∂u/∂x = ∂v/∂y"]
    A --> C["Développable en série entière"]
    C --> D["Théorème de Cauchy\n∮ f dz = 0"]
    D --> E["Formule intégrale\nf(z0) = 1/(2πi) ∮ f(z)/(z-z0) dz"]
    E --> F["Principe de prolongement\nanalytique — unicité"]
    F --> G["ζ(s) = Σ 1/nˢ pour Re(s) > 1"]
    G --> H["Pôle simple en s=1"]
    G --> I["Prolongement à C\\{1}"]
    I --> J["Équation fonctionnelle\nζ(s) = 2ˢπˢ⁻¹ sin(πs/2) Γ(1-s) ζ(1-s)"]
    J --> K["Symétrie autour de Re(s)=1/2"]
    K --> L["Zéros non triviaux\ndans 0 < Re(s) < 1"]
    L --> M["Hypothèse de Riemann :\ntous sur Re(s) = 1/2"]
Loading

📌 Résumé clé

Concept Formule Rôle dans ζ
Holomorphie $f'(z_0) = \lim_{h\to 0} \frac{f(z_0+h)-f(z_0)}{h}$ ζ(s) est holomorphe pour Re(s) > 1
Cauchy-Riemann $\partial_x u = \partial_y v$, $\partial_y u = -\partial_x v$ Condition équivalente à l'holomorphie
Théorème de Cauchy $\oint_\gamma f dz = 0$ Régularité globale des fonctions holomorphes
Formule intégrale $f(z_0) = \frac{1}{2\pi i}\oint \frac{f(z)}{z-z_0} dz$ Base du prolongement analytique
Prolongement Unicité de l'extension holomorphe ζ(s) défini sur $\mathbb{C}\setminus{1}$
Équation fonctionnelle $\zeta(s) = 2^s\pi^{s-1}\sin(\tfrac{\pi s}{2}) \Gamma(1-s) \zeta(1-s)$ Symétrie autour de Re(s) = 1/2
Pôle de ζ $\text{Res}_{s=1} \zeta(s) = 1$ Seule singularité de ζ sur $\mathbb{C}$

Prochaine session : Fonction Γ et séries de Dirichlet — vers la démonstration de l'équation fonctionnelle de $\zeta(s)$.


Dernière mise à jour : 22 mai 2026 — 518 lignes

Clone this wiki locally