diff --git a/src/main/java/agency/AbstractVehicle.java b/src/main/java/agency/AbstractVehicle.java
new file mode 100644
index 0000000000000000000000000000000000000000..b84af77254c843db5fd7fc486fd4d9894e0fdf98
--- /dev/null
+++ b/src/main/java/agency/AbstractVehicle.java
@@ -0,0 +1,54 @@
+package agency;
+
+import util.TimeProvider;
+
+public abstract class AbstractVehicle implements Vehicle {
+    protected String brand;
+    protected String model;
+    protected int productionYear;
+
+    protected static final int MINIMAL_YEAR_VALUE = 1900;
+
+    public AbstractVehicle(String brand, String model, int productionYear) {
+        int currentYear = TimeProvider.currentYearValue();
+        if (productionYear < MINIMAL_YEAR_VALUE || productionYear > currentYear) {
+            throw new IllegalArgumentException("Invalid production year: " + productionYear);
+        }
+        this.brand = brand;
+        this.model = model;
+        this.productionYear = productionYear;
+    }
+
+    @Override
+    public String getBrand() {
+        return brand;
+    }
+
+    @Override
+    public String getModel() {
+        return model;
+    }
+
+    @Override
+    public int getProductionYear() {
+        return productionYear;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AbstractVehicle that = (AbstractVehicle) o;
+
+        return productionYear == that.productionYear &&
+                brand.equals(that.brand) &&
+                model.equals(that.model);
+    }
+
+    @Override
+    public abstract String toString();
+
+    @Override
+    public abstract double dailyRentalPrice();
+}
\ No newline at end of file
diff --git a/src/main/java/agency/App.java b/src/main/java/agency/App.java
index fdd6a397c562be765ea6826b2102797f872237fe..71857b84a944befab9818c4a1313601dcfa00a65 100644
--- a/src/main/java/agency/App.java
+++ b/src/main/java/agency/App.java
@@ -1,7 +1,52 @@
 package agency;
 
