de java à swift en 2 temps trois mouvements
TRANSCRIPT
![Page 1: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/1.jpg)
DE JAVA À SWIFT EN 2 TEMPS
TROIS MOUVEMENTS
3 novembre 2016 ( )Didier Plaindoux @dplaindoux
![Page 2: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/2.jpg)
Computer scientist Freelance
λ
![Page 3: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/3.jpg)
Développement lancé en 2010 par Chris Lattner
HISTORIQUE DE SWIFT
v1.0: Dévoilé durant la WWDC en 2014v2.0: Ouverture du compilateur en 2015v3.0: Publication en septembre 2016
![Page 4: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/4.jpg)
DÉVELOPPER AVEC SWIFT
XCode
CLion
Vi, Emacs
![Page 5: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/5.jpg)
EXÉCUTER SWIFT
iOS, OSX
Version 14.04+
(Docker)
IBM Cloud (LinuxOne)
![Page 6: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/6.jpg)
LANGAGE INSPIRÉ PAR ...
Objective-C C#
Orienté Objet
Haskell OCaml
Fonctionnel
Ruby Python
Expressivité
![Page 7: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/7.jpg)
MÉTAMORPHOSE D'UNE CLASSE JAVA
public class Personne { private final String nom; private int age;
public Personne(String nom, int age) { this.nom = nom; this.age = age; }
public void anniversaire() { this.age += 1; } }
![Page 8: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/8.jpg)
SÉPARATEURS
public class Personne { private final String nom private int age
public Personne(String nom, int age) { this.nom = nom this.age = age } public void anniversaire() { this.age += 1 } }
![Page 9: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/9.jpg)
ATTRIBUTS
public class Personne { private let nom:String // Constant private var age:Int // Variable
public Personne(String nom, int age) { this.nom = nom this.age = age }
public void anniversaire() { this.age += 1 } }
![Page 10: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/10.jpg)
PARAMÈTRES
public class Personne { private let nom:String private var age:Int
public Personne(nom:String, age:Int) { this.nom = nom this.age = age }
public void anniversaire() { this.age += 1 } }
![Page 11: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/11.jpg)
INITIALISATION
public class Personne { private let nom:String private var age:Int
public init(nom:String, age:Int) { this.nom = nom this.age = age }
public void anniversaire() { this.age += 1 } }
![Page 12: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/12.jpg)
FONCTION
public class Personne { private let nom:String private var age:Int
public init(nom:String, age:Int) { this.nom = nom this.age = age }
public func anniversaire() -> Void { this.age += 1 } }
![Page 13: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/13.jpg)
FONCTION OU PROCÉDURE
public class Personne { private let nom:String private var age:Int
public init(nom:String, age:Int) { this.nom = nom this.age = age }
public func anniversaire() { this.age += 1 } }
![Page 14: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/14.jpg)
UNE CLASSE SWIFT
public class Personne { private let nom:String private var age:Int
public init(nom:String, age:Int) { self.nom = nom self.age = age }
public func anniversaire() { self.age += 1 } }
![Page 15: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/15.jpg)
SURVOL DU LANGAGE
![Page 16: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/16.jpg)
DONNÉES, TYPES INITIAUX ETC.
Le Fonctionnel
Les Objets
![Page 17: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/17.jpg)
VARIABLES OU CONSTANTES
JAVA SWIFT
int age
final String nom
var age:Int
let nom:String
![Page 18: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/18.jpg)
LES COLLECTIONS
JAVA SWIFT
Arrays.asList("Hello", "World")
Map<String, Integer> m = new HashMap<>(); m.put("A", 10); m.put("B", 20);
["Hello", "World"]
["A":10, "B":20]
Fonctions disponibles map, �atMap, �lter etc.
![Page 19: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/19.jpg)
DONNÉE OPTIONNELLE
JAVA SWIFT
Optional<String> n = Optional.of("A"); Optional<Integer> t = n.map(v -> v.length()); if (t.isPresent()) { // t.get(); }
let n:String? = "A" // ou nil let t:Int? = n?.characters.count if let taille = t { // taille utilisable }
Fonctions disponibles map, �atMap, �lter etc.
Donnée optionnelle "portée" par le typage uniquement. Non structurel !
![Page 20: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/20.jpg)
TUPLES
JAVA
∅
SWIFT
Index ↔ Nom
(42, "John Doe") // (Int, String) (42, "John Doe").1 == "John Doe"
(42, nom:"John Doe") // (Int, String) (42, nom:"John Doe").1 == "John Doe" (42, nom:"John Doe").nom == "John Doe"
![Page 21: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/21.jpg)
STRUCTURES DE CONTRÔLE
Sélection conditionnelle
Garde pour les optionnels
Répétition
if expression { // bloc en cas de succés } else { // bloc optionnel en cas d'échec }
guard let valeur = expression else { // valeur n'est pas définie }
// valeur est définie
let segment = 0..<100 for index in segment { // bloc répété}
![Page 22: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/22.jpg)
Données, Types initiaux etc.
LE FONCTIONNEL
Les Objets
![Page 23: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/23.jpg)
TYPE FONCTIONNEL
JAVA SWIFT
Type aliasing
Function<A,B> Supplier<B> Consumer<A> Predicate<A> ...
(A) -> B () -> B (A) -> () (A) -> Bool ...
typealias Supplier<B> = () -> B
![Page 24: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/24.jpg)
FONCTION
func Nom(Parametres) -> Type Resultat { Corps De La Fonction }
![Page 25: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/25.jpg)
FONCTION :: PARAMÈTRES
func multiplier(a:Int, b:Int) -> Int { return a * b }
En interne les noms des paramètres capturent les valeurs lors de l'appel
multiplier(a:2, b:3)
En externe les noms des paramètres servent de "marques" pour les arguments
Permutation des arguments interdite
![Page 26: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/26.jpg)
FONCTION :: NOM EXTERNE SPÉCIFIQUE
Spéci�cation d'un nom externe di�érent
func multiplier(a:Int, par b:Int) -> Int { return multiplier(a:a, b:b) }
multiplier(a:2, par:3)
![Page 27: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/27.jpg)
FONCTION :: AUCUN NOM EXTERNE
Spéci�cation a�n de ne pas avoir de nom externe
func multiplier( _ a:Int, par b:Int) -> Int { return multiplier(a:a, b:b) }
multiplier(2, par:3)
![Page 28: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/28.jpg)
FONCTION ANONYME :: CLOSURE
JAVA
SWIFT
[Parametres] -> [Corps De La Fonction]
{ [Parametres] -> [Type Retour] in [Corps De La Fonction] } { [Parametres] in [Corps De La Fonction] }
Objet de Première Classe
![Page 29: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/29.jpg)
CLOSURE :: EXEMPLES
let multiplier = { (a:Int, b:Int) -> Int in a * b }
Pas de séléction par nommage des paramètres car inutile !
multiplier(2,3)
![Page 30: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/30.jpg)
CLOSURE :: SYNTHÈSE DE TYPE
let multiplier = { (a:Int,b:Int) in a * b } let multiplier = { (a,b:Int) in a * b } let multiplier = { a,b -> Int in a * b }
// (Int, Int) -> Int
![Page 31: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/31.jpg)
CLOSURE :: SYNTHÈSE DE TYPE
let multiplier = { a,b in a * b }
error ambiguous use of operator '*'
Int ? Float ? Double ? ...
![Page 32: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/32.jpg)
CLOSURE :: SYNTHÈSE DE TYPE !
let multiplier : (Int,Int) -> Int = { a,b in a * b }
Spéci�cation vs. Mise en oeuvre
![Page 33: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/33.jpg)
FONCTION :: ORDRE SUPÉRIEUR
Fonction qui manipule une fonction
func appliquer(_ f:(Int) -> Int, _ a:Int) -> Int { return f(a) }
// appliquer(f,a) ⟶* f(a)
Forme restreinte au type Int → Int !
![Page 34: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/34.jpg)
FONCTION :: GÉNÉRICITÉ
Paramétrisation à la C++, Java, C#
func appliquer<A,B>(_ f:(A) -> B, _ a:A) -> B { return f(a) }
Possibilité de spéci�er des contraintes
func estEgal<A:Equatable>(_ a:A, _ b:A) -> Bool { return a == b }
![Page 35: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/35.jpg)
INCONSISTANCE & PIÈCES MANQUANTES
η-conversion pas généralisable en présence de surcharges équivalentes
Récursivité terminale Non garantie par le compilateur
Compréhension Concept inexistant
{ x in f(x) } ≡? f
![Page 36: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/36.jpg)
Données, Types initiaux etcs.
Le Fonctionnel
LES OBJETS
![Page 37: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/37.jpg)
LES OBJETS
Ecole Scandinave
Simula, C++, Objective-C, Ei�el, Java, C# ... Swift
Abstraction de donnée ↔ Classe ↔ Type
Repose sur un Typage Statique
![Page 38: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/38.jpg)
PARADIGME OBJET
JAVA SWIFT
Interface Protocole
Classe Classe
∅ Structure
Enumération Enumération
![Page 39: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/39.jpg)
PROTOCOLE
Base de connaissancesExtension de Protocoles
![Page 40: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/40.jpg)
PROTOCOLE :: BASE DE CONNAISSANCES
public protocol Monde { func vivants() -> [Personne] func recherche(nom:String) -> Personne? }
![Page 41: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/41.jpg)
PROTOCOLE :: MISE EN OEUVRE
extension Monde { func recherche(nom:String) -> Personne? { return vivants().filter{ p in p.nom == nom }.first } }
Assimilable au "default" des interfaces dans Java 8
Idem pour les classes, structures et enumérations
![Page 42: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/42.jpg)
PROTOCOLE :: GÉNÉRICITÉ
protocol Copiable { associatedtype E func copier<C:Copiable where C.E == E>() -> C // 0_o }
Spéci�cation de Type Membre ≢ Paramétrisation
Spécialisation par le typealias
![Page 43: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/43.jpg)
CLASSE
Etat interneBase de connaissancesHéritage simpleMise en oeuvre de Protocoles
![Page 44: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/44.jpg)
CLASSE :: ETAT INTERNE & INITIALISATION
public class Personne { private let nom:String private var age:Int
public init(nom:String, age:Int) { self.nom = nom self.age = age } }
Pas de mot clé new
Personne(nom:"John Doe", age:42)
![Page 45: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/45.jpg)
CLASSE :: INITIALISATION & OPTIONNEL
Initialisation pouvant retourner nil
public class Personne { private let nom:String private var age:Int
public init?(nom:String, age:Int) { guard age > -1 else { return nil } // if age < 0 { return nil }
self.nom = nom self.age = age } }
let personne:Personne? = Personne(nom:"John Doe", age:-1)
![Page 46: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/46.jpg)
CLASSE :: BASE DE CONNAISSANCES
Méthode d'instance(surchargeable)
Méthode statique(non surchargeable)
Méthode de classe(surchargeables)
class Personne { ⊞ ... func aPourNom() -> String { return self.nom } }
class Personne { ⊞ ... static func new(nom:String) -> Personne {...} }
class Personne { ⊞ ... class func new(nom:String) -> Personne {...} }
![Page 47: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/47.jpg)
CLASSE :: REFERENCE TYPEpublic class Personne { private let nom:String private var age:Int
⊞ public init(nom:String, age:Int) { ... } }
let personne1 = Personne(nom:"John Doe", age:42)let personne2 = personne1
personne1 et personne2 référencent la même donnée en mémoire
![Page 48: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/48.jpg)
STRUCTURE
Etat interneBase de connaissancesMise en oeuvre de Protocoles
![Page 49: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/49.jpg)
STRUCTURE :: INITIALISATION
public struct Personne { let nom:String var age:Int }
Méthode init implicite. Redé�nition possible.
Personne(nom:"John Doe", age:42)
![Page 50: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/50.jpg)
STRUCTURE :: REFERENCE VALUEvar personne1 = Personne(nom:"John Doe", age:42)let personne2 = personne1
personne1.age += 1
// personne1.age == 43 // personne2.age == 42
personne1 et personne2 ne référencent pas la même donnée en mémoire
![Page 51: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/51.jpg)
ENUMÉRATION
Spéci�cation de formesEtat interneBase de connaissancesMise en oeuvre de Protocoles
![Page 52: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/52.jpg)
ENUMÉRATION :: SPÉCIFICATION DE FORMES
public enum StadePersonne { case Enfant, Adolescent, Adulte }
let s : StadePersonne = ... switch s { case StadePersonne.Enfant: // ... case StadePersonne.Adolescent: // ... case StadePersonne.Adulte: // ... }
Le switch/case doit être exhaustif / Véri�é à la compilation
![Page 53: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/53.jpg)
ENUMÉRATION :: SWITCH AVANCÉ
public enum PeutEtre<T> { case QuelqueChose(value:T), Rien
public func get(_ valeurParDefaut:T) -> T { switch self { case .QuelqueChose(let v): return v case _: return valeurParDefaut } } }
Pattern Matching
![Page 54: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/54.jpg)
self ou ... Self
![Page 55: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/55.jpg)
self : Self
public class Personne { private let nom:String private var age:Int
⊞ public init(nom:String) { ... }
public func anniversaire() -> Self { self.age += 1 return self } }
Le type Self dénote le type de l'objet courant à savoir ... self
![Page 56: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/56.jpg)
DÉNOTATION DU TYPE COURANT
JAVA SWIFT
interface Copiable<Self extends Copiable<Self>> { Self copie(); }
protocol Copiable { func copie() -> Self }
"F-Bounded quanti�cation polymorphism"
![Page 57: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/57.jpg)
SELF :: COPIABLE
class Personne : Copiable { private let nom:String private var age:Int
func copie() -> Self { return type(of:self).init(nom:self.nom, age:self.age) }
required init(nom:String, age:Int) { self.nom = nom self.age = 0 } }
required force la dé�nition dans les sous-classes
![Page 58: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/58.jpg)
SELF :: INITIALISATION
class Personne { private let nom:String private var age:Int
required init(nom:String, age:Int) { self.nom = nom self.age = 0 }
class func new(nom:String) -> Self { return self.init(nom:nom, age:0) // self ≡ Personne } }
Cela me rappelle furieusement le new de Perl !
![Page 59: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/59.jpg)
UN TOUR D'HORIZON (TROP) RAPIDE !
Gestion des erreursStructure & MutationNotion de moduleSwift & Android via le NDK (Swift ⇒ C)etc ...
![Page 60: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/60.jpg)
PROSÉLYTISME !
Meetup !
Site o�cielA curated list of awesome iOS ecosystem
![Page 61: De java à swift en 2 temps trois mouvements](https://reader036.vdocuments.pub/reader036/viewer/2022062600/5a66be2a7f8b9a21208b4813/html5/thumbnails/61.jpg)
MERCI