+import java.util.List;
+
 public class App {
-  public static void main(String[] args){
+  public static void main(String[] args) {
+    Vehicle car1 = new Car("Toyota", "Corolla", 2020, 5);  // Prix : 200.0€
+    Vehicle car2 = new Car("Ford", "Focus", 2018, 4);      // Prix : 160.0€
+    Vehicle car3 = new Car("Toyota", "Yaris", 2015, 3);    // Prix : 60.0€
+
+    RentalAgency agency = new RentalAgency(List.of(car1, car2, car3));
+
+    Client client1 = new Client("John", "Doe", 1990);
+    Client client2 = new Client("Anna", "Smith", 1985);
+
+    System.out.println("Véhicules disponibles dans l'agence :");
+    agency.getVehicles().forEach(System.out::println);
+
+    try {
+      double price = agency.rentVehicle(client1, car1);
+      System.out.println(client1.getFirstName() + " " + client1.getLastName() + " a loué " + car1 + " pour " + price + "€.");
+    } catch (Exception e) {
+      System.out.println("Erreur lors de la location : " + e.getMessage());
+    }
+
+    System.out.println("Car1 est-il loué ? " + agency.vehicleIsRented(car1)); // true
+
+    try {
+      agency.rentVehicle(client2, car1);
+    } catch (Exception e) {
+      System.out.println("Erreur pour " + client2.getFirstName() + " : " + e.getMessage());
+    }
+
+    try {
+      double price = agency.rentVehicle(client2, car2);
+      System.out.println(client2.getFirstName() + " " + client2.getLastName() + " a loué " + car2 + " pour " + price + "€.");
+    } catch (Exception e) {
+      System.out.println("Erreur lors de la location : " + e.getMessage());
+    }
+
+    System.out.println("Véhicules actuellement loués :");
+    agency.allRentedVehicles().forEach(System.out::println);
+
+    agency.returnVehicle(client1);
+    System.out.println(client1.getFirstName() + " " + client1.getLastName() + " a rendu sa voiture.");
+
+    System.out.println("Car1 est-il encore loué ? " + agency.vehicleIsRented(car1)); // false
 
+    System.out.println("Véhicules actuellement loués après retour :");
+    agency.allRentedVehicles().forEach(System.out::println);
   }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/agency/BrandCriterion.java b/src/main/java/agency/BrandCriterion.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f235409092e6490b71ff1a2b635afde3c37dac5
--- /dev/null
+++ b/src/main/java/agency/BrandCriterion.java
@@ -0,0 +1,26 @@
+import agency.Vehicle;
+
+import java.util.function.Predicate;
+
+public class BrandCriterion implements Predicate<Vehicle> {
+    private final String brand;
+
+    public BrandCriterion(String brand) {
+        if (brand == null || brand.isEmpty()) {
+            throw new IllegalArgumentException("The brand cannot be null or empty.");
+        }
+        this.brand = brand;
+    }
+
+    @Override
+    public boolean test(Vehicle vehicle) {
+        if (vehicle == null) {
+            return false;
+        }
+        return brand.equals(vehicle.getBrand());
+    }
+
+    public String getBrand() {
+        return brand;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/Car.java b/src/main/java/agency/Car.java
new file mode 100644
index 0000000000000000000000000000000000000000..428f6b62cedd27c560bc86541d51af5cc130b3d3
--- /dev/null
+++ b/src/main/java/agency/Car.java
@@ -0,0 +1,68 @@
+package agency;
+
+public class Car implements Vehicle {
+    private String brand;
+    private String model;
+    private int productionYear;
+    private VehiclesSpecifics specifics;
+
+    public Car(String brand, String model, int productionYear, int numberOfSeats) {
+        if (productionYear < 1900 || productionYear > util.TimeProvider.currentYearValue()) {
+            throw new IllegalArgumentException("Invalid production year: " + productionYear);
+        }
+
+        this.brand = brand;
+        this.model = model;
+        this.productionYear = productionYear;
+        this.specifics = new CarSpecifics(numberOfSeats, productionYear);
+    }
+
+    @Override
+    public String getBrand() {
+        return brand;
+    }
+
+    @Override
+    public String getModel() {
+        return model;
+    }
+
+    @Override
+    public int getProductionYear() {
+        return productionYear;
+    }
+
+    public int getNumberOfSeats() {
+        return ((CarSpecifics) specifics).getNumberOfSeats();
+    }
+
+    @Override
+    public double dailyRentalPrice() {
+        return specifics.calculateDailyRentalPrice();
+    }
+
+    public boolean isNew() {
+        if (specifics instanceof CarSpecifics) {
+            return ((CarSpecifics) specifics).isNew();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Car car = (Car) o;
+
+        return productionYear == car.productionYear &&
+                brand.equals(car.brand) &&
+                model.equals(car.model);
+    }
+
+    @Override
+    public String toString() {
+        return "Car " + brand + " " + model + " " + productionYear +
+                " (" + specifics.getDetails() + ") : " + dailyRentalPrice() + "€";
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/CarSpecifics.java b/src/main/java/agency/CarSpecifics.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f6a743b8a79c9cb84835c72d1fbb92118d974ec
--- /dev/null
+++ b/src/main/java/agency/CarSpecifics.java
@@ -0,0 +1,41 @@
+package agency;
+
+import util.TimeProvider;
+
+public class CarSpecifics implements VehiclesSpecifics {
+    private int numberOfSeats;
+    private int productionYear;
+    private static final int PRICE_PER_SEAT_FOR_OLD_CAR = 20;
+    private static final int PRICE_PER_SEAT_FOR_NEW_CAR = 40;
+
+    public CarSpecifics(int numberOfSeats, int productionYear) {
+        if (numberOfSeats < 1) {
+            throw new IllegalArgumentException("Invalid number of seats: " + numberOfSeats);
+        }
+        this.numberOfSeats = numberOfSeats;
+        this.productionYear = productionYear;
+    }
+
+    public int getNumberOfSeats() {
+        return numberOfSeats;
+    }
+
+    public int getProductionYear() {
+        return productionYear;
+    }
+
+    boolean isNew() {
+        int currentYear = TimeProvider.currentYearValue();
+        return (currentYear - productionYear) <= 5;
+    }
+
+    @Override
+    public double calculateDailyRentalPrice() {
+        return numberOfSeats * (isNew() ? PRICE_PER_SEAT_FOR_NEW_CAR : PRICE_PER_SEAT_FOR_OLD_CAR);
+    }
+
+    @Override
+    public String getDetails() {
+        return (numberOfSeats > 1 ? numberOfSeats + " seats" : "1 seat");
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/Client.java b/src/main/java/agency/Client.java
new file mode 100644
index 0000000000000000000000000000000000000000..11cb505da53832006096d3c34ca0d89c963d537f
--- /dev/null
+++ b/src/main/java/agency/Client.java
@@ -0,0 +1,57 @@
+package agency;
+
+import java.util.Objects;
+
+public class Client {
+    private final int yearOfBirth;
+    private final String lastName;
+    private final String firstName;
+
+    public Client(String firstName, String lastName, int yearOfBirth) {
+        if (yearOfBirth < 1900 || yearOfBirth > java.time.Year.now().getValue()) {
+            throw new IllegalArgumentException("Invalid year of birth: " + yearOfBirth);
+        }
+        if (lastName == null || lastName.isEmpty() || firstName == null || firstName.isEmpty()) {
+            throw new IllegalArgumentException("First name and last name cannot be null or empty.");
+        }
+        this.yearOfBirth = yearOfBirth;
+        this.lastName = lastName;
+        this.firstName = firstName;
+    }
+
+    public int getYearOfBirth() {
+        return yearOfBirth;
+    }
+
+    public String getLastName() {
+        return lastName;
+    }
+
+    public String getFirstName() {
+        return firstName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Client client = (Client) o;
+        return yearOfBirth == client.yearOfBirth &&
+                lastName.equals(client.lastName) &&
+                firstName.equals(client.firstName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(yearOfBirth, lastName, firstName);
+    }
+
+    @Override
+    public String toString() {
+        return "Client{" +
+                "yearOfBirth=" + yearOfBirth +
+                ", lastName='" + lastName + '\'' +
+                ", firstName='" + firstName + '\'' +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/IntersectionCriterion.java b/src/main/java/agency/IntersectionCriterion.java
new file mode 100644
index 0000000000000000000000000000000000000000..573674c27c95c54c2a0ebe7bb026af2de0710a32
--- /dev/null
+++ b/src/main/java/agency/IntersectionCriterion.java
@@ -0,0 +1,25 @@
+package agency;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+public class IntersectionCriterion<T> implements Predicate<T> {
+    private final List<Predicate<T>> criteria;
+
+    public IntersectionCriterion(List<Predicate<T>> criteria) {
+        if (criteria == null || criteria.isEmpty()) {
+            throw new IllegalArgumentException("The list of criteria cannot be null or empty.");
+        }
+        this.criteria = criteria;
+    }
+
+    @Override
+    public boolean test(T t) {
+        for (Predicate<T> criterion : criteria) {
+            if (!criterion.test(t)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/MaxPriceCriterion.java b/src/main/java/agency/MaxPriceCriterion.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1d6f7351c19f8b4c086bea56411d296a126a77c
--- /dev/null
+++ b/src/main/java/agency/MaxPriceCriterion.java
@@ -0,0 +1,26 @@
+import agency.Vehicle;
+
+import java.util.function.Predicate;
+
+public class MaxPriceCriterion implements Predicate<Vehicle> {
+    private final double maxPrice;
+
+    public MaxPriceCriterion(double maxPrice) {
+        if (maxPrice < 0) {
+            throw new IllegalArgumentException("The maximum price must be non-negative.");
+        }
+        this.maxPrice = maxPrice;
+    }
+
+    @Override
+    public boolean test(Vehicle vehicle) {
+        if (vehicle == null) {
+            return false;
+        }
+        return vehicle.dailyRentalPrice() <= maxPrice;
+    }
+
+    public double getMaxPrice() {
+        return maxPrice;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/Motorbike.java b/src/main/java/agency/Motorbike.java
new file mode 100644
index 0000000000000000000000000000000000000000..31a20a529516e7a7b62f51f555e65d8852b4fd65
--- /dev/null
+++ b/src/main/java/agency/Motorbike.java
@@ -0,0 +1,57 @@
+package agency;
+
+public class Motorbike implements Vehicle {
+    private String brand;
+    private String model;
+    private int productionYear;
+    private VehiclesSpecifics specifics;
+
+    public Motorbike(String brand, String model, int productionYear, int cylinderCapacity) {
+        if (productionYear < 1900 || productionYear > util.TimeProvider.currentYearValue()) {
+            throw new IllegalArgumentException("Invalid production year: " + productionYear);
+        }
+
+        this.brand = brand;
+        this.model = model;
+        this.productionYear = productionYear;
+        this.specifics = new MotorbikeSpecifics(cylinderCapacity);
+    }
+
+    @Override
+    public String getBrand() {
+        return brand;
+    }
+
+    @Override
+    public String getModel() {
+        return model;
+    }
+
+    @Override
+    public int getProductionYear() {
+        return productionYear;
+    }
+
+    @Override
+    public double dailyRentalPrice() {
+        return specifics.calculateDailyRentalPrice();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Motorbike motorbike = (Motorbike) o;
+
+        return productionYear == motorbike.productionYear &&
+                brand.equals(motorbike.brand) &&
+                model.equals(motorbike.model);
+    }
+
+    @Override
+    public String toString() {
+        return "Motorbike " + brand + " " + model + " " + productionYear +
+                " (" + specifics.getDetails() + ") : " + dailyRentalPrice() + "€";
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/MotorbikeSpecifics.java b/src/main/java/agency/MotorbikeSpecifics.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c4e4ba9d79777613cb16b3869e79178e248ca64
--- /dev/null
+++ b/src/main/java/agency/MotorbikeSpecifics.java
@@ -0,0 +1,24 @@
+package agency;
+
+public class MotorbikeSpecifics implements VehiclesSpecifics {
+    private int cylinderCapacity;
+    private static final int MINIMAL_CAPACITY = 50;
+    private static final double PRICE_PER_UNIT_OF_CYLINDER_CAPACITY = 0.25;
+
+    public MotorbikeSpecifics(int cylinderCapacity) {
+        if (cylinderCapacity < MINIMAL_CAPACITY) {
+            throw new IllegalArgumentException("Cylinder capacity too low: " + cylinderCapacity + "cm³. Minimum is " + MINIMAL_CAPACITY + "cm³.");
+        }
+        this.cylinderCapacity = cylinderCapacity;
+    }
+
+    @Override
+    public double calculateDailyRentalPrice() {
+        return cylinderCapacity * PRICE_PER_UNIT_OF_CYLINDER_CAPACITY;
+    }
+
+    @Override
+    public String getDetails() {
+        return cylinderCapacity + "cm³";
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/RentalAgency.java b/src/main/java/agency/RentalAgency.java
new file mode 100644
index 0000000000000000000000000000000000000000..21d1d8d02a5932490f7c4d642c197780c3991667
--- /dev/null
+++ b/src/main/java/agency/RentalAgency.java
@@ -0,0 +1,88 @@
+package agency;
+
+import java.util.*;
+import java.util.function.Predicate;
+
+public class RentalAgency {
+    private final List<Vehicle> vehicles;
+    private final Map<Client, Vehicle> rentedVehicles;
+
+    public RentalAgency() {
+        this.vehicles = new ArrayList<>();
+        this.rentedVehicles = new HashMap<>();
+    }
+
+    public RentalAgency(List<Vehicle> vehicles) {
+        this.vehicles = new ArrayList<>(vehicles);
+        this.rentedVehicles = new HashMap<>();
+    }
+
+    public boolean contains(Vehicle vehicle) {
+        return vehicles.contains(vehicle);
+    }
+
+    public boolean add(Vehicle vehicle) {
+        if (!vehicles.contains(vehicle)) {
+            vehicles.add(vehicle);
+            return true;
+        }
+        return false;
+    }
+
+    public void remove(Vehicle vehicle) {
+        if (!vehicles.remove(vehicle)) {
+            throw new UnknownVehicleException(vehicle);
+        }
+    }
+
+    public List<Vehicle> getVehicles() {
+        return new ArrayList<>(vehicles);
+    }
+
+    public List<Vehicle> select(Predicate<Vehicle> criterion) {
+        return vehicles.stream()
+                .filter(criterion)
+                .toList();
+    }
+
+    public void printSelectedVehicles(Predicate<Vehicle> criterion) {
+        vehicles.stream()
+                .filter(criterion)
+                .forEach(System.out::println);
+    }
+
+
+    public boolean vehicleIsRented(Vehicle vehicle) {
+        return rentedVehicles.containsValue(vehicle);
+    }
+
+
+    public boolean aVehicleIsRentedBy(Client client) {
+        return rentedVehicles.containsKey(client);
+    }
+
+
+    public double rentVehicle(Client client, Vehicle vehicle) throws UnknownVehicleException, IllegalStateException {
+        if (!vehicles.contains(vehicle)) {
+            throw new UnknownVehicleException(vehicle);
+        }
+        if (vehicleIsRented(vehicle)) {
+            throw new IllegalStateException("The vehicle is already rented.");
+        }
+        if (aVehicleIsRentedBy(client)) {
+            throw new IllegalStateException("The client is already renting another vehicle.");
+        }
+
+        rentedVehicles.put(client, vehicle);
+        return vehicle.dailyRentalPrice();
+    }
+
+
+    public void returnVehicle(Client client) {
+        rentedVehicles.remove(client);
+    }
+
+    public Collection<Vehicle> allRentedVehicles() {
+        return rentedVehicles.values();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/UnknownVehicleException.java b/src/main/java/agency/UnknownVehicleException.java
new file mode 100644
index 0000000000000000000000000000000000000000..046d0e930cc396484c59bcd919477b5e70e65be6
--- /dev/null
+++ b/src/main/java/agency/UnknownVehicleException.java
@@ -0,0 +1,18 @@
+package agency;
+
+public class UnknownVehicleException extends RuntimeException {
+    private final Vehicle vehicle;
+
+    public UnknownVehicleException(Vehicle vehicle) {
+        this.vehicle = vehicle;
+    }
+
+    @Override
+    public String getMessage() {
+        return "The vehicle does not exist in the agency!!: " + vehicle.toString();
+    }
+
+    public Vehicle getVehicle() {
+        return vehicle;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/agency/Vehicle.java b/src/main/java/agency/Vehicle.java
new file mode 100644
index 0000000000000000000000000000000000000000..11f9526ce24af2b748189b4f9b559c1b2f6d7b0d
--- /dev/null
+++ b/src/main/java/agency/Vehicle.java
@@ -0,0 +1,18 @@
+package agency;
+
+public interface Vehicle {
+
+    String getBrand();
+
+    String getModel();
+
+    int getProductionYear();
+
+    double dailyRentalPrice();
+
+    @Override
+    boolean equals(Object o);
+
+    @Override
+    String toString();
+}
\ No newline at end of file
diff --git a/src/main/java/agency/VehiclesSpecifics.java b/src/main/java/agency/VehiclesSpecifics.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3c05928f2a7a599ffa96c8fa7fdf648e6ac7dca
--- /dev/null
+++ b/src/main/java/agency/VehiclesSpecifics.java
@@ -0,0 +1,6 @@
+package agency;
+
+public interface VehiclesSpecifics {
+    double calculateDailyRentalPrice();
+    String getDetails();
+}
\ No newline at end of file
diff --git a/src/test/java/agency/TestCar.java b/src/test/java/agency/TestCar.java
index 78d80931f50a795542ecafa7b9012ca379ad7ff2..522d9d36a0328c33ae0bd33e644fef8742182513 100644
--- a/src/test/java/agency/TestCar.java
+++ b/src/test/java/agency/TestCar.java
@@ -12,8 +12,6 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
 
 
 class TestCar {
-  // TODO : décommenter le code ci-dessous pour tester la tâche 2.
-  /*
 
   Car catalinaCar = new Car(apple, catalina, catalinaYear, catalinaNumberOfSeats);
   Car windows95Car = new Car(microsoft, windows95, windows95Year, windows95NumberOfSeats);
@@ -120,5 +118,4 @@ class TestCar {
     String expectedStringWin = "Car Microsoft Windows95 1995 (1 seat) : 20.0€";
     assertThat(windows95Car).returns(expectedStringWin, Objects::toString);
   }
-  */
 }
diff --git a/src/test/java/agency/TestRentalAgency.java b/src/test/java/agency/TestRentalAgency.java
index 7ecab66602ea3ac39d1bbc906badc3c943dbabf9..3d998c10056330427b785ba6c4cf772bae8b2e26 100644
--- a/src/test/java/agency/TestRentalAgency.java
+++ b/src/test/java/agency/TestRentalAgency.java
@@ -8,8 +8,6 @@ import static org.assertj.core.api.Assertions.*;
 
 class TestRentalAgency extends agency.TestCar {
 
-  // TODO : décommenter le code ci-dessous pour tester la tâche 2.
-  /*
   private RentalAgency rentalAgency;
 
   @BeforeEach
@@ -40,21 +38,15 @@ class TestRentalAgency extends agency.TestCar {
     assertThat(rentalAgency.getVehicles()).doesNotContain(catalinaCar);
   }
 
-   */
 
-  // TODO : décommenter le code ci-dessous pour tester la méthode select.
-
-  /*
   @Test
   void testRemovingNonExistingVehicle(){
     assertThatThrownBy(() -> rentalAgency.remove(catalinaCar))
             .isInstanceOf(UnknownVehicleException.class)
             .hasMessageContaining(catalinaCar.toString());
   }
-  */
 
-  // TODO : décommenter le code ci-dessous pour tester la tâche 6.
-  /*
+
   @Test
   void testSelect(){
     rentalAgency.add(catalinaCar);
@@ -66,7 +58,6 @@ class TestRentalAgency extends agency.TestCar {
   }
 
 
-
   private Client arnaud = new Client("Arnaud", "Labourel", 1981);
   private Client paul = new Client("Paul", "Calcul", 2018);
 
@@ -102,5 +93,4 @@ class TestRentalAgency extends agency.TestCar {
             .isInstanceOf(UnknownVehicleException.class)
             .hasMessageContaining(catalinaCar.toString());
   }
-  */
 